Skip to content

Commit ae56a82

Browse files
authored
♻️ Remove overloaded loops in tests (ITISFoundation#2674)
* remove module scoped loop * removed pytest-lazy-fixture * removed nest-asyncio * create xml report for vscode extension
1 parent 670cb22 commit ae56a82

39 files changed

+555
-551
lines changed

.env-devel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,12 @@ SCICRUNCH_API_KEY=REPLACE_ME_with_valid_api_key
6363
SMTP_HOST=mail.speag.com
6464
SMTP_PORT=25
6565

66+
SIMCORE_SERVICES_NETWORK_NAME=interactive_services_subnet
67+
6668
STORAGE_ENDPOINT=storage:8080
6769

70+
SWARM_STACK_NAME=master-simcore
71+
6872
TRACING_ENABLED=1
6973
TRACING_ZIPKIN_ENDPOINT=http://jaeger:9411
7074
TRACING_THRIFT_COMPACT_ENDPOINT=http://jaeger:5775

packages/pytest-simcore/src/pytest_simcore/docker_swarm.py

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# pylint:disable=unused-variable
22
# pylint:disable=unused-argument
33
# pylint:disable=redefined-outer-name
4+
# pylint: disable=too-many-branches
45

5-
6+
import asyncio
67
import json
78
import logging
89
import subprocess
10+
import sys
911
from contextlib import suppress
1012
from pathlib import Path
1113
from typing import Any, Dict, Iterator
@@ -136,10 +138,10 @@ def _fetch_and_print_services(
136138
"Slot": ...,
137139
},
138140
)
139-
for task in service_obj.tasks()
141+
for task in service_obj.tasks() # type: ignore
140142
]
141143

142-
print(HEADER_STR.format(service_obj.name))
144+
print(HEADER_STR.format(service_obj.name)) # type: ignore
143145
print(json.dumps({"service": service, "tasks": tasks}, indent=1))
144146

145147

