Skip to content

Commit 7d3e99e

Browse files
committed
refactor endpoint request handling
1 parent 8b7bb78 commit 7d3e99e

File tree

12 files changed

+418
-99
lines changed

12 files changed

+418
-99
lines changed

conftest.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -68,45 +68,58 @@ def start_testing(
6868

6969
@pytest.fixture(scope="session")
7070
def generate_api_token():
71-
base_url = "http://167.172.172.115:52355"
71+
logger.info("Verifying API token")
72+
73+
# Get the environment variables
74+
base_url = os.getenv("BASE_URL")
7275
token = os.getenv("API_TOKEN")
73-
logger.info("Getting API token. Current token: %s", token)
76+
user_name = os.getenv("USER_NAME")
7477

7578
# Verify that the token is valid
7679
post_authorize_verify_url = f"{base_url}/authorize/{token}"
77-
logger.info("Verifying token: %s", post_authorize_verify_url)
7880
response = requests.get(post_authorize_verify_url)
7981
if response.status_code != 200:
8082
# If the token is not valid, get a new one
81-
logger.info("Token is not valid. Getting a new one")
83+
logger.info("API token is not valid. Getting a new one")
8284
post_authorize_url = f"{base_url}/authorize"
8385
response = requests.post(
8486
post_authorize_url,
85-
json={"name": "Summerduck"},
87+
json={"name": user_name},
8688
)
8789
assert response.status_code == 200
8890
token = response.json()["token"]
89-
os.environ["API_TOKEN"] = token
9091
set_key(
9192
dotenv_path=find_dotenv(),
9293
key_to_set="API_TOKEN",
9394
value_to_set=token,
9495
)
96+
logger.info("API token has been updated")
9597

96-
logger.info(f"Token: {token}")
98+
logger.info("API token is valid")
9799

98100
yield token
99101

100-
logger.info("Deleting API token")
101-
102102

103-
# TODO: Implement the clean_up fixture
104103
@pytest.fixture(scope="function")
105-
def clean_up(post_meme, delete_meme):
104+
def temporary_meme_cleanup(post_meme, delete_meme):
106105
yield
107-
logger.info("Cleaning up")
108-
meme_id = post_meme.receive_post_meme_id()
109-
delete_meme.delete_meme_by_id(meme_id)
106+
id = post_meme.meme_id
107+
logger.info(
108+
"------------ TearDown: Deleting the meme that was created: %s ------------", id
109+
)
110+
delete_meme.delete_meme_by_id(id)
111+
logger.info("------------ TearDown: Meme has been deleted ------------")
112+
113+
114+
@pytest.fixture(scope="function")
115+
def temporary_meme_id(post_meme):
116+
logger.info("------------ SetUp: Creating a new meme ------------")
117+
response = post_meme.post_new_meme()
118+
logger.info(
119+
"------------ SetUp: Created a new meme with id: %s ------------ ",
120+
response.json()["id"],
121+
)
122+
yield response.json()["id"]
110123

111124

112125
def __make_dir_for_logs():
@@ -164,19 +177,6 @@ def pytest_runtest_setup(item):
164177
logger.info(f"Starting test - {item.nodeid}")
165178

166179

167-
@pytest.hookimpl(tryfirst=True)
168-
def pytest_runtest_teardown(item, nextitem):
169-
"""leans up the logger after the test is completed"""
170-
logger = logging.getLogger()
171-
logger.info(f"Finished test - {item.nodeid}")
172-
173-
# Remove test-specific handlers
174-
for handler in logger.handlers[:]:
175-
if isinstance(handler, logging.FileHandler):
176-
handler.close()
177-
logger.removeHandler(handler)
178-
179-
180180
@pytest.hookimpl(tryfirst=True)
181181
def pytest_runtest_logreport(report):
182182
"""Handles special processing for logs of failed tests"""

data/base_meme.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,98 @@ class BaseMemeData:
33
({"Authorization": "invalid"}, 401),
44
({"Authorization": ""}, 500),
55
]
6+
7+
memes_not_existing_ids = [
8+
(9999999999999),
9+
("string"),
10+
([]),
11+
({}),
12+
(None),
13+
(True),
14+
(False),
15+
(0.123456789),
16+
(-1),
17+
(0),
18+
(3.14159),
19+
({"key": "value"}),
20+
(["list", "of", "strings"]),
21+
]
22+
23+
# "text": "string"
24+
invalid_text = [
25+
# Non-string data types
26+
123,
27+
123.45,
28+
True,
29+
False,
30+
None,
31+
[1, 2, 3],
32+
{"key": "value"},
33+
# Empty or whitespace strings
34+
"",
35+
" ",
36+
# # Boundary conditions
37+
# "a" * XX, # Assuming max length is XX
38+
# "a" * X, # Assuming min length is X
39+
# Edge cases
40+
"\n",
41+
"\t",
42+
"\r",
43+
]
44+
45+
# "tags": ["string", "string"]
46+
invalid_tags = [
47+
# Non-array data types
48+
"justastring",
49+
123,
50+
123.45,
51+
True,
52+
False,
53+
None,
54+
{"key": "value"},
55+
# Invalid array structures
56+
[],
57+
[123, True, None, ["nestedArray"]],
58+
["valid", 123, True],
59+
[["nested", "array"]],
60+
[{"key": "value"}],
61+
# Invalid content in tags
62+
["", " "],
63+
["@#$%^&*()"],
64+
["DROP TABLE tags;"],
65+
["<script>alert('XSS')</script>"],
66+
["\xC0"],
67+
["a" * 10001], # Assuming max tag length = ???
68+
# Boundary conditions
69+
["tag" + str(i) for i in range(1000)], # Assuming max tags = ???
70+
# Edge cases
71+
["\n", "\t", "\r"],
72+
["duplicate", "duplicate"],
73+
]
74+
75+
# "info": { "key": "value" }
76+
invalid_info = [
77+
# Non-object data types
78+
"justastring",
79+
["key", "value"],
80+
123,
81+
123.45,
82+
True,
83+
False,
84+
None,
85+
# Invalid object structures
86+
{},
87+
{123: "value", True: "value"},
88+
{"key": None, "key2": 123},
89+
{"key": {"nestedKey": "nestedValue"}},
90+
# Invalid key-value content
91+
{"": "value", "key": ""},
92+
{"a" * 10001: "value", "key": "b" * 10001},
93+
# Boundary conditions
94+
{f"key{i}": f"value{i}" for i in range(1000)}, # Assuming max keys = ???
95+
{"a" * 51: "value", "key": "b" * 51}, # Assuming max length = ???
96+
# Edge cases
97+
{" key ": " value "},
98+
{"\nkey": "value", "key": "\tvalue"},
99+
{"key": "value1", "key": "value2"},
100+
]

