From 785a6c838f91f3c2d225dc64fdecaa389b9ad6f0 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 4 Aug 2020 22:18:59 +0530 Subject: [PATCH 01/29] Added a test for read all API of people application and which makes use of assertpy's fluent assertions --- Pipfile | 3 ++ Pipfile.lock | 109 ++++++++++++++++++++++++++++++++++++++++- config.py | 1 + tests/__init__.py | 0 tests/people_test.py | 15 ++++++ utils/__init__.py | 0 utils/print_helpers.py | 6 +++ 7 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 config.py create mode 100644 tests/__init__.py create mode 100644 tests/people_test.py create mode 100644 utils/__init__.py create mode 100644 utils/print_helpers.py diff --git a/Pipfile b/Pipfile index b799f0f..cd21e2c 100644 --- a/Pipfile +++ b/Pipfile @@ -7,6 +7,9 @@ verify_ssl = true [packages] requests = "*" +pytest = "*" +assertpy = "*" +jsonpath-ng = "*" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index 33e9b8f..5eb92ad 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "acbc8c4e7f2f98f1059b2a93d581ef43f4aa0c9741e64e6253adff8e35fbd99e" + "sha256": "048f3b1a3acbc6b5edd911b9db08e05e32f080ec1df52378ff6be8b5b276359a" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,21 @@ ] }, "default": { + "assertpy": { + "hashes": [ + "sha256:acc64329934ad71a3221de185517a43af33e373bb44dc05b5a9b174394ef4833" + ], + "index": "pypi", + "version": "==1.1" + }, + "attrs": { + "hashes": [ + "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", + "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==19.3.0" + }, "certifi": { "hashes": [ "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", @@ -30,6 +45,13 @@ ], "version": "==3.0.4" }, + "decorator": { + "hashes": [ + "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760", + "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7" + ], + "version": "==4.4.2" + }, "idna": { "hashes": [ "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", @@ -38,6 +60,76 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.10" }, + "iniconfig": { + "hashes": [ + "sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437", + "sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69" + ], + "version": "==1.0.1" + }, + "jsonpath-ng": { + "hashes": [ + "sha256:77b1f93f4444a50c924cb11cdc273546ff79f41830d485916fc6ddf4e0c1ce55", + "sha256:a4f014c28b5a1279c3a189fb1d2f37a98848f359f19fd296b54e38ec6fc841a9" + ], + "index": "pypi", + "version": "==1.5.1" + }, + "more-itertools": { + "hashes": [ + "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5", + "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2" + ], + "markers": "python_version >= '3.5'", + "version": "==8.4.0" + }, + "packaging": { + "hashes": [ + "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", + "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==20.4" + }, + "pluggy": { + "hashes": [ + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.13.1" + }, + "ply": { + "hashes": [ + "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", + "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce" + ], + "version": "==3.11" + }, + "py": { + "hashes": [ + "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2", + "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.9.0" + }, + "pyparsing": { + "hashes": [ + "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", + "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.4.7" + }, + "pytest": { + "hashes": [ + "sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4", + "sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad" + ], + "index": "pypi", + "version": "==6.0.1" + }, "requests": { "hashes": [ "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", @@ -46,6 +138,21 @@ "index": "pypi", "version": "==2.24.0" }, + "six": { + "hashes": [ + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.15.0" + }, + "toml": { + "hashes": [ + "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", + "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88" + ], + "version": "==0.10.1" + }, "urllib3": { "hashes": [ "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a", diff --git a/config.py b/config.py new file mode 100644 index 0000000..07fe22b --- /dev/null +++ b/config.py @@ -0,0 +1 @@ +BASE_URI = 'http://0.0.0.0:5000/api/people' \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/people_test.py b/tests/people_test.py new file mode 100644 index 0000000..2cbb40a --- /dev/null +++ b/tests/people_test.py @@ -0,0 +1,15 @@ +import requests +from assertpy.assertpy import assert_that + +from config import BASE_URI +from utils.print_helpers import pretty_print + + +def test_read_all_has_kent(): + response = requests.get(BASE_URI) + response_text = response.json() + pretty_print(response_text) + + assert_that(response.status_code).is_equal_to(200) + first_names = [people['fname'] for people in response_text] + assert_that(first_names).contains('Kent') diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/print_helpers.py b/utils/print_helpers.py new file mode 100644 index 0000000..dfd81cc --- /dev/null +++ b/utils/print_helpers.py @@ -0,0 +1,6 @@ +from pprint import pprint + + +def pretty_print(msg, indent=2): + print() + pprint(msg, indent=indent) \ No newline at end of file From e72acc1c2801c4ce7b88d8b6d2f88eff38616a6d Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 4 Aug 2020 22:20:00 +0530 Subject: [PATCH 02/29] Updated README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e89cd3c..c49ec57 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -# course-api-framework-python -TAU course on Building an API framework with python +# Building an API framework with Python + +This is the code for TAU course on building an API framework with python From edc7e8ad2da3a87046a964d07c4c57aa1884ce61 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Wed, 25 Nov 2020 20:57:20 +0530 Subject: [PATCH 03/29] Added assert py into Pipfile --- Pipfile | 1 + Pipfile.lock | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Pipfile b/Pipfile index ccde694..5a95f1f 100644 --- a/Pipfile +++ b/Pipfile @@ -8,6 +8,7 @@ verify_ssl = true [packages] requests = "*" pytest = "*" +assertpy = "*" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index 7340c1c..6ceefd6 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c8d9d4fb822dc60498ddcc1ea583873a3cdfd5094418db000376ddd01c15b487" + "sha256": "6faeba730f9fdeb1c3295cba784ae2a3efd8456d4ae584086d7c080f63e913e2" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,13 @@ ] }, "default": { + "assertpy": { + "hashes": [ + "sha256:acc64329934ad71a3221de185517a43af33e373bb44dc05b5a9b174394ef4833" + ], + "index": "pypi", + "version": "==1.1" + }, "attrs": { "hashes": [ "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6", @@ -26,10 +33,10 @@ }, "certifi": { "hashes": [ - "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", - "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" + "sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd", + "sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4" ], - "version": "==2020.6.20" + "version": "==2020.11.8" }, "chardet": { "hashes": [ @@ -119,11 +126,11 @@ }, "urllib3": { "hashes": [ - "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a", - "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461" + "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", + "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.25.10" + "version": "==1.26.2" } }, "develop": {} From 09caa481bebbfbfeaa7130980dac1d0894d87e87 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Wed, 25 Nov 2020 21:16:46 +0530 Subject: [PATCH 04/29] Added test to show use of POST method to create a new person and assert if it is present in get requests --- tests/people_test.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/people_test.py b/tests/people_test.py index 2cbb40a..8ef0dd5 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -1,8 +1,10 @@ import requests from assertpy.assertpy import assert_that +from json import dumps from config import BASE_URI from utils.print_helpers import pretty_print +from uuid import uuid4 def test_read_all_has_kent(): @@ -13,3 +15,23 @@ def test_read_all_has_kent(): assert_that(response.status_code).is_equal_to(200) first_names = [people['fname'] for people in response_text] assert_that(first_names).contains('Kent') + + +def test_new_person_can_be_added(): + unique_last_name = f'User {str(uuid4())}' + payload = dumps({ + 'fname': 'New', + 'lname': unique_last_name + }) + + headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + } + + response = requests.post(url=BASE_URI, data=payload, headers=headers) + assert_that(response.status_code).is_equal_to(204) + + people = requests.get(BASE_URI).json() + is_new_user_created = filter(lambda person: person['lname'] == unique_last_name, people) + assert_that(is_new_user_created).is_true() From ae5ac9336531082cab3bd602fe31bffff1d8c230 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Wed, 25 Nov 2020 21:37:30 +0530 Subject: [PATCH 05/29] - Added test to show use of POST method to create a new person and assert if it is present in get requests - Also added inline comments to explain the test --- tests/people_test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/people_test.py b/tests/people_test.py index 8ef0dd5..87c5ebd 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -8,30 +8,41 @@ def test_read_all_has_kent(): + # We use requests.get() with url to make a get request response = requests.get(BASE_URI) + # response from requests has many useful properties + # We can get python dict as response by using .json() method response_text = response.json() pretty_print(response_text) + # Also we can assert on the response status code assert_that(response.status_code).is_equal_to(200) first_names = [people['fname'] for people in response_text] assert_that(first_names).contains('Kent') def test_new_person_can_be_added(): + # Ensure a user with a unique last name is created everytime the test runs + # Note: json.dumps() is used to convert python dict to json string unique_last_name = f'User {str(uuid4())}' payload = dumps({ 'fname': 'New', 'lname': unique_last_name }) + # Setting default headers to show that the client accepts json + # And will send json in the headers headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } + # We use requests.post method with keyword params to make the request more readable response = requests.post(url=BASE_URI, data=payload, headers=headers) assert_that(response.status_code).is_equal_to(204) + # After user is created, we read all the users and then use filter expression to find if the + # created user is present in the response list people = requests.get(BASE_URI).json() is_new_user_created = filter(lambda person: person['lname'] == unique_last_name, people) assert_that(is_new_user_created).is_true() From 1a494c41334e6b844ce4034be9e0cb0353fe293a Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Wed, 25 Nov 2020 21:51:41 +0530 Subject: [PATCH 06/29] Showing off user of requests.codes to have readable http codes --- tests/people_test.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/people_test.py b/tests/people_test.py index 87c5ebd..61d8688 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -11,12 +11,10 @@ def test_read_all_has_kent(): # We use requests.get() with url to make a get request response = requests.get(BASE_URI) # response from requests has many useful properties + # we can assert on the response status code + assert_that(response.status_code).is_equal_to(requests.codes.ok) # We can get python dict as response by using .json() method response_text = response.json() - pretty_print(response_text) - - # Also we can assert on the response status code - assert_that(response.status_code).is_equal_to(200) first_names = [people['fname'] for people in response_text] assert_that(first_names).contains('Kent') @@ -39,7 +37,7 @@ def test_new_person_can_be_added(): # We use requests.post method with keyword params to make the request more readable response = requests.post(url=BASE_URI, data=payload, headers=headers) - assert_that(response.status_code).is_equal_to(204) + assert_that(response.status_code).is_equal_to(requests.codes.no_content) # After user is created, we read all the users and then use filter expression to find if the # created user is present in the response list From ec6c3cd148fd81a45c5ea464e9c44165b362491b Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Fri, 27 Nov 2020 07:46:35 +0530 Subject: [PATCH 07/29] Extracted create person into its own method and added test for delete operation --- tests/people_test.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/people_test.py b/tests/people_test.py index 61d8688..9124f56 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -1,10 +1,10 @@ +from json import dumps +from uuid import uuid4 + import requests from assertpy.assertpy import assert_that -from json import dumps from config import BASE_URI -from utils.print_helpers import pretty_print -from uuid import uuid4 def test_read_all_has_kent(): @@ -20,6 +20,29 @@ def test_read_all_has_kent(): def test_new_person_can_be_added(): + unique_last_name = create_new_person() + + # After user is created, we read all the users and then use filter expression to find if the + # created user is present in the response list + peoples = requests.get(BASE_URI).json() + is_new_user_created = [person for person in peoples if person['lname'] == unique_last_name] + assert_that(is_new_user_created).is_not_empty() + + +def test_created_person_can_be_deleted(): + persons_last_name = create_new_person() + if not persons_last_name: + raise AssertionError('User not created') + + peoples = requests.get(BASE_URI).json() + newly_created_user = [person for person in peoples if person['lname'] == persons_last_name][0] + + delete_url = f'{BASE_URI}/{newly_created_user["person_id"]}' + response = requests.delete(delete_url) + assert_that(response.status_code).is_equal_to(requests.codes.ok) + + +def create_new_person(): # Ensure a user with a unique last name is created everytime the test runs # Note: json.dumps() is used to convert python dict to json string unique_last_name = f'User {str(uuid4())}' @@ -38,9 +61,4 @@ def test_new_person_can_be_added(): # We use requests.post method with keyword params to make the request more readable response = requests.post(url=BASE_URI, data=payload, headers=headers) assert_that(response.status_code).is_equal_to(requests.codes.no_content) - - # After user is created, we read all the users and then use filter expression to find if the - # created user is present in the response list - people = requests.get(BASE_URI).json() - is_new_user_created = filter(lambda person: person['lname'] == unique_last_name, people) - assert_that(is_new_user_created).is_true() + return unique_last_name From 342f060be13d079200d2765afd87b5fe8282db0d Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Fri, 27 Nov 2020 13:46:00 +0530 Subject: [PATCH 08/29] Extracted search for users as a function --- tests/people_test.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/people_test.py b/tests/people_test.py index 9124f56..f24daf6 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -25,7 +25,7 @@ def test_new_person_can_be_added(): # After user is created, we read all the users and then use filter expression to find if the # created user is present in the response list peoples = requests.get(BASE_URI).json() - is_new_user_created = [person for person in peoples if person['lname'] == unique_last_name] + is_new_user_created = search_created_user_in(peoples, unique_last_name) assert_that(is_new_user_created).is_not_empty() @@ -35,7 +35,7 @@ def test_created_person_can_be_deleted(): raise AssertionError('User not created') peoples = requests.get(BASE_URI).json() - newly_created_user = [person for person in peoples if person['lname'] == persons_last_name][0] + newly_created_user = search_created_user_in(peoples, persons_last_name)[0] delete_url = f'{BASE_URI}/{newly_created_user["person_id"]}' response = requests.delete(delete_url) @@ -60,5 +60,9 @@ def create_new_person(): # We use requests.post method with keyword params to make the request more readable response = requests.post(url=BASE_URI, data=payload, headers=headers) - assert_that(response.status_code).is_equal_to(requests.codes.no_content) + assert_that(response.status_code, description='Person not created').is_equal_to(requests.codes.no_content) return unique_last_name + + +def search_created_user_in(peoples, last_name): + return [person for person in peoples if person['lname'] == last_name] From 3f9fc63a007d7e0e55c5bc27334ae071091e4d4f Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Fri, 27 Nov 2020 16:55:13 +0530 Subject: [PATCH 09/29] Removed explicit assertion since that is already made within create user test --- tests/people_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/people_test.py b/tests/people_test.py index f24daf6..850df4c 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -31,8 +31,6 @@ def test_new_person_can_be_added(): def test_created_person_can_be_deleted(): persons_last_name = create_new_person() - if not persons_last_name: - raise AssertionError('User not created') peoples = requests.get(BASE_URI).json() newly_created_user = search_created_user_in(peoples, persons_last_name)[0] From 2ca9964aa732662e064a8d66989befd0bb8032dc Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 1 Dec 2020 22:34:26 +0530 Subject: [PATCH 10/29] Replaced get methods assetions with assertpy's fluent assertion --- tests/people_test.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/people_test.py b/tests/people_test.py index 850df4c..d96a949 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -14,9 +14,11 @@ def test_read_all_has_kent(): # we can assert on the response status code assert_that(response.status_code).is_equal_to(requests.codes.ok) # We can get python dict as response by using .json() method - response_text = response.json() - first_names = [people['fname'] for people in response_text] - assert_that(first_names).contains('Kent') + response_content = response.json() + + # Use assertpy's fluent assertions to extract all fnames and then see the result is non empty and has + # Kent in it. + assert_that(response_content).extracting('fname').is_not_empty().contains('Kent') def test_new_person_can_be_added(): From 657cf980ad11c35c85b9f64d7204c801145aa7bd Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Mon, 14 Dec 2020 08:47:24 +0530 Subject: [PATCH 11/29] Added lxml dependency and covid_test.py to demo how to work with xml responses --- Pipfile | 1 + Pipfile.lock | 65 ++++++++++++++++++++++++++++++++++----------- config.py | 3 ++- tests/covid_test.py | 17 ++++++++++++ 4 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 tests/covid_test.py diff --git a/Pipfile b/Pipfile index 5a95f1f..7e74069 100644 --- a/Pipfile +++ b/Pipfile @@ -9,6 +9,7 @@ verify_ssl = true requests = "*" pytest = "*" assertpy = "*" +lxml = "*" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index 6ceefd6..b082e2e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "6faeba730f9fdeb1c3295cba784ae2a3efd8456d4ae584086d7c080f63e913e2" + "sha256": "b462b97af57f8ba0b5af2dac99bf081bd7d11384a3b912b420d6b384a614e4e3" }, "pipfile-spec": 6, "requires": { @@ -33,10 +33,10 @@ }, "certifi": { "hashes": [ - "sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd", - "sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4" + "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", + "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" ], - "version": "==2020.11.8" + "version": "==2020.12.5" }, "chardet": { "hashes": [ @@ -60,13 +60,56 @@ ], "version": "==1.1.1" }, + "lxml": { + "hashes": [ + "sha256:0448576c148c129594d890265b1a83b9cd76fd1f0a6a04620753d9a6bcfd0a4d", + "sha256:127f76864468d6630e1b453d3ffbbd04b024c674f55cf0a30dc2595137892d37", + "sha256:1471cee35eba321827d7d53d104e7b8c593ea3ad376aa2df89533ce8e1b24a01", + "sha256:2363c35637d2d9d6f26f60a208819e7eafc4305ce39dc1d5005eccc4593331c2", + "sha256:2e5cc908fe43fe1aa299e58046ad66981131a66aea3129aac7770c37f590a644", + "sha256:2e6fd1b8acd005bd71e6c94f30c055594bbd0aa02ef51a22bbfa961ab63b2d75", + "sha256:366cb750140f221523fa062d641393092813b81e15d0e25d9f7c6025f910ee80", + "sha256:42ebca24ba2a21065fb546f3e6bd0c58c3fe9ac298f3a320147029a4850f51a2", + "sha256:4e751e77006da34643ab782e4a5cc21ea7b755551db202bc4d3a423b307db780", + "sha256:4fb85c447e288df535b17ebdebf0ec1cf3a3f1a8eba7e79169f4f37af43c6b98", + "sha256:50c348995b47b5a4e330362cf39fc503b4a43b14a91c34c83b955e1805c8e308", + "sha256:535332fe9d00c3cd455bd3dd7d4bacab86e2d564bdf7606079160fa6251caacf", + "sha256:535f067002b0fd1a4e5296a8f1bf88193080ff992a195e66964ef2a6cfec5388", + "sha256:5be4a2e212bb6aa045e37f7d48e3e1e4b6fd259882ed5a00786f82e8c37ce77d", + "sha256:60a20bfc3bd234d54d49c388950195d23a5583d4108e1a1d47c9eef8d8c042b3", + "sha256:648914abafe67f11be7d93c1a546068f8eff3c5fa938e1f94509e4a5d682b2d8", + "sha256:681d75e1a38a69f1e64ab82fe4b1ed3fd758717bed735fb9aeaa124143f051af", + "sha256:68a5d77e440df94011214b7db907ec8f19e439507a70c958f750c18d88f995d2", + "sha256:69a63f83e88138ab7642d8f61418cf3180a4d8cd13995df87725cb8b893e950e", + "sha256:6e4183800f16f3679076dfa8abf2db3083919d7e30764a069fb66b2b9eff9939", + "sha256:6fd8d5903c2e53f49e99359b063df27fdf7acb89a52b6a12494208bf61345a03", + "sha256:791394449e98243839fa822a637177dd42a95f4883ad3dec2a0ce6ac99fb0a9d", + "sha256:7a7669ff50f41225ca5d6ee0a1ec8413f3a0d8aa2b109f86d540887b7ec0d72a", + "sha256:7e9eac1e526386df7c70ef253b792a0a12dd86d833b1d329e038c7a235dfceb5", + "sha256:7ee8af0b9f7de635c61cdd5b8534b76c52cd03536f29f51151b377f76e214a1a", + "sha256:8246f30ca34dc712ab07e51dc34fea883c00b7ccb0e614651e49da2c49a30711", + "sha256:8c88b599e226994ad4db29d93bc149aa1aff3dc3a4355dd5757569ba78632bdf", + "sha256:923963e989ffbceaa210ac37afc9b906acebe945d2723e9679b643513837b089", + "sha256:94d55bd03d8671686e3f012577d9caa5421a07286dd351dfef64791cf7c6c505", + "sha256:97db258793d193c7b62d4e2586c6ed98d51086e93f9a3af2b2034af01450a74b", + "sha256:a9d6bc8642e2c67db33f1247a77c53476f3a166e09067c0474facb045756087f", + "sha256:cd11c7e8d21af997ee8079037fff88f16fda188a9776eb4b81c7e4c9c0a7d7fc", + "sha256:d8d3d4713f0c28bdc6c806a278d998546e8efc3498949e3ace6e117462ac0a5e", + "sha256:e0bfe9bb028974a481410432dbe1b182e8191d5d40382e5b8ff39cdd2e5c5931", + "sha256:f4822c0660c3754f1a41a655e37cb4dbbc9be3d35b125a37fab6f82d47674ebc", + "sha256:f83d281bb2a6217cd806f4cf0ddded436790e66f393e124dfe9731f6b3fb9afe", + "sha256:fc37870d6716b137e80d19241d0e2cff7a7643b925dfa49b4c8ebd1295eb506e" + ], + "index": "pypi", + "version": "==4.6.2" + }, "packaging": { "hashes": [ - "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", - "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" + "sha256:05af3bb85d320377db281cf254ab050e1a7ebcbf5410685a9a407e18a1f81236", + "sha256:eb41423378682dadb7166144a4926e443093863024de508ca5c9737d6bc08376" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.4" + "version": "==20.7" }, "pluggy": { "hashes": [ @@ -108,14 +151,6 @@ "index": "pypi", "version": "==2.25.0" }, - "six": { - "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.15.0" - }, "toml": { "hashes": [ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", diff --git a/config.py b/config.py index 07fe22b..b770bde 100644 --- a/config.py +++ b/config.py @@ -1 +1,2 @@ -BASE_URI = 'http://0.0.0.0:5000/api/people' \ No newline at end of file +BASE_URI = 'http://0.0.0.0:5000/api/people' +COVID_TRACKER_HOST = 'http://127.0.0.1:5000' \ No newline at end of file diff --git a/tests/covid_test.py b/tests/covid_test.py new file mode 100644 index 0000000..fdd0e26 --- /dev/null +++ b/tests/covid_test.py @@ -0,0 +1,17 @@ +import requests +from assertpy import assert_that +from lxml import etree + +from config import COVID_TRACKER_HOST +from utils.print_helpers import pretty_print + + +def test_covid_cases_have_crossed_a_million(): + response = requests.get(f'{COVID_TRACKER_HOST}/api/v1/summary/latest') + pretty_print(response.headers) + + response_xml = response.text + tree = etree.fromstring(bytes(response_xml, encoding='utf8')) + total_cases = tree.xpath("//data/summary/total_cases")[0].text + + assert_that(int(total_cases)).is_greater_than(1000000) From d3699796073c53af95ac2699b9e04196839b6429 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 15 Dec 2020 08:50:29 +0530 Subject: [PATCH 12/29] Added another test to show couple of ways we can get values from XML response using Xpath --- config.py | 2 +- tests/covid_test.py | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/config.py b/config.py index b770bde..2279649 100644 --- a/config.py +++ b/config.py @@ -1,2 +1,2 @@ BASE_URI = 'http://0.0.0.0:5000/api/people' -COVID_TRACKER_HOST = 'http://127.0.0.1:5000' \ No newline at end of file +COVID_TRACKER_HOST = 'http://127.0.0.1:3000' \ No newline at end of file diff --git a/tests/covid_test.py b/tests/covid_test.py index fdd0e26..07e3c0b 100644 --- a/tests/covid_test.py +++ b/tests/covid_test.py @@ -11,7 +11,27 @@ def test_covid_cases_have_crossed_a_million(): pretty_print(response.headers) response_xml = response.text - tree = etree.fromstring(bytes(response_xml, encoding='utf8')) - total_cases = tree.xpath("//data/summary/total_cases")[0].text + xml_tree = etree.fromstring(bytes(response_xml, encoding='utf8')) + # use .xpath on xml_tree object to evaluate the expression + total_cases = xml_tree.xpath("//data/summary/total_cases")[0].text assert_that(int(total_cases)).is_greater_than(1000000) + + +def test_overall_covid_cases_match_sum_of_total_cases_by_country(): + response = requests.get(f'{COVID_TRACKER_HOST}/api/v1/summary/latest') + pretty_print(response.headers) + + response_xml = response.text + xml_tree = etree.fromstring(bytes(response_xml, encoding='utf8')) + + overall_cases = int(xml_tree.xpath("//data/summary/total_cases")[0].text) + # Another way to specify XPath first and then use to evaluate + # on an XML tree + search_for = etree.XPath("//data//regions//total_cases") + cases_by_country = 0 + for region in search_for(xml_tree): + cases_by_country += int(region.text) + + assert_that(overall_cases).is_greater_than(cases_by_country) + From d2d92520ae220a45154e3ba99897e2279d3a4c56 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 22 Dec 2020 08:56:03 +0530 Subject: [PATCH 13/29] - Added a json file to store the template for a request - Added a file_reader.py to support reading any JSON within tests/data directory - Added a tests example which gets data from JSON and makes use of pytest fixture to inject it into the test, also makes use of jsonpath-ng syntax to extract values out of the JSON array - Added jsonpath-ng to the Pipfile --- Pipfile | 1 + Pipfile.lock | 63 ++++++++++++++++++++++++++--------- tests/data/create_person.json | 4 +++ tests/people_test.py | 57 +++++++++++++++++++++++++------ utils/file_reader.py | 19 +++++++++++ 5 files changed, 117 insertions(+), 27 deletions(-) create mode 100644 tests/data/create_person.json create mode 100644 utils/file_reader.py diff --git a/Pipfile b/Pipfile index 7e74069..03b17b3 100644 --- a/Pipfile +++ b/Pipfile @@ -10,6 +10,7 @@ requests = "*" pytest = "*" assertpy = "*" lxml = "*" +jsonpath-ng = "*" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index b082e2e..f86a3ab 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "b462b97af57f8ba0b5af2dac99bf081bd7d11384a3b912b420d6b384a614e4e3" + "sha256": "f44cc5f140272efc41f2a70b3f239a2cb68477a8c0048f0043dbfeab3051eb48" }, "pipfile-spec": 6, "requires": { @@ -40,10 +40,18 @@ }, "chardet": { "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", + "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" ], - "version": "==3.0.4" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==4.0.0" + }, + "decorator": { + "hashes": [ + "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760", + "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7" + ], + "version": "==4.4.2" }, "idna": { "hashes": [ @@ -60,6 +68,14 @@ ], "version": "==1.1.1" }, + "jsonpath-ng": { + "hashes": [ + "sha256:144d91379be14d9019f51973bd647719c877bfc07dc6f3f5068895765950c69d", + "sha256:93d1f248be68e485eb6635c3a01b2d681f296dc349d71e37c8755837b8944d36" + ], + "index": "pypi", + "version": "==1.5.2" + }, "lxml": { "hashes": [ "sha256:0448576c148c129594d890265b1a83b9cd76fd1f0a6a04620753d9a6bcfd0a4d", @@ -105,11 +121,11 @@ }, "packaging": { "hashes": [ - "sha256:05af3bb85d320377db281cf254ab050e1a7ebcbf5410685a9a407e18a1f81236", - "sha256:eb41423378682dadb7166144a4926e443093863024de508ca5c9737d6bc08376" + "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858", + "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.7" + "version": "==20.8" }, "pluggy": { "hashes": [ @@ -119,13 +135,20 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.13.1" }, + "ply": { + "hashes": [ + "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", + "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce" + ], + "version": "==3.11" + }, "py": { "hashes": [ - "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2", - "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342" + "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", + "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.9.0" + "version": "==1.10.0" }, "pyparsing": { "hashes": [ @@ -137,19 +160,27 @@ }, "pytest": { "hashes": [ - "sha256:4288fed0d9153d9646bfcdf0c0428197dba1ecb27a33bb6e031d002fa88653fe", - "sha256:c0a7e94a8cdbc5422a51ccdad8e6f1024795939cc89159a0ae7f0b316ad3823e" + "sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8", + "sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306" ], "index": "pypi", - "version": "==6.1.2" + "version": "==6.2.1" }, "requests": { "hashes": [ - "sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8", - "sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998" + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" ], "index": "pypi", - "version": "==2.25.0" + "version": "==2.25.1" + }, + "six": { + "hashes": [ + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.15.0" }, "toml": { "hashes": [ diff --git a/tests/data/create_person.json b/tests/data/create_person.json new file mode 100644 index 0000000..a3d2848 --- /dev/null +++ b/tests/data/create_person.json @@ -0,0 +1,4 @@ +{ + "fname": "Sample firstname", + "lname": "Sample lastname" + } \ No newline at end of file diff --git a/tests/people_test.py b/tests/people_test.py index d96a949..9ede990 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -1,10 +1,14 @@ -from json import dumps +import random +from json import dumps, loads from uuid import uuid4 +import pytest import requests from assertpy.assertpy import assert_that +from jsonpath_ng import parse from config import BASE_URI +from utils.file_reader import read_file def test_read_all_has_kent(): @@ -22,7 +26,7 @@ def test_read_all_has_kent(): def test_new_person_can_be_added(): - unique_last_name = create_new_person() + unique_last_name = create_person_with_unique_last_name() # After user is created, we read all the users and then use filter expression to find if the # created user is present in the response list @@ -32,7 +36,7 @@ def test_new_person_can_be_added(): def test_created_person_can_be_deleted(): - persons_last_name = create_new_person() + persons_last_name = create_person_with_unique_last_name() peoples = requests.get(BASE_URI).json() newly_created_user = search_created_user_in(peoples, persons_last_name)[0] @@ -42,14 +46,45 @@ def test_created_person_can_be_deleted(): assert_that(response.status_code).is_equal_to(requests.codes.ok) -def create_new_person(): - # Ensure a user with a unique last name is created everytime the test runs - # Note: json.dumps() is used to convert python dict to json string - unique_last_name = f'User {str(uuid4())}' - payload = dumps({ - 'fname': 'New', - 'lname': unique_last_name - }) +@pytest.fixture +def create_data(): + payload = read_file('create_person.json') + + random_no = random.randint(0, 1000) + last_name = f'Olabini{random_no}' + + payload['lname'] = last_name + yield payload + + +def test_person_can_be_added_with_a_json_template(create_data): + create_person_with_unique_last_name(create_data) + + response = requests.get(BASE_URI) + peoples = loads(response.text) + + # Get all last names for any object in the root array + # Here $ = root, [*] represents any element in the array + # Read full syntax: https://pypi.org/project/jsonpath-ng/ + jsonpath_expr = parse("$.[*].lname") + result = [match.value for match in jsonpath_expr.find(peoples)] + + expected_last_name = create_data['lname'] + assert_that(result).contains(expected_last_name) + + +def create_person_with_unique_last_name(body=None): + if body is None: + # Ensure a user with a unique last name is created everytime the test runs + # Note: json.dumps() is used to convert python dict to json string + unique_last_name = f'User {str(uuid4())}' + payload = dumps({ + 'fname': 'New', + 'lname': unique_last_name + }) + else: + unique_last_name = body['lname'] + payload = dumps(body) # Setting default headers to show that the client accepts json # And will send json in the headers diff --git a/utils/file_reader.py b/utils/file_reader.py new file mode 100644 index 0000000..6c39b0a --- /dev/null +++ b/utils/file_reader.py @@ -0,0 +1,19 @@ +import json +from pathlib import Path + +BASE_PATH = Path.cwd().joinpath('..', 'tests', 'data') + + +def read_file(file_name): + path = get_file_with_json_extension(file_name) + + with path.open(mode='r') as f: + return json.load(f) + + +def get_file_with_json_extension(file_name): + if '.json' in file_name: + path = BASE_PATH.joinpath(file_name) + else: + path = BASE_PATH.joinpath(f'{file_name}.json') + return path From 701791c61f4bd4b696d1c14dcede1100e5bc720c Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Fri, 25 Dec 2020 08:09:36 +0530 Subject: [PATCH 14/29] Formatted json --- tests/data/create_person.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/data/create_person.json b/tests/data/create_person.json index a3d2848..b909072 100644 --- a/tests/data/create_person.json +++ b/tests/data/create_person.json @@ -1,4 +1,4 @@ { - "fname": "Sample firstname", - "lname": "Sample lastname" - } \ No newline at end of file + "fname": "Sample firstname", + "lname": "Sample lastname" +} \ No newline at end of file From becf0d76fa104da0bcfe82f07898ee6e4787ec8b Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Sun, 27 Dec 2020 14:02:44 +0530 Subject: [PATCH 15/29] Added example of schema validation for Read all operation in people API --- Pipfile | 1 + Pipfile.lock | 9 ++++++++- tests/people_test.py | 1 + tests/schema_test.py | 26 ++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/schema_test.py diff --git a/Pipfile b/Pipfile index 03b17b3..e56e1cf 100644 --- a/Pipfile +++ b/Pipfile @@ -11,6 +11,7 @@ pytest = "*" assertpy = "*" lxml = "*" jsonpath-ng = "*" +cerberus = "*" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index f86a3ab..b21d509 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f44cc5f140272efc41f2a70b3f239a2cb68477a8c0048f0043dbfeab3051eb48" + "sha256": "6b3764b346dcb14c5c2dd83a08bc4b179d819d7cdb91da8954c02fb784605c58" }, "pipfile-spec": 6, "requires": { @@ -31,6 +31,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==20.3.0" }, + "cerberus": { + "hashes": [ + "sha256:302e6694f206dd85cb63f13fd5025b31ab6d38c99c50c6d769f8fa0b0f299589" + ], + "index": "pypi", + "version": "==1.3.2" + }, "certifi": { "hashes": [ "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", diff --git a/tests/people_test.py b/tests/people_test.py index 9ede990..5ac5023 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -68,6 +68,7 @@ def test_person_can_be_added_with_a_json_template(create_data): # Read full syntax: https://pypi.org/project/jsonpath-ng/ jsonpath_expr = parse("$.[*].lname") result = [match.value for match in jsonpath_expr.find(peoples)] + print(result) expected_last_name = create_data['lname'] assert_that(result).contains(expected_last_name) diff --git a/tests/schema_test.py b/tests/schema_test.py new file mode 100644 index 0000000..645d09d --- /dev/null +++ b/tests/schema_test.py @@ -0,0 +1,26 @@ +import json + +import requests +from cerberus import Validator + +from config import BASE_URI + + +def test_read_all_operation_has_expected_schema(): + schema = { + "fname": {'type': 'string'}, + "lname": {'type': 'string'}, + "person_id": {'type': 'integer'}, + "timestamp": {'type': 'string'} + } + + response = requests.get(BASE_URI) + persons = json.loads(response.text) + + validator = Validator(schema) + + for person in persons: + is_valid = validator.validate(person) + + if not is_valid: + print(validator.errors) From 2ed2046d486c3abc234e8fb9238349b959a8eed4 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Mon, 28 Dec 2020 07:12:52 +0530 Subject: [PATCH 16/29] Extracted schema outside the functions and added a separate function to validate it for read one operation --- tests/schema_test.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/schema_test.py b/tests/schema_test.py index 645d09d..9f5acae 100644 --- a/tests/schema_test.py +++ b/tests/schema_test.py @@ -5,15 +5,26 @@ from config import BASE_URI +schema = { + "fname": {'type': 'string'}, + "lname": {'type': 'string'}, + "person_id": {'type': 'integer'}, + "timestamp": {'type': 'string'} +} -def test_read_all_operation_has_expected_schema(): - schema = { - "fname": {'type': 'string'}, - "lname": {'type': 'string'}, - "person_id": {'type': 'integer'}, - "timestamp": {'type': 'string'} - } +def test_read_one_operation_has_expected_schema(): + response = requests.get(f'{BASE_URI}/1') + person = json.loads(response.text) + + validator = Validator(schema) + is_valid = validator.validate(person) + + if not is_valid: + print(validator.errors) + + +def test_read_all_operation_has_expected_schema(): response = requests.get(BASE_URI) persons = json.loads(response.text) From e8c001664485feadf8fe4174bc155f967ce234f6 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Mon, 28 Dec 2020 12:37:22 +0530 Subject: [PATCH 17/29] Updated schema tests to use assertpy fluent assertions to validate instead of printing on the console. --- tests/schema_test.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/schema_test.py b/tests/schema_test.py index 9f5acae..ada361e 100644 --- a/tests/schema_test.py +++ b/tests/schema_test.py @@ -1,6 +1,7 @@ import json import requests +from assertpy import assert_that, soft_assertions from cerberus import Validator from config import BASE_URI @@ -8,7 +9,7 @@ schema = { "fname": {'type': 'string'}, "lname": {'type': 'string'}, - "person_id": {'type': 'integer'}, + "person_id": {'type': 'number'}, "timestamp": {'type': 'string'} } @@ -17,21 +18,19 @@ def test_read_one_operation_has_expected_schema(): response = requests.get(f'{BASE_URI}/1') person = json.loads(response.text) - validator = Validator(schema) + validator = Validator(schema, require_all=True) is_valid = validator.validate(person) - if not is_valid: - print(validator.errors) + assert_that(is_valid, description=validator.errors).is_true() def test_read_all_operation_has_expected_schema(): response = requests.get(BASE_URI) persons = json.loads(response.text) - validator = Validator(schema) + validator = Validator(schema, require_all=True) - for person in persons: - is_valid = validator.validate(person) - - if not is_valid: - print(validator.errors) + with soft_assertions(): + for person in persons: + is_valid = validator.validate(person) + assert_that(is_valid, description=validator.errors).is_true() From 6204734b5cfbcf48a966e09879efb91ce82a5db5 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Mon, 28 Dec 2020 16:21:47 +0530 Subject: [PATCH 18/29] - Abstracted API methods into a people_client which makes use of a custom request wrapper instead of directly depending on requests Note: This change breaks few tests. --- clients/__init__.py | 0 clients/people/__init__.py | 0 clients/people/people_client.py | 50 ++++++++++++++++++++++++ endpoints/__init__.py | 0 tests/assertions/__init__.py | 0 tests/helpers/__init__.py | 0 tests/helpers/people_helpers.py | 2 + tests/people_test.py | 69 ++++++++------------------------- utils/file_reader.py | 2 +- utils/request.py | 42 ++++++++++++++++++++ 10 files changed, 111 insertions(+), 54 deletions(-) create mode 100644 clients/__init__.py create mode 100644 clients/people/__init__.py create mode 100644 clients/people/people_client.py create mode 100644 endpoints/__init__.py create mode 100644 tests/assertions/__init__.py create mode 100644 tests/helpers/__init__.py create mode 100644 tests/helpers/people_helpers.py create mode 100644 utils/request.py diff --git a/clients/__init__.py b/clients/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/clients/people/__init__.py b/clients/people/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/clients/people/people_client.py b/clients/people/people_client.py new file mode 100644 index 0000000..3d087a2 --- /dev/null +++ b/clients/people/people_client.py @@ -0,0 +1,50 @@ +from json import dumps +from uuid import uuid4 + +import requests +from assertpy import assert_that + +from config import BASE_URI +from utils.request import get, post + + +class PeopleClient: + def __init__(self): + self.base_url = BASE_URI + + def create_person(self, body=None): + last_name, response = self.create_person_with_unique_last_name(body) + assert_that(response.status_code, description='Person not created').is_equal_to(requests.codes.no_content) + return last_name, response + + def read_one_person_by_id(self, person_id): + pass + + def read_all_persons(self): + return get(self.base_url) + + def update_person(self): + pass + + def delete_person(self, person_id): + delete_url = f'{BASE_URI}/{person_id}' + + + def create_person_with_unique_last_name(self, body=None): + if body is None: + last_name = f'User {str(uuid4())}' + payload = dumps({ + 'fname': 'New', + 'lname': last_name + }) + else: + last_name = body['lname'] + payload = dumps(body) + + headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + } + + response = post(self.base_url, payload, headers) + return last_name, response diff --git a/endpoints/__init__.py b/endpoints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/assertions/__init__.py b/tests/assertions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/helpers/__init__.py b/tests/helpers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/helpers/people_helpers.py b/tests/helpers/people_helpers.py new file mode 100644 index 0000000..3602a74 --- /dev/null +++ b/tests/helpers/people_helpers.py @@ -0,0 +1,2 @@ +def search_created_user_in(peoples, last_name): + return [person for person in peoples if person['lname'] == last_name] \ No newline at end of file diff --git a/tests/people_test.py b/tests/people_test.py index 5ac5023..fc560de 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -1,48 +1,41 @@ import random -from json import dumps, loads -from uuid import uuid4 +from json import loads import pytest import requests from assertpy.assertpy import assert_that from jsonpath_ng import parse +from clients.people.people_client import PeopleClient from config import BASE_URI +from tests.helpers.people_helpers import search_created_user_in from utils.file_reader import read_file +client = PeopleClient() + def test_read_all_has_kent(): - # We use requests.get() with url to make a get request - response = requests.get(BASE_URI) - # response from requests has many useful properties - # we can assert on the response status code - assert_that(response.status_code).is_equal_to(requests.codes.ok) - # We can get python dict as response by using .json() method - response_content = response.json() + response = client.read_all_persons() - # Use assertpy's fluent assertions to extract all fnames and then see the result is non empty and has - # Kent in it. - assert_that(response_content).extracting('fname').is_not_empty().contains('Kent') + assert_that(response.status_code).is_equal_to(requests.codes.ok) + assert_that(response.as_dict).extracting('fname').is_not_empty().contains('Kent') def test_new_person_can_be_added(): - unique_last_name = create_person_with_unique_last_name() + last_name, response = client.create_person() + peoples = client.read_all_persons().as_dict - # After user is created, we read all the users and then use filter expression to find if the - # created user is present in the response list - peoples = requests.get(BASE_URI).json() - is_new_user_created = search_created_user_in(peoples, unique_last_name) + is_new_user_created = search_created_user_in(peoples, last_name) assert_that(is_new_user_created).is_not_empty() def test_created_person_can_be_deleted(): - persons_last_name = create_person_with_unique_last_name() + persons_last_name = client.create_person() - peoples = requests.get(BASE_URI).json() - newly_created_user = search_created_user_in(peoples, persons_last_name)[0] + peoples = client.read_all_persons().as_dict + new_person_id = search_created_user_in(peoples, persons_last_name)[0]['person_id'] - delete_url = f'{BASE_URI}/{newly_created_user["person_id"]}' - response = requests.delete(delete_url) + response = client.delete_person(new_person_id) assert_that(response.status_code).is_equal_to(requests.codes.ok) @@ -58,7 +51,7 @@ def create_data(): def test_person_can_be_added_with_a_json_template(create_data): - create_person_with_unique_last_name(create_data) + client.create_person(create_data) response = requests.get(BASE_URI) peoples = loads(response.text) @@ -72,33 +65,3 @@ def test_person_can_be_added_with_a_json_template(create_data): expected_last_name = create_data['lname'] assert_that(result).contains(expected_last_name) - - -def create_person_with_unique_last_name(body=None): - if body is None: - # Ensure a user with a unique last name is created everytime the test runs - # Note: json.dumps() is used to convert python dict to json string - unique_last_name = f'User {str(uuid4())}' - payload = dumps({ - 'fname': 'New', - 'lname': unique_last_name - }) - else: - unique_last_name = body['lname'] - payload = dumps(body) - - # Setting default headers to show that the client accepts json - # And will send json in the headers - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - } - - # We use requests.post method with keyword params to make the request more readable - response = requests.post(url=BASE_URI, data=payload, headers=headers) - assert_that(response.status_code, description='Person not created').is_equal_to(requests.codes.no_content) - return unique_last_name - - -def search_created_user_in(peoples, last_name): - return [person for person in peoples if person['lname'] == last_name] diff --git a/utils/file_reader.py b/utils/file_reader.py index 6c39b0a..6b0c496 100644 --- a/utils/file_reader.py +++ b/utils/file_reader.py @@ -1,7 +1,7 @@ import json from pathlib import Path -BASE_PATH = Path.cwd().joinpath('..', 'tests', 'data') +BASE_PATH = Path.cwd().joinpath('tests', 'data') def read_file(file_name): diff --git a/utils/request.py b/utils/request.py new file mode 100644 index 0000000..418994a --- /dev/null +++ b/utils/request.py @@ -0,0 +1,42 @@ +from dataclasses import dataclass + +import requests + + +@dataclass +class Response: + status_code: int + text: str + as_dict: object + headers: dict + + +def __get_responses(response): + status_code = response.status_code + text = response.text + + try: + as_dict = response.json() + except Exception: + as_dict = {} + + headers = response.headers + + return Response( + status_code, text, as_dict, headers + ) + + +def get(url): + response = requests.get(url) + return __get_responses(response) + + +def post(url, payload, headers): + response = requests.post(url, data=payload, headers=headers) + return __get_responses(response) + + +def delete(url): + response = requests.delete(url) + return __get_responses(response) From e5fe84666bc3e5678971cbfd132650f31abc6e37 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Mon, 28 Dec 2020 19:03:38 +0530 Subject: [PATCH 19/29] - Created BaseClient with default headers - Moved create_data() into conftest file - Introduced an assertion helper to abstract common assertions - Added remaining methods to people_client.py - Moved search related methods to a people_helpers.py - Refactored these methods out of the test file - Created APIRequest as a wrapper over requests methods (always wrap third party library if possible) --- clients/people/base_client.py | 6 ++++ clients/people/people_client.py | 49 ++++++++++++--------------- endpoints/__init__.py | 0 tests/assertions/people_assertions.py | 9 +++++ tests/conftest.py | 16 +++++++++ tests/helpers/people_helpers.py | 10 +++++- tests/people_test.py | 44 ++++++------------------ utils/request.py | 44 ++++++++++++------------ 8 files changed, 94 insertions(+), 84 deletions(-) create mode 100644 clients/people/base_client.py delete mode 100644 endpoints/__init__.py create mode 100644 tests/assertions/people_assertions.py create mode 100644 tests/conftest.py diff --git a/clients/people/base_client.py b/clients/people/base_client.py new file mode 100644 index 0000000..1993a42 --- /dev/null +++ b/clients/people/base_client.py @@ -0,0 +1,6 @@ +class BaseClient: + def __init__(self): + self.headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + } \ No newline at end of file diff --git a/clients/people/people_client.py b/clients/people/people_client.py index 3d087a2..992f429 100644 --- a/clients/people/people_client.py +++ b/clients/people/people_client.py @@ -1,36 +1,23 @@ from json import dumps from uuid import uuid4 -import requests -from assertpy import assert_that - +from clients.people.base_client import BaseClient from config import BASE_URI -from utils.request import get, post +from utils.request import APIRequest -class PeopleClient: +class PeopleClient(BaseClient): def __init__(self): + super().__init__() + self.base_url = BASE_URI + self.request = APIRequest() def create_person(self, body=None): - last_name, response = self.create_person_with_unique_last_name(body) - assert_that(response.status_code, description='Person not created').is_equal_to(requests.codes.no_content) + last_name, response = self.__create_person_with_unique_last_name(body) return last_name, response - def read_one_person_by_id(self, person_id): - pass - - def read_all_persons(self): - return get(self.base_url) - - def update_person(self): - pass - - def delete_person(self, person_id): - delete_url = f'{BASE_URI}/{person_id}' - - - def create_person_with_unique_last_name(self, body=None): + def __create_person_with_unique_last_name(self, body=None): if body is None: last_name = f'User {str(uuid4())}' payload = dumps({ @@ -41,10 +28,18 @@ def create_person_with_unique_last_name(self, body=None): last_name = body['lname'] payload = dumps(body) - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - } - - response = post(self.base_url, payload, headers) + response = self.request.post(self.base_url, payload, self.headers) return last_name, response + + def read_one_person_by_id(self, person_id): + pass + + def read_all_persons(self): + return self.request.get(self.base_url) + + def update_person(self): + pass + + def delete_person(self, person_id): + url = f'{BASE_URI}/{person_id}' + return self.request.delete(url) diff --git a/endpoints/__init__.py b/endpoints/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/assertions/people_assertions.py b/tests/assertions/people_assertions.py new file mode 100644 index 0000000..4bfc4ee --- /dev/null +++ b/tests/assertions/people_assertions.py @@ -0,0 +1,9 @@ +from assertpy import assert_that + + +def assert_people_have_person_with_first_name(response, first_name): + assert_that(response.as_dict).extracting('fname').is_not_empty().contains(first_name) + + +def assert_person_is_present(is_new_user_created): + assert_that(is_new_user_created).is_not_empty() diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..1e81912 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,16 @@ +import random + +import pytest + +from utils.file_reader import read_file + + +@pytest.fixture +def create_data(): + payload = read_file('create_person.json') + + random_no = random.randint(0, 1000) + last_name = f'Olabini{random_no}' + + payload['lname'] = last_name + yield payload diff --git a/tests/helpers/people_helpers.py b/tests/helpers/people_helpers.py index 3602a74..a0d9fa8 100644 --- a/tests/helpers/people_helpers.py +++ b/tests/helpers/people_helpers.py @@ -1,2 +1,10 @@ +from jsonpath_ng import parse + + def search_created_user_in(peoples, last_name): - return [person for person in peoples if person['lname'] == last_name] \ No newline at end of file + return [person for person in peoples if person['lname'] == last_name][0] + + +def search_nodes_using_json_path(peoples, json_path): + jsonpath_expr = parse(json_path) + return [match.value for match in jsonpath_expr.find(peoples)] diff --git a/tests/people_test.py b/tests/people_test.py index fc560de..c11b2da 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -1,15 +1,8 @@ -import random -from json import loads - -import pytest import requests -from assertpy.assertpy import assert_that -from jsonpath_ng import parse from clients.people.people_client import PeopleClient -from config import BASE_URI -from tests.helpers.people_helpers import search_created_user_in -from utils.file_reader import read_file +from tests.assertions.people_assertions import * +from tests.helpers.people_helpers import search_created_user_in, search_nodes_using_json_path client = PeopleClient() @@ -18,50 +11,35 @@ def test_read_all_has_kent(): response = client.read_all_persons() assert_that(response.status_code).is_equal_to(requests.codes.ok) - assert_that(response.as_dict).extracting('fname').is_not_empty().contains('Kent') + assert_people_have_person_with_first_name(response, first_name='Kent') def test_new_person_can_be_added(): last_name, response = client.create_person() - peoples = client.read_all_persons().as_dict + assert_that(response.status_code, description='Person not created').is_equal_to(requests.codes.no_content) + peoples = client.read_all_persons().as_dict is_new_user_created = search_created_user_in(peoples, last_name) - assert_that(is_new_user_created).is_not_empty() + assert_person_is_present(is_new_user_created) def test_created_person_can_be_deleted(): - persons_last_name = client.create_person() + persons_last_name, _ = client.create_person() peoples = client.read_all_persons().as_dict - new_person_id = search_created_user_in(peoples, persons_last_name)[0]['person_id'] + new_person_id = search_created_user_in(peoples, persons_last_name)['person_id'] response = client.delete_person(new_person_id) assert_that(response.status_code).is_equal_to(requests.codes.ok) -@pytest.fixture -def create_data(): - payload = read_file('create_person.json') - - random_no = random.randint(0, 1000) - last_name = f'Olabini{random_no}' - - payload['lname'] = last_name - yield payload - - def test_person_can_be_added_with_a_json_template(create_data): client.create_person(create_data) - response = requests.get(BASE_URI) - peoples = loads(response.text) + response = client.read_all_persons() + peoples = response.as_dict - # Get all last names for any object in the root array - # Here $ = root, [*] represents any element in the array - # Read full syntax: https://pypi.org/project/jsonpath-ng/ - jsonpath_expr = parse("$.[*].lname") - result = [match.value for match in jsonpath_expr.find(peoples)] - print(result) + result = search_nodes_using_json_path(peoples, json_path="$.[*].lname") expected_last_name = create_data['lname'] assert_that(result).contains(expected_last_name) diff --git a/utils/request.py b/utils/request.py index 418994a..22cfd98 100644 --- a/utils/request.py +++ b/utils/request.py @@ -11,32 +11,30 @@ class Response: headers: dict -def __get_responses(response): - status_code = response.status_code - text = response.text +class APIRequest: + def get(self, url): + response = requests.get(url) + return self.__get_responses(response) - try: - as_dict = response.json() - except Exception: - as_dict = {} + def post(self, url, payload, headers): + response = requests.post(url, data=payload, headers=headers) + return self.__get_responses(response) - headers = response.headers + def delete(self, url): + response = requests.delete(url) + return self.__get_responses(response) - return Response( - status_code, text, as_dict, headers - ) + def __get_responses(self, response): + status_code = response.status_code + text = response.text + try: + as_dict = response.json() + except Exception: + as_dict = {} -def get(url): - response = requests.get(url) - return __get_responses(response) + headers = response.headers - -def post(url, payload, headers): - response = requests.post(url, data=payload, headers=headers) - return __get_responses(response) - - -def delete(url): - response = requests.delete(url) - return __get_responses(response) + return Response( + status_code, text, as_dict, headers + ) From 8d2157dbe3de259e8115b75824f87c8bd3354489 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 29 Dec 2020 08:02:45 +0530 Subject: [PATCH 20/29] Replaced specific method imports with * --- tests/people_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/people_test.py b/tests/people_test.py index c11b2da..c5e5e74 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -2,7 +2,7 @@ from clients.people.people_client import PeopleClient from tests.assertions.people_assertions import * -from tests.helpers.people_helpers import search_created_user_in, search_nodes_using_json_path +from tests.helpers.people_helpers import * client = PeopleClient() From 77c77021f6265b29e05b4e9cd0a764cd75162202 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 29 Dec 2020 08:15:46 +0530 Subject: [PATCH 21/29] Updated README.md --- README.md | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c49ec57..64a4ee9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,42 @@ -# Building an API framework with Python +# Building an API test automation framework with Python + +## Purpose + +Code for TAU (Test automation university) course on building an API framework with Python. Once ready this would be +published at [Test automation university](https://testautomationu.applitools.com/), You can also find a series of blogs +that I'm writing for this course on my blog [https://automationhacks.io/](https://automationhacks.io/tags/) +under `Python` tag. However, the video courses are going to have much more context and in depth discussions + +## Setup + +Ensure you +have [pipenv already installed](https://automationhacks.io/2020/07/12/how-to-manage-your-python-virtualenvs-with-pipenv/): + +```zsh +# Activate virtualenv +pipenv shell +# Install all dependencies in your virtualenv +pipenv install +``` + +## How to navigate + +Each chapter has its own dedicated branch in `/example/_` format. For +e.g. `example/01_setup_python_dependencies` + +You can either use your IDE or terminal to switch to that branch and see the last updated commit. + +```zsh +# Checkout the entire branch +git checkout example/01_setup_python_dependencies +# Checkout to a specific commit, here can be found using `git log` command +git checkout +``` + +## Discuss? + +Feel free to use the [Github discussions](https://github.com/automationhacks/course-api-framework-python/discussions/1) +in this repo to ✍🏼 your thoughts or even use the disqus comments section on the blogs. + +Happy learning! -This is the code for TAU course on building an API framework with python From 69034c7e1d805fdc9c08891d2b88b64e21344647 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Wed, 20 Jan 2021 09:54:55 +0530 Subject: [PATCH 22/29] Added docker-compose for report portal --- .gitignore | 1 + docker-compose.yml | 248 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index e17e6b7..33543f2 100644 --- a/.gitignore +++ b/.gitignore @@ -128,3 +128,4 @@ dmypy.json # Pyre type checker .pyre/ .idea +data/ \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e4748fd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,248 @@ +## You can generate a custom docker compose file automatically on http://reportportal.io/download (Step 2) + +## This is example of Docker Compose for ReportPortal +## Do not forget to configure data volumes for production usage + +## Execute 'docker-compose -f docker-compose.yml -p reportportal up -d --force-recreate' --build +## to start all containers in daemon mode +## Where: +## '-f docker-compose.yml' -- specifies this compose file +## '-p reportportal' -- specifies container's prefix (project name) +## '-d' -- enables daemon mode +## '--force-recreate' -- forces re-recreating of all containers + +version: '2.4' +services: + + gateway: + image: traefik:v2.0.5 + ports: + - "8080:8080" # HTTP exposed + - "8081:8081" # HTTP Administration exposed + volumes: + - /var/run/docker.sock:/var/run/docker.sock + command: + - --providers.docker=true + - --providers.docker.constraints=Label(`traefik.expose`, `true`) + - --entrypoints.web.address=:8080 + - --entrypoints.traefik.address=:8081 + - --api.dashboard=true + - --api.insecure=true + restart: always + + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.3.0 + volumes: + - ./data/elasticsearch:/usr/share/elasticsearch/data + environment: + - "bootstrap.memory_lock=true" + - "discovery.type=single-node" + - "logger.level=INFO" + - "xpack.security.enabled=true" + - "ELASTIC_PASSWORD=elastic1q2w3e" + ulimits: + memlock: + soft: -1 + hard: -1 + nofile: + soft: 65536 + hard: 65536 + # ports: + # - "9200:9200" + healthcheck: + test: ["CMD", "curl","-s" ,"-f", "http://elastic:elastic1q2w3e@localhost:9200/_cat/health"] + restart: always + + analyzer: + image: reportportal/service-auto-analyzer:5.3.4 + environment: + LOGGING_LEVEL: info + AMQP_URL: amqp://rabbitmq:rabbitmq@rabbitmq:5672 + ES_HOSTS: http://elastic:elastic1q2w3e@elasticsearch:9200 + MINIO_SHORT_HOST: minio:9000 + MINIO_ACCESS_KEY: minio + MINIO_SECRET_KEY: minio123 + depends_on: + - elasticsearch + restart: always + + ### Initial reportportal db schema. Run once. + db-scripts: + image: reportportal/migrations:5.3.4 + depends_on: + postgres: + condition: service_healthy + environment: + POSTGRES_SERVER: postgres + POSTGRES_PORT: 5432 + POSTGRES_DB: reportportal + POSTGRES_USER: rpuser + POSTGRES_PASSWORD: rppass + restart: on-failure + + postgres: + image: postgres:12-alpine + shm_size: '512m' + environment: + POSTGRES_USER: rpuser + POSTGRES_PASSWORD: rppass + POSTGRES_DB: reportportal + volumes: + # For unix host + - ./data/postgres:/var/lib/postgresql/data + # For windows host + # - postgres:/var/lib/postgresql/data + # If you need to access the DB locally. Could be a security risk to expose DB. + # ports: + # - "5432:5432" + command: + -c checkpoint_completion_target=0.9 + -c work_mem=96MB + -c wal_writer_delay=20ms + -c synchronous_commit=off + -c wal_buffers=32MB + -c min_wal_size=2GB + -c max_wal_size=4GB + # Optional, for SSD Data Storage. If you are using the HDD, set up this command to '2' + # -c effective_io_concurrency=200 + # Optional, for SSD Data Storage. If you are using the HDD, set up this command to '4' + # -c random_page_cost=1.1 + # Optional, can be scaled. Example for 4 CPU, 16GB RAM instance, where only the database is deployed + # -c max_worker_processes=4 + # -c max_parallel_workers_per_gather=2 + # -c max_parallel_workers=4 + # -c shared_buffers=4GB + # -c effective_cache_size=12GB + # -c maintenance_work_mem=1GB + healthcheck: + test: ["CMD-SHELL", "pg_isready -d $$POSTGRES_DB -U $$POSTGRES_USER"] + interval: 10s + timeout: 120s + retries: 10 + restart: always + + rabbitmq: + image: rabbitmq:3.7.16-management + #ports: + # - "5672:5672" + #- "15672:15672" + environment: + RABBITMQ_DEFAULT_USER: "rabbitmq" + RABBITMQ_DEFAULT_PASS: "rabbitmq" + healthcheck: + test: ["CMD", "rabbitmqctl", "status"] + retries: 5 + restart: always + + uat: + image: reportportal/service-authorization:5.3.3 + #ports: + # - "9999:9999" + environment: + - RP_DB_HOST=postgres + - RP_DB_USER=rpuser + - RP_DB_PASS=rppass + - RP_DB_NAME=reportportal + - RP_BINARYSTORE_TYPE=minio + - RP_BINARYSTORE_MINIO_ENDPOINT=http://minio:9000 + - RP_BINARYSTORE_MINIO_ACCESSKEY=minio + - RP_BINARYSTORE_MINIO_SECRETKEY=minio123 + - RP_SESSION_LIVE=86400 #in seconds + labels: + - "traefik.http.middlewares.uat-strip-prefix.stripprefix.prefixes=/uat" + - "traefik.http.routers.uat.middlewares=uat-strip-prefix@docker" + - "traefik.http.routers.uat.rule=PathPrefix(`/uat`)" + - "traefik.http.routers.uat.service=uat" + - "traefik.http.services.uat.loadbalancer.server.port=9999" + - "traefik.http.services.uat.loadbalancer.server.scheme=http" + - "traefik.expose=true" + restart: always + + index: + image: reportportal/service-index:5.0.10 + depends_on: + gateway: + condition: service_started + environment: + - LB_URL=http://gateway:8081 + - TRAEFIK_V2_MODE=true + labels: + - "traefik.http.routers.index.rule=PathPrefix(`/`)" + - "traefik.http.routers.index.service=index" + - "traefik.http.services.index.loadbalancer.server.port=8080" + - "traefik.http.services.index.loadbalancer.server.scheme=http" + - "traefik.expose=true" + restart: always + + api: + image: reportportal/service-api:5.3.4 + depends_on: + rabbitmq: + condition: service_healthy + gateway: + condition: service_started + postgres: + condition: service_healthy + environment: + - RP_DB_HOST=postgres + - RP_DB_USER=rpuser + - RP_DB_PASS=rppass + - RP_DB_NAME=reportportal + - RP_AMQP_USER=rabbitmq + - RP_AMQP_PASS=rabbitmq + - RP_AMQP_APIUSER=rabbitmq + - RP_AMQP_APIPASS=rabbitmq + - RP_BINARYSTORE_TYPE=minio + - RP_BINARYSTORE_MINIO_ENDPOINT=http://minio:9000 + - RP_BINARYSTORE_MINIO_ACCESSKEY=minio + - RP_BINARYSTORE_MINIO_SECRETKEY=minio123 + - LOGGING_LEVEL_ORG_HIBERNATE_SQL=info + - JAVA_OPTS=-Xmx1g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Dcom.sun.management.jmxremote.rmi.port=12349 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=0.0.0.0 + labels: + - "traefik.http.middlewares.api-strip-prefix.stripprefix.prefixes=/api" + - "traefik.http.routers.api.middlewares=api-strip-prefix@docker" + - "traefik.http.routers.api.rule=PathPrefix(`/api`)" + - "traefik.http.routers.api.service=api" + - "traefik.http.services.api.loadbalancer.server.port=8585" + - "traefik.http.services.api.loadbalancer.server.scheme=http" + - "traefik.expose=true" + restart: always + + ui: + image: reportportal/service-ui:5.3.4 + environment: + - RP_SERVER_PORT=8080 + labels: + - "traefik.http.middlewares.ui-strip-prefix.stripprefix.prefixes=/ui" + - "traefik.http.routers.ui.middlewares=ui-strip-prefix@docker" + - "traefik.http.routers.ui.rule=PathPrefix(`/ui`)" + - "traefik.http.routers.ui.service=ui" + - "traefik.http.services.ui.loadbalancer.server.port=8080" + - "traefik.http.services.ui.loadbalancer.server.scheme=http" + - "traefik.expose=true" + restart: always + + minio: + image: minio/minio:RELEASE.2020-10-27T04-03-55Z + #ports: + # - '9000:9000' + volumes: + # For unix host + - ./data/storage:/data + # For windows host + # - minio:/data + environment: + MINIO_ACCESS_KEY: minio + MINIO_SECRET_KEY: minio123 + command: server /data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + restart: always + + # Docker volume for Windows host +#volumes: +# postgres: +# minio: From dec1b56165124573d4ff6d961a3427ed66a4a969 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Wed, 20 Jan 2021 09:55:27 +0530 Subject: [PATCH 23/29] Added report portal agent into dependencies and added config for local project in pytest.ini --- Pipfile | 2 ++ Pipfile.lock | 41 ++++++++++++++++++++++++++++++++++++++++- pytest.ini | 9 +++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 pytest.ini diff --git a/Pipfile b/Pipfile index e56e1cf..e6abd1b 100644 --- a/Pipfile +++ b/Pipfile @@ -12,6 +12,8 @@ assertpy = "*" lxml = "*" jsonpath-ng = "*" cerberus = "*" +reportportal-client = "*" +pytest-reportportal = "*" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index b21d509..9b69697 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "6b3764b346dcb14c5c2dd83a08bc4b179d819d7cdb91da8954c02fb784605c58" + "sha256": "026b46bbe7e0e0e144b7c95ee1d90b5852e433e1f8ffe4436f5c37a233d54f3e" }, "pipfile-spec": 6, "requires": { @@ -60,6 +60,29 @@ ], "version": "==4.4.2" }, + "delayed-assert": { + "hashes": [ + "sha256:2205b7dea7b20fbe4e91b87ebe32cb2da5490f5a8d7fc194de5f90e7e2a79a78", + "sha256:e27669c740300e150271dee2dc82164ac6f1d6fe41911e0ea4c6e4d2e9d547f7" + ], + "version": "==0.3.5" + }, + "dill": { + "hashes": [ + "sha256:78370261be6ea49037ace8c17e0b7dd06d0393af6513cc23f9b222d9367ce389", + "sha256:efb7f6cb65dba7087c1e111bb5390291ba3616741f96840bfc75792a1a9b5ded" + ], + "markers": "python_version >= '2.6' and python_version != '3.0'", + "version": "==0.3.3" + }, + "enum34": { + "hashes": [ + "sha256:a98a201d6de3f2ab3db284e70a33b0f896fbf35f8086594e8c9e74b909058d53", + "sha256:c3858660960c984d6ab0ebad691265180da2b43f07e061c0f8dca9ef3cffd328", + "sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248" + ], + "version": "==1.1.10" + }, "idna": { "hashes": [ "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", @@ -173,6 +196,22 @@ "index": "pypi", "version": "==6.2.1" }, + "pytest-reportportal": { + "hashes": [ + "sha256:201317aaa70c2a21e25002112a3e57c392b6c8cb8b78b775faf515bcb2302c86", + "sha256:39cde7eaaf6237e31f1592f785ff244cf193d5197ba22833145e830c47499b8f" + ], + "index": "pypi", + "version": "==5.0.7" + }, + "reportportal-client": { + "hashes": [ + "sha256:8aa524a8bbbbcfb974c86fd162e126dd61768d9ca55e6c1c34bba2870bc7d47f", + "sha256:e718134ebe1448f707cf33a7bdd33aaf15f1975fdcf309d345940a3b7193abc4" + ], + "index": "pypi", + "version": "==5.0.7" + }, "requests": { "hashes": [ "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..fbfe8eb --- /dev/null +++ b/pytest.ini @@ -0,0 +1,9 @@ +[pytest] +rp_uuid = fb586627-32be-47dd-93c1-678873458a5f +rp_endpoint = http://192.168.1.10:8080 +rp_project = user_personal +rp_launch = AnyLaunchName +rp_launch_attributes = 'PyTest' 'Smoke' +rp_launch_description = 'Smoke test' +rp_ignore_errors = True +rp_ignore_attributes = 'xfail' 'usefixture' \ No newline at end of file From 33308f2d46a50b2b89e3de4b1d9b12abfa1f5a4b Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Wed, 20 Jan 2021 09:56:05 +0530 Subject: [PATCH 24/29] Added logger in conftest.py and updated a test method to log to the console --- tests/conftest.py | 27 +++++++++++++++++++++++++++ tests/people_test.py | 8 +++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 1e81912..8a17b36 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,9 @@ +import logging import random +import sys import pytest +from pytest_reportportal import RPLogger, RPLogHandler from utils.file_reader import read_file @@ -14,3 +17,27 @@ def create_data(): payload['lname'] = last_name yield payload + + +@pytest.fixture(scope="session") +def logger(request): + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + + # Create handler for Report Portal if the service has been + # configured and started. + if hasattr(request.node.config, 'py_test_service'): + # Import Report Portal logger and handler to the test module. + logging.setLoggerClass(RPLogger) + rp_handler = RPLogHandler(request.node.config.py_test_service) + + # Add additional handlers if it is necessary + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setLevel(logging.INFO) + logger.addHandler(console_handler) + else: + rp_handler = logging.StreamHandler(sys.stdout) + + # Set INFO level for Report Portal handler. + rp_handler.setLevel(logging.INFO) + return logger diff --git a/tests/people_test.py b/tests/people_test.py index c5e5e74..db9b426 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -7,10 +7,16 @@ client = PeopleClient() -def test_read_all_has_kent(): +def test_read_all_has_kent(logger): + """ + Verify people API database GET operation returns a user with first name as kent + :param logger: + :return: + """ response = client.read_all_persons() assert_that(response.status_code).is_equal_to(requests.codes.ok) + logger.info("User successfully read") assert_people_have_person_with_first_name(response, first_name='Kent') From b390b1b43817609f0bd8d64190b9bd12adfa187d Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 2 Feb 2021 22:06:32 +0530 Subject: [PATCH 25/29] Updated docker-compose to generate report portal environment, Updated tests and pytest.ini file --- pytest.ini | 14 ++++++++------ tests/people_test.py | 4 +--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pytest.ini b/pytest.ini index fbfe8eb..5ec92d9 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,9 +1,11 @@ [pytest] -rp_uuid = fb586627-32be-47dd-93c1-678873458a5f -rp_endpoint = http://192.168.1.10:8080 -rp_project = user_personal -rp_launch = AnyLaunchName -rp_launch_attributes = 'PyTest' 'Smoke' -rp_launch_description = 'Smoke test' +rp_uuid = 3a105970-9304-4c08-93c0-fc6b063a27ae +rp_endpoint = http://localhost:8080 +rp_project = people-tests +rp_launch = people-tests +# Additional tags that would be printed +rp_launch_attributes = 'people-api' 'covid-tracker' +# Would be mentioned as a description of any test suite run +rp_launch_description = 'People and covid tracker tests' rp_ignore_errors = True rp_ignore_attributes = 'xfail' 'usefixture' \ No newline at end of file diff --git a/tests/people_test.py b/tests/people_test.py index db9b426..716e63a 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -9,9 +9,7 @@ def test_read_all_has_kent(logger): """ - Verify people API database GET operation returns a user with first name as kent - :param logger: - :return: + Test on hitting People GET API, we get a user named kent in the list of people """ response = client.read_all_persons() From d4482fa4447dada023d7dbbdebbd856306061375 Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 23 Feb 2021 07:43:43 +0530 Subject: [PATCH 26/29] - Added pytest-xdist to Pipfile - Updated README.md --- Pipfile | 1 + Pipfile.lock | 110 +++++++++++++++++++++++++++++++++++++++++---------- README.md | 24 +++++++++++ 3 files changed, 114 insertions(+), 21 deletions(-) diff --git a/Pipfile b/Pipfile index e6abd1b..07757c4 100644 --- a/Pipfile +++ b/Pipfile @@ -14,6 +14,7 @@ jsonpath-ng = "*" cerberus = "*" reportportal-client = "*" pytest-reportportal = "*" +pytest-xdist = {extras = ["psutil"], version = "*"} [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index 9b69697..86ba075 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "026b46bbe7e0e0e144b7c95ee1d90b5852e433e1f8ffe4436f5c37a233d54f3e" + "sha256": "8a633053070ab315750f1c9515de3fe0e94f27fcb5008d75e8bccee551ffe091" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,22 @@ ] }, "default": { + "aenum": { + "hashes": [ + "sha256:17cd8cfed1ee4b617198c9fabbabd70ebd8f01e54ac29cd6c3a92df14bd86656", + "sha256:58b899111b3fa9f9569e30c6305b07308f5b0dfdbbd2a9b9f01e8e08def7fdbb", + "sha256:701c4fecd4c5237ed5ab80a18930a0ebe26a8c729a21e1b7302197a3f430da7c" + ], + "version": "==3.0.0" + }, + "apipkg": { + "hashes": [ + "sha256:37228cda29411948b422fae072f57e31d3396d2ee1c9783775980ee9c9990af6", + "sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.5" + }, "assertpy": { "hashes": [ "sha256:acc64329934ad71a3221de185517a43af33e373bb44dc05b5a9b174394ef4833" @@ -75,13 +91,13 @@ "markers": "python_version >= '2.6' and python_version != '3.0'", "version": "==0.3.3" }, - "enum34": { + "execnet": { "hashes": [ - "sha256:a98a201d6de3f2ab3db284e70a33b0f896fbf35f8086594e8c9e74b909058d53", - "sha256:c3858660960c984d6ab0ebad691265180da2b43f07e061c0f8dca9ef3cffd328", - "sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248" + "sha256:7a13113028b1e1cc4c6492b28098b3c6576c9dccc7973bfe47b342afadafb2ac", + "sha256:b73c5565e517f24b62dea8a5ceac178c661c4309d3aa0c3e420856c072c411b4" ], - "version": "==1.1.10" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.8.0" }, "idna": { "hashes": [ @@ -151,11 +167,11 @@ }, "packaging": { "hashes": [ - "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858", - "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093" + "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5", + "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.8" + "version": "==20.9" }, "pluggy": { "hashes": [ @@ -172,6 +188,39 @@ ], "version": "==3.11" }, + "psutil": { + "hashes": [ + "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64", + "sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131", + "sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c", + "sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6", + "sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023", + "sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df", + "sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394", + "sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4", + "sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b", + "sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2", + "sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d", + "sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65", + "sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d", + "sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef", + "sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7", + "sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60", + "sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6", + "sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8", + "sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b", + "sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d", + "sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac", + "sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935", + "sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d", + "sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28", + "sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876", + "sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0", + "sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3", + "sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563" + ], + "version": "==5.8.0" + }, "py": { "hashes": [ "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", @@ -190,27 +239,46 @@ }, "pytest": { "hashes": [ - "sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8", - "sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306" + "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9", + "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839" ], "index": "pypi", - "version": "==6.2.1" + "version": "==6.2.2" + }, + "pytest-forked": { + "hashes": [ + "sha256:6aa9ac7e00ad1a539c41bec6d21011332de671e938c7637378ec9710204e37ca", + "sha256:dc4147784048e70ef5d437951728825a131b81714b398d5d52f17c7c144d8815" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.3.0" }, "pytest-reportportal": { "hashes": [ - "sha256:201317aaa70c2a21e25002112a3e57c392b6c8cb8b78b775faf515bcb2302c86", - "sha256:39cde7eaaf6237e31f1592f785ff244cf193d5197ba22833145e830c47499b8f" + "sha256:a6d9d6c00cd398c4ac70ece532a5961f84ae05bcac111b2688f53fd920751181", + "sha256:bc295cf4c388994c755570dced591f5b7c4914628d413b66ee15887e9c48b0d7" + ], + "index": "pypi", + "version": "==5.0.8" + }, + "pytest-xdist": { + "extras": [ + "psutil" + ], + "hashes": [ + "sha256:2447a1592ab41745955fb870ac7023026f20a5f0bfccf1b52a879bd193d46450", + "sha256:718887296892f92683f6a51f25a3ae584993b06f7076ce1e1fd482e59a8220a2" ], "index": "pypi", - "version": "==5.0.7" + "version": "==2.2.1" }, "reportportal-client": { "hashes": [ - "sha256:8aa524a8bbbbcfb974c86fd162e126dd61768d9ca55e6c1c34bba2870bc7d47f", - "sha256:e718134ebe1448f707cf33a7bdd33aaf15f1975fdcf309d345940a3b7193abc4" + "sha256:2d79f73451ebe901f5ffbac98dcded0cea56ba71bfe6c6254332e5637946564c", + "sha256:f07be65a43d087d20c6bc5a7d9313d503673635014880dc440f3a3af3017d5d3" ], "index": "pypi", - "version": "==5.0.7" + "version": "==5.0.9" }, "requests": { "hashes": [ @@ -238,11 +306,11 @@ }, "urllib3": { "hashes": [ - "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", - "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" + "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", + "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.2" + "version": "==1.26.3" } }, "develop": {} diff --git a/README.md b/README.md index 64a4ee9..fa77866 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,30 @@ git checkout example/01_setup_python_dependencies git checkout ``` +## Application under test + +This automated test suite covers features of `people-api`, Please refer the Github +repo [here](https://github.com/automationhacks/people-api). + +Note: These tests expect the `people-api` and `covid-tracker` API to be up. You would find instructions in +the `people-api` repo + +## How to run + +```zsh +# Setup report portal on docker +# Update rp_uuid in pytest.ini with project token +docker-compose -f docker-compose.yml -p reportportal up -d +# Launch pipenv +pipenv shell +# Install all packages +pipenv install +# Run tests via pytest (single threaded) +python -m pytest +# RUn tests in parallel +python -m pytest -n auto +``` + ## Discuss? Feel free to use the [Github discussions](https://github.com/automationhacks/course-api-framework-python/discussions/1) From 924e0fa95ff1fa18ba97a457114535e53b9d9ffc Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Tue, 23 Feb 2021 22:21:37 +0530 Subject: [PATCH 27/29] Updated readme --- .gitignore | 1 + README.md | 39 ++++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 33543f2..5708994 100644 --- a/.gitignore +++ b/.gitignore @@ -128,4 +128,5 @@ dmypy.json # Pyre type checker .pyre/ .idea +.vscode/ data/ \ No newline at end of file diff --git a/README.md b/README.md index fa77866..6133800 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,17 @@ ## Purpose -Code for TAU (Test automation university) course on building an API framework with Python. Once ready this would be -published at [Test automation university](https://testautomationu.applitools.com/), You can also find a series of blogs -that I'm writing for this course on my blog [https://automationhacks.io/](https://automationhacks.io/tags/) -under `Python` tag. However, the video courses are going to have much more context and in depth discussions +Code for TAU (Test automation university) course on building an API framework with Python. Once +ready this would be published at +[Test automation university](https://testautomationu.applitools.com/), You can also find a series of +blogs that I'm writing for this course on my blog +[https://automationhacks.io/](https://automationhacks.io/tags/) under `Python` tag. However, the +video courses are going to have much more context and in depth discussions ## Setup -Ensure you -have [pipenv already installed](https://automationhacks.io/2020/07/12/how-to-manage-your-python-virtualenvs-with-pipenv/): +Ensure you have +[pipenv already installed](https://automationhacks.io/2020/07/12/how-to-manage-your-python-virtualenvs-with-pipenv/): ```zsh # Activate virtualenv @@ -21,8 +23,8 @@ pipenv install ## How to navigate -Each chapter has its own dedicated branch in `/example/_` format. For -e.g. `example/01_setup_python_dependencies` +Each chapter has its own dedicated branch in `/example/_` format. For e.g. +`example/01_setup_python_dependencies` You can either use your IDE or terminal to switch to that branch and see the last updated commit. @@ -35,11 +37,11 @@ git checkout ## Application under test -This automated test suite covers features of `people-api`, Please refer the Github -repo [here](https://github.com/automationhacks/people-api). +This automated test suite covers features of `people-api`, Please refer the Github repo +[here](https://github.com/automationhacks/people-api). -Note: These tests expect the `people-api` and `covid-tracker` API to be up. You would find instructions in -the `people-api` repo +Note: These tests expect the `people-api` and `covid-tracker` API to be up. You would find +instructions in the `people-api` repo ## How to run @@ -47,20 +49,27 @@ the `people-api` repo # Setup report portal on docker # Update rp_uuid in pytest.ini with project token docker-compose -f docker-compose.yml -p reportportal up -d + # Launch pipenv pipenv shell + # Install all packages pipenv install + # Run tests via pytest (single threaded) python -m pytest -# RUn tests in parallel + +# Run tests in parallel python -m pytest -n auto + +# Report results to report portal +python -m pytest -n auto ./tests --reportportal ``` ## Discuss? -Feel free to use the [Github discussions](https://github.com/automationhacks/course-api-framework-python/discussions/1) +Feel free to use the +[Github discussions](https://github.com/automationhacks/course-api-framework-python/discussions/1) in this repo to ✍🏼 your thoughts or even use the disqus comments section on the blogs. Happy learning! - From c8dd36ad1abc29039a61b77e3208d3d3349b08ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Dec 2021 20:52:39 +0000 Subject: [PATCH 28/29] Bump lxml from 4.6.2 to 4.6.5 Bumps [lxml](https://github.com/lxml/lxml) from 4.6.2 to 4.6.5. - [Release notes](https://github.com/lxml/lxml/releases) - [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt) - [Commits](https://github.com/lxml/lxml/compare/lxml-4.6.2...lxml-4.6.5) --- updated-dependencies: - dependency-name: lxml dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Pipfile.lock | 208 ++++++++++++++++++++++++++++----------------------- 1 file changed, 116 insertions(+), 92 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 86ba075..2153f13 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -18,19 +18,11 @@ "default": { "aenum": { "hashes": [ - "sha256:17cd8cfed1ee4b617198c9fabbabd70ebd8f01e54ac29cd6c3a92df14bd86656", - "sha256:58b899111b3fa9f9569e30c6305b07308f5b0dfdbbd2a9b9f01e8e08def7fdbb", - "sha256:701c4fecd4c5237ed5ab80a18930a0ebe26a8c729a21e1b7302197a3f430da7c" + "sha256:2ebad8590b6a0183c0d9893523b458edce987ae4533339c5ac185cfac32daf1a", + "sha256:7db6e790434baece9e14a97da69118edc89ade821f36590ce32a295f1e500e89", + "sha256:d50b9f8aa3e75c179056182820227eb09485e0bd07f968983744dfbd11958350" ], - "version": "==3.0.0" - }, - "apipkg": { - "hashes": [ - "sha256:37228cda29411948b422fae072f57e31d3396d2ee1c9783775980ee9c9990af6", - "sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5" + "version": "==3.1.5" }, "assertpy": { "hashes": [ @@ -41,11 +33,11 @@ }, "attrs": { "hashes": [ - "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6", - "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700" + "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", + "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.3.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==21.2.0" }, "cerberus": { "hashes": [ @@ -56,10 +48,10 @@ }, "certifi": { "hashes": [ - "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", - "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" + "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" ], - "version": "==2020.12.5" + "version": "==2021.10.8" }, "chardet": { "hashes": [ @@ -71,33 +63,34 @@ }, "decorator": { "hashes": [ - "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760", - "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7" + "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374", + "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7" ], - "version": "==4.4.2" + "markers": "python_version >= '3.5'", + "version": "==5.1.0" }, "delayed-assert": { "hashes": [ - "sha256:2205b7dea7b20fbe4e91b87ebe32cb2da5490f5a8d7fc194de5f90e7e2a79a78", - "sha256:e27669c740300e150271dee2dc82164ac6f1d6fe41911e0ea4c6e4d2e9d547f7" + "sha256:0e1c65afae4bae9c57b91c76e38287562924c9964a58c309249790c725c46239", + "sha256:9987466c4d05c94af21151f27e58a8c13beba176e5f358d16c21b6abd3e6268b" ], - "version": "==0.3.5" + "version": "==0.3.6" }, "dill": { "hashes": [ - "sha256:78370261be6ea49037ace8c17e0b7dd06d0393af6513cc23f9b222d9367ce389", - "sha256:efb7f6cb65dba7087c1e111bb5390291ba3616741f96840bfc75792a1a9b5ded" + "sha256:7e40e4a70304fd9ceab3535d36e58791d9c4a776b38ec7f7ec9afc8d3dca4d4f", + "sha256:9f9734205146b2b353ab3fec9af0070237b6ddae78452af83d2fca84d739e675" ], - "markers": "python_version >= '2.6' and python_version != '3.0'", - "version": "==0.3.3" + "markers": "python_version >= '2.7' and python_version != '3.0'", + "version": "==0.3.4" }, "execnet": { "hashes": [ - "sha256:7a13113028b1e1cc4c6492b28098b3c6576c9dccc7973bfe47b342afadafb2ac", - "sha256:b73c5565e517f24b62dea8a5ceac178c661c4309d3aa0c3e420856c072c411b4" + "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5", + "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.8.0" + "version": "==1.9.0" }, "idna": { "hashes": [ @@ -124,54 +117,77 @@ }, "lxml": { "hashes": [ - "sha256:0448576c148c129594d890265b1a83b9cd76fd1f0a6a04620753d9a6bcfd0a4d", - "sha256:127f76864468d6630e1b453d3ffbbd04b024c674f55cf0a30dc2595137892d37", - "sha256:1471cee35eba321827d7d53d104e7b8c593ea3ad376aa2df89533ce8e1b24a01", - "sha256:2363c35637d2d9d6f26f60a208819e7eafc4305ce39dc1d5005eccc4593331c2", - "sha256:2e5cc908fe43fe1aa299e58046ad66981131a66aea3129aac7770c37f590a644", - "sha256:2e6fd1b8acd005bd71e6c94f30c055594bbd0aa02ef51a22bbfa961ab63b2d75", - "sha256:366cb750140f221523fa062d641393092813b81e15d0e25d9f7c6025f910ee80", - "sha256:42ebca24ba2a21065fb546f3e6bd0c58c3fe9ac298f3a320147029a4850f51a2", - "sha256:4e751e77006da34643ab782e4a5cc21ea7b755551db202bc4d3a423b307db780", - "sha256:4fb85c447e288df535b17ebdebf0ec1cf3a3f1a8eba7e79169f4f37af43c6b98", - "sha256:50c348995b47b5a4e330362cf39fc503b4a43b14a91c34c83b955e1805c8e308", - "sha256:535332fe9d00c3cd455bd3dd7d4bacab86e2d564bdf7606079160fa6251caacf", - "sha256:535f067002b0fd1a4e5296a8f1bf88193080ff992a195e66964ef2a6cfec5388", - "sha256:5be4a2e212bb6aa045e37f7d48e3e1e4b6fd259882ed5a00786f82e8c37ce77d", - "sha256:60a20bfc3bd234d54d49c388950195d23a5583d4108e1a1d47c9eef8d8c042b3", - "sha256:648914abafe67f11be7d93c1a546068f8eff3c5fa938e1f94509e4a5d682b2d8", - "sha256:681d75e1a38a69f1e64ab82fe4b1ed3fd758717bed735fb9aeaa124143f051af", - "sha256:68a5d77e440df94011214b7db907ec8f19e439507a70c958f750c18d88f995d2", - "sha256:69a63f83e88138ab7642d8f61418cf3180a4d8cd13995df87725cb8b893e950e", - "sha256:6e4183800f16f3679076dfa8abf2db3083919d7e30764a069fb66b2b9eff9939", - "sha256:6fd8d5903c2e53f49e99359b063df27fdf7acb89a52b6a12494208bf61345a03", - "sha256:791394449e98243839fa822a637177dd42a95f4883ad3dec2a0ce6ac99fb0a9d", - "sha256:7a7669ff50f41225ca5d6ee0a1ec8413f3a0d8aa2b109f86d540887b7ec0d72a", - "sha256:7e9eac1e526386df7c70ef253b792a0a12dd86d833b1d329e038c7a235dfceb5", - "sha256:7ee8af0b9f7de635c61cdd5b8534b76c52cd03536f29f51151b377f76e214a1a", - "sha256:8246f30ca34dc712ab07e51dc34fea883c00b7ccb0e614651e49da2c49a30711", - "sha256:8c88b599e226994ad4db29d93bc149aa1aff3dc3a4355dd5757569ba78632bdf", - "sha256:923963e989ffbceaa210ac37afc9b906acebe945d2723e9679b643513837b089", - "sha256:94d55bd03d8671686e3f012577d9caa5421a07286dd351dfef64791cf7c6c505", - "sha256:97db258793d193c7b62d4e2586c6ed98d51086e93f9a3af2b2034af01450a74b", - "sha256:a9d6bc8642e2c67db33f1247a77c53476f3a166e09067c0474facb045756087f", - "sha256:cd11c7e8d21af997ee8079037fff88f16fda188a9776eb4b81c7e4c9c0a7d7fc", - "sha256:d8d3d4713f0c28bdc6c806a278d998546e8efc3498949e3ace6e117462ac0a5e", - "sha256:e0bfe9bb028974a481410432dbe1b182e8191d5d40382e5b8ff39cdd2e5c5931", - "sha256:f4822c0660c3754f1a41a655e37cb4dbbc9be3d35b125a37fab6f82d47674ebc", - "sha256:f83d281bb2a6217cd806f4cf0ddded436790e66f393e124dfe9731f6b3fb9afe", - "sha256:fc37870d6716b137e80d19241d0e2cff7a7643b925dfa49b4c8ebd1295eb506e" + "sha256:11ae552a78612620afd15625be9f1b82e3cc2e634f90d6b11709b10a100cba59", + "sha256:121fc6f71c692b49af6c963b84ab7084402624ffbe605287da362f8af0668ea3", + "sha256:124f09614f999551ac65e5b9875981ce4b66ac4b8e2ba9284572f741935df3d9", + "sha256:12ae2339d32a2b15010972e1e2467345b7bf962e155671239fba74c229564b7f", + "sha256:12d8d6fe3ddef629ac1349fa89a638b296a34b6529573f5055d1cb4e5245f73b", + "sha256:1a2a7659b8eb93c6daee350a0d844994d49245a0f6c05c747f619386fb90ba04", + "sha256:1ccbfe5d17835db906f2bab6f15b34194db1a5b07929cba3cf45a96dbfbfefc0", + "sha256:2f77556266a8fe5428b8759fbfc4bd70be1d1d9c9b25d2a414f6a0c0b0f09120", + "sha256:3534d7c468c044f6aef3c0aff541db2826986a29ea73f2ca831f5d5284d9b570", + "sha256:3884476a90d415be79adfa4e0e393048630d0d5bcd5757c4c07d8b4b00a1096b", + "sha256:3b95fb7e6f9c2f53db88f4642231fc2b8907d854e614710996a96f1f32018d5c", + "sha256:46515773570a33eae13e451c8fcf440222ef24bd3b26f40774dd0bd8b6db15b2", + "sha256:46f21f2600d001af10e847df9eb3b832e8a439f696c04891bcb8a8cedd859af9", + "sha256:473701599665d874919d05bb33b56180447b3a9da8d52d6d9799f381ce23f95c", + "sha256:4b9390bf973e3907d967b75be199cf1978ca8443183cf1e78ad80ad8be9cf242", + "sha256:4f415624cf8b065796649a5e4621773dc5c9ea574a944c76a7f8a6d3d2906b41", + "sha256:534032a5ceb34bba1da193b7d386ac575127cc39338379f39a164b10d97ade89", + "sha256:558485218ee06458643b929765ac1eb04519ca3d1e2dcc288517de864c747c33", + "sha256:57cf05466917e08f90e323f025b96f493f92c0344694f5702579ab4b7e2eb10d", + "sha256:59d77bfa3bea13caee95bc0d3f1c518b15049b97dd61ea8b3d71ce677a67f808", + "sha256:5d5254c815c186744c8f922e2ce861a2bdeabc06520b4b30b2f7d9767791ce6e", + "sha256:5ea121cb66d7e5cb396b4c3ca90471252b94e01809805cfe3e4e44be2db3a99c", + "sha256:60aeb14ff9022d2687ef98ce55f6342944c40d00916452bb90899a191802137a", + "sha256:642eb4cabd997c9b949a994f9643cd8ae00cf4ca8c5cd9c273962296fadf1c44", + "sha256:6548fc551de15f310dd0564751d9dc3d405278d45ea9b2b369ed1eccf142e1f5", + "sha256:68a851176c931e2b3de6214347b767451243eeed3bea34c172127bbb5bf6c210", + "sha256:6e84edecc3a82f90d44ddee2ee2a2630d4994b8471816e226d2b771cda7ac4ca", + "sha256:73e8614258404b2689a26cb5d002512b8bc4dfa18aca86382f68f959aee9b0c8", + "sha256:7679bb6e4d9a3978a46ab19a3560e8d2b7265ef3c88152e7fdc130d649789887", + "sha256:76b6c296e4f7a1a8a128aec42d128646897f9ae9a700ef6839cdc9b3900db9b5", + "sha256:7f00cc64b49d2ef19ddae898a3def9dd8fda9c3d27c8a174c2889ee757918e71", + "sha256:8021eeff7fabde21b9858ed058a8250ad230cede91764d598c2466b0ba70db8b", + "sha256:87f8f7df70b90fbe7b49969f07b347e3f978f8bd1046bb8ecae659921869202b", + "sha256:916d457ad84e05b7db52700bad0a15c56e0c3000dcaf1263b2fb7a56fe148996", + "sha256:925174cafb0f1179a7fd38da90302555d7445e34c9ece68019e53c946be7f542", + "sha256:9801bcd52ac9c795a7d81ea67471a42cffe532e46cfb750cd5713befc5c019c0", + "sha256:99cf827f5a783038eb313beee6533dddb8bdb086d7269c5c144c1c952d142ace", + "sha256:a21b78af7e2e13bec6bea12fc33bc05730197674f3e5402ce214d07026ccfebd", + "sha256:a52e8f317336a44836475e9c802f51c2dc38d612eaa76532cb1d17690338b63b", + "sha256:a702005e447d712375433ed0499cb6e1503fadd6c96a47f51d707b4d37b76d3c", + "sha256:a708c291900c40a7ecf23f1d2384ed0bc0604e24094dd13417c7e7f8f7a50d93", + "sha256:a7790a273225b0c46e5f859c1327f0f659896cc72eaa537d23aa3ad9ff2a1cc1", + "sha256:abcf7daa5ebcc89328326254f6dd6d566adb483d4d00178892afd386ab389de2", + "sha256:add017c5bd6b9ec3a5f09248396b6ee2ce61c5621f087eb2269c813cd8813808", + "sha256:af4139172ff0263d269abdcc641e944c9de4b5d660894a3ec7e9f9db63b56ac9", + "sha256:b4015baed99d046c760f09a4c59d234d8f398a454380c3cf0b859aba97136090", + "sha256:ba0006799f21d83c3717fe20e2707a10bbc296475155aadf4f5850f6659b96b9", + "sha256:bdb98f4c9e8a1735efddfaa995b0c96559792da15d56b76428bdfc29f77c4cdb", + "sha256:c34234a1bc9e466c104372af74d11a9f98338a3f72fae22b80485171a64e0144", + "sha256:c580c2a61d8297a6e47f4d01f066517dbb019be98032880d19ece7f337a9401d", + "sha256:ca9a40497f7e97a2a961c04fa8a6f23d790b0521350a8b455759d786b0bcb203", + "sha256:cab343b265e38d4e00649cbbad9278b734c5715f9bcbb72c85a1f99b1a58e19a", + "sha256:ce52aad32ec6e46d1a91ff8b8014a91538800dd533914bfc4a82f5018d971408", + "sha256:da07c7e7fc9a3f40446b78c54dbba8bfd5c9100dfecb21b65bfe3f57844f5e71", + "sha256:dc8a0dbb2a10ae8bb609584f5c504789f0f3d0d81840da4849102ec84289f952", + "sha256:e5b4b0d9440046ead3bd425eb2b852499241ee0cef1ae151038e4f87ede888c4", + "sha256:f33d8efb42e4fc2b31b3b4527940b25cdebb3026fb56a80c1c1c11a4271d2352", + "sha256:f6befb83bca720b71d6bd6326a3b26e9496ae6649e26585de024890fe50f49b8", + "sha256:fcc849b28f584ed1dbf277291ded5c32bb3476a37032df4a1d523b55faa5f944", + "sha256:ff44de36772b05c2eb74f2b4b6d1ae29b8f41ed5506310ce1258d44826ee38c1" ], "index": "pypi", - "version": "==4.6.2" + "version": "==4.6.5" }, "packaging": { "hashes": [ - "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5", - "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a" + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.9" + "markers": "python_version >= '3.6'", + "version": "==21.3" }, "pluggy": { "hashes": [ @@ -223,19 +239,19 @@ }, "py": { "hashes": [ - "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", - "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" + "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", + "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.10.0" + "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:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", - "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" + "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4", + "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.7" + "markers": "python_version >= '3.6'", + "version": "==3.0.6" }, "pytest": { "hashes": [ @@ -247,11 +263,11 @@ }, "pytest-forked": { "hashes": [ - "sha256:6aa9ac7e00ad1a539c41bec6d21011332de671e938c7637378ec9710204e37ca", - "sha256:dc4147784048e70ef5d437951728825a131b81714b398d5d52f17c7c144d8815" + "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e", + "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.3.0" + "markers": "python_version >= '3.6'", + "version": "==1.4.0" }, "pytest-reportportal": { "hashes": [ @@ -288,13 +304,21 @@ "index": "pypi", "version": "==2.25.1" }, + "setuptools": { + "hashes": [ + "sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373", + "sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e" + ], + "markers": "python_version >= '3.6'", + "version": "==59.6.0" + }, "six": { "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.15.0" + "version": "==1.16.0" }, "toml": { "hashes": [ @@ -306,11 +330,11 @@ }, "urllib3": { "hashes": [ - "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", - "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" + "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", + "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.3" + "version": "==1.26.7" } }, "develop": {} From 046293f9694614ae30673297f8a89395e6b3ae0b Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Sat, 12 Mar 2022 19:42:51 +0000 Subject: [PATCH 29/29] Updated dependencies versions --- Pipfile.lock | 309 +++++++++++++++++++++++++-------------------------- 1 file changed, 154 insertions(+), 155 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 2153f13..fd3adbb 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -18,11 +18,11 @@ "default": { "aenum": { "hashes": [ - "sha256:2ebad8590b6a0183c0d9893523b458edce987ae4533339c5ac185cfac32daf1a", - "sha256:7db6e790434baece9e14a97da69118edc89ade821f36590ce32a295f1e500e89", - "sha256:d50b9f8aa3e75c179056182820227eb09485e0bd07f968983744dfbd11958350" + "sha256:07ea89f43d78b3d5997b32b8d5b0ec3e5be17b3e05b7bac0154b8c484a4aeff5", + "sha256:859fe994719e6b5e39f15f73acd84e08b4e57dc642373b177a5fa6646798706a", + "sha256:8dbe15f446eb8264b788dfeca163fb0a043d408d212152397dc11377b851e4ae" ], - "version": "==3.1.5" + "version": "==3.1.8" }, "assertpy": { "hashes": [ @@ -33,18 +33,18 @@ }, "attrs": { "hashes": [ - "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", - "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" + "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", + "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.2.0" + "version": "==21.4.0" }, "cerberus": { "hashes": [ - "sha256:302e6694f206dd85cb63f13fd5025b31ab6d38c99c50c6d769f8fa0b0f299589" + "sha256:d1b21b3954b2498d9a79edf16b3170a3ac1021df88d197dc2ce5928ba519237c" ], "index": "pypi", - "version": "==1.3.2" + "version": "==1.3.4" }, "certifi": { "hashes": [ @@ -53,28 +53,21 @@ ], "version": "==2021.10.8" }, - "chardet": { + "charset-normalizer": { "hashes": [ - "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", - "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" + "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", + "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.0.0" + "markers": "python_version >= '3'", + "version": "==2.0.12" }, "decorator": { "hashes": [ - "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374", - "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7" + "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", + "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" ], "markers": "python_version >= '3.5'", - "version": "==5.1.0" - }, - "delayed-assert": { - "hashes": [ - "sha256:0e1c65afae4bae9c57b91c76e38287562924c9964a58c309249790c725c46239", - "sha256:9987466c4d05c94af21151f27e58a8c13beba176e5f358d16c21b6abd3e6268b" - ], - "version": "==0.3.6" + "version": "==5.1.1" }, "dill": { "hashes": [ @@ -94,11 +87,11 @@ }, "idna": { "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.10" + "markers": "python_version >= '3'", + "version": "==3.3" }, "iniconfig": { "hashes": [ @@ -109,77 +102,79 @@ }, "jsonpath-ng": { "hashes": [ - "sha256:144d91379be14d9019f51973bd647719c877bfc07dc6f3f5068895765950c69d", - "sha256:93d1f248be68e485eb6635c3a01b2d681f296dc349d71e37c8755837b8944d36" + "sha256:292a93569d74029ba75ac2dc3d3630fc0e17b2df26119a165fa1d498ca47bf65", + "sha256:a273b182a82c1256daab86a313b937059261b5c5f8c4fa3fc38b882b344dd567", + "sha256:f75b95dbecb8a0f3b86fd2ead21c2b022c3f5770957492b9b6196ecccfeb10aa" ], "index": "pypi", - "version": "==1.5.2" + "version": "==1.5.3" }, "lxml": { "hashes": [ - "sha256:11ae552a78612620afd15625be9f1b82e3cc2e634f90d6b11709b10a100cba59", - "sha256:121fc6f71c692b49af6c963b84ab7084402624ffbe605287da362f8af0668ea3", - "sha256:124f09614f999551ac65e5b9875981ce4b66ac4b8e2ba9284572f741935df3d9", - "sha256:12ae2339d32a2b15010972e1e2467345b7bf962e155671239fba74c229564b7f", - "sha256:12d8d6fe3ddef629ac1349fa89a638b296a34b6529573f5055d1cb4e5245f73b", - "sha256:1a2a7659b8eb93c6daee350a0d844994d49245a0f6c05c747f619386fb90ba04", - "sha256:1ccbfe5d17835db906f2bab6f15b34194db1a5b07929cba3cf45a96dbfbfefc0", - "sha256:2f77556266a8fe5428b8759fbfc4bd70be1d1d9c9b25d2a414f6a0c0b0f09120", - "sha256:3534d7c468c044f6aef3c0aff541db2826986a29ea73f2ca831f5d5284d9b570", - "sha256:3884476a90d415be79adfa4e0e393048630d0d5bcd5757c4c07d8b4b00a1096b", - "sha256:3b95fb7e6f9c2f53db88f4642231fc2b8907d854e614710996a96f1f32018d5c", - "sha256:46515773570a33eae13e451c8fcf440222ef24bd3b26f40774dd0bd8b6db15b2", - "sha256:46f21f2600d001af10e847df9eb3b832e8a439f696c04891bcb8a8cedd859af9", - "sha256:473701599665d874919d05bb33b56180447b3a9da8d52d6d9799f381ce23f95c", - "sha256:4b9390bf973e3907d967b75be199cf1978ca8443183cf1e78ad80ad8be9cf242", - "sha256:4f415624cf8b065796649a5e4621773dc5c9ea574a944c76a7f8a6d3d2906b41", - "sha256:534032a5ceb34bba1da193b7d386ac575127cc39338379f39a164b10d97ade89", - "sha256:558485218ee06458643b929765ac1eb04519ca3d1e2dcc288517de864c747c33", - "sha256:57cf05466917e08f90e323f025b96f493f92c0344694f5702579ab4b7e2eb10d", - "sha256:59d77bfa3bea13caee95bc0d3f1c518b15049b97dd61ea8b3d71ce677a67f808", - "sha256:5d5254c815c186744c8f922e2ce861a2bdeabc06520b4b30b2f7d9767791ce6e", - "sha256:5ea121cb66d7e5cb396b4c3ca90471252b94e01809805cfe3e4e44be2db3a99c", - "sha256:60aeb14ff9022d2687ef98ce55f6342944c40d00916452bb90899a191802137a", - "sha256:642eb4cabd997c9b949a994f9643cd8ae00cf4ca8c5cd9c273962296fadf1c44", - "sha256:6548fc551de15f310dd0564751d9dc3d405278d45ea9b2b369ed1eccf142e1f5", - "sha256:68a851176c931e2b3de6214347b767451243eeed3bea34c172127bbb5bf6c210", - "sha256:6e84edecc3a82f90d44ddee2ee2a2630d4994b8471816e226d2b771cda7ac4ca", - "sha256:73e8614258404b2689a26cb5d002512b8bc4dfa18aca86382f68f959aee9b0c8", - "sha256:7679bb6e4d9a3978a46ab19a3560e8d2b7265ef3c88152e7fdc130d649789887", - "sha256:76b6c296e4f7a1a8a128aec42d128646897f9ae9a700ef6839cdc9b3900db9b5", - "sha256:7f00cc64b49d2ef19ddae898a3def9dd8fda9c3d27c8a174c2889ee757918e71", - "sha256:8021eeff7fabde21b9858ed058a8250ad230cede91764d598c2466b0ba70db8b", - "sha256:87f8f7df70b90fbe7b49969f07b347e3f978f8bd1046bb8ecae659921869202b", - "sha256:916d457ad84e05b7db52700bad0a15c56e0c3000dcaf1263b2fb7a56fe148996", - "sha256:925174cafb0f1179a7fd38da90302555d7445e34c9ece68019e53c946be7f542", - "sha256:9801bcd52ac9c795a7d81ea67471a42cffe532e46cfb750cd5713befc5c019c0", - "sha256:99cf827f5a783038eb313beee6533dddb8bdb086d7269c5c144c1c952d142ace", - "sha256:a21b78af7e2e13bec6bea12fc33bc05730197674f3e5402ce214d07026ccfebd", - "sha256:a52e8f317336a44836475e9c802f51c2dc38d612eaa76532cb1d17690338b63b", - "sha256:a702005e447d712375433ed0499cb6e1503fadd6c96a47f51d707b4d37b76d3c", - "sha256:a708c291900c40a7ecf23f1d2384ed0bc0604e24094dd13417c7e7f8f7a50d93", - "sha256:a7790a273225b0c46e5f859c1327f0f659896cc72eaa537d23aa3ad9ff2a1cc1", - "sha256:abcf7daa5ebcc89328326254f6dd6d566adb483d4d00178892afd386ab389de2", - "sha256:add017c5bd6b9ec3a5f09248396b6ee2ce61c5621f087eb2269c813cd8813808", - "sha256:af4139172ff0263d269abdcc641e944c9de4b5d660894a3ec7e9f9db63b56ac9", - "sha256:b4015baed99d046c760f09a4c59d234d8f398a454380c3cf0b859aba97136090", - "sha256:ba0006799f21d83c3717fe20e2707a10bbc296475155aadf4f5850f6659b96b9", - "sha256:bdb98f4c9e8a1735efddfaa995b0c96559792da15d56b76428bdfc29f77c4cdb", - "sha256:c34234a1bc9e466c104372af74d11a9f98338a3f72fae22b80485171a64e0144", - "sha256:c580c2a61d8297a6e47f4d01f066517dbb019be98032880d19ece7f337a9401d", - "sha256:ca9a40497f7e97a2a961c04fa8a6f23d790b0521350a8b455759d786b0bcb203", - "sha256:cab343b265e38d4e00649cbbad9278b734c5715f9bcbb72c85a1f99b1a58e19a", - "sha256:ce52aad32ec6e46d1a91ff8b8014a91538800dd533914bfc4a82f5018d971408", - "sha256:da07c7e7fc9a3f40446b78c54dbba8bfd5c9100dfecb21b65bfe3f57844f5e71", - "sha256:dc8a0dbb2a10ae8bb609584f5c504789f0f3d0d81840da4849102ec84289f952", - "sha256:e5b4b0d9440046ead3bd425eb2b852499241ee0cef1ae151038e4f87ede888c4", - "sha256:f33d8efb42e4fc2b31b3b4527940b25cdebb3026fb56a80c1c1c11a4271d2352", - "sha256:f6befb83bca720b71d6bd6326a3b26e9496ae6649e26585de024890fe50f49b8", - "sha256:fcc849b28f584ed1dbf277291ded5c32bb3476a37032df4a1d523b55faa5f944", - "sha256:ff44de36772b05c2eb74f2b4b6d1ae29b8f41ed5506310ce1258d44826ee38c1" + "sha256:078306d19a33920004addeb5f4630781aaeabb6a8d01398045fcde085091a169", + "sha256:0c1978ff1fd81ed9dcbba4f91cf09faf1f8082c9d72eb122e92294716c605428", + "sha256:1010042bfcac2b2dc6098260a2ed022968dbdfaf285fc65a3acf8e4eb1ffd1bc", + "sha256:1d650812b52d98679ed6c6b3b55cbb8fe5a5460a0aef29aeb08dc0b44577df85", + "sha256:20b8a746a026017acf07da39fdb10aa80ad9877046c9182442bf80c84a1c4696", + "sha256:2403a6d6fb61c285969b71f4a3527873fe93fd0abe0832d858a17fe68c8fa507", + "sha256:24f5c5ae618395ed871b3d8ebfcbb36e3f1091fd847bf54c4de623f9107942f3", + "sha256:28d1af847786f68bec57961f31221125c29d6f52d9187c01cd34dc14e2b29430", + "sha256:31499847fc5f73ee17dbe1b8e24c6dafc4e8d5b48803d17d22988976b0171f03", + "sha256:31ba2cbc64516dcdd6c24418daa7abff989ddf3ba6d3ea6f6ce6f2ed6e754ec9", + "sha256:330bff92c26d4aee79c5bc4d9967858bdbe73fdbdbacb5daf623a03a914fe05b", + "sha256:5045ee1ccd45a89c4daec1160217d363fcd23811e26734688007c26f28c9e9e7", + "sha256:52cbf2ff155b19dc4d4100f7442f6a697938bf4493f8d3b0c51d45568d5666b5", + "sha256:530f278849031b0eb12f46cca0e5db01cfe5177ab13bd6878c6e739319bae654", + "sha256:545bd39c9481f2e3f2727c78c169425efbfb3fbba6e7db4f46a80ebb249819ca", + "sha256:5804e04feb4e61babf3911c2a974a5b86f66ee227cc5006230b00ac6d285b3a9", + "sha256:5a58d0b12f5053e270510bf12f753a76aaf3d74c453c00942ed7d2c804ca845c", + "sha256:5f148b0c6133fb928503cfcdfdba395010f997aa44bcf6474fcdd0c5398d9b63", + "sha256:5f7d7d9afc7b293147e2d506a4596641d60181a35279ef3aa5778d0d9d9123fe", + "sha256:60d2f60bd5a2a979df28ab309352cdcf8181bda0cca4529769a945f09aba06f9", + "sha256:6259b511b0f2527e6d55ad87acc1c07b3cbffc3d5e050d7e7bcfa151b8202df9", + "sha256:6268e27873a3d191849204d00d03f65c0e343b3bcb518a6eaae05677c95621d1", + "sha256:627e79894770783c129cc5e89b947e52aa26e8e0557c7e205368a809da4b7939", + "sha256:62f93eac69ec0f4be98d1b96f4d6b964855b8255c345c17ff12c20b93f247b68", + "sha256:6d6483b1229470e1d8835e52e0ff3c6973b9b97b24cd1c116dca90b57a2cc613", + "sha256:6f7b82934c08e28a2d537d870293236b1000d94d0b4583825ab9649aef7ddf63", + "sha256:6fe4ef4402df0250b75ba876c3795510d782def5c1e63890bde02d622570d39e", + "sha256:719544565c2937c21a6f76d520e6e52b726d132815adb3447ccffbe9f44203c4", + "sha256:730766072fd5dcb219dd2b95c4c49752a54f00157f322bc6d71f7d2a31fecd79", + "sha256:74eb65ec61e3c7c019d7169387d1b6ffcfea1b9ec5894d116a9a903636e4a0b1", + "sha256:7993232bd4044392c47779a3c7e8889fea6883be46281d45a81451acfd704d7e", + "sha256:80bbaddf2baab7e6de4bc47405e34948e694a9efe0861c61cdc23aa774fcb141", + "sha256:86545e351e879d0b72b620db6a3b96346921fa87b3d366d6c074e5a9a0b8dadb", + "sha256:891dc8f522d7059ff0024cd3ae79fd224752676447f9c678f2a5c14b84d9a939", + "sha256:8a31f24e2a0b6317f33aafbb2f0895c0bce772980ae60c2c640d82caac49628a", + "sha256:8b99ec73073b37f9ebe8caf399001848fced9c08064effdbfc4da2b5a8d07b93", + "sha256:986b7a96228c9b4942ec420eff37556c5777bfba6758edcb95421e4a614b57f9", + "sha256:a1547ff4b8a833511eeaceacbcd17b043214fcdb385148f9c1bc5556ca9623e2", + "sha256:a2bfc7e2a0601b475477c954bf167dee6d0f55cb167e3f3e7cefad906e7759f6", + "sha256:a3c5f1a719aa11866ffc530d54ad965063a8cbbecae6515acbd5f0fae8f48eaa", + "sha256:a9f1c3489736ff8e1c7652e9dc39f80cff820f23624f23d9eab6e122ac99b150", + "sha256:aa0cf4922da7a3c905d000b35065df6184c0dc1d866dd3b86fd961905bbad2ea", + "sha256:ad4332a532e2d5acb231a2e5d33f943750091ee435daffca3fec0a53224e7e33", + "sha256:b2582b238e1658c4061ebe1b4df53c435190d22457642377fd0cb30685cdfb76", + "sha256:b6fc2e2fb6f532cf48b5fed57567ef286addcef38c28874458a41b7837a57807", + "sha256:b92d40121dcbd74831b690a75533da703750f7041b4bf951befc657c37e5695a", + "sha256:bbab6faf6568484707acc052f4dfc3802bdb0cafe079383fbaa23f1cdae9ecd4", + "sha256:c0b88ed1ae66777a798dc54f627e32d3b81c8009967c63993c450ee4cbcbec15", + "sha256:ce13d6291a5f47c1c8dbd375baa78551053bc6b5e5c0e9bb8e39c0a8359fd52f", + "sha256:db3535733f59e5605a88a706824dfcb9bd06725e709ecb017e165fc1d6e7d429", + "sha256:dd10383f1d6b7edf247d0960a3db274c07e96cf3a3fc7c41c8448f93eac3fb1c", + "sha256:e01f9531ba5420838c801c21c1b0f45dbc9607cb22ea2cf132844453bec863a5", + "sha256:e11527dc23d5ef44d76fef11213215c34f36af1608074561fcc561d983aeb870", + "sha256:e1ab2fac607842ac36864e358c42feb0960ae62c34aa4caaf12ada0a1fb5d99b", + "sha256:e1fd7d2fe11f1cb63d3336d147c852f6d07de0d0020d704c6031b46a30b02ca8", + "sha256:e9f84ed9f4d50b74fbc77298ee5c870f67cb7e91dcdc1a6915cb1ff6a317476c", + "sha256:ec4b4e75fc68da9dc0ed73dcdb431c25c57775383fec325d23a770a64e7ebc87", + "sha256:f10ce66fcdeb3543df51d423ede7e238be98412232fca5daec3e54bcd16b8da0", + "sha256:f63f62fc60e6228a4ca9abae28228f35e1bd3ce675013d1dfb828688d50c6e23", + "sha256:fa56bb08b3dd8eac3a8c5b7d075c94e74f755fd9d8a04543ae8d37b1612dd170", + "sha256:fa9b7c450be85bfc6cd39f6df8c5b8cbd76b5d6fc1f69efec80203f9894b885f" ], "index": "pypi", - "version": "==4.6.5" + "version": "==4.8.0" }, "packaging": { "hashes": [ @@ -191,11 +186,11 @@ }, "pluggy": { "hashes": [ - "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", - "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", + "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.13.1" + "markers": "python_version >= '3.6'", + "version": "==1.0.0" }, "ply": { "hashes": [ @@ -206,36 +201,40 @@ }, "psutil": { "hashes": [ - "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64", - "sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131", - "sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c", - "sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6", - "sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023", - "sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df", - "sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394", - "sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4", - "sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b", - "sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2", - "sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d", - "sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65", - "sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d", - "sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef", - "sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7", - "sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60", - "sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6", - "sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8", - "sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b", - "sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d", - "sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac", - "sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935", - "sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d", - "sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28", - "sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876", - "sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0", - "sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3", - "sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563" + "sha256:072664401ae6e7c1bfb878c65d7282d4b4391f1bc9a56d5e03b5a490403271b5", + "sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a", + "sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4", + "sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841", + "sha256:32acf55cb9a8cbfb29167cd005951df81b567099295291bcfd1027365b36591d", + "sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d", + "sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0", + "sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845", + "sha256:539e429da49c5d27d5a58e3563886057f8fc3868a5547b4f1876d9c0f007bccf", + "sha256:55ce319452e3d139e25d6c3f85a1acf12d1607ddedea5e35fb47a552c051161b", + "sha256:58c7d923dc209225600aec73aa2c4ae8ea33b1ab31bc11ef8a5933b027476f07", + "sha256:7336292a13a80eb93c21f36bde4328aa748a04b68c13d01dfddd67fc13fd0618", + "sha256:742c34fff804f34f62659279ed5c5b723bb0195e9d7bd9907591de9f8f6558e2", + "sha256:7641300de73e4909e5d148e90cc3142fb890079e1525a840cf0dfd39195239fd", + "sha256:76cebf84aac1d6da5b63df11fe0d377b46b7b500d892284068bacccf12f20666", + "sha256:7779be4025c540d1d65a2de3f30caeacc49ae7a2152108adeaf42c7534a115ce", + "sha256:7d190ee2eaef7831163f254dc58f6d2e2a22e27382b936aab51c835fc080c3d3", + "sha256:8293942e4ce0c5689821f65ce6522ce4786d02af57f13c0195b40e1edb1db61d", + "sha256:869842dbd66bb80c3217158e629d6fceaecc3a3166d3d1faee515b05dd26ca25", + "sha256:90a58b9fcae2dbfe4ba852b57bd4a1dded6b990a33d6428c7614b7d48eccb492", + "sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b", + "sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d", + "sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2", + "sha256:c51f1af02334e4b516ec221ee26b8fdf105032418ca5a5ab9737e8c87dafe203", + "sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2", + "sha256:d62a2796e08dd024b8179bd441cb714e0f81226c352c802fca0fd3f89eeacd94", + "sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9", + "sha256:e5c783d0b1ad6ca8a5d3e7b680468c9c926b804be83a3a8e95141b05c39c9f64", + "sha256:e9805fed4f2a81de98ae5fe38b75a74c6e6ad2df8a5c479594c7629a1fe35f56", + "sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3", + "sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c", + "sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3" ], - "version": "==5.8.0" + "version": "==5.9.0" }, "py": { "hashes": [ @@ -247,19 +246,19 @@ }, "pyparsing": { "hashes": [ - "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4", - "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81" + "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea", + "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484" ], "markers": "python_version >= '3.6'", - "version": "==3.0.6" + "version": "==3.0.7" }, "pytest": { "hashes": [ - "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9", - "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839" + "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db", + "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171" ], "index": "pypi", - "version": "==6.2.2" + "version": "==7.0.1" }, "pytest-forked": { "hashes": [ @@ -271,46 +270,46 @@ }, "pytest-reportportal": { "hashes": [ - "sha256:a6d9d6c00cd398c4ac70ece532a5961f84ae05bcac111b2688f53fd920751181", - "sha256:bc295cf4c388994c755570dced591f5b7c4914628d413b66ee15887e9c48b0d7" + "sha256:5b900d65047d59851e1dfb3a229275a92b5e6be030d880e847156d722a628ca7", + "sha256:9a55468d339e551955cc93247965c7e144f901da5949a8b847e0d965688154e4" ], "index": "pypi", - "version": "==5.0.8" + "version": "==5.0.12" }, "pytest-xdist": { "extras": [ "psutil" ], "hashes": [ - "sha256:2447a1592ab41745955fb870ac7023026f20a5f0bfccf1b52a879bd193d46450", - "sha256:718887296892f92683f6a51f25a3ae584993b06f7076ce1e1fd482e59a8220a2" + "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf", + "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65" ], "index": "pypi", - "version": "==2.2.1" + "version": "==2.5.0" }, "reportportal-client": { "hashes": [ - "sha256:2d79f73451ebe901f5ffbac98dcded0cea56ba71bfe6c6254332e5637946564c", - "sha256:f07be65a43d087d20c6bc5a7d9313d503673635014880dc440f3a3af3017d5d3" + "sha256:3910b3413311c47fdbed92b85fc01266e7a5185b406a35f8a6214eaa42f23a22", + "sha256:48bb05b7daf266f0eb5dbb8c7c5debcc257ece404f88a40c472ae61528b23f3c" ], "index": "pypi", - "version": "==5.0.9" + "version": "==5.1.0" }, "requests": { "hashes": [ - "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", - "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", + "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" ], "index": "pypi", - "version": "==2.25.1" + "version": "==2.27.1" }, "setuptools": { "hashes": [ - "sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373", - "sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e" + "sha256:2347b2b432c891a863acadca2da9ac101eae6169b1d3dfee2ec605ecd50dbfe5", + "sha256:e4f30b9f84e5ab3decf945113119649fec09c1fc3507c6ebffec75646c56e62b" ], - "markers": "python_version >= '3.6'", - "version": "==59.6.0" + "markers": "python_version >= '3.7'", + "version": "==60.9.3" }, "six": { "hashes": [ @@ -320,21 +319,21 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, - "toml": { + "tomli": { "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" + "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" + "markers": "python_version >= '3.7'", + "version": "==2.0.1" }, "urllib3": { "hashes": [ - "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", - "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" + "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed", + "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.7" + "version": "==1.26.8" } }, "develop": {}