Skip to content

Commit c68b163

Browse files
author
michael.yak
committed
deregister_from_admin_server should be covered by E2E
E2E's test_recurring_registration was extended to verify that deregistration is working properly for all the web frameworks. Note that the actual invocation of test_recurring_registration is registered in `atexit` however in the test its too hard to invoke `atexit` therefore it is called directly. Solves #25
1 parent 28a30b0 commit c68b163

File tree

7 files changed

+48
-10
lines changed

7 files changed

+48
-10
lines changed

pyctuator/impl/aiohttp_pyctuator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from datetime import datetime
55
from functools import partial
66
from http import HTTPStatus
7-
from typing import Any, Callable, List, Mapping, Optional
7+
from typing import Any, Callable, List, Mapping
88

99
from aiohttp import web
1010
from multidict import CIMultiDictProxy

pyctuator/impl/spring_boot_admin_registration.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,7 @@ def __init__(
3636

3737
self.should_continue_registration_schedule: bool = False
3838

39-
def _schedule_next_registration(
40-
self,
41-
registration_interval_sec: int
42-
) -> None:
39+
def _schedule_next_registration(self, registration_interval_sec: int) -> None:
4340
timer = threading.Timer(
4441
registration_interval_sec,
4542
self._register_with_admin_server,

tests/aiohttp_test_server.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ def start(self) -> None:
7979
time.sleep(0.01)
8080

8181
def stop(self) -> None:
82+
logging.info("Stopping aiohttp server")
8283
self.pyctuator.stop()
8384
self.should_stop_server = True
8485
self.thread.join()
86+
logging.info("aiohttp server stopped")
87+
88+
def atexit(self) -> None:
89+
if self.pyctuator.boot_admin_registration_handler:
90+
self.pyctuator.boot_admin_registration_handler.deregister_from_admin_server()

tests/conftest.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class RegistrationTrackerFixture:
4343
registration: Optional[RegistrationRequest]
4444
count: int
4545
start_time: Optional[str]
46+
deregistration_time: Optional[datetime]
4647
test_start_time: datetime
4748

4849

@@ -53,7 +54,7 @@ def install_signal_handlers(self) -> None:
5354

5455
@pytest.fixture
5556
def registration_tracker() -> RegistrationTrackerFixture:
56-
return RegistrationTrackerFixture(None, 0, None, datetime.now(timezone.utc))
57+
return RegistrationTrackerFixture(None, 0, None, None, datetime.now(timezone.utc))
5758

5859

5960
@pytest.fixture
@@ -75,6 +76,13 @@ def register(request: Request, registration: RegistrationRequest) -> Dict[str, s
7576
registration_tracker.start_time = registration.metadata["startup"]
7677
return {"id": "JB007"}
7778

79+
# pylint: disable=unused-argument,unused-variable
80+
@boot_admin_app.delete("/register/{registration_id}", tags=["admin-server"])
81+
def deregister(registration_id: str) -> None:
82+
logging.debug("Got deregistration, delete %s (previous deregistration time is %s)",
83+
registration_id, registration_tracker.deregistration_time)
84+
registration_tracker.deregistration_time = datetime.now(timezone.utc)
85+
7886
# Start the mock boot-admin server that is needed to test pyctuator's registration
7987
boot_admin_config = Config(app=boot_admin_app, port=8001, loop="asyncio")
8088
boot_admin_server = CustomServer(config=boot_admin_config)
@@ -87,6 +95,7 @@ def register(request: Request, registration: RegistrationRequest) -> Dict[str, s
8795
yield None
8896

8997
boot_admin_server.should_exit = True
98+
boot_admin_server.force_exit = True
9099
boot_admin_thread.join()
91100

92101

@@ -127,3 +136,7 @@ def start(self) -> None:
127136
@abstractmethod
128137
def stop(self) -> None:
129138
pass
139+
140+
@abstractmethod
141+
def atexit(self) -> None:
142+
pass

tests/fast_api_test_server.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ def start(self) -> None:
5555
time.sleep(0.01)
5656

5757
def stop(self) -> None:
58+
logging.info("Stopping FastAPI server")
5859
self.pyctuator.stop()
60+
61+
# Allow the recurring registration to complete any in-progress request before stopping FastAPI
62+
time.sleep(1)
63+
5964
self.server.should_exit = True
65+
self.server.force_exit = True
6066
self.thread.join()
67+
logging.info("FastAPI server stopped")
68+
69+
def atexit(self) -> None:
70+
if self.pyctuator.boot_admin_registration_handler:
71+
self.pyctuator.boot_admin_registration_handler.deregister_from_admin_server()

tests/flask_test_server.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,8 @@ def stop(self) -> None:
7171
self.pyctuator.stop()
7272
requests.post("http://localhost:5000/shutdown")
7373
self.thread.join()
74-
logging.info("Flask server is shutdown")
74+
logging.info("Flask server stopped")
75+
76+
def atexit(self) -> None:
77+
if self.pyctuator.boot_admin_registration_handler:
78+
self.pyctuator.boot_admin_registration_handler.deregister_from_admin_server()

tests/test_pyctuator_e2e.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def pyctuator_server(request) -> Generator: # type: ignore
3232
pyctuator_server.start()
3333

3434
# Yield back to pytest until the module is done
35-
yield None
35+
yield pyctuator_server
3636

3737
# Once the module is done, stop the pyctuator-server
3838
pyctuator_server.stop()
@@ -176,14 +176,17 @@ def test_metrics_endpoint(endpoints: Endpoints) -> None:
176176

177177
@pytest.mark.usefixtures("boot_admin_server", "pyctuator_server")
178178
@pytest.mark.mark_recurring_registration
179-
def test_recurring_registration(registration_tracker: RegistrationTrackerFixture) -> None:
179+
def test_recurring_registration_and_deregistration(
180+
registration_tracker: RegistrationTrackerFixture,
181+
pyctuator_server: PyctuatorServer
182+
) -> None:
180183
# Verify that at least 4 registrations occurred within 10 seconds since the test started
181184
start = time.time()
182185
while registration_tracker.count < 4:
183186
time.sleep(0.5)
184187
if time.time() - start > 15:
185188
pytest.fail(
186-
f"Expected at least 4 recurring registrations within 10 seconds but got {registration_tracker.count}")
189+
"Expected at least 4 recurring registrations within 10 seconds but got {registration_tracker.count}")
187190

188191
# Verify that the reported startup time is the same across all the registrations and that its later then the test's
189192
# start time
@@ -192,6 +195,10 @@ def test_recurring_registration(registration_tracker: RegistrationTrackerFixture
192195
registration_start_time = datetime.fromisoformat(registration_tracker.start_time)
193196
assert registration_start_time > registration_tracker.test_start_time - timedelta(seconds=10)
194197

198+
# Ask to deregister (in real life, called by atexit) and verify it was registered
199+
pyctuator_server.atexit()
200+
assert registration_tracker.deregistration_time > registration_start_time
201+
195202

196203
@pytest.mark.usefixtures("boot_admin_server", "pyctuator_server")
197204
@pytest.mark.mark_threads_endpoint

0 commit comments

Comments
 (0)