data/get_meme.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,3 @@ class GetMemeData:
33
(1),
44
(5),
55
]
6-
7-
memes_not_existing_ids = [
8-
(9999999999999),
9-
("string"),
10-
([]),
11-
({}),
12-
(None),
13-
(True),
14-
(False),
15-
(0.123456789),
16-
(-1),
17-
(0),
18-
(3.14159),
19-
({"key": "value"}),
20-
(["list", "of", "strings"]),
21-
(set([1, 2, 3])),
22-
(frozenset([4, 5, 6])),
23-
(bytearray(b"byte array")),
24-
(complex(1, 2)),
25-
]

endpoints/base_endpoint.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,4 @@ def verify_response_status_code(
110110
f"Expected status code {status_code},"
111111
f"but got {self.response.status_code}"
112112
)
113+

endpoints/post_meme.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ def post_new_meme(
2121
tags: Optional[list] = None,
2222
info: Optional[dict] = None,
2323
headers: Optional[dict] = None,
24+
json: Optional[dict] = None,
2425
) -> requests.Response:
2526
"""Make a POST request to the /meme endpoint"""
26-
json = {
27-
"text": text or self._generate_text(),
28-
"url": url or self._generate_url(),
29-
"tags": tags or self._generate_tags(),
30-
"info": info or self._generate_picture_info(),
31-
}
27+
if json is None:
28+
json = {
29+
"text": text or self._generate_text(),
30+
"url": url or self._generate_url(),
31+
"tags": tags or self._generate_tags(),
32+
"info": info or self._generate_picture_info(),
33+
}
3234

3335
self.response = self._send_request(
3436
"POST",

endpoints/put_meme.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,21 @@ def put_meme_by_id(
2222
tags: Optional[list] = None,
2323
info: Optional[dict] = None,
2424
headers: Optional[dict] = None,
25+
json: Optional[dict] = None,
2526
) -> requests.Response:
2627
"""Make a POST request to the /meme endpoint"""
27-
json = {
28-
"id": id,
29-
"text": text or self._generate_text(),
30-
"url": url or self._generate_url(),
31-
"tags": tags or self._generate_tags(),
32-
"info": info or self._generate_picture_info(),
33-
}
28+
if json is None:
29+
json = {
30+
"id": id,
31+
"text": text or self._generate_text(),
32+
"url": url or self._generate_url(),
33+
"tags": tags or self._generate_tags(),
34+
"info": info or self._generate_picture_info(),
35+
}
3436

3537
self.response = self._send_request(
36-
"POST",
37-
"/meme",
38+
"PUT",
39+
f"/meme/{id}",
3840
headers=headers,
3941
json=json,
4042
)

pytest.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ python_files = test_*
44
python_classes = *Test
55
python_functions = test_*
66
log_cli = true
7+
log_cli_level = INFO
78
log_level = INFO
89
markers =
910
delete_meme
1011
positive
1112
negative
1213

13-
addopts = -v -s --alluredir=test-report
14+
addopts = --alluredir=test-report

rlogger.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,26 @@ def filter(self, record):
1919
logger.addFilter(FunctionNameFilter())
2020

2121

22-
def requests_logging(request: Request):
22+
def requests_logging(request: Request, endpoint: str):
2323
# Map the request method to the corresponding logging level
24-
extra = {"func_name": request.method}
24+
extra = {"func_name": f"{request.method} {endpoint}"}
2525

2626
# Log the request data
27-
logger.info(
28-
f"Request data: {request.data}",
29-
extra=extra,
30-
)
3127
logger.info(
3228
f"Request method: {request.method}",
3329
extra=extra,
3430
)
3531
logger.info(
36-
f"Request URL: {request.url}",
32+
f"Request url: {request.url}",
3733
extra=extra,
3834
)
35+
36+
# Do not show token in logs
37+
headers = dict(request.headers)
38+
if "Authorization" in headers:
39+
headers["Authorization"] = "***SECRET***"
3940
logger.info(
40-
f"Request headers: {json.dumps(dict(request.headers), indent=2)}",
41+
f"Request headers: {headers}",
4142
extra=extra,
4243
)
4344
try:
@@ -48,24 +49,27 @@ def requests_logging(request: Request):
4849
)
4950
except TypeError:
5051
logger.info(
51-
"'Request' object has no attribute 'body'",
52+
"Request object has no attribute body",
5253
extra=extra,
5354
)
5455

5556

56-
def response_logging(response: Response):
57+
def response_logging(response: Response, endpoint: str):
58+
# Map the request method to the corresponding logging level
59+
extra = {"func_name": f"{response.request.method} {endpoint}"}
60+
5761
logger.info(
5862
f"Response status code: {response.status_code}",
59-
extra={"func_name": response.request.method},
63+
extra=extra,
6064
)
6165
try:
6266
response_content = response.json()
6367
logger.info(
6468
f"Response content: {json.dumps(response_content, indent=2)}",
65-
extra={"func_name": response.request.method},
69+
extra=extra,
6670
)
6771
except ValueError:
6872
logger.info(
69-
f"Response content is not in JSON format: {response.text}",
70-
extra={"func_name": response.request.method},
73+
f"Response content: {response.text}",
74+
extra=extra,
7175
)

0 commit comments

Comments
 (0)