├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── AUTHORS
├── CHANGELOG.rst
├── LICENSE
├── MANIFEST.in
├── Pipfile
├── Pipfile.lock
├── README.rst
├── setup.py
├── src
└── pytest_stress
│ ├── __init__.py
│ └── pytest_stress.py
├── tests
└── test_stress.py
└── tox.ini
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on: [push, pull_request, workflow_dispatch]
4 |
5 | env:
6 | FORCE_COLOR: 1
7 |
8 | jobs:
9 | test:
10 | runs-on: ${{ matrix.os }}
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | python-version: ["3.6", "3.7", "3.8", "3.9", "3.10-dev"]
15 | os: [ubuntu-latest, macos-latest, windows-latest]
16 | include:
17 | # Add new helper variables to existing jobs
18 | - {python-version: "3.6", TOX_ENV: "py36"}
19 | - {python-version: "3.7", TOX_ENV: "py37"}
20 | - {python-version: "3.8", TOX_ENV: "py38"}
21 | - {python-version: "3.9", TOX_ENV: "py39"}
22 | - {python-version: "3.10-dev", TOX_ENV: "py310"}
23 |
24 | steps:
25 | - uses: actions/checkout@v2
26 |
27 | - name: Set up Python ${{ matrix.python-version }}
28 | uses: actions/setup-python@v2
29 | with:
30 | python-version: ${{ matrix.python-version }}
31 |
32 | - name: Get pip cache dir
33 | id: pip-cache
34 | run: |
35 | echo "::set-output name=dir::$(pip cache dir)"
36 |
37 | - name: Cache
38 | uses: actions/cache@v2
39 | with:
40 | path: ${{ steps.pip-cache.outputs.dir }}
41 | key:
42 | ${{ matrix.os }}-${{ matrix.python-version }}-v1-${{ hashFiles('**/tox.ini') }}
43 | restore-keys: |
44 | ${{ matrix.os }}-${{ matrix.python-version }}-v1-
45 |
46 | - name: Install dependencies
47 | run: |
48 | python -m pip install -U pip
49 | python -m pip install -U wheel
50 | python -m pip install -U tox
51 |
52 | - name: Tox tests
53 | run: |
54 | tox -e ${{ matrix.TOX_ENV }}
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .coverage
41 | .coverage.*
42 | .cache
43 | nosetests.xml
44 | coverage.xml
45 | *,cover
46 | .hypothesis/
47 | .pytest_cache
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask instance folder
58 | instance/
59 |
60 | # Sphinx documentation
61 | docs/_build/
62 |
63 | # MkDocs documentation
64 | /site/
65 |
66 | # PyBuilder
67 | target/
68 |
69 | # IPython Notebook
70 | .ipynb_checkpoints
71 |
72 | # pyenv
73 | .python-version
74 |
75 | # Apps
76 | .idea/
77 | .mypy_cache/
78 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | Imran Mumtaz
--------------------------------------------------------------------------------
/CHANGELOG.rst:
--------------------------------------------------------------------------------
1 | =========
2 | Changelog
3 | =========
4 |
5 | Versions follow `Semantic Versioning `_ (``..``).
6 |
7 | pytest-stress 1.0.0 (2019-11-16)
8 | ================================
9 |
10 | * First release v1.0.0.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2019 Imran Mumtaz
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 | include README.rst
3 |
4 | recursive-exclude * __pycache__
5 | recursive-exclude * *.py[co]
6 |
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [dev-packages]
7 | cookiecutter = "*"
8 | pytest = "*"
9 | tox = "*"
10 | flake8 = "*"
11 |
12 | [requires]
13 | python_version = "3.7"
14 |
--------------------------------------------------------------------------------
/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "6856ce12cf353d3ad22dcb0ac481514e4316aa46e39fbcf7a6858a91ed20313c"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3.7"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {},
19 | "develop": {
20 | "appdirs": {
21 | "hashes": [
22 | "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41",
23 | "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
24 | ],
25 | "version": "==1.4.4"
26 | },
27 | "arrow": {
28 | "hashes": [
29 | "sha256:8cbe6a629b1c54ae11b52d6d9e70890089241958f63bc59467e277e34b7a5378",
30 | "sha256:b8fe13abf3517abab315e09350c903902d1447bd311afbc17547ba1cb3ff5bd8"
31 | ],
32 | "version": "==1.1.0"
33 | },
34 | "attrs": {
35 | "hashes": [
36 | "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
37 | "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
38 | ],
39 | "version": "==21.2.0"
40 | },
41 | "binaryornot": {
42 | "hashes": [
43 | "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061",
44 | "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"
45 | ],
46 | "version": "==0.4.4"
47 | },
48 | "certifi": {
49 | "hashes": [
50 | "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee",
51 | "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"
52 | ],
53 | "version": "==2021.5.30"
54 | },
55 | "chardet": {
56 | "hashes": [
57 | "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
58 | "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
59 | ],
60 | "version": "==4.0.0"
61 | },
62 | "click": {
63 | "hashes": [
64 | "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a",
65 | "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"
66 | ],
67 | "version": "==8.0.1"
68 | },
69 | "cookiecutter": {
70 | "hashes": [
71 | "sha256:430eb882d028afb6102c084bab6cf41f6559a77ce9b18dc6802e3bc0cc5f4a30",
72 | "sha256:efb6b2d4780feda8908a873e38f0e61778c23f6a2ea58215723bcceb5b515dac"
73 | ],
74 | "index": "pypi",
75 | "version": "==1.7.2"
76 | },
77 | "distlib": {
78 | "hashes": [
79 | "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736",
80 | "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"
81 | ],
82 | "version": "==0.3.2"
83 | },
84 | "filelock": {
85 | "hashes": [
86 | "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
87 | "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"
88 | ],
89 | "version": "==3.0.12"
90 | },
91 | "flake8": {
92 | "hashes": [
93 | "sha256:1aa8990be1e689d96c745c5682b687ea49f2e05a443aff1f8251092b0014e378",
94 | "sha256:3b9f848952dddccf635be78098ca75010f073bfe14d2c6bda867154bea728d2a"
95 | ],
96 | "index": "pypi",
97 | "version": "==3.9.1"
98 | },
99 | "idna": {
100 | "hashes": [
101 | "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
102 | "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
103 | ],
104 | "version": "==2.10"
105 | },
106 | "importlib-metadata": {
107 | "hashes": [
108 | "sha256:960d52ba7c21377c990412aca380bf3642d734c2eaab78a2c39319f67c6a5786",
109 | "sha256:e592faad8de1bda9fe920cf41e15261e7131bcf266c30306eec00e8e225c1dd5"
110 | ],
111 | "markers": "python_version < '3.8'",
112 | "version": "==4.4.0"
113 | },
114 | "iniconfig": {
115 | "hashes": [
116 | "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
117 | "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"
118 | ],
119 | "version": "==1.1.1"
120 | },
121 | "jinja2": {
122 | "hashes": [
123 | "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
124 | "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
125 | ],
126 | "version": "==2.11.3"
127 | },
128 | "jinja2-time": {
129 | "hashes": [
130 | "sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40",
131 | "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa"
132 | ],
133 | "version": "==0.2.0"
134 | },
135 | "markupsafe": {
136 | "hashes": [
137 | "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
138 | "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
139 | "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
140 | "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
141 | "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
142 | "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f",
143 | "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39",
144 | "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
145 | "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
146 | "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014",
147 | "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f",
148 | "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
149 | "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
150 | "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
151 | "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
152 | "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
153 | "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
154 | "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
155 | "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
156 | "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85",
157 | "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1",
158 | "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
159 | "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
160 | "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
161 | "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850",
162 | "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0",
163 | "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
164 | "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
165 | "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb",
166 | "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
167 | "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
168 | "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
169 | "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1",
170 | "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2",
171 | "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
172 | "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
173 | "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
174 | "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7",
175 | "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
176 | "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8",
177 | "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
178 | "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193",
179 | "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
180 | "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b",
181 | "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
182 | "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
183 | "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5",
184 | "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c",
185 | "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032",
186 | "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
187 | "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be",
188 | "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"
189 | ],
190 | "version": "==1.1.1"
191 | },
192 | "mccabe": {
193 | "hashes": [
194 | "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
195 | "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
196 | ],
197 | "version": "==0.6.1"
198 | },
199 | "packaging": {
200 | "hashes": [
201 | "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5",
202 | "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"
203 | ],
204 | "version": "==20.9"
205 | },
206 | "pluggy": {
207 | "hashes": [
208 | "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
209 | "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
210 | ],
211 | "version": "==0.13.1"
212 | },
213 | "poyo": {
214 | "hashes": [
215 | "sha256:3e2ca8e33fdc3c411cd101ca395668395dd5dc7ac775b8e809e3def9f9fe041a",
216 | "sha256:e26956aa780c45f011ca9886f044590e2d8fd8b61db7b1c1cf4e0869f48ed4dd"
217 | ],
218 | "version": "==0.5.0"
219 | },
220 | "py": {
221 | "hashes": [
222 | "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
223 | "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
224 | ],
225 | "version": "==1.10.0"
226 | },
227 | "pycodestyle": {
228 | "hashes": [
229 | "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068",
230 | "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"
231 | ],
232 | "version": "==2.7.0"
233 | },
234 | "pyflakes": {
235 | "hashes": [
236 | "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3",
237 | "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"
238 | ],
239 | "version": "==2.3.1"
240 | },
241 | "pyparsing": {
242 | "hashes": [
243 | "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
244 | "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
245 | ],
246 | "version": "==2.4.7"
247 | },
248 | "pytest": {
249 | "hashes": [
250 | "sha256:671238a46e4df0f3498d1c3270e5deb9b32d25134c99b7d75370a68cfbe9b634",
251 | "sha256:6ad9c7bdf517a808242b998ac20063c41532a570d088d77eec1ee12b0b5574bc"
252 | ],
253 | "index": "pypi",
254 | "version": "==6.2.3"
255 | },
256 | "python-dateutil": {
257 | "hashes": [
258 | "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
259 | "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
260 | ],
261 | "version": "==2.8.1"
262 | },
263 | "python-slugify": {
264 | "hashes": [
265 | "sha256:6d8c5df75cd4a7c3a2d21e257633de53f52ab0265cd2d1dc62a730e8194a7380",
266 | "sha256:f13383a0b9fcbe649a1892b9c8eb4f8eab1d6d84b84bb7a624317afa98159cab"
267 | ],
268 | "version": "==5.0.2"
269 | },
270 | "requests": {
271 | "hashes": [
272 | "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
273 | "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
274 | ],
275 | "version": "==2.25.1"
276 | },
277 | "six": {
278 | "hashes": [
279 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
280 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
281 | ],
282 | "version": "==1.16.0"
283 | },
284 | "text-unidecode": {
285 | "hashes": [
286 | "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8",
287 | "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"
288 | ],
289 | "version": "==1.3"
290 | },
291 | "toml": {
292 | "hashes": [
293 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
294 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
295 | ],
296 | "version": "==0.10.2"
297 | },
298 | "tox": {
299 | "hashes": [
300 | "sha256:05a4dbd5e4d3d8269b72b55600f0b0303e2eb47ad5c6fe76d3576f4c58d93661",
301 | "sha256:e007673f3595cede9b17a7c4962389e4305d4a3682a6c5a4159a1453b4f326aa"
302 | ],
303 | "index": "pypi",
304 | "version": "==3.23.0"
305 | },
306 | "typing-extensions": {
307 | "hashes": [
308 | "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497",
309 | "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342",
310 | "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"
311 | ],
312 | "markers": "python_version < '3.8'",
313 | "version": "==3.10.0.0"
314 | },
315 | "urllib3": {
316 | "hashes": [
317 | "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c",
318 | "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"
319 | ],
320 | "index": "pypi",
321 | "version": "==1.26.5"
322 | },
323 | "virtualenv": {
324 | "hashes": [
325 | "sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467",
326 | "sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"
327 | ],
328 | "version": "==20.4.7"
329 | },
330 | "zipp": {
331 | "hashes": [
332 | "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76",
333 | "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"
334 | ],
335 | "version": "==3.4.1"
336 | }
337 | }
338 | }
339 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | =============
2 | Pytest-stress
3 | =============
4 |
5 | .. image:: https://github.com/pytest-dev/pytest-stress/actions/workflows/test.yml/badge.svg
6 | :target: https://github.com/pytest-dev/pytest-cov/actions
7 | :alt: See Build Status on GitHub Actions
8 |
9 | .. image:: https://img.shields.io/pypi/v/pytest-stress.svg
10 | :target: https://pypi.org/project/pytest-stress
11 | :alt: PyPI version
12 |
13 | .. image:: https://img.shields.io/pypi/pyversions/pytest-stress.svg
14 | :target: https://pypi.org/project/pytest-stress
15 | :alt: Python versions
16 |
17 | A plugin that allows you to loop tests for a user-defined amount of time.
18 |
19 | Requirements
20 | ------------
21 |
22 | Only tested with `Pytest`_ version 5.2.2.
23 |
24 |
25 | Installation
26 | ------------
27 |
28 | You can install "pytest-stress" via `pip`_ from `PyPI`_ (highly recommend installing in a `Pipenv`_)::
29 |
30 | $ pip3 install pytest-stress
31 |
32 | Usage
33 | -----
34 |
35 | Loop tests for 30 seconds::
36 |
37 | $ pytest --seconds 30
38 |
39 | Loop tests for 45 minutes::
40 |
41 | $ pytest --minutes 45
42 |
43 | Loop tests for 8 hours::
44 |
45 | $ pytest --hours 8
46 |
47 | Loop tests for 1 hour 8 minutes and 9 seconds::
48 |
49 | $ pytest --hours 1 --minutes 8 --seconds 9
50 |
51 | Need to wait some time after each test loop? Don't say I don't love you::
52 |
53 | $ pytest --delay 5 --hours 4 --minutes 30
54 |
55 | You can also add these values to config files::
56 |
57 | [pytest]
58 | addopts = --hours 1 --minutes 30
59 |
60 | Note: These loop times include setup and teardown operations as well. So if you have a test setup that takes 5
61 | seconds, your actual tests will run for 5 seconds less than your desired time.
62 |
63 | Contributing
64 | ------------
65 | Contributions are very welcome! Tests can be run with `tox`_, please ensure
66 | the coverage at least stays the same before you submit a pull request.
67 |
68 | License
69 | -------
70 |
71 | Distributed under the terms of the `MIT`_ license, "pytest-stress" is free and open source software
72 |
73 |
74 | Issues
75 | ------
76 |
77 | If you encounter any problems, please `file an issue`_ along with a detailed description.
78 |
79 | ____
80 |
81 | This `pytest`_ plugin was generated with `Cookiecutter`_ along with `@hackebrot`_'s `cookiecutter-pytest-plugin`_ template.
82 |
83 | .. _`Cookiecutter`: https://github.com/audreyr/cookiecutter
84 | .. _`@hackebrot`: https://github.com/hackebrot
85 | .. _`MIT`: http://opensource.org/licenses/MIT
86 | .. _`BSD-3`: http://opensource.org/licenses/BSD-3-Clause
87 | .. _`GNU GPL v3.0`: http://www.gnu.org/licenses/gpl-3.0.txt
88 | .. _`Apache Software License 2.0`: http://www.apache.org/licenses/LICENSE-2.0
89 | .. _`cookiecutter-pytest-plugin`: https://github.com/pytest-dev/cookiecutter-pytest-plugin
90 | .. _`file an issue`: https://github.com/pytest-dev/pytest-stress/issues
91 | .. _`pytest`: https://github.com/pytest-dev/pytest
92 | .. _`tox`: https://tox.readthedocs.io/en/latest/
93 | .. _`pip`: https://pypi.org/project/pip/
94 | .. _`pipenv`: https://pypi.org/project/pipenv/
95 | .. _`PyPI`: https://pypi.org/project
96 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import codecs
4 | import os
5 |
6 | from setuptools import setup, find_packages
7 |
8 |
9 | def read(file_name):
10 | file_path = os.path.join(os.path.dirname(__file__), file_name)
11 | return codecs.open(file_path, encoding="utf-8").read()
12 |
13 |
14 | setup(
15 | name="pytest-stress",
16 | version="1.0.1",
17 | author="Imran Mumtaz",
18 | author_email="iomumtaz@gmail.com",
19 | maintainer="Imran Mumtaz",
20 | maintainer_email="iomumtaz@gmail.com",
21 | license="MIT",
22 | url="https://pypi.org/project/pytest-stress",
23 | description="A Pytest plugin that allows you to loop tests for a user defined amount of time.",
24 | long_description=read("README.rst"),
25 | packages=find_packages(where="src"),
26 | package_dir={"": "src"},
27 | project_urls={
28 | 'Homepage': 'https://github.com/pytest-dev/pytest-stress',
29 | 'Source': 'https://github.com/pytest-dev/pytest-stress',
30 | 'Tracker': 'https://github.com/pytest-dev/pytest-stress/issues',
31 | },
32 | python_requires=">=3.6",
33 | install_requires=["pytest>=3.6.0"],
34 | entry_points={"pytest11": ["pytest_stress = pytest_stress.pytest_stress"]},
35 | classifiers=[
36 | "Development Status :: 4 - Beta",
37 | "Framework :: Pytest",
38 | "Intended Audience :: Developers",
39 | "Topic :: Software Development :: Testing",
40 | "Programming Language :: Python",
41 | "Programming Language :: Python :: 3",
42 | "Programming Language :: Python :: 3.6",
43 | "Programming Language :: Python :: 3.7",
44 | "Programming Language :: Python :: 3.8",
45 | "Programming Language :: Python :: 3.9",
46 | "Programming Language :: Python :: 3.10",
47 | "Operating System :: OS Independent",
48 | "License :: OSI Approved :: MIT License",
49 | ],
50 | )
51 |
--------------------------------------------------------------------------------
/src/pytest_stress/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pytest-dev/pytest-stress/2f4a6fb8a3be26963854a3ed7f341668b3cdeefa/src/pytest_stress/__init__.py
--------------------------------------------------------------------------------
/src/pytest_stress/pytest_stress.py:
--------------------------------------------------------------------------------
1 | import shutil
2 | import time
3 |
4 | SECONDS_IN_HOUR = 3600
5 | SECONDS_IN_MINUTE = 60
6 | SHORTEST_AMOUNT_OF_TIME = 0
7 |
8 |
9 | class InvalidTimeParameterError(Exception):
10 | pass
11 |
12 |
13 | def _get_delay_time(session):
14 | """
15 | Helper function to extract the delay time from the session.
16 |
17 | :param session: Pytest session object.
18 | :return: Returns the delay time for each test loop.
19 | """
20 | return session.config.option.delay
21 |
22 |
23 | def _get_total_time(session):
24 | """
25 | Takes all the user available time options, adds them and returns it in seconds.
26 |
27 | :param session: Pytest session object.
28 | :return: Returns total amount of time in seconds.
29 | """
30 | hours_in_seconds = session.config.option.hours * SECONDS_IN_HOUR
31 | minutes_in_seconds = session.config.option.minutes * SECONDS_IN_MINUTE
32 | seconds = session.config.option.seconds
33 | total_time = hours_in_seconds + minutes_in_seconds + seconds
34 | if total_time < SHORTEST_AMOUNT_OF_TIME:
35 | raise InvalidTimeParameterError(f"Total time cannot be less than: {SHORTEST_AMOUNT_OF_TIME}!")
36 | return total_time
37 |
38 |
39 | def _print_loop_count(count):
40 | """
41 | Helper function to simply print out what loop number we're on.
42 |
43 | :param count: The number to print.
44 | :return: None.
45 | """
46 | column_length = shutil.get_terminal_size().columns
47 | print("\n")
48 | print(f" Loop # {count} ".center(column_length, "="))
49 |
50 |
51 | def _timed_out(session, start_time):
52 | """
53 | Helper function to check if the user specified amount of time has lapsed.
54 |
55 | :param session: Pytest session object.
56 | :return: Returns True if the timeout has expired, False otherwise.
57 | """
58 | return time.time() - start_time > _get_total_time(session)
59 |
60 |
61 | def pytest_addoption(parser):
62 | """
63 | Add our command line options.
64 | """
65 | stress = parser.getgroup("stress")
66 | stress.addoption(
67 | "--delay",
68 | action="store",
69 | default=0,
70 | help="The amount of time to wait between each test loop.",
71 | type=int,
72 | )
73 | stress.addoption(
74 | "--hours",
75 | action="store",
76 | default=0,
77 | help="The number of hours to loop the tests for.",
78 | type=int,
79 | )
80 | stress.addoption(
81 | "--minutes",
82 | action="store",
83 | default=0,
84 | help="The number of minutes to loop the tests for.",
85 | type=int,
86 | )
87 | stress.addoption(
88 | "--seconds",
89 | action="store",
90 | default=0,
91 | help="The number of seconds to loop the tests for.",
92 | type=int,
93 | )
94 |
95 |
96 | def pytest_runtestloop(session):
97 | """
98 | Reimplement the test loop but loop for the user defined amount of time.
99 |
100 | Note: Check against pytest repo for any updates so we don't fall behind.
101 | """
102 | if session.testsfailed and not session.config.option.continue_on_collection_errors:
103 | raise session.Interrupted("%d errors during collection" % session.testsfailed)
104 |
105 | if session.config.option.collectonly:
106 | return True
107 |
108 | start_time = time.time()
109 | count = 1
110 |
111 | while True:
112 | if _get_total_time(session):
113 | _print_loop_count(count)
114 | for index, item in enumerate(session.items):
115 | next_item = session.items[index + 1] if index + 1 < len(session.items) else None
116 | item.config.hook.pytest_runtest_protocol(item=item, nextitem=next_item)
117 | if session.shouldfail:
118 | raise session.Failed(session.shouldfail)
119 | if session.shouldstop:
120 | raise session.Interrupted(session.shouldstop)
121 | count += 1
122 | if _timed_out(session, start_time):
123 | break
124 | time.sleep(_get_delay_time(session))
125 | return True
126 |
--------------------------------------------------------------------------------
/tests/test_stress.py:
--------------------------------------------------------------------------------
1 | pytest_plugins = ("pytester",)
2 |
3 |
4 | def test_help_message(testdir):
5 | result = testdir.runpytest("--help")
6 | # fnmatch_lines does an assertion internally
7 | result.stdout.fnmatch_lines(
8 | [
9 | "stress:",
10 | "*--delay=DELAY*The amount of time to wait between each test loop.",
11 | "*--hours=HOURS*The number of hours to loop the tests for.",
12 | "*--minutes=MINUTES*The number of minutes to loop the tests for.",
13 | "*--seconds=SECONDS*The number of seconds to loop the tests for.",
14 | ]
15 | )
16 |
17 |
18 | def test_ini_file(testdir):
19 | testdir.makeini(
20 | """
21 | [pytest]
22 | addopts = --delay=0 --hours=0 --minutes=0 --seconds=0
23 | """
24 | )
25 |
26 | testdir.makepyfile(
27 | """
28 | import pytest
29 |
30 | @pytest.fixture
31 | def addopts(request):
32 | return request.config.getini('addopts')
33 |
34 | def test_ini(addopts):
35 | assert addopts[0] == "--delay=0"
36 | assert addopts[1] == "--hours=0"
37 | assert addopts[2] == "--minutes=0"
38 | assert addopts[3] == "--seconds=0"
39 | """
40 | )
41 |
42 | result = testdir.runpytest("-v")
43 |
44 | # fnmatch_lines does an assertion internally
45 | result.stdout.fnmatch_lines(
46 | ["*::test_ini PASSED*", ]
47 | )
48 |
49 | # Make sure that that we get a '0' exit code for the testsuite
50 | assert result.ret == 0
51 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | # For more information about tox, see https://tox.readthedocs.io/en/latest/
2 | [tox]
3 | envlist = py36, py37, py38, py39, py310, flake8
4 |
5 | [testenv]
6 | passenv =
7 | FORCE_COLOR
8 | commands = pytest tests --verbose
9 | deps = pytest>=3.0
10 |
11 | [testenv:flake8]
12 | basepython = python
13 | deps = flake8
14 | commands = flake8
15 |
16 | [flake8]
17 | max-line-length = 120
18 |
--------------------------------------------------------------------------------