@@ -216,8 +218,9 @@ def docker_stack(
216218
stacks_deployed: Dict[str, Dict] = {}
217219
for key, stack_name, compose_file in stacks:
218220
subprocess.run(
219-
f"docker stack deploy --with-registry-auth -c {compose_file.name} {stack_name}",
220-
shell=True,
221+
f"docker stack deploy --with-registry-auth -c {compose_file.name} {stack_name}".split(
222+
" "
223+
),
221224
check=True,
222225
cwd=compose_file.parent,
223226
)
@@ -230,22 +233,45 @@ def docker_stack(
230233
# - notice that the timeout is set for all services in both stacks
231234
# - TODO: the time to deploy will depend on the number of services selected
232235
try:
233-
for attempt in Retrying(
234-
wait=wait_fixed(5),
235-
stop=stop_after_delay(8 * MINUTE),
236-
before_sleep=before_sleep_log(log, logging.INFO),
237-
reraise=True,
238-
):
239-
with attempt:
240-
for service in docker_client.services.list():
241-
assert_service_is_running(service)
236+
if sys.version_info >= (3, 7):
237+
from tenacity._asyncio import AsyncRetrying
238+
239+
async def _check_all_services_are_running():
240+
async for attempt in AsyncRetrying(
241+
wait=wait_fixed(5),
242+
stop=stop_after_delay(8 * MINUTE),
243+
before_sleep=before_sleep_log(log, logging.INFO),
244+
reraise=True,
245+
):
246+
with attempt:
247+
await asyncio.gather(
248+
*[
249+
asyncio.get_event_loop().run_in_executor(
250+
None, assert_service_is_running, service
251+
)
252+
for service in docker_client.services.list()
253+
]
254+
)
255+
256+
asyncio.run(_check_all_services_are_running())
257+
258+
else:
259+
for attempt in Retrying(
260+
wait=wait_fixed(5),
261+
stop=stop_after_delay(8 * MINUTE),
262+
before_sleep=before_sleep_log(log, logging.INFO),
263+
reraise=True,
264+
):
265+
with attempt:
266+
for service in docker_client.services.list():
267+
assert_service_is_running(service)
242268

243269
finally:
244270
_fetch_and_print_services(docker_client, "[BEFORE TEST]")
245271

246272
yield {
247273
"stacks": stacks_deployed,
248-
"services": [service.name for service in docker_client.services.list()],
274+
"services": [service.name for service in docker_client.services.list()], # type: ignore
249275
}
250276

251277
## TEAR DOWN ----------------------
@@ -276,8 +302,7 @@ def docker_stack(
276302

277303
try:
278304
subprocess.run(
279-
f"docker stack remove {stack}",
280-
shell=True,
305+
f"docker stack remove {stack}".split(" "),
281306
check=True,
282307
capture_output=True,
283308
)

packages/pytest-simcore/src/pytest_simcore/postgres_service.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# pylint:disable=unused-variable
2-
# pylint:disable=unused-argument
31
# pylint:disable=redefined-outer-name
2+
# pylint:disable=unused-argument
3+
# pylint:disable=unused-variable
44
import asyncio
55
import logging
66
from typing import AsyncIterator, Dict, Iterator, List
@@ -72,13 +72,6 @@ def drop_template_db(postgres_engine: sa.engine.Engine) -> None:
7272
execute_queries(postgres_engine, queries)
7373

7474

75-
@pytest.fixture(scope="module")
76-
def loop(request):
77-
loop = asyncio.get_event_loop_policy().new_event_loop()
78-
yield loop
79-
loop.close()
80-
81-
8275
@pytest.fixture(scope="module")
8376
def postgres_with_template_db(
8477
postgres_db: sa.engine.Engine, postgres_dsn: Dict, postgres_engine: sa.engine.Engine
@@ -173,9 +166,10 @@ def postgres_db(
173166
yield postgres_engine
174167

175168

176-
@pytest.fixture(scope="module")
169+
@pytest.fixture(scope="function")
177170
async def aiopg_engine(
178-
postgres_db: sa.engine.Engine, loop
171+
loop: asyncio.AbstractEventLoop,
172+
postgres_db: sa.engine.Engine,
179173
) -> AsyncIterator[aiopg.sa.engine.Engine]:
180174
"""An aiopg engine connected to an initialized database"""
181175
from aiopg.sa import create_engine

packages/pytest-simcore/src/pytest_simcore/rabbit_service.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
# pylint: disable=unused-argument
33
# pylint: disable=unused-variable
44

5-
import asyncio
65
import json
76
import logging
87
import os
98
import socket
109
from dataclasses import dataclass
11-
from typing import Any, AsyncIterator, Dict, Iterator, Optional
10+
from typing import Any, AsyncIterator, Dict, Optional
1211

1312
import aio_pika
1413
import pytest
@@ -39,17 +38,8 @@ async def wait_till_rabbit_responsive(url: str) -> None:
3938
# FIXTURES ------------------------------------------------------------------------------------
4039

4140

42-
@pytest.fixture(scope="module")
43-
def loop(request) -> Iterator[asyncio.AbstractEventLoop]:
44-
loop = asyncio.get_event_loop_policy().new_event_loop()
45-
yield loop
46-
loop.close()
47-
48-
49-
@pytest.fixture(scope="module")
50-
async def rabbit_config(
51-
loop: asyncio.AbstractEventLoop, docker_stack: Dict, testing_environ_vars: Dict
52-
) -> RabbitConfig:
41+
@pytest.fixture(scope="function")
42+
async def rabbit_config(docker_stack: Dict, testing_environ_vars: Dict) -> RabbitConfig:
5343
prefix = testing_environ_vars["SWARM_STACK_NAME"]
5444
assert f"{prefix}_rabbit" in docker_stack["services"]
5545
rabbit_config = RabbitConfig(

packages/pytest-simcore/src/pytest_simcore/redis_service.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,25 @@
22
# pylint:disable=unused-argument
33
# pylint:disable=redefined-outer-name
44

5-
import asyncio
65
import logging
7-
from typing import Dict, Iterator, Union
6+
from typing import AsyncIterator, Dict, Union
87

98
import aioredis
109
import pytest
1110
import tenacity
1211
from models_library.settings.redis import RedisConfig
12+
from tenacity.before_sleep import before_sleep_log
13+
from tenacity.stop import stop_after_delay
14+
from tenacity.wait import wait_fixed
1315
from yarl import URL
1416

1517
from .helpers.utils_docker import get_service_published_port
1618

1719
log = logging.getLogger(__name__)
1820

1921

20-
@pytest.fixture(scope="module")
21-
def loop(request) -> Iterator[asyncio.AbstractEventLoop]:
22-
loop = asyncio.get_event_loop_policy().new_event_loop()
23-
yield loop
24-
loop.close()
25-
26-
27-
@pytest.fixture(scope="module")
28-
async def redis_config(
29-
loop, docker_stack: Dict, testing_environ_vars: Dict
30-
) -> RedisConfig:
22+
@pytest.fixture(scope="function")
23+
async def redis_config(docker_stack: Dict, testing_environ_vars: Dict) -> RedisConfig:
3124
prefix = testing_environ_vars["SWARM_STACK_NAME"]
3225
assert f"{prefix}_redis" in docker_stack["services"]
3326

@@ -43,14 +36,14 @@ async def redis_config(
4336

4437

4538
@pytest.fixture(scope="function")
46-
async def redis_service(redis_config: RedisConfig, monkeypatch) -> RedisConfig:
39+
def redis_service(redis_config: RedisConfig, monkeypatch) -> RedisConfig:
4740
monkeypatch.setenv("REDIS_HOST", redis_config.host)
4841
monkeypatch.setenv("REDIS_PORT", str(redis_config.port))
4942
return redis_config
5043

5144

5245
@pytest.fixture(scope="function")
53-
async def redis_client(loop, redis_config: RedisConfig) -> Iterator[aioredis.Redis]:
46+
async def redis_client(redis_config: RedisConfig) -> AsyncIterator[aioredis.Redis]:
5447
client = await aioredis.create_redis_pool(redis_config.dsn, encoding="utf-8")
5548

5649
yield client
@@ -64,9 +57,9 @@ async def redis_client(loop, redis_config: RedisConfig) -> Iterator[aioredis.Red
6457

6558

6659
@tenacity.retry(
67-
wait=tenacity.wait_fixed(5),
68-
stop=tenacity.stop_after_attempt(60),
69-
before_sleep=tenacity.before_sleep_log(log, logging.INFO),
60+
wait=wait_fixed(5),
61+
stop=stop_after_delay(60),
62+
before_sleep=before_sleep_log(log, logging.INFO),
7063
reraise=True,
7164
)
7265
async def wait_till_redis_responsive(redis_url: Union[URL, str]) -> None:

packages/pytest-simcore/src/pytest_simcore/simcore_services.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def services_endpoint(
135135

136136

137137
@pytest.fixture(scope="module")
138-
async def simcore_services_ready(
138+
def simcore_services_ready(
139139
services_endpoint: Dict[str, URL], monkeypatch_module: MonkeyPatch
140140
) -> None:
141141
"""
@@ -155,11 +155,14 @@ async def simcore_services_ready(
155155
for h in health_endpoints:
156156
print(f" - {h.name} -> {h.url}")
157157

158+
async def _check_all_services_are_healthy():
159+
await asyncio.gather(
160+
*[wait_till_service_healthy(h.name, h.url) for h in health_endpoints],
161+
return_exceptions=False,
162+
)
163+
158164
# check ready
159-
await asyncio.gather(
160-
*[wait_till_service_healthy(h.name, h.url) for h in health_endpoints],
161-
return_exceptions=False,
162-
)
165+
asyncio.run(_check_all_services_are_healthy())
163166

164167
# patches environment variables with right host/port per service
165168
for service, endpoint in services_endpoint.items():

scripts/common-service.Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ _run-test-dev: _check_venv_active
105105
--color=yes \
106106
--cov-config=.coveragerc \
107107
--cov-report=term-missing \
108+
--cov-report=xml \
108109
--cov=$(APP_PACKAGE_NAME) \
109110
--durations=10 \
110111
--exitfirst \

services/api-server/tests/unit/conftest.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
# pylint:disable=unused-variable
2-
# pylint:disable=unused-argument
1+
# pylint:disable=no-name-in-module
32
# pylint:disable=redefined-outer-name
3+
# pylint:disable=unused-argument
4+
# pylint:disable=unused-variable
45

56
import os
67
import shutil

services/catalog/tests/unit/with_dbs/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# pylint:disable=redefined-outer-name
44

55

6+
import asyncio
67
import itertools
78
import random
89
from typing import Any, Callable, Dict, Iterable, Iterator, List, Tuple
@@ -41,7 +42,7 @@ def app(
4142

4243

4344
@pytest.fixture
44-
def client(app: FastAPI) -> Iterable[TestClient]:
45+
def client(loop: asyncio.AbstractEventLoop, app: FastAPI) -> Iterable[TestClient]:
4546
with TestClient(app) as cli:
4647
# Note: this way we ensure the events are run in the application
4748
yield cli

services/catalog/tests/unit/with_dbs/test_db_repositories.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ async def test_list_service_releases_version_filtered(
232232
latest = await services_repo.get_latest_release(
233233
"simcore/services/dynamic/jupyterlab"
234234
)
235+
assert latest
235236
assert latest.version == fake_catalog_with_jupyterlab.expected_latest
236237

237238
releases_1_1_x: List[

0 commit comments

Comments
 (0)