Remove old test dependencies, updated ones still being used. Introduce Black formatter

This commit is contained in:
Daniel 2022-09-17 04:28:01 +00:00
parent 2164220c69
commit 4da66313f4
No known key found for this signature in database
GPG Key ID: 4940B41048AF73EA
9 changed files with 442 additions and 840 deletions

View File

@ -1,4 +1,4 @@
FROM python:3.8-slim-bullseye
FROM python:3.10-slim-bullseye
# Only works for docker CLIENT (bind mounted socket)
COPY --from=docker:20.10.17 /usr/local/bin/docker /usr/local/bin/
@ -10,7 +10,7 @@ RUN apt-get update && \
&& rm -rf /var/lib/apt/lists/* \
&& pip3 install --no-cache-dir -U pip pipenv
RUN curl -L https://github.com/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose && \
RUN curl -L https://github.com/docker/compose/releases/download/2.10.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose && \
chmod +x /usr/local/bin/docker-compose
COPY ./cmd.sh /usr/local/bin/
@ -18,7 +18,7 @@ COPY Pipfile* /root/
WORKDIR /root
RUN pipenv install --system \
&& sed -i 's|/bin/sh|/bin/bash|g' /usr/local/lib/python3.8/site-packages/testinfra/backend/docker.py
&& sed -i 's|/bin/sh|/bin/bash|g' /usr/local/lib/python3.10/site-packages/testinfra/backend/docker.py
RUN echo "set -ex && cmd.sh && \$@" > /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

View File

@ -6,59 +6,10 @@ verify_ssl = true
[dev-packages]
[packages]
apipkg = "==1.5"
atomicwrites = "==1.4.1"
attrs = "==19.3.0"
bcrypt = "==3.1.7"
cached-property = "==1.5.1"
certifi = "==2019.11.28"
cffi = "==1.13.2"
chardet = "==3.0.4"
configparser = "==4.0.2"
contextlib2 = "==0.6.0.post1"
coverage = "==5.0.1"
cryptography = "==3.3.2"
docker = "==4.1.0"
dockerpty = "==0.4.1"
docopt = "==0.6.2"
enum34 = "==1.1.6"
execnet = "==1.7.1"
filelock = "==3.0.12"
funcsigs = "==1.0.2"
idna = "==2.8"
importlib-metadata = "==1.3.0"
ipaddress = "==1.0.23"
jsonschema = "==3.2.0"
more-itertools = "==5.0.0"
pathlib2 = "==2.3.5"
pluggy = "==0.13.1"
py = "==1.10.0"
pycparser = "==2.19"
pyparsing = "==2.4.6"
pyrsistent = "==0.15.6"
pytest = "==4.6.8"
pytest-cov = "==2.8.1"
pytest-forked = "==1.1.3"
pytest-xdist = "==1.31.0"
requests = "==2.28.1"
scandir = "==1.10.0"
six = "==1.13.0"
subprocess32 = "==3.5.4"
testinfra = "==3.3.0"
texttable = "==1.6.2"
toml = "==0.10.0"
tox = "==3.14.3"
urllib3 = "==1.26.5"
virtualenv = "==16.7.9"
wcwidth = "==0.1.7"
zipp = "==0.6.0"
"backports.shutil_get_terminal_size" = "==1.0.0"
"backports.ssl_match_hostname" = "==3.7.0.1"
Jinja2 = "==2.11.3"
MarkupSafe = "==1.1.1"
PyYAML = "==5.4"
websocket_client = "==0.57.0"
python-dotenv = "==0.17.1"
pytest = "==7.1.3"
pytest-xdist = "==2.5.0"
pytest-testinfra = "==6.8.0"
black = "==22.8.0"
[requires]
python_version = "3.8"
python_version = "3"

655
test/Pipfile.lock generated
View File

@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
"sha256": "c679c3eaa7a38959fa47159a01b66d7f7dd1e1667c188c9437a52302ee5a9290"
"sha256": "7cd0c8140d8505e7613e9bf2a9853aaf7cb08a1f100f49db0bec1b94b93be3e1"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
"python_version": "3"
},
"sources": [
{
@ -16,619 +16,160 @@
]
},
"default": {
"apipkg": {
"hashes": [
"sha256:37228cda29411948b422fae072f57e31d3396d2ee1c9783775980ee9c9990af6",
"sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c"
],
"index": "pypi",
"version": "==1.5"
},
"atomicwrites": {
"hashes": [
"sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"
],
"index": "pypi",
"version": "==1.4.1"
},
"attrs": {
"hashes": [
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
"sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6",
"sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"
],
"markers": "python_version >= '3.5'",
"version": "==22.1.0"
},
"black": {
"hashes": [
"sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411",
"sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c",
"sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497",
"sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e",
"sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342",
"sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27",
"sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41",
"sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab",
"sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5",
"sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16",
"sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e",
"sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c",
"sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe",
"sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3",
"sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec",
"sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3",
"sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd",
"sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c",
"sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4",
"sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90",
"sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869",
"sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747",
"sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"
],
"index": "pypi",
"version": "==19.3.0"
"version": "==22.8.0"
},
"backports.shutil-get-terminal-size": {
"click": {
"hashes": [
"sha256:0975ba55054c15e346944b38956a4c9cbee9009391e41b86c68990effb8c1f64",
"sha256:713e7a8228ae80341c70586d1cc0a8caa5207346927e23d09dcbcaf18eadec80"
"sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
"sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
],
"index": "pypi",
"version": "==1.0.0"
},
"backports.ssl-match-hostname": {
"hashes": [
"sha256:bb82e60f9fbf4c080eabd957c39f0641f0fc247d9a16e31e26d594d8f42b9fd2"
],
"index": "pypi",
"version": "==3.7.0.1"
},
"bcrypt": {
"hashes": [
"sha256:0258f143f3de96b7c14f762c770f5fc56ccd72f8a1857a451c1cd9a655d9ac89",
"sha256:0b0069c752ec14172c5f78208f1863d7ad6755a6fae6fe76ec2c80d13be41e42",
"sha256:19a4b72a6ae5bb467fea018b825f0a7d917789bcfe893e53f15c92805d187294",
"sha256:436a487dec749bca7e6e72498a75a5fa2433bda13bac91d023e18df9089ae0b8",
"sha256:5432dd7b34107ae8ed6c10a71b4397f1c853bd39a4d6ffa7e35f40584cffd161",
"sha256:6305557019906466fc42dbc53b46da004e72fd7a551c044a827e572c82191752",
"sha256:69361315039878c0680be456640f8705d76cb4a3a3fe1e057e0f261b74be4b31",
"sha256:6fe49a60b25b584e2f4ef175b29d3a83ba63b3a4df1b4c0605b826668d1b6be5",
"sha256:74a015102e877d0ccd02cdeaa18b32aa7273746914a6c5d0456dd442cb65b99c",
"sha256:763669a367869786bb4c8fcf731f4175775a5b43f070f50f46f0b59da45375d0",
"sha256:8b10acde4e1919d6015e1df86d4c217d3b5b01bb7744c36113ea43d529e1c3de",
"sha256:9fe92406c857409b70a38729dbdf6578caf9228de0aef5bc44f859ffe971a39e",
"sha256:a190f2a5dbbdbff4b74e3103cef44344bc30e61255beb27310e2aec407766052",
"sha256:a595c12c618119255c90deb4b046e1ca3bcfad64667c43d1166f2b04bc72db09",
"sha256:c9457fa5c121e94a58d6505cadca8bed1c64444b83b3204928a866ca2e599105",
"sha256:cb93f6b2ab0f6853550b74e051d297c27a638719753eb9ff66d1e4072be67133",
"sha256:ce4e4f0deb51d38b1611a27f330426154f2980e66582dc5f438aad38b5f24fc1",
"sha256:d7bdc26475679dd073ba0ed2766445bb5b20ca4793ca0db32b399dccc6bc84b7",
"sha256:ff032765bb8716d9387fd5376d987a937254b0619eff0972779515b5c98820bc"
],
"index": "pypi",
"version": "==3.1.7"
},
"cached-property": {
"hashes": [
"sha256:3a026f1a54135677e7da5ce819b0c690f156f37976f3e30c5430740725203d7f",
"sha256:9217a59f14a5682da7c4b8829deadbfc194ac22e9908ccf7c8820234e80a1504"
],
"index": "pypi",
"version": "==1.5.1"
},
"certifi": {
"hashes": [
"sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3",
"sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"
],
"index": "pypi",
"version": "==2019.11.28"
},
"cffi": {
"hashes": [
"sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42",
"sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04",
"sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5",
"sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54",
"sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba",
"sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57",
"sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396",
"sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12",
"sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97",
"sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43",
"sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db",
"sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3",
"sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b",
"sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579",
"sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346",
"sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159",
"sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652",
"sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e",
"sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a",
"sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506",
"sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f",
"sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d",
"sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c",
"sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20",
"sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858",
"sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc",
"sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a",
"sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3",
"sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e",
"sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410",
"sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25",
"sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b",
"sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d"
],
"index": "pypi",
"version": "==1.13.2"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"index": "pypi",
"version": "==3.0.4"
},
"charset-normalizer": {
"hashes": [
"sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5",
"sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413"
],
"markers": "python_full_version >= '3.6.0'",
"version": "==2.1.0"
},
"configparser": {
"hashes": [
"sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c",
"sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df"
],
"index": "pypi",
"version": "==4.0.2"
},
"contextlib2": {
"hashes": [
"sha256:01f490098c18b19d2bd5bb5dc445b2054d2fa97f09a4280ba2c5f3c394c8162e",
"sha256:3355078a159fbb44ee60ea80abd0d87b80b78c248643b49aa6d94673b413609b"
],
"index": "pypi",
"version": "==0.6.0.post1"
},
"coverage": {
"hashes": [
"sha256:0101888bd1592a20ccadae081ba10e8b204d20235d18d05c6f7d5e904a38fc10",
"sha256:04b961862334687549eb91cd5178a6fbe977ad365bddc7c60f2227f2f9880cf4",
"sha256:1ca43dbd739c0fc30b0a3637a003a0d2c7edc1dd618359d58cc1e211742f8bd1",
"sha256:1cbb88b34187bdb841f2599770b7e6ff8e259dc3bb64fc7893acf44998acf5f8",
"sha256:232f0b52a5b978288f0bbc282a6c03fe48cd19a04202df44309919c142b3bb9c",
"sha256:24bcfa86fd9ce86b73a8368383c39d919c497a06eebb888b6f0c12f13e920b1a",
"sha256:25b8f60b5c7da71e64c18888f3067d5b6f1334b9681876b2fb41eea26de881ae",
"sha256:2714160a63da18aed9340c70ed514973971ee7e665e6b336917ff4cca81a25b1",
"sha256:2ca2cd5264e84b2cafc73f0045437f70c6378c0d7dbcddc9ee3fe192c1e29e5d",
"sha256:2cc707fc9aad2592fc686d63ef72dc0031fc98b6fb921d2f5395d9ab84fbc3ef",
"sha256:348630edea485f4228233c2f310a598abf8afa5f8c716c02a9698089687b6085",
"sha256:40fbfd6b044c9db13aeec1daf5887d322c710d811f944011757526ef6e323fd9",
"sha256:46c9c6a1d1190c0b75ec7c0f339088309952b82ae8d67a79ff1319eb4e749b96",
"sha256:591506e088901bdc25620c37aec885e82cc896528f28c57e113751e3471fc314",
"sha256:5ac71bba1e07eab403b082c4428f868c1c9e26a21041436b4905c4c3d4e49b08",
"sha256:5f622f19abda4e934938e24f1d67599249abc201844933a6f01aaa8663094489",
"sha256:65bead1ac8c8930cf92a1ccaedcce19a57298547d5d1db5c9d4d068a0675c38b",
"sha256:7362a7f829feda10c7265b553455de596b83d1623b3d436b6d3c51c688c57bf6",
"sha256:7f2675750c50151f806070ec11258edf4c328340916c53bac0adbc465abd6b1e",
"sha256:960d7f42277391e8b1c0b0ae427a214e1b31a1278de6b73f8807b20c2e913bba",
"sha256:a50b0888d8a021a3342d36a6086501e30de7d840ab68fca44913e97d14487dc1",
"sha256:b7dbc5e8c39ea3ad3db22715f1b5401cd698a621218680c6daf42c2f9d36e205",
"sha256:bb3d29df5d07d5399d58a394d0ef50adf303ab4fbf66dfd25b9ef258effcb692",
"sha256:c0fff2733f7c2950f58a4fd09b5db257b00c6fec57bf3f68c5bae004d804b407",
"sha256:c792d3707a86c01c02607ae74364854220fb3e82735f631cd0a345dea6b4cee5",
"sha256:c90bda74e16bcd03861b09b1d37c0a4158feda5d5a036bb2d6e58de6ff65793e",
"sha256:cfce79ce41cc1a1dc7fc85bb41eeeb32d34a4cf39a645c717c0550287e30ff06",
"sha256:eeafb646f374988c22c8e6da5ab9fb81367ecfe81c70c292623373d2a021b1a1",
"sha256:f425f50a6dd807cb9043d15a4fcfba3b5874a54d9587ccbb748899f70dc18c47",
"sha256:fcd4459fe35a400b8f416bc57906862693c9f88b66dc925e7f2a933e77f6b18b",
"sha256:ff3936dd5feaefb4f91c8c1f50a06c588b5dc69fba4f7d9c79a6617ad80bb7df"
],
"index": "pypi",
"version": "==5.0.1"
},
"cryptography": {
"hashes": [
"sha256:0d7b69674b738068fa6ffade5c962ecd14969690585aaca0a1b1fc9058938a72",
"sha256:1bd0ccb0a1ed775cd7e2144fe46df9dc03eefd722bbcf587b3e0616ea4a81eff",
"sha256:3c284fc1e504e88e51c428db9c9274f2da9f73fdf5d7e13a36b8ecb039af6e6c",
"sha256:49570438e60f19243e7e0d504527dd5fe9b4b967b5a1ff21cc12b57602dd85d3",
"sha256:541dd758ad49b45920dda3b5b48c968f8b2533d8981bcdb43002798d8f7a89ed",
"sha256:5a60d3780149e13b7a6ff7ad6526b38846354d11a15e21068e57073e29e19bed",
"sha256:7951a966613c4211b6612b0352f5bf29989955ee592c4a885d8c7d0f830d0433",
"sha256:922f9602d67c15ade470c11d616f2b2364950602e370c76f0c94c94ae672742e",
"sha256:a0f0b96c572fc9f25c3f4ddbf4688b9b38c69836713fb255f4a2715d93cbaf44",
"sha256:a777c096a49d80f9d2979695b835b0f9c9edab73b59e4ceb51f19724dda887ed",
"sha256:a9a4ac9648d39ce71c2f63fe7dc6db144b9fa567ddfc48b9fde1b54483d26042",
"sha256:aa4969f24d536ae2268c902b2c3d62ab464b5a66bcb247630d208a79a8098e9b",
"sha256:c7390f9b2119b2b43160abb34f63277a638504ef8df99f11cb52c1fda66a2e6f",
"sha256:e18e6ab84dfb0ab997faf8cca25a86ff15dfea4027b986322026cc99e0a892da"
],
"index": "pypi",
"version": "==3.3.2"
},
"docker": {
"hashes": [
"sha256:6e06c5e70ba4fad73e35f00c55a895a448398f3ada7faae072e2bb01348bafc1",
"sha256:8f93775b8bdae3a2df6bc9a5312cce564cade58d6555f2c2570165a1270cd8a7"
],
"index": "pypi",
"version": "==4.1.0"
},
"dockerpty": {
"hashes": [
"sha256:69a9d69d573a0daa31bcd1c0774eeed5c15c295fe719c61aca550ed1393156ce"
],
"index": "pypi",
"version": "==0.4.1"
},
"docopt": {
"hashes": [
"sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
],
"index": "pypi",
"version": "==0.6.2"
},
"enum34": {
"hashes": [
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
"sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a",
"sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
"sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
],
"index": "pypi",
"version": "==1.1.6"
"markers": "python_version >= '3.7'",
"version": "==8.1.3"
},
"execnet": {
"hashes": [
"sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50",
"sha256:d4efd397930c46415f62f8a31388d6be4f27a91d7550eb79bc64a756e0056547"
"sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5",
"sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"
],
"index": "pypi",
"version": "==1.7.1"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==1.9.0"
},
"filelock": {
"iniconfig": {
"hashes": [
"sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
"sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"
"sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
"sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"
],
"index": "pypi",
"version": "==3.0.12"
},
"funcsigs": {
"hashes": [
"sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca",
"sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"
],
"index": "pypi",
"version": "==1.0.2"
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
],
"index": "pypi",
"version": "==2.8"
},
"importlib-metadata": {
"hashes": [
"sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45",
"sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f"
],
"index": "pypi",
"version": "==1.3.0"
},
"ipaddress": {
"hashes": [
"sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc",
"sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2"
],
"index": "pypi",
"version": "==1.0.23"
},
"jinja2": {
"hashes": [
"sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
"sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
],
"index": "pypi",
"version": "==2.11.3"
},
"jsonschema": {
"hashes": [
"sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163",
"sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"
],
"index": "pypi",
"version": "==3.2.0"
},
"markupsafe": {
"hashes": [
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
"sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f",
"sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39",
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
"sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014",
"sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f",
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
"sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85",
"sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1",
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
"sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850",
"sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0",
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
"sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb",
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
"sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1",
"sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2",
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
"sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7",
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
"sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8",
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
"sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193",
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
"sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b",
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
"sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5",
"sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c",
"sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032",
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be",
"sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"
],
"index": "pypi",
"version": "==1.1.1"
},
"more-itertools": {
"mypy-extensions": {
"hashes": [
"sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4",
"sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc",
"sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
"sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
],
"index": "pypi",
"version": "==5.0.0"
"version": "==0.4.3"
},
"packaging": {
"hashes": [
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
],
"markers": "python_full_version >= '3.6.0'",
"markers": "python_version >= '3.6'",
"version": "==21.3"
},
"pathlib2": {
"pathspec": {
"hashes": [
"sha256:0ec8205a157c80d7acc301c0b18fbd5d44fe655968f5d947b6ecef5290fc35db",
"sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868"
"sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93",
"sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"
],
"index": "pypi",
"version": "==2.3.5"
"markers": "python_version >= '3.7'",
"version": "==0.10.1"
},
"platformdirs": {
"hashes": [
"sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788",
"sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"
],
"markers": "python_version >= '3.7'",
"version": "==2.5.2"
},
"pluggy": {
"hashes": [
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
"sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
"sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
],
"index": "pypi",
"version": "==0.13.1"
"markers": "python_version >= '3.6'",
"version": "==1.0.0"
},
"py": {
"hashes": [
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
"sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719",
"sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"
],
"index": "pypi",
"version": "==1.10.0"
},
"pycparser": {
"hashes": [
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
],
"index": "pypi",
"version": "==2.19"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==1.11.0"
},
"pyparsing": {
"hashes": [
"sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f",
"sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"
"sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb",
"sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"
],
"index": "pypi",
"version": "==2.4.6"
},
"pyrsistent": {
"hashes": [
"sha256:f3b280d030afb652f79d67c5586157c5c1355c9a58dfc7940566e28d28f3df1b"
],
"index": "pypi",
"version": "==0.15.6"
"markers": "python_full_version >= '3.6.8'",
"version": "==3.0.9"
},
"pytest": {
"hashes": [
"sha256:6192875be8af57b694b7c4904e909680102befcb99e610ef3d9f786952f795aa",
"sha256:f8447ebf8fd3d362868a5d3f43a9df786dfdfe9608843bd9002a2d47a104808f"
"sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7",
"sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"
],
"index": "pypi",
"version": "==4.6.8"
},
"pytest-cov": {
"hashes": [
"sha256:cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b",
"sha256:cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"
],
"index": "pypi",
"version": "==2.8.1"
"version": "==7.1.3"
},
"pytest-forked": {
"hashes": [
"sha256:1805699ed9c9e60cb7a8179b8d4fa2b8898098e82d229b0825d8095f0f261100",
"sha256:1ae25dba8ee2e56fb47311c9638f9e58552691da87e82d25b0ce0e4bf52b7d87"
"sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e",
"sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"
],
"markers": "python_version >= '3.6'",
"version": "==1.4.0"
},
"pytest-testinfra": {
"hashes": [
"sha256:07c8c2c472aca7d83099ebc5f850d383721cd654b66c60ffbb145e45e584ff99",
"sha256:56ac1dfc61342632a1189091473e253db1a3cdcecce0d49d6a769f33cd264814"
],
"index": "pypi",
"version": "==1.1.3"
"version": "==6.8.0"
},
"pytest-xdist": {
"hashes": [
"sha256:0f46020d3d9619e6d17a65b5b989c1ebbb58fc7b1da8fb126d70f4bac4dfeed1",
"sha256:7dc0d027d258cd0defc618fb97055fbd1002735ca7a6d17037018cf870e24011"
"sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf",
"sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"
],
"index": "pypi",
"version": "==1.31.0"
"version": "==2.5.0"
},
"python-dotenv": {
"tomli": {
"hashes": [
"sha256:00aa34e92d992e9f8383730816359647f358f4a3be1ba45e5a5cefd27ee91544",
"sha256:b1ae5e9643d5ed987fc57cc2583021e38db531946518130777734f9589b3141f"
"sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
"sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
],
"index": "pypi",
"version": "==0.17.1"
},
"pyyaml": {
"hashes": [
"sha256:02c78d77281d8f8d07a255e57abdbf43b02257f59f50cc6b636937d68efa5dd0",
"sha256:0dc9f2eb2e3c97640928dec63fd8dc1dd91e6b6ed236bd5ac00332b99b5c2ff9",
"sha256:124fd7c7bc1e95b1eafc60825f2daf67c73ce7b33f1194731240d24b0d1bf628",
"sha256:26fcb33776857f4072601502d93e1a619f166c9c00befb52826e7b774efaa9db",
"sha256:31ba07c54ef4a897758563e3a0fcc60077698df10180abe4b8165d9895c00ebf",
"sha256:3c49e39ac034fd64fd576d63bb4db53cda89b362768a67f07749d55f128ac18a",
"sha256:52bf0930903818e600ae6c2901f748bc4869c0c406056f679ab9614e5d21a166",
"sha256:5a3f345acff76cad4aa9cb171ee76c590f37394186325d53d1aa25318b0d4a09",
"sha256:5e7ac4e0e79a53451dc2814f6876c2fa6f71452de1498bbe29c0b54b69a986f4",
"sha256:7242790ab6c20316b8e7bb545be48d7ed36e26bbe279fd56f2c4a12510e60b4b",
"sha256:737bd70e454a284d456aa1fa71a0b429dd527bcbf52c5c33f7c8eee81ac16b89",
"sha256:8635d53223b1f561b081ff4adecb828fd484b8efffe542edcfdff471997f7c39",
"sha256:8b818b6c5a920cbe4203b5a6b14256f0e5244338244560da89b7b0f1313ea4b6",
"sha256:8bf38641b4713d77da19e91f8b5296b832e4db87338d6aeffe422d42f1ca896d",
"sha256:a36a48a51e5471513a5aea920cdad84cbd56d70a5057cca3499a637496ea379c",
"sha256:b2243dd033fd02c01212ad5c601dafb44fbb293065f430b0d3dbf03f3254d615",
"sha256:cc547d3ead3754712223abb7b403f0a184e4c3eae18c9bb7fd15adef1597cc4b",
"sha256:cc552b6434b90d9dbed6a4f13339625dc466fd82597119897e9489c953acbc22",
"sha256:f3790156c606299ff499ec44db422f66f05a7363b39eb9d5b064f17bd7d7c47b",
"sha256:f7a21e3d99aa3095ef0553e7ceba36fb693998fbb1226f1392ce33681047465f",
"sha256:fdc6b2cb4b19e431994f25a9160695cc59a4e861710cc6fc97161c5e845fc579"
],
"index": "pypi",
"version": "==5.4"
},
"requests": {
"hashes": [
"sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983",
"sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"
],
"index": "pypi",
"version": "==2.28.1"
},
"scandir": {
"hashes": [
"sha256:2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e",
"sha256:2ae41f43797ca0c11591c0c35f2f5875fa99f8797cb1a1fd440497ec0ae4b022",
"sha256:2b8e3888b11abb2217a32af0766bc06b65cc4a928d8727828ee68af5a967fa6f",
"sha256:2c712840c2e2ee8dfaf36034080108d30060d759c7b73a01a52251cc8989f11f",
"sha256:4d4631f6062e658e9007ab3149a9b914f3548cb38bfb021c64f39a025ce578ae",
"sha256:67f15b6f83e6507fdc6fca22fedf6ef8b334b399ca27c6b568cbfaa82a364173",
"sha256:7d2d7a06a252764061a020407b997dd036f7bd6a175a5ba2b345f0a357f0b3f4",
"sha256:8c5922863e44ffc00c5c693190648daa6d15e7c1207ed02d6f46a8dcc2869d32",
"sha256:92c85ac42f41ffdc35b6da57ed991575bdbe69db895507af88b9f499b701c188",
"sha256:b24086f2375c4a094a6b51e78b4cf7ca16c721dcee2eddd7aa6494b42d6d519d",
"sha256:cb925555f43060a1745d0a321cca94bcea927c50114b623d73179189a4e100ac"
],
"index": "pypi",
"version": "==1.10.0"
},
"setuptools": {
"hashes": [
"sha256:16923d366ced322712c71ccb97164d07472abeecd13f3a6c283f6d5d26722793",
"sha256:db3b8e2f922b2a910a29804776c643ea609badb6a32c4bcc226fd4fd902cce65"
],
"markers": "python_version >= '3.7'",
"version": "==63.1.0"
},
"six": {
"hashes": [
"sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
"sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
],
"index": "pypi",
"version": "==1.13.0"
},
"subprocess32": {
"hashes": [
"sha256:88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b",
"sha256:e45d985aef903c5b7444d34350b05da91a9e0ea015415ab45a21212786c649d0",
"sha256:eb2937c80497978d181efa1b839ec2d9622cf9600a039a79d0e108d1f9aec79d"
],
"index": "pypi",
"version": "==3.5.4"
},
"testinfra": {
"hashes": [
"sha256:780e6c2ab392ea93c26cee1777c968a144c2189a56b3e239a3a66e6d256925b5",
"sha256:c3492b39c8d2c98d8419ce1a91d7fe348213f9b98b91198d2e7e88b3954b050b"
],
"index": "pypi",
"version": "==3.3.0"
},
"texttable": {
"hashes": [
"sha256:7dc282a5b22564fe0fdc1c771382d5dd9a54742047c61558e071c8cd595add86",
"sha256:eff3703781fbc7750125f50e10f001195174f13825a92a45e9403037d539b4f4"
],
"index": "pypi",
"version": "==1.6.2"
},
"toml": {
"hashes": [
"sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
"sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e",
"sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"
],
"index": "pypi",
"version": "==0.10.0"
},
"tox": {
"hashes": [
"sha256:06ba73b149bf838d5cd25dc30c2dd2671ae5b2757cf98e5c41a35fe449f131b3",
"sha256:806d0a9217584558cc93747a945a9d9bff10b141a5287f0c8429a08828a22192"
],
"index": "pypi",
"version": "==3.14.3"
},
"urllib3": {
"hashes": [
"sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c",
"sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"
],
"index": "pypi",
"version": "==1.26.5"
},
"virtualenv": {
"hashes": [
"sha256:0d62c70883c0342d59c11d0ddac0d954d0431321a41ab20851facf2b222598f3",
"sha256:55059a7a676e4e19498f1aad09b8313a38fcc0cdbe4fdddc0e9b06946d21b4bb"
],
"index": "pypi",
"version": "==16.7.9"
},
"wcwidth": {
"hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"
],
"index": "pypi",
"version": "==0.1.7"
},
"websocket-client": {
"hashes": [
"sha256:0fc45c961324d79c781bab301359d5a1b00b13ad1b10415a4780229ef71a5549",
"sha256:d735b91d6d1692a6a181f2a8c9e0238e5f6373356f561bb9dc4c7af36f452010"
],
"index": "pypi",
"version": "==0.57.0"
},
"zipp": {
"hashes": [
"sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e",
"sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"
],
"index": "pypi",
"version": "==0.6.0"
"markers": "python_full_version < '3.11.0a7'",
"version": "==2.0.1"
}
},
"develop": {}

View File

@ -12,3 +12,8 @@ Should result in:
- An image named `pihole:[branch-name]` being built
- Tests being ran to confirm the image doesn't have any regressions
# Modify Pipfile
You can enter into the test docker image using `./build-and-test.sh enter`.
From there, you can `cd test` and execute any needed pipenv commands.

View File

@ -4,6 +4,9 @@ set -eux
docker build ./src --tag pihole:${GIT_TAG} --no-cache
docker images
# auto-format the pytest code
python -m black ./test/tests/
# TODO: Add junitxml output and have something consume it
# 2 parallel max b/c race condition with docker fixture (I think?)
py.test -vv -n 2 ./test/tests/

View File

@ -1,55 +0,0 @@
-i https://pypi.org/simple/
apipkg==1.5
atomicwrites==1.3.0
attrs==19.3.0
backports.shutil-get-terminal-size==1.0.0
backports.ssl-match-hostname==3.7.0.1
bcrypt==3.1.7
cached-property==1.5.1
certifi==2019.11.28
cffi==1.13.2
chardet==3.0.4
configparser==4.0.2
contextlib2==0.6.0.post1
coverage==5.0.1
cryptography==3.3.2
docker==4.1.0
dockerpty==0.4.1
docopt==0.6.2
enum34==1.1.6
execnet==1.7.1
filelock==3.0.12
funcsigs==1.0.2
idna==2.8
importlib-metadata==1.3.0
ipaddress==1.0.23
jinja2==2.11.3
jsonschema==3.2.0
markupsafe==1.1.1
more-itertools==5.0.0
packaging==20.9
pathlib2==2.3.5
pluggy==0.13.1
py==1.10.0
pycparser==2.19
pyparsing==2.4.6
pyrsistent==0.15.6
pytest-cov==2.8.1
pytest-forked==1.1.3
pytest-xdist==1.31.0
pytest==4.6.8
pyyaml==5.4
requests==2.22.0
scandir==1.10.0
six==1.13.0
subprocess32==3.5.4
testinfra==3.3.0
texttable==1.6.2
toml==0.10.0
tox==3.14.3
urllib3==1.26.5
virtualenv==16.7.9
wcwidth==0.1.7
websocket-client==0.57.0
zipp==0.6.0
python-dotenv==0.17.1

View File

@ -3,63 +3,79 @@ import pytest
import subprocess
import testinfra
local_host = testinfra.get_host('local://')
local_host = testinfra.get_host("local://")
check_output = local_host.check_output
TAIL_DEV_NULL='tail -f /dev/null'
TAIL_DEV_NULL = "tail -f /dev/null"
@pytest.fixture()
def run_and_stream_command_output():
def run_and_stream_command_output_inner(command, verbose=False):
print("Running", command)
build_env = os.environ.copy()
build_env['PIHOLE_DOCKER_TAG'] = version
build_result = subprocess.Popen(command.split(), env=build_env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
bufsize=1, universal_newlines=True)
build_env["PIHOLE_DOCKER_TAG"] = version
build_result = subprocess.Popen(
command.split(),
env=build_env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
bufsize=1,
universal_newlines=True,
)
if verbose:
while build_result.poll() is None:
for line in build_result.stdout:
print(line, end='')
print(line, end="")
build_result.wait()
if build_result.returncode != 0:
print(f' [i] Error running: {command}')
print(f" [i] Error running: {command}")
print(build_result.stderr)
return run_and_stream_command_output_inner
@pytest.fixture()
def args_volumes():
return '-v /dev/null:/etc/pihole/adlists.list'
return "-v /dev/null:/etc/pihole/adlists.list"
@pytest.fixture()
def args_env():
return '-e FTLCONF_LOCAL_IPV4="127.0.0.1"'
@pytest.fixture()
def args(args_volumes, args_env):
return "{} {}".format(args_volumes, args_env)
@pytest.fixture()
def test_args():
''' test override fixture to provide arguments separate from our core args '''
return ''
"""test override fixture to provide arguments separate from our core args"""
return ""
def docker_generic(request, _test_args, _args, _image, _cmd, _entrypoint):
#assert 'docker' in check_output('id'), "Are you in the docker group?"
# assert 'docker' in check_output('id'), "Are you in the docker group?"
# Always appended PYTEST arg to tell pihole we're testing
if 'pihole' in _image and 'PYTEST=1' not in _args:
_args = '{} -e PYTEST=1'.format(_args)
docker_run = 'docker run -d -t {args} {test_args} {entry} {image} {cmd}'\
.format(args=_args, test_args=_test_args, entry=_entrypoint, image=_image, cmd=_cmd)
if "pihole" in _image and "PYTEST=1" not in _args:
_args = "{} -e PYTEST=1".format(_args)
docker_run = "docker run -d -t {args} {test_args} {entry} {image} {cmd}".format(
args=_args, test_args=_test_args, entry=_entrypoint, image=_image, cmd=_cmd
)
# Print a human runable version of the container run command for faster debugging
print(docker_run.replace('-d -t', '--rm -it').replace(TAIL_DEV_NULL, 'bash'))
print(docker_run.replace("-d -t", "--rm -it").replace(TAIL_DEV_NULL, "bash"))
docker_id = check_output(docker_run)
def teardown():
check_output("docker logs {}".format(docker_id))
check_output("docker rm -f {}".format(docker_id))
request.addfinalizer(teardown)
docker_container = testinfra.backend.get_backend("docker://" + docker_id, sudo=False)
request.addfinalizer(teardown)
docker_container = testinfra.backend.get_backend(
"docker://" + docker_id, sudo=False
)
docker_container.id = docker_id
return docker_container
@ -67,90 +83,126 @@ def docker_generic(request, _test_args, _args, _image, _cmd, _entrypoint):
@pytest.fixture
def docker(request, test_args, args, image, cmd, entrypoint):
''' One-off Docker container run '''
"""One-off Docker container run"""
return docker_generic(request, test_args, args, image, cmd, entrypoint)
@pytest.fixture(scope='module')
def docker_persist(request, persist_test_args, persist_args, persist_image, persist_cmd, persist_entrypoint, dig):
''' Persistent Docker container for multiple tests, instead of stopping container after one test '''
''' Uses DUP'd module scoped fixtures because smaller scoped fixtures won't mix with module scope '''
persistent_container = docker_generic(request, persist_test_args, persist_args, persist_image, persist_cmd, persist_entrypoint)
''' attach a dig container for lookups '''
@pytest.fixture(scope="module")
def docker_persist(
request,
persist_test_args,
persist_args,
persist_image,
persist_cmd,
persist_entrypoint,
dig,
):
"""
Persistent Docker container for multiple tests, instead of stopping container after one test
Uses DUP'd module scoped fixtures because smaller scoped fixtures won't mix with module scope
"""
persistent_container = docker_generic(
request,
persist_test_args,
persist_args,
persist_image,
persist_cmd,
persist_entrypoint,
)
""" attach a dig container for lookups """
persistent_container.dig = dig(persistent_container.id)
return persistent_container
@pytest.fixture
def entrypoint():
return ''
return ""
@pytest.fixture()
def version():
return os.environ.get('GIT_TAG', None)
return os.environ.get("GIT_TAG", None)
@pytest.fixture()
def tag(version):
return '{}'.format(version)
return "{}".format(version)
@pytest.fixture
def webserver(tag):
''' TODO: this is obvious without alpine+nginx as the alternative, remove fixture, hard code lighttpd in tests? '''
return 'lighttpd'
"""TODO: this is obvious without alpine+nginx as the alternative, remove fixture, hard code lighttpd in tests?"""
return "lighttpd"
@pytest.fixture()
def image(tag):
image = 'pihole'
return '{}:{}'.format(image, tag)
image = "pihole"
return "{}:{}".format(image, tag)
@pytest.fixture()
def cmd():
return TAIL_DEV_NULL
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_version():
return version
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_args_dns():
return '--dns 127.0.0.1 --dns 1.1.1.1'
return "--dns 127.0.0.1 --dns 1.1.1.1"
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_args_volumes():
return '-v /dev/null:/etc/pihole/adlists.list'
return "-v /dev/null:/etc/pihole/adlists.list"
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_args_env():
return '-e ServerIP="127.0.0.1"'
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_args(persist_args_volumes, persist_args_env):
return "{} {}".format(persist_args_volumes, persist_args_env)
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_test_args():
''' test override fixture to provide arguments separate from our core args '''
return ''
"""test override fixture to provide arguments separate from our core args"""
return ""
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_tag(persist_version):
return '{}'.format(persist_version)
return "{}".format(persist_version)
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_webserver(persist_tag):
''' TODO: this is obvious without alpine+nginx as the alternative, remove fixture, hard code lighttpd in tests? '''
return 'lighttpd'
"""TODO: this is obvious without alpine+nginx as the alternative, remove fixture, hard code lighttpd in tests?"""
return "lighttpd"
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_image(persist_tag):
image = 'pihole'
return '{}:{}'.format(image, persist_tag)
image = "pihole"
return "{}:{}".format(image, persist_tag)
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_cmd():
return TAIL_DEV_NULL
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def persist_entrypoint():
return ''
return ""
@pytest.fixture
def slow():
@ -158,6 +210,7 @@ def slow():
Run a slow check, check if the state is correct for `timeout` seconds.
"""
import time
def _slow(check, timeout=20):
timeout_at = time.time() + timeout
while True:
@ -170,26 +223,28 @@ def slow():
raise e
else:
return
return _slow
@pytest.fixture(scope='module')
@pytest.fixture(scope="module")
def dig():
''' separate container to link to pi-hole and perform lookups '''
''' a docker pull is faster than running an install of dnsutils '''
"""separate container to link to pi-hole and perform lookups"""
""" a docker pull is faster than running an install of dnsutils """
def _dig(docker_id):
args = '--link {}:test_pihole'.format(docker_id)
image = 'azukiapp/dig'
cmd = TAIL_DEV_NULL
dig_container = docker_generic(request, '', args, image, cmd, '')
args = "--link {}:test_pihole".format(docker_id)
image = "azukiapp/dig"
cmd = TAIL_DEV_NULL
dig_container = docker_generic(request, "", args, image, cmd, "")
return dig_container
return _dig
'''
Persistent Docker container for testing service post _startup.sh
'''
@pytest.fixture
def running_pihole(docker_persist, slow, persist_webserver):
''' Persist a fully started docker-pi-hole to help speed up subsequent tests '''
slow(lambda: docker_persist.run('pgrep pihole-FTL').rc == 0)
slow(lambda: docker_persist.run('pgrep lighttpd').rc == 0)
return docker_persist
"""Persist a fully started docker-pi-hole to help speed up subsequent tests"""
slow(lambda: docker_persist.run("pgrep pihole-FTL").rc == 0)
slow(lambda: docker_persist.run("pgrep lighttpd").rc == 0)
return docker_persist

View File

@ -1,165 +1,249 @@
import os
import pytest
import re
SETUPVARS_LOC='/etc/pihole/setupVars.conf'
DNSMASQ_CONFIG_LOC = '/etc/dnsmasq.d/01-pihole.conf'
CMD_SETUP_FTL_CACHESIZE='. bash_functions.sh ; setup_FTL_CacheSize'
CMD_SETUP_FTL_INTERFACE='. bash_functions.sh ; setup_FTL_Interface'
CMD_SETUP_WEB_PASSWORD='. bash_functions.sh ; setup_web_password'
SETUPVARS_LOC = "/etc/pihole/setupVars.conf"
DNSMASQ_CONFIG_LOC = "/etc/dnsmasq.d/01-pihole.conf"
CMD_SETUP_FTL_CACHESIZE = ". bash_functions.sh ; setup_FTL_CacheSize"
CMD_SETUP_FTL_INTERFACE = ". bash_functions.sh ; setup_FTL_Interface"
CMD_SETUP_WEB_PASSWORD = ". bash_functions.sh ; setup_web_password"
def _cat(file):
return 'cat {}'.format(file)
return "cat {}".format(file)
def _grep(string, file):
return 'grep -q \'{}\' {}'.format(string,file)
return "grep -q '{}' {}".format(string, file)
@pytest.mark.parametrize('test_args,expected_ipv6,expected_stdout', [
('', True, 'IPv4 and IPv6'),
('-e "IPv6=True"', True, 'IPv4 and IPv6'),
('-e "IPv6=False"', False, 'IPv4'),
('-e "IPv6=foobar"', False, 'IPv4'),
])
def test_ipv6_not_true_removes_ipv6(docker, slow, test_args, expected_ipv6, expected_stdout):
''' When a user overrides IPv6=True they only get IPv4 listening webservers '''
IPV6_LINE = 'use-ipv6.pl'
WEB_CONFIG = '/etc/lighttpd/lighttpd.conf'
function = docker.run('. /usr/local/bin/bash_functions.sh ; setup_ipv4_ipv6')
@pytest.mark.parametrize(
"test_args,expected_ipv6,expected_stdout",
[
("", True, "IPv4 and IPv6"),
('-e "IPv6=True"', True, "IPv4 and IPv6"),
('-e "IPv6=False"', False, "IPv4"),
('-e "IPv6=foobar"', False, "IPv4"),
],
)
def test_ipv6_not_true_removes_ipv6(
docker, slow, test_args, expected_ipv6, expected_stdout
):
"""When a user overrides IPv6=True they only get IPv4 listening webservers"""
IPV6_LINE = "use-ipv6.pl"
WEB_CONFIG = "/etc/lighttpd/lighttpd.conf"
function = docker.run(". /usr/local/bin/bash_functions.sh ; setup_ipv4_ipv6")
assert "Using {}".format(expected_stdout) in function.stdout
if expected_stdout == 'IPv4':
assert 'IPv6' not in function.stdout
if expected_stdout == "IPv4":
assert "IPv6" not in function.stdout
# On overlay2(?) docker sometimes writes to disk are slow enough to break some tests...
expected_ipv6_check = lambda: (\
IPV6_LINE in docker.run('grep \'use-ipv6.pl\' {}'.format(WEB_CONFIG)).stdout
) == expected_ipv6
expected_ipv6_check = (
lambda: (
IPV6_LINE in docker.run("grep 'use-ipv6.pl' {}".format(WEB_CONFIG)).stdout
)
== expected_ipv6
)
slow(expected_ipv6_check)
@pytest.mark.parametrize('test_args', ['-e "WEB_PORT=999"'])
@pytest.mark.parametrize("test_args", ['-e "WEB_PORT=999"'])
def test_overrides_default_web_port(docker, slow, test_args):
''' When a --net=host user sets WEB_PORT to avoid synology's 80 default IPv4 and or IPv6 ports are updated'''
CONFIG_LINE = r'server.port\s*=\s*999'
WEB_CONFIG = '/etc/lighttpd/lighttpd.conf'
"""When a --net=host user sets WEB_PORT to avoid synology's 80 default IPv4 and or IPv6 ports are updated"""
CONFIG_LINE = r"server.port\s*=\s*999"
WEB_CONFIG = "/etc/lighttpd/lighttpd.conf"
function = docker.run('. /usr/local/bin/bash_functions.sh ; eval `grep setup_web_port /usr/local/bin/_startup.sh`')
function = docker.run(
". /usr/local/bin/bash_functions.sh ; eval `grep setup_web_port /usr/local/bin/_startup.sh`"
)
assert " [i] Custom WEB_PORT set to 999" in function.stdout
assert " [i] Without proper router DNAT forwarding to 127.0.0.1:999, you may not get any blocked websites on ads" in function.stdout
slow(lambda: re.search(CONFIG_LINE, docker.run(_cat(WEB_CONFIG)).stdout) != None)
assert (
" [i] Without proper router DNAT forwarding to 127.0.0.1:999, you may not get any blocked websites on ads"
in function.stdout
)
slow(
lambda: re.search(CONFIG_LINE, docker.run(_cat(WEB_CONFIG)).stdout) is not None
)
@pytest.mark.parametrize('test_args,expected_error', [
('-e WEB_PORT="LXXX"', 'WARNING: Custom WEB_PORT not used - LXXX is not an integer'),
('-e WEB_PORT="1,000"', 'WARNING: Custom WEB_PORT not used - 1,000 is not an integer'),
('-e WEB_PORT="99999"', 'WARNING: Custom WEB_PORT not used - 99999 is not within valid port range of 1-65535'),
])
@pytest.mark.parametrize(
"test_args,expected_error",
[
(
'-e WEB_PORT="LXXX"',
"WARNING: Custom WEB_PORT not used - LXXX is not an integer",
),
(
'-e WEB_PORT="1,000"',
"WARNING: Custom WEB_PORT not used - 1,000 is not an integer",
),
(
'-e WEB_PORT="99999"',
"WARNING: Custom WEB_PORT not used - 99999 is not within valid port range of 1-65535",
),
],
)
def test_bad_input_to_web_port(docker, test_args, expected_error):
function = docker.run('. /usr/local/bin/bash_functions.sh ; eval `grep setup_web_port /usr/local/bin/_startup.sh`')
function = docker.run(
". /usr/local/bin/bash_functions.sh ; eval `grep setup_web_port /usr/local/bin/_startup.sh`"
)
assert expected_error in function.stdout
@pytest.mark.parametrize('test_args,cache_size', [('-e CUSTOM_CACHE_SIZE="0"', '0'), ('-e CUSTOM_CACHE_SIZE="20000"', '20000')])
@pytest.mark.parametrize(
"test_args,cache_size",
[('-e CUSTOM_CACHE_SIZE="0"', "0"), ('-e CUSTOM_CACHE_SIZE="20000"', "20000")],
)
def test_overrides_default_custom_cache_size(docker, slow, test_args, cache_size):
''' Changes the cache_size setting to increase or decrease the cache size for dnsmasq'''
CONFIG_LINE = r'cache-size\s*=\s*{}'.format(cache_size)
"""Changes the cache_size setting to increase or decrease the cache size for dnsmasq"""
CONFIG_LINE = r"cache-size\s*=\s*{}".format(cache_size)
function = docker.run('echo ${CUSTOM_CACHE_SIZE};. ./usr/local/bin/bash_functions.sh; echo ${CUSTOM_CACHE_SIZE}; eval `grep setup_FTL_CacheSize /usr/local/bin/_startup.sh`')
function = docker.run(
"echo ${CUSTOM_CACHE_SIZE};. ./usr/local/bin/bash_functions.sh; echo ${CUSTOM_CACHE_SIZE}; eval `grep setup_FTL_CacheSize /usr/local/bin/_startup.sh`"
)
assert "Custom CUSTOM_CACHE_SIZE set to {}".format(cache_size) in function.stdout
slow(lambda: re.search(CONFIG_LINE, docker.run(_cat(DNSMASQ_CONFIG_LOC)).stdout) != None)
slow(
lambda: re.search(CONFIG_LINE, docker.run(_cat(DNSMASQ_CONFIG_LOC)).stdout)
is not None
)
@pytest.mark.parametrize('test_args', [
'-e CUSTOM_CACHE_SIZE="-1"',
'-e CUSTOM_CACHE_SIZE="1,000"',
])
@pytest.mark.parametrize(
"test_args",
[
'-e CUSTOM_CACHE_SIZE="-1"',
'-e CUSTOM_CACHE_SIZE="1,000"',
],
)
def test_bad_input_to_custom_cache_size(docker, slow, test_args):
CONFIG_LINE = r'cache-size\s*=\s*10000'
CONFIG_LINE = r"cache-size\s*=\s*10000"
docker.run(CMD_SETUP_FTL_CACHESIZE)
slow(lambda: re.search(CONFIG_LINE, docker.run(_cat(DNSMASQ_CONFIG_LOC)).stdout) != None)
slow(
lambda: re.search(CONFIG_LINE, docker.run(_cat(DNSMASQ_CONFIG_LOC)).stdout)
is not None
)
@pytest.mark.parametrize('test_args', [
'-e DNSSEC="true" -e CUSTOM_CACHE_SIZE="0"',
])
@pytest.mark.parametrize(
"test_args",
[
'-e DNSSEC="true" -e CUSTOM_CACHE_SIZE="0"',
],
)
def test_dnssec_enabled_with_custom_cache_size(docker, slow, test_args):
CONFIG_LINE = r'cache-size\s*=\s*10000'
CONFIG_LINE = r"cache-size\s*=\s*10000"
docker.run(CMD_SETUP_FTL_CACHESIZE)
slow(lambda: re.search(CONFIG_LINE, docker.run(_cat(DNSMASQ_CONFIG_LOC)).stdout) != None)
slow(
lambda: re.search(CONFIG_LINE, docker.run(_cat(DNSMASQ_CONFIG_LOC)).stdout)
is not None
)
@pytest.mark.parametrize('args_env, expected_stdout, expected_config_line', [
('', 'binding to default interface: eth0', 'PIHOLE_INTERFACE=eth0'),
('-e INTERFACE="br0"', 'binding to custom interface: br0', 'PIHOLE_INTERFACE=br0'),
])
def test_dns_interface_override_defaults(docker, slow, args_env, expected_stdout, expected_config_line):
''' When INTERFACE environment var is passed in, overwrite dnsmasq interface '''
@pytest.mark.parametrize(
"args_env, expected_stdout, expected_config_line",
[
("", "binding to default interface: eth0", "PIHOLE_INTERFACE=eth0"),
(
'-e INTERFACE="br0"',
"binding to custom interface: br0",
"PIHOLE_INTERFACE=br0",
),
],
)
def test_dns_interface_override_defaults(
docker, slow, args_env, expected_stdout, expected_config_line
):
"""When INTERFACE environment var is passed in, overwrite dnsmasq interface"""
function = docker.run(CMD_SETUP_FTL_INTERFACE)
assert expected_stdout in function.stdout
slow(lambda: expected_config_line + '\n' == docker.run('grep "^PIHOLE_INTERFACE" {}'.format(SETUPVARS_LOC)).stdout)
slow(
lambda: expected_config_line + "\n"
== docker.run('grep "^PIHOLE_INTERFACE" {}'.format(SETUPVARS_LOC)).stdout
)
expected_debian_lines = [
'"VIRTUAL_HOST" => "127.0.0.1"',
'"PHP_ERROR_LOG" => "/var/log/lighttpd/error-pihole.log"'
'"PHP_ERROR_LOG" => "/var/log/lighttpd/error-pihole.log"',
]
@pytest.mark.parametrize('expected_lines,repeat_function', [
(expected_debian_lines, 1),
(expected_debian_lines, 2)
])
@pytest.mark.parametrize(
"expected_lines,repeat_function",
[(expected_debian_lines, 1), (expected_debian_lines, 2)],
)
def test_debian_setup_php_env(docker, expected_lines, repeat_function):
''' confirm all expected output is there and nothing else '''
"""confirm all expected output is there and nothing else"""
for _ in range(repeat_function):
docker.run('. /usr/local/bin/bash_functions.sh ; eval `grep setup_php_env /usr/local/bin/_startup.sh`').stdout
docker.run(
". /usr/local/bin/bash_functions.sh ; eval `grep setup_php_env /usr/local/bin/_startup.sh`"
)
for expected_line in expected_lines:
search_config_cmd = "grep -c '{}' /etc/lighttpd/conf-enabled/15-fastcgi-php.conf".format(expected_line)
search_config_cmd = (
"grep -c '{}' /etc/lighttpd/conf-enabled/15-fastcgi-php.conf".format(
expected_line
)
)
search_config_count = docker.run(search_config_cmd)
found_lines = int(search_config_count.stdout.rstrip('\n'))
found_lines = int(search_config_count.stdout.rstrip("\n"))
if found_lines > 1:
assert False, f'Found line {expected_line} times (more than once): {found_lines}'
assert (
False
), f"Found line {expected_line} times (more than once): {found_lines}"
def test_webpassword_random_generation(docker):
''' When a user sets webPassword env the admin password gets set to that '''
"""When a user sets webPassword env the admin password gets set to that"""
function = docker.run(CMD_SETUP_WEB_PASSWORD)
assert 'assigning random password' in function.stdout.lower()
assert "assigning random password" in function.stdout.lower()
@pytest.mark.parametrize('entrypoint,cmd', [('--entrypoint=tail','-f /dev/null')])
@pytest.mark.parametrize('args_env,secure,setupvars_hash', [
('-e WEBPASSWORD=login', True, 'WEBPASSWORD=6060d59351e8c2f48140f01b2c3f3b61652f396c53a5300ae239ebfbe7d5ff08'),
('-e WEBPASSWORD=""', False, ''),
])
def test_webpassword_env_assigns_password_to_file_or_removes_if_empty(docker, args_env, secure, setupvars_hash):
''' When a user sets webPassword env the admin password gets set or removed if empty '''
@pytest.mark.parametrize("entrypoint,cmd", [("--entrypoint=tail", "-f /dev/null")])
@pytest.mark.parametrize(
"args_env,secure,setupvars_hash",
[
(
"-e WEBPASSWORD=login",
True,
"WEBPASSWORD=6060d59351e8c2f48140f01b2c3f3b61652f396c53a5300ae239ebfbe7d5ff08",
),
('-e WEBPASSWORD=""', False, ""),
],
)
def test_webpassword_env_assigns_password_to_file_or_removes_if_empty(
docker, args_env, secure, setupvars_hash
):
"""When a user sets webPassword env the admin password gets set or removed if empty"""
function = docker.run(CMD_SETUP_WEB_PASSWORD)
if secure:
assert 'new password set' in function.stdout.lower()
assert "new password set" in function.stdout.lower()
assert docker.run(_grep(setupvars_hash, SETUPVARS_LOC)).rc == 0
else:
assert 'password removed' in function.stdout.lower()
assert docker.run(_grep('^WEBPASSWORD=$', SETUPVARS_LOC)).rc == 0
assert "password removed" in function.stdout.lower()
assert docker.run(_grep("^WEBPASSWORD=$", SETUPVARS_LOC)).rc == 0
@pytest.mark.parametrize('entrypoint,cmd', [('--entrypoint=tail','-f /dev/null')])
@pytest.mark.parametrize('test_args', ['-e WEBPASSWORD=login', '-e WEBPASSWORD=""'])
@pytest.mark.parametrize("entrypoint,cmd", [("--entrypoint=tail", "-f /dev/null")])
@pytest.mark.parametrize("test_args", ["-e WEBPASSWORD=login", '-e WEBPASSWORD=""'])
def test_env_always_updates_password(docker, args_env, test_args):
'''When a user sets the WEBPASSWORD environment variable, ensure it always sets the password'''
"""When a user sets the WEBPASSWORD environment variable, ensure it always sets the password"""
function = docker.run(CMD_SETUP_WEB_PASSWORD)
assert ' [i] Assigning password defined by Environment Variable' in function.stdout
assert " [i] Assigning password defined by Environment Variable" in function.stdout
@pytest.mark.parametrize('entrypoint,cmd', [('--entrypoint=tail','-f /dev/null')])
@pytest.mark.parametrize("entrypoint,cmd", [("--entrypoint=tail", "-f /dev/null")])
def test_setupvars_trumps_random_password_if_set(docker, args_env, test_args):
'''If a password is already set in setupvars, and no password is set in the environment variable, do not generate a random password'''
docker.run('. /opt/pihole/utils.sh ; addOrEditKeyValPair {} WEBPASSWORD volumepass'.format(SETUPVARS_LOC))
"""If a password is already set in setupvars, and no password is set in the environment variable, do not generate a random password"""
docker.run(
". /opt/pihole/utils.sh ; addOrEditKeyValPair {} WEBPASSWORD volumepass".format(
SETUPVARS_LOC
)
)
function = docker.run(CMD_SETUP_WEB_PASSWORD)
assert 'Pre existing WEBPASSWORD found' in function.stdout
assert docker.run(_grep('WEBPASSWORD=volumepass', SETUPVARS_LOC)).rc == 0
assert "Pre existing WEBPASSWORD found" in function.stdout
assert docker.run(_grep("WEBPASSWORD=volumepass", SETUPVARS_LOC)).rc == 0

View File

@ -1,19 +1,37 @@
import pytest
import time
''' conftest.py provides the defaults through fixtures '''
''' Note, testinfra builtins don't seem fully compatible with
docker containers (esp. musl based OSs) stripped down nature '''
""" conftest.py provides the defaults through fixtures """
""" Note, testinfra builtins don't seem fully compatible with
docker containers (esp. musl based OSs) stripped down nature """
# If the test runs /usr/local/bin/_startup.sh, do not let s6 run it too! Kill entrypoint to avoid race condition/duplicated execution
@pytest.mark.parametrize('entrypoint,cmd', [('--entrypoint=tail','-f /dev/null')])
@pytest.mark.parametrize('args,error_msg,expect_rc', [
('-e FTLCONF_LOCAL_IPV4="1.2.3.z"', "FTLCONF_LOCAL_IPV4 Environment variable (1.2.3.z) doesn't appear to be a valid IPv4 address",1),
('-e FTLCONF_LOCAL_IPV4="1.2.3.4" -e FTLCONF_LOCAL_IPV6="1234:1234:1234:ZZZZ"', "Environment variable (1234:1234:1234:ZZZZ) doesn't appear to be a valid IPv6 address",1),
('-e FTLCONF_LOCAL_IPV4="1.2.3.4" -e FTLCONF_LOCAL_IPV6="kernel"', "ERROR: You passed in IPv6 with a value of 'kernel'",1),
])
def test_ftlconf_local_addr_invalid_ips_triggers_exit_error(docker, error_msg, expect_rc):
start = docker.run('/usr/local/bin/_startup.sh')
@pytest.mark.parametrize("entrypoint,cmd", [("--entrypoint=tail", "-f /dev/null")])
@pytest.mark.parametrize(
"args,error_msg,expect_rc",
[
(
'-e FTLCONF_LOCAL_IPV4="1.2.3.z"',
"FTLCONF_LOCAL_IPV4 Environment variable (1.2.3.z) doesn't appear to be a valid IPv4 address",
1,
),
(
'-e FTLCONF_LOCAL_IPV4="1.2.3.4" -e FTLCONF_LOCAL_IPV6="1234:1234:1234:ZZZZ"',
"Environment variable (1234:1234:1234:ZZZZ) doesn't appear to be a valid IPv6 address",
1,
),
(
'-e FTLCONF_LOCAL_IPV4="1.2.3.4" -e FTLCONF_LOCAL_IPV6="kernel"',
"ERROR: You passed in IPv6 with a value of 'kernel'",
1,
),
],
)
def test_ftlconf_local_addr_invalid_ips_triggers_exit_error(
docker, error_msg, expect_rc
):
start = docker.run("/usr/local/bin/_startup.sh")
assert start.rc == expect_rc
assert 'ERROR' in start.stdout
assert "ERROR" in start.stdout
assert error_msg in start.stdout