mite 2.5.2__tar.gz → 2.5.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. {mite-2.5.2 → mite-2.5.4}/Dockerfile.perftest +1 -1
  2. {mite-2.5.2 → mite-2.5.4}/PKG-INFO +2 -2
  3. mite-2.5.4/cd-scripts/cdBuild.sh +17 -0
  4. mite-2.5.2/cd-scripts/cdRelease.py → mite-2.5.4/cd-scripts/cdTagRelease.py +6 -0
  5. mite-2.5.2/cd-scripts/cdTagRelease.sh → mite-2.5.4/cd-scripts/lib.sh +17 -23
  6. mite-2.5.4/cd-scripts/manualRelease.sh +32 -0
  7. mite-2.5.4/cd-scripts/runTests.sh +15 -0
  8. mite-2.5.4/cd.yml +49 -0
  9. {mite-2.5.2 → mite-2.5.4}/dev-requirements.txt +1 -0
  10. {mite-2.5.2 → mite-2.5.4}/mite.egg-info/PKG-INFO +2 -2
  11. {mite-2.5.2 → mite-2.5.4}/mite.egg-info/SOURCES.txt +10 -3
  12. {mite-2.5.2 → mite-2.5.4}/mite.egg-info/requires.txt +1 -1
  13. {mite-2.5.2 → mite-2.5.4}/mite.egg-info/top_level.txt +1 -0
  14. mite-2.5.4/mite_db_datapool/README.md +45 -0
  15. mite-2.5.4/mite_db_datapool/__init__.py +8 -0
  16. mite-2.5.4/mite_db_datapool/db_to_pool.py +95 -0
  17. mite-2.5.4/mite_db_datapool/mite_db_example.py +39 -0
  18. {mite-2.5.2 → mite-2.5.4}/setup.cfg +1 -1
  19. mite-2.5.4/test/test_db_to_pool.py +155 -0
  20. {mite-2.5.2 → mite-2.5.4}/test-requirements.txt +4 -2
  21. mite-2.5.2/cd-scripts/runTests.sh +0 -31
  22. mite-2.5.2/cd.yml +0 -32
  23. {mite-2.5.2 → mite-2.5.4}/.dockerignore +0 -0
  24. {mite-2.5.2 → mite-2.5.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  25. {mite-2.5.2 → mite-2.5.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  26. {mite-2.5.2 → mite-2.5.4}/.github/pull_request_template.md +0 -0
  27. {mite-2.5.2 → mite-2.5.4}/.gitignore +0 -0
  28. {mite-2.5.2 → mite-2.5.4}/.isort.cfg +0 -0
  29. {mite-2.5.2 → mite-2.5.4}/.pre-commit-config.yaml +0 -0
  30. {mite-2.5.2 → mite-2.5.4}/.travis.yml +0 -0
  31. {mite-2.5.2 → mite-2.5.4}/CODE_OF_CONDUCT.md +0 -0
  32. {mite-2.5.2 → mite-2.5.4}/CONTRIBUTING.md +0 -0
  33. {mite-2.5.2 → mite-2.5.4}/DEV.md +0 -0
  34. {mite-2.5.2 → mite-2.5.4}/Dockerfile +0 -0
  35. {mite-2.5.2 → mite-2.5.4}/LICENSE +0 -0
  36. {mite-2.5.2 → mite-2.5.4}/MANIFEST.in +0 -0
  37. {mite-2.5.2 → mite-2.5.4}/README.md +0 -0
  38. /mite-2.5.2/cd-scripts/cdBuild-1.sh → /mite-2.5.4/cd-scripts/cdBuild-old.sh +0 -0
  39. {mite-2.5.2 → mite-2.5.4}/docker_compose.yml +0 -0
  40. {mite-2.5.2 → mite-2.5.4}/docker_compose_monitoring.yml +0 -0
  41. {mite-2.5.2 → mite-2.5.4}/docs/Makefile +0 -0
  42. {mite-2.5.2 → mite-2.5.4}/docs/components.rst +0 -0
  43. {mite-2.5.2 → mite-2.5.4}/docs/conf.py +0 -0
  44. {mite-2.5.2 → mite-2.5.4}/docs/config.rst +0 -0
  45. {mite-2.5.2 → mite-2.5.4}/docs/design-deployment.rst +0 -0
  46. {mite-2.5.2 → mite-2.5.4}/docs/index.rst +0 -0
  47. {mite-2.5.2 → mite-2.5.4}/docs/journeys.rst +0 -0
  48. {mite-2.5.2 → mite-2.5.4}/docs/notes.txt +0 -0
  49. {mite-2.5.2 → mite-2.5.4}/docs/prometheus.rst +0 -0
  50. {mite-2.5.2 → mite-2.5.4}/docs/stats.rst +0 -0
  51. {mite-2.5.2 → mite-2.5.4}/docs/volume-model.rst +0 -0
  52. {mite-2.5.2 → mite-2.5.4}/grafana/Dockerfile +0 -0
  53. {mite-2.5.2 → mite-2.5.4}/grafana/config.ini +0 -0
  54. {mite-2.5.2 → mite-2.5.4}/grafana/provisioning/dashboards/dashboards.yml +0 -0
  55. {mite-2.5.2 → mite-2.5.4}/grafana/provisioning/dashboards/grafana_dashboard_template.json +0 -0
  56. {mite-2.5.2 → mite-2.5.4}/grafana/provisioning/dashboards/mite_docker.json +0 -0
  57. {mite-2.5.2 → mite-2.5.4}/grafana/provisioning/datasources/datasources.yml +0 -0
  58. {mite-2.5.2 → mite-2.5.4}/local/Makefile +0 -0
  59. {mite-2.5.2 → mite-2.5.4}/local/README.md +0 -0
  60. {mite-2.5.2 → mite-2.5.4}/local/demo.py +0 -0
  61. {mite-2.5.2 → mite-2.5.4}/local/run_mite.sh +0 -0
  62. {mite-2.5.2 → mite-2.5.4}/mite/__init__.py +0 -0
  63. {mite-2.5.2 → mite-2.5.4}/mite/__main__.py +0 -0
  64. {mite-2.5.2 → mite-2.5.4}/mite/cli/__init__.py +0 -0
  65. {mite-2.5.2 → mite-2.5.4}/mite/cli/cat.py +0 -0
  66. {mite-2.5.2 → mite-2.5.4}/mite/cli/collector.py +0 -0
  67. {mite-2.5.2 → mite-2.5.4}/mite/cli/common.py +0 -0
  68. {mite-2.5.2 → mite-2.5.4}/mite/cli/duplicator.py +0 -0
  69. {mite-2.5.2 → mite-2.5.4}/mite/cli/receiver.py +0 -0
  70. {mite-2.5.2 → mite-2.5.4}/mite/cli/stats.py +0 -0
  71. {mite-2.5.2 → mite-2.5.4}/mite/cli/test.py +0 -0
  72. {mite-2.5.2 → mite-2.5.4}/mite/collector.py +0 -0
  73. {mite-2.5.2 → mite-2.5.4}/mite/config.py +0 -0
  74. {mite-2.5.2 → mite-2.5.4}/mite/context.py +0 -0
  75. {mite-2.5.2 → mite-2.5.4}/mite/controller.py +0 -0
  76. {mite-2.5.2 → mite-2.5.4}/mite/datapools.py +0 -0
  77. {mite-2.5.2 → mite-2.5.4}/mite/example.py +0 -0
  78. {mite-2.5.2 → mite-2.5.4}/mite/exceptions.py +0 -0
  79. {mite-2.5.2 → mite-2.5.4}/mite/har_to_mite.py +0 -0
  80. {mite-2.5.2 → mite-2.5.4}/mite/logoutput.py +0 -0
  81. {mite-2.5.2 → mite-2.5.4}/mite/nanomsg.py +0 -0
  82. {mite-2.5.2 → mite-2.5.4}/mite/recorder.py +0 -0
  83. {mite-2.5.2 → mite-2.5.4}/mite/runner.py +0 -0
  84. {mite-2.5.2 → mite-2.5.4}/mite/s3datapools.py +0 -0
  85. {mite-2.5.2 → mite-2.5.4}/mite/scenario.py +0 -0
  86. {mite-2.5.2 → mite-2.5.4}/mite/stats.py +0 -0
  87. {mite-2.5.2 → mite-2.5.4}/mite/test.py +0 -0
  88. {mite-2.5.2 → mite-2.5.4}/mite/utils.py +0 -0
  89. {mite-2.5.2 → mite-2.5.4}/mite/volume_model.py +0 -0
  90. {mite-2.5.2 → mite-2.5.4}/mite/web/__init__.py +0 -0
  91. {mite-2.5.2 → mite-2.5.4}/mite/web/prometheus.py +0 -0
  92. {mite-2.5.2 → mite-2.5.4}/mite/zmq.py +0 -0
  93. {mite-2.5.2 → mite-2.5.4}/mite.egg-info/dependency_links.txt +0 -0
  94. {mite-2.5.2 → mite-2.5.4}/mite.egg-info/entry_points.txt +0 -0
  95. {mite-2.5.2 → mite-2.5.4}/mite_amqp/__init__.py +0 -0
  96. {mite-2.5.2 → mite-2.5.4}/mite_browser/__init__.py +0 -0
  97. {mite-2.5.2 → mite-2.5.4}/mite_finagle/README.md +0 -0
  98. {mite-2.5.2 → mite-2.5.4}/mite_finagle/__init__.py +0 -0
  99. {mite-2.5.2 → mite-2.5.4}/mite_finagle/mux.py +0 -0
  100. {mite-2.5.2 → mite-2.5.4}/mite_finagle/stats.py +0 -0
  101. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/__init__.py +0 -0
  102. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/conftest.py +0 -0
  103. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/foo_service/Foo-remote +0 -0
  104. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/foo_service/Foo.py +0 -0
  105. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/foo_service/__init__.py +0 -0
  106. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/foo_service/constants.py +0 -0
  107. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/foo_service/ttypes.py +0 -0
  108. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/foo_service.thrift +0 -0
  109. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/test_integration.py +0 -0
  110. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/test_mux.py +0 -0
  111. {mite-2.5.2 → mite-2.5.4}/mite_finagle/tests/test_thrift.py +0 -0
  112. {mite-2.5.2 → mite-2.5.4}/mite_finagle/thrift.py +0 -0
  113. {mite-2.5.2 → mite-2.5.4}/mite_http/__init__.py +0 -0
  114. {mite-2.5.2 → mite-2.5.4}/mite_http/stats.py +0 -0
  115. {mite-2.5.2 → mite-2.5.4}/mite_kafka/__init__.py +0 -0
  116. {mite-2.5.2 → mite-2.5.4}/mite_kafka/mite_kafka_example.py +0 -0
  117. {mite-2.5.2 → mite-2.5.4}/mite_kafka/stats.py +0 -0
  118. {mite-2.5.2 → mite-2.5.4}/mite_selenium/__init__.py +0 -0
  119. {mite-2.5.2 → mite-2.5.4}/mite_selenium/stats.py +0 -0
  120. {mite-2.5.2 → mite-2.5.4}/mite_websocket/__init__.py +0 -0
  121. {mite-2.5.2 → mite-2.5.4}/prometheus/Dockerfile +0 -0
  122. {mite-2.5.2 → mite-2.5.4}/prometheus/prometheus_config_docker.yml +0 -0
  123. {mite-2.5.2 → mite-2.5.4}/prometheus/prometheus_config_template.yml +0 -0
  124. {mite-2.5.2 → mite-2.5.4}/pyproject.toml +0 -0
  125. {mite-2.5.2 → mite-2.5.4}/requirements.txt +0 -0
  126. {mite-2.5.2 → mite-2.5.4}/setup.py +0 -0
  127. {mite-2.5.2 → mite-2.5.4}/test/legacy.py +0 -0
  128. {mite-2.5.2 → mite-2.5.4}/test/mocks/mock_collector.py +0 -0
  129. {mite-2.5.2 → mite-2.5.4}/test/mocks/mock_context.py +0 -0
  130. {mite-2.5.2 → mite-2.5.4}/test/mocks/mock_direct_receiver.py +0 -0
  131. {mite-2.5.2 → mite-2.5.4}/test/mocks/mock_direct_runner_transport.py +0 -0
  132. {mite-2.5.2 → mite-2.5.4}/test/mocks/mock_recorder_msg_http.py +0 -0
  133. {mite-2.5.2 → mite-2.5.4}/test/mocks/mock_selenium.py +0 -0
  134. {mite-2.5.2 → mite-2.5.4}/test/mocks/mock_sender.py +0 -0
  135. {mite-2.5.2 → mite-2.5.4}/test/perf/.gitignore +0 -0
  136. {mite-2.5.2 → mite-2.5.4}/test/perf/http_server.py +0 -0
  137. {mite-2.5.2 → mite-2.5.4}/test/perf/http_server_aiohttp.py +0 -0
  138. {mite-2.5.2 → mite-2.5.4}/test/perf/mite_perftest.py +0 -0
  139. {mite-2.5.2 → mite-2.5.4}/test/perf/perftest.py +0 -0
  140. {mite-2.5.2 → mite-2.5.4}/test/perf/run-perftest.sh +0 -0
  141. {mite-2.5.2 → mite-2.5.4}/test/perf/test-requirements.txt +0 -0
  142. {mite-2.5.2 → mite-2.5.4}/test/test.har +0 -0
  143. {mite-2.5.2 → mite-2.5.4}/test/test_collector.py +0 -0
  144. {mite-2.5.2 → mite-2.5.4}/test/test_config.py +0 -0
  145. {mite-2.5.2 → mite-2.5.4}/test/test_context.py +0 -0
  146. {mite-2.5.2 → mite-2.5.4}/test/test_controller.py +0 -0
  147. {mite-2.5.2 → mite-2.5.4}/test/test_datapools.py +0 -0
  148. {mite-2.5.2 → mite-2.5.4}/test/test_har_to_mite.py +0 -0
  149. {mite-2.5.2 → mite-2.5.4}/test/test_logging.py +0 -0
  150. {mite-2.5.2 → mite-2.5.4}/test/test_mite_amqp.py +0 -0
  151. {mite-2.5.2 → mite-2.5.4}/test/test_mite_browser.py +0 -0
  152. {mite-2.5.2 → mite-2.5.4}/test/test_mite_http.py +0 -0
  153. {mite-2.5.2 → mite-2.5.4}/test/test_mite_kafka.py +0 -0
  154. {mite-2.5.2 → mite-2.5.4}/test/test_mite_utils.py +0 -0
  155. {mite-2.5.2 → mite-2.5.4}/test/test_mite_websockets.py +0 -0
  156. {mite-2.5.2 → mite-2.5.4}/test/test_prometheus_mite.py +0 -0
  157. {mite-2.5.2 → mite-2.5.4}/test/test_recorder.py +0 -0
  158. {mite-2.5.2 → mite-2.5.4}/test/test_runner.py +0 -0
  159. {mite-2.5.2 → mite-2.5.4}/test/test_runner_tracker.py +0 -0
  160. {mite-2.5.2 → mite-2.5.4}/test/test_scenario.py +0 -0
  161. {mite-2.5.2 → mite-2.5.4}/test/test_stats.py +0 -0
  162. {mite-2.5.2 → mite-2.5.4}/test/test_volume_model.py +0 -0
  163. {mite-2.5.2 → mite-2.5.4}/test/test_webdriver.py +0 -0
  164. {mite-2.5.2 → mite-2.5.4}/test/test_work_tracker.py +0 -0
  165. {mite-2.5.2 → mite-2.5.4}/test.har +0 -0
  166. {mite-2.5.2 → mite-2.5.4}/tox.ini +0 -0
@@ -4,7 +4,7 @@ COPY ./test/perf/test-requirements.txt /test-requirements.txt
4
4
 
5
5
  RUN pip install -r test-requirements.txt
6
6
 
7
- RUN pip install bs4 docopt flask msgpack-python nanomsg pyzmq uvloop
7
+ RUN pip install bs4 docopt flask msgpack-python nanomsg pyzmq uvloop==0.21.0
8
8
 
9
9
  COPY . /package
10
10
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mite
3
- Version: 2.5.2
3
+ Version: 2.5.4
4
4
  Summary: A Python Performance Testing Framework
5
5
  Home-page: https://github.com/sky-uk/mite/
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -21,7 +21,7 @@ Requires-Dist: nanomsg
21
21
  Requires-Dist: prettytable
22
22
  Requires-Dist: pyzmq
23
23
  Requires-Dist: selenium<4
24
- Requires-Dist: uvloop
24
+ Requires-Dist: uvloop==0.21.0
25
25
  Requires-Dist: websockets
26
26
  Provides-Extra: amqp
27
27
  Requires-Dist: aio_pika; extra == "amqp"
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+
3
+ source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
4
+
5
+ # Because of the settings of the environment where the pipeline runs, cdBuild.sh is used for both CI testing and manual releases as we can change the default scripts used.
6
+ # In a normal situation, we would have two separate scripts, one for CI and one for manual releases.
7
+ # Here we check the JOB_NAME variable to determine which kind of run it is and call the appropriate script.
8
+
9
+ # manual-release job will run the release script directly
10
+ # any other job (like miteci-release) will run the test script. Then the pipeline shape will take care of calling the release script if the tests pass for the CI job.
11
+
12
+ echo $JOB_NAME
13
+
14
+ if [[ "$JOB_NAME" =~ "mite-ci" ]]; then
15
+ echo "##### Job running as CI. Proceeding with the Test script. ######"
16
+ ./cd-scripts/runTests.sh
17
+ fi
@@ -83,6 +83,12 @@ def create_and_push_tag(repo, tag):
83
83
 
84
84
  def parse_pr(pr_number):
85
85
  resp = requests.get(f"https://api.github.com/repos/sky-uk/mite/pulls/{pr_number}")
86
+ if resp.status_code != 200:
87
+ logger.error(
88
+ f"Request to GitHub not successfull: {resp.status_code} - {resp.text}"
89
+ )
90
+ sys.exit(1)
91
+
86
92
  pr_message = resp.json()["body"]
87
93
 
88
94
  matches = re.findall(
@@ -1,10 +1,25 @@
1
1
  #!/bin/bash
2
2
 
3
+ function isOnMaster() {
4
+ current_revision=$(git rev-parse HEAD)
5
+ branch=$(git branch -r --contains $current_revision)
6
+ set +e
7
+ echo "$branch" | grep -q "origin/master$"
8
+ result=$?
9
+ set -e
10
+ return ${result}
11
+ }
12
+
3
13
  function tagBuild() {
14
+ if [ -z "$1" ]; then
15
+ VERSION_INCREMENT_TYPE=""
16
+ else
17
+ VERSION_INCREMENT_TYPE="--${1}"
18
+ fi
4
19
  git config user.email "mite@noreply.github.com"
5
20
  git config user.name "Jenkins-CI"
6
21
  pip3 install docopt GitPython packaging requests
7
- python3 cd-scripts/cdRelease.py
22
+ python3 cd-scripts/cdTagRelease.py ${VERSION_INCREMENT_TYPE}
8
23
  if (( $? == 1)); then
9
24
  VERSION_INCREMENT=false
10
25
  fi
@@ -49,25 +64,4 @@ function initPypirc() {
49
64
  echo -e "[pypi]" > ~/.pypirc
50
65
  echo -e "username = __token__" >> ~/.pypirc
51
66
  echo -e "password = $PYPI_TOKEN" >> ~/.pypirc
52
- }
53
-
54
- ###### MAIN SECTION ######
55
-
56
- echo "##### Starting tag process and check for version increment #####"
57
- tagBuild
58
-
59
- echo "##### Look for Acurl changes #####"
60
- checkAcurl
61
-
62
- echo "##### Build Linux-Wheels #####"
63
- buildLinuxWheels
64
-
65
- if [ "$VERSION_INCREMENT" = false ]; then
66
- echo "Mite version not incremented, nothing to upload"
67
- else
68
- echo "##### Init .pypirc #####"
69
- initPypirc
70
-
71
- echo "##### Upload package #####"
72
- python3 -m twine upload wheelhouse/*
73
- fi
67
+ }
@@ -0,0 +1,32 @@
1
+ #!/bin/bash
2
+
3
+ source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
4
+
5
+ VERSION_INCREMENT_TYPE=${1}
6
+
7
+ if isOnMaster; then
8
+ echo "##### Job running on MASTER. Proceeding with the Tag and Release script. ######"
9
+ echo "##### Starting tag process and check for version increment #####"
10
+ # We are passing over the VERSION_TYPE argument to tagBuild which will set the type of increment for the new version
11
+ # If not passed, cdRelease.py will use the GH PR to check which kind of increment it is supposed to be as VERSION_TYPE will be an empty string
12
+ tagBuild ${VERSION_INCREMENT_TYPE}
13
+
14
+ echo "##### Look for Acurl changes #####"
15
+ checkAcurl
16
+
17
+ echo "##### Build Linux-Wheels #####"
18
+ buildLinuxWheels
19
+
20
+ if [ "$VERSION_INCREMENT" = false ]; then
21
+ echo "Mite version not incremented, nothing to upload"
22
+ else
23
+ echo "##### Init .pypirc #####"
24
+ initPypirc
25
+
26
+ echo "##### Upload package #####"
27
+ python3 -m twine upload wheelhouse/*
28
+ fi
29
+
30
+ else
31
+ echo "Not going to build the mite image because the job is not running on the master branch"
32
+ fi
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+
3
+
4
+ echo "##### Run pre-commit checks #####"
5
+ /home/jenkins/.local/bin/pre-commit run --origin HEAD --source origin/master
6
+ PRE_COMMIT_STATUS=$?
7
+
8
+ if [ $PRE_COMMIT_STATUS -ne 0 ]; then
9
+ git diff
10
+ fi
11
+
12
+ echo "##### Run tests with tox #####"
13
+ tox; TOX_EXIT_CODE=$?
14
+ [ "$TOX_EXIT_CODE" -eq 0 -a "$PRE_COMMIT_STATUS" -eq 0 ] || exit 1
15
+ echo "##### Pre-commit and Tests passed #####"
mite-2.5.4/cd.yml ADDED
@@ -0,0 +1,49 @@
1
+ version: 1
2
+
3
+ # Further ideas for jobs to run:
4
+ # - license check
5
+ # - make sure test coverage increases
6
+ # - merge all tox tests into one using pyenv
7
+ # And, once we're sure that the pipeline is working:
8
+ # - integration/performance tests
9
+ # Once we have docs:
10
+ # - documentation coverage
11
+ # - docs build (on master only)
12
+
13
+ context: sky-identity
14
+ triggering: multibranch
15
+
16
+ defaultNodes:
17
+ default: sky-identity-nonprod-mite-slave-buildkit
18
+
19
+ modules:
20
+ mite-ci:
21
+ pipelineShape: simple
22
+ directory: "/"
23
+ htmlReports:
24
+ - name: Coverage Report
25
+ directory: coverage_html_report
26
+ files: ["index.html"]
27
+
28
+
29
+ mite-manual-release:
30
+ pipelineShape: simple
31
+ defaultTaskExecution: ./cd-scripts/manualRelease.sh
32
+ phaseLocks:
33
+ cdBuild:
34
+ defaultLockEnabled: false
35
+ parameters:
36
+ main:
37
+ - name: VERSION_INCREMENT_TYPE
38
+ type: choice
39
+ description: The version segment that you want increment for the release
40
+ options: [patch, minor, major]
41
+
42
+ # TODO find a work around for the issue with combining build and release in one pipeline
43
+ # mite-ci-and-release:
44
+ # pipelineShape: build-release
45
+ # directory: "/"
46
+ # htmlReports:
47
+ # - name: Coverage Report
48
+ # directory: coverage_html_report
49
+ # files: ["index.html"]
@@ -5,3 +5,4 @@ pre-commit~=2.20.0
5
5
  flake8~=3.7.8
6
6
  black~=24.3.0
7
7
  coverage~=5.1
8
+ sqlalchemy
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mite
3
- Version: 2.5.2
3
+ Version: 2.5.4
4
4
  Summary: A Python Performance Testing Framework
5
5
  Home-page: https://github.com/sky-uk/mite/
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -21,7 +21,7 @@ Requires-Dist: nanomsg
21
21
  Requires-Dist: prettytable
22
22
  Requires-Dist: pyzmq
23
23
  Requires-Dist: selenium<4
24
- Requires-Dist: uvloop
24
+ Requires-Dist: uvloop==0.21.0
25
25
  Requires-Dist: websockets
26
26
  Provides-Extra: amqp
27
27
  Requires-Dist: aio_pika; extra == "amqp"
@@ -25,9 +25,11 @@ tox.ini
25
25
  .github/pull_request_template.md
26
26
  .github/ISSUE_TEMPLATE/bug_report.md
27
27
  .github/ISSUE_TEMPLATE/feature_request.md
28
- cd-scripts/cdBuild-1.sh
29
- cd-scripts/cdRelease.py
30
- cd-scripts/cdTagRelease.sh
28
+ cd-scripts/cdBuild-old.sh
29
+ cd-scripts/cdBuild.sh
30
+ cd-scripts/cdTagRelease.py
31
+ cd-scripts/lib.sh
32
+ cd-scripts/manualRelease.sh
31
33
  cd-scripts/runTests.sh
32
34
  docs/Makefile
33
35
  docs/components.rst
@@ -89,6 +91,10 @@ mite/web/__init__.py
89
91
  mite/web/prometheus.py
90
92
  mite_amqp/__init__.py
91
93
  mite_browser/__init__.py
94
+ mite_db_datapool/README.md
95
+ mite_db_datapool/__init__.py
96
+ mite_db_datapool/db_to_pool.py
97
+ mite_db_datapool/mite_db_example.py
92
98
  mite_finagle/README.md
93
99
  mite_finagle/__init__.py
94
100
  mite_finagle/mux.py
@@ -123,6 +129,7 @@ test/test_config.py
123
129
  test/test_context.py
124
130
  test/test_controller.py
125
131
  test/test_datapools.py
132
+ test/test_db_to_pool.py
126
133
  test/test_har_to_mite.py
127
134
  test/test_logging.py
128
135
  test/test_mite_amqp.py
@@ -7,7 +7,7 @@ nanomsg
7
7
  prettytable
8
8
  pyzmq
9
9
  selenium<4
10
- uvloop
10
+ uvloop==0.21.0
11
11
  websockets
12
12
 
13
13
  [amqp]
@@ -1,6 +1,7 @@
1
1
  mite
2
2
  mite_amqp
3
3
  mite_browser
4
+ mite_db_datapool
4
5
  mite_finagle
5
6
  mite_http
6
7
  mite_kafka
@@ -0,0 +1,45 @@
1
+ # Database -> DataPool for Mite
2
+
3
+ ## Overview
4
+
5
+ This module provides database-backed data pools for Mite testing scenarios. It allows you to load test data directly from databases and use it in your load testing journeys.
6
+
7
+ ## Why SQLAlchemy?
8
+
9
+ We chose **SQLAlchemy** over **pyodbc** for several reasons:
10
+
11
+ - **Database Agnostic**: Works with SQLite, PostgreSQL, MySQL, SQL Server, Oracle, etc.
12
+ - **Connection Pooling**: Built-in connection management and pooling
13
+ - **Simpler API**: Clean, Pythonic interface for database operations
14
+ - **Better Error Handling**: More informative error messages
15
+ - **No Driver Dependencies**: SQLAlchemy handles driver selection automatically
16
+ - **URL-based Configuration**: Easy connection string format
17
+
18
+ ## Files
19
+
20
+ ### `db_to_pool.py`
21
+ Core implementation containing:
22
+ - `DBIterableDataPool`: Load data once, consume sequentially (burned data)
23
+ - `DBRecyclableIterableDataPool`: Load data once, reuse infinitely
24
+ - Memory protection with `max_size` parameter to prevent OOM with large datasets
25
+
26
+ ### `mite_db_example.py`
27
+ Working example showing:
28
+ - SQLite database creation with test data
29
+ - DataPool setup and configuration
30
+ - Integration with Mite journey functions
31
+ - Basic load testing scenario
32
+
33
+
34
+ ## Testing
35
+
36
+ Run the example:
37
+ ```bash
38
+ # From mite directory
39
+ python mite_db_datapool/mite_db_example.py
40
+ ```
41
+
42
+ Run unit tests:
43
+ ```bash
44
+ pytest test/test_db_to_pool.py -v
45
+ ```
@@ -0,0 +1,8 @@
1
+ # mite_db_datapool package
2
+ from .db_to_pool import (
3
+ DataPoolExhausted,
4
+ DBIterableDataPool,
5
+ DBRecyclableIterableDataPool,
6
+ )
7
+
8
+ __all__ = ["DBIterableDataPool", "DBRecyclableIterableDataPool", "DataPoolExhausted"]
@@ -0,0 +1,95 @@
1
+ import logging
2
+ from collections import deque
3
+
4
+ from sqlalchemy import text
5
+
6
+ from mite.datapools import DataPoolExhausted, DataPoolItem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class DBIterableDataPool:
12
+ def __init__(
13
+ self,
14
+ db_engine,
15
+ query,
16
+ preload_minimum=None,
17
+ max_size=None,
18
+ ):
19
+ self.db_engine = db_engine
20
+ self.query = query
21
+ self.max_size = max_size
22
+ self._data = []
23
+ self.item_index = 0
24
+ self.db_exhausted = False
25
+ self.preload_minimum = preload_minimum
26
+
27
+ # Adjust preload_minimum if needed
28
+ if max_size and preload_minimum and preload_minimum > max_size:
29
+ self.preload_minimum = max_size
30
+
31
+ # Load initial data
32
+ if preload_minimum:
33
+ while len(self._data) < self.preload_minimum and not self.db_exhausted:
34
+ self.populate()
35
+ else:
36
+ while not self.db_exhausted:
37
+ self.populate()
38
+
39
+ def populate(self):
40
+ # Stop if at max_size
41
+ if self.max_size is not None and len(self._data) >= self.max_size:
42
+ return
43
+
44
+ with self.db_engine.connect() as conn:
45
+ result = conn.execute(text(self.query))
46
+ rows = result.fetchall()
47
+
48
+ if not rows:
49
+ self.db_exhausted = True
50
+ return
51
+
52
+ # Add rows up to max_size
53
+ rows_added = 0
54
+ for row in rows:
55
+ if self.max_size is not None and len(self._data) >= self.max_size:
56
+ break
57
+ self._data.append((self.item_index, dict(row._mapping)))
58
+ self.item_index += 1
59
+ rows_added += 1
60
+
61
+ # Only mark as exhausted if we processed all available rows
62
+ # If we only processed some rows due to max_size limit, don't mark as exhausted
63
+ if rows_added == len(rows):
64
+ self.db_exhausted = True
65
+
66
+ async def checkout(self, config):
67
+ try:
68
+ item_id, row = self._data.pop(0)
69
+ return DataPoolItem(item_id, row)
70
+ except IndexError as e:
71
+ raise DataPoolExhausted() from e
72
+
73
+ async def checkin(self, item_id):
74
+ pass
75
+
76
+
77
+ class DBRecyclableIterableDataPool(DBIterableDataPool):
78
+ def __init__(self, *args, **kwargs):
79
+ super().__init__(*args, **kwargs)
80
+ self._available = deque(range(len(self._data)))
81
+ self._checked_out = set()
82
+
83
+ async def checkout(self, config):
84
+ if self._available:
85
+ item_id = self._available.popleft()
86
+ self._checked_out.add(item_id)
87
+ row = self._data[item_id][1]
88
+ return DataPoolItem(item_id, row)
89
+ else:
90
+ raise DataPoolExhausted("Recyclable iterable datapool was emptied!")
91
+
92
+ async def checkin(self, item_id):
93
+ if item_id in self._checked_out:
94
+ self._checked_out.remove(item_id)
95
+ self._available.append(item_id)
@@ -0,0 +1,39 @@
1
+ import sqlite3
2
+
3
+ from db_to_pool import DBIterableDataPool
4
+ from sqlalchemy import create_engine
5
+
6
+ from mite import ensure_average_separation
7
+
8
+ # Step 1: Create a test SQLite database and table (local file)
9
+ DB_PATH = "example_test.db"
10
+ conn = sqlite3.connect(DB_PATH)
11
+ conn.execute("CREATE TABLE IF NOT EXISTS test_table (id INTEGER PRIMARY KEY, value TEXT)")
12
+ conn.execute("DELETE FROM test_table")
13
+ conn.execute("INSERT INTO test_table (value) VALUES ('mite1'), ('mite2'), ('mite3')")
14
+ conn.commit()
15
+ conn.close()
16
+
17
+ # Step 2: Set up SQLAlchemy engine (same file)
18
+ engine = create_engine(f"sqlite:///{DB_PATH}")
19
+
20
+ # Step 3: Test DBIterableDataPool
21
+ db_datapool = DBIterableDataPool(
22
+ engine, "SELECT * FROM test_table", preload_minimum=3, max_size=2
23
+ )
24
+
25
+
26
+ async def db_journey(ctx, item_id, row):
27
+ async with ensure_average_separation(1):
28
+ print("running journey", item_id, row)
29
+
30
+
31
+ def scenario():
32
+ return [["db_folder:db_journey", db_datapool, lambda s, e: 1]]
33
+
34
+
35
+ # Simple test to see it working
36
+ if __name__ == "__main__":
37
+ print(f"✓ DataPool created with {len(db_datapool._data)} items")
38
+ for i, (item_id, data) in enumerate(db_datapool._data):
39
+ print(f" Item {i}: {data}")
@@ -25,7 +25,7 @@ install_requires =
25
25
  prettytable
26
26
  pyzmq
27
27
  selenium<4
28
- uvloop
28
+ uvloop==0.21.0
29
29
  websockets
30
30
  setup_requires = pytest-runner
31
31
  packages = find:
@@ -0,0 +1,155 @@
1
+ import sqlite3
2
+
3
+ import pytest
4
+ from sqlalchemy import create_engine
5
+
6
+ from mite_db_datapool.db_to_pool import (
7
+ DataPoolExhausted,
8
+ DBIterableDataPool,
9
+ DBRecyclableIterableDataPool,
10
+ )
11
+
12
+
13
+ @pytest.fixture
14
+ def setup_test_db():
15
+ """Set up a test SQLite database and table"""
16
+ conn = sqlite3.connect("testdb.sqlite")
17
+ conn.execute(
18
+ "CREATE TABLE IF NOT EXISTS test_table (id INTEGER PRIMARY KEY, value TEXT)"
19
+ )
20
+ conn.execute("DELETE FROM test_table")
21
+ conn.execute("INSERT INTO test_table (value) VALUES ('foo'), ('bar'), ('baz')")
22
+ conn.commit()
23
+ conn.close()
24
+
25
+ engine = create_engine("sqlite:///testdb.sqlite")
26
+ yield engine
27
+
28
+ # Cleanup
29
+ import os
30
+
31
+ if os.path.exists("testdb.sqlite"):
32
+ os.remove("testdb.sqlite")
33
+
34
+
35
+ @pytest.fixture
36
+ def setup_large_test_db():
37
+ """Set up a test SQLite database with more data for max_size testing"""
38
+ conn = sqlite3.connect("testdb_large.sqlite")
39
+ conn.execute(
40
+ "CREATE TABLE IF NOT EXISTS large_table (id INTEGER PRIMARY KEY, value TEXT)"
41
+ )
42
+ conn.execute("DELETE FROM large_table")
43
+
44
+ # Insert 100 rows for testing max_size functionality
45
+ values = [(f"item_{i}",) for i in range(100)]
46
+ conn.executemany("INSERT INTO large_table (value) VALUES (?)", values)
47
+ conn.commit()
48
+ conn.close()
49
+
50
+ engine = create_engine("sqlite:///testdb_large.sqlite")
51
+ yield engine
52
+
53
+ # Cleanup
54
+ import os
55
+
56
+ if os.path.exists("testdb_large.sqlite"):
57
+ os.remove("testdb_large.sqlite")
58
+
59
+
60
+ @pytest.mark.asyncio
61
+ async def test_db_iterable_datapool(setup_test_db):
62
+ """Test basic DBIterableDataPool functionality"""
63
+ engine = setup_test_db
64
+ pool = DBIterableDataPool(engine, "SELECT * FROM test_table", preload_minimum=3)
65
+
66
+ checked_out_items = []
67
+ try:
68
+ while True:
69
+ item = await pool.checkout(config={})
70
+ checked_out_items.append(item)
71
+ except DataPoolExhausted:
72
+ pass
73
+
74
+ assert len(checked_out_items) == 3
75
+
76
+
77
+ @pytest.mark.asyncio
78
+ async def test_db_recyclable_iterable_datapool(setup_test_db):
79
+ """Test basic DBRecyclableIterableDataPool functionality"""
80
+ engine = setup_test_db
81
+ recycle_pool = DBRecyclableIterableDataPool(
82
+ engine, "SELECT * FROM test_table", preload_minimum=3
83
+ )
84
+
85
+ # Checkout items
86
+ items = []
87
+ for _ in range(3):
88
+ item = await recycle_pool.checkout(config={})
89
+ items.append(item.id)
90
+
91
+ # Check them back in
92
+ for item_id in items:
93
+ await recycle_pool.checkin(item_id)
94
+
95
+ # Try to checkout again - should work since items are recycled
96
+ recycled_items = []
97
+ for _ in range(3):
98
+ item = await recycle_pool.checkout(config={})
99
+ recycled_items.append(item.id)
100
+
101
+ assert len(recycled_items) == 3
102
+
103
+
104
+ def test_max_size_limits_data_loading(setup_large_test_db):
105
+ """Test that max_size prevents OOM with large datasets"""
106
+ engine = setup_large_test_db
107
+
108
+ pool = DBIterableDataPool(
109
+ engine,
110
+ "SELECT * FROM large_table",
111
+ preload_minimum=3, # Wants to load 3 items
112
+ max_size=2, # Limit to 2 items even though 100 are available
113
+ )
114
+
115
+ assert len(pool._data) == 2
116
+
117
+
118
+ def test_infinite_loop_prevention(setup_large_test_db):
119
+ """Test that preload_minimum > max_size doesn't cause infinite loop (critical fix)"""
120
+ import time
121
+
122
+ start_time = time.time()
123
+
124
+ pool = DBIterableDataPool(
125
+ setup_large_test_db,
126
+ "SELECT * FROM large_table",
127
+ preload_minimum=50, # Want 50
128
+ max_size=10, # Limited to 10
129
+ )
130
+
131
+ end_time = time.time()
132
+
133
+ assert end_time - start_time < 1.0 # Should complete quickly
134
+ assert pool.preload_minimum == 10 # Auto-adjusted
135
+ assert len(pool._data) == 10
136
+
137
+
138
+ @pytest.mark.asyncio
139
+ async def test_recyclable_with_max_size(setup_large_test_db):
140
+ """Test recyclable pool respects max_size"""
141
+ engine = setup_large_test_db
142
+
143
+ recycle_pool = DBRecyclableIterableDataPool(
144
+ engine, "SELECT * FROM large_table", preload_minimum=3, max_size=2
145
+ )
146
+
147
+ assert len(recycle_pool._data) == 2
148
+ assert len(recycle_pool._available) == 2
149
+
150
+ # Test checkout/checkin cycle
151
+ item = await recycle_pool.checkout(config={})
152
+ assert len(recycle_pool._available) == 1
153
+
154
+ await recycle_pool.checkin(item.id)
155
+ assert len(recycle_pool._available) == 2
@@ -14,5 +14,7 @@ pytest-httpbin
14
14
  pytest-httpserver
15
15
  sanic
16
16
  werkzeug==3.1.3
17
- uvloop~=0.19.0
18
- setuptools>=78.1.1 # not directly required, pinned by Snyk to avoid a vulnerability
17
+ sqlalchemy
18
+ uvloop==0.21.0
19
+ setuptools>=78.1.1 # not directly required, pinned by Snyk to avoid a vulnerability
20
+
@@ -1,31 +0,0 @@
1
- #!/bin/bash
2
-
3
- function isOnMaster() {
4
- current_revision=$(git rev-parse HEAD)
5
- branch=$(git branch -r --contains $current_revision)
6
- set +e
7
- echo "$branch" | grep -q "origin/master$"
8
- result=$?
9
- set -e
10
- return ${result}
11
- }
12
-
13
-
14
- echo "##### Run pre-commit checks #####"
15
- /home/jenkins/.local/bin/pre-commit run --origin HEAD --source origin/master
16
- PRE_COMMIT_STATUS=$?
17
-
18
- if [ $PRE_COMMIT_STATUS -ne 0 ]; then
19
- git diff
20
- fi
21
-
22
- echo "##### Run tests with tox #####"
23
- tox; TOX_EXIT_CODE=$?
24
- [ "$TOX_EXIT_CODE" -eq 0 -a "$PRE_COMMIT_STATUS" -eq 0 ] || exit 1
25
-
26
- if isOnMaster ; then
27
- echo "##### Job running on MASTER. Proceeding with the Tag and Release script. ######"
28
- ./cd-scripts/cdTagRelease.sh
29
- else
30
- echo "###### Job running on a Branch. Stopping here. ######"
31
- fi