-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathpubsub.py
More file actions
136 lines (111 loc) · 4.04 KB
/
Copy pathpubsub.py
File metadata and controls
136 lines (111 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
from __future__ import annotations
import socket
from dataclasses import dataclass
from typing import TYPE_CHECKING
import pytest
from pytest_databases.helpers import get_xdist_worker_id
from pytest_databases.types import ServiceContainer, XdistIsolationLevel
if TYPE_CHECKING:
from collections.abc import Generator
from docker.models.containers import Container
from pytest_databases._service import ContainerService
PUBSUB_EMULATOR_IMAGE = "gcr.io/google.com/cloudsdktool/google-cloud-cli:577.0.0-emulators"
PUBSUB_EMULATOR_PORT = 8085
_PUBSUB_SMOKE_SCRIPT = """\
set -eu
topic="pytest-databases-smoke"
subscription="pytest-databases-smoke"
cleanup() {
gcloud pubsub subscriptions delete "$subscription" --quiet >/dev/null 2>&1 || true
gcloud pubsub topics delete "$topic" --quiet >/dev/null 2>&1 || true
}
trap cleanup EXIT
cleanup
gcloud pubsub topics create "$topic" --quiet
gcloud pubsub subscriptions create "$subscription" --topic="$topic" --quiet
gcloud pubsub topics publish "$topic" --message=pytest-databases --quiet
payload="$(timeout 30 gcloud pubsub subscriptions pull "$subscription" --auto-ack --limit=1 --format='value(message.data)' --quiet)"
test "$payload" = "pytest-databases"
"""
@dataclass
class PubSubService(ServiceContainer):
project: str
emulator_host: str
@pytest.fixture(scope="session")
def pubsub_image() -> str:
return PUBSUB_EMULATOR_IMAGE
@pytest.fixture(scope="session")
def pubsub_project() -> str:
worker_id = get_xdist_worker_id()
if worker_id is None or worker_id == "master":
return "pytest-databases"
return f"pytest-databases-{worker_id}"
@pytest.fixture(scope="session")
def xdist_pubsub_isolation_level() -> XdistIsolationLevel:
return "database"
def _pubsub_start_command(project: str) -> list[str]:
return [
"gcloud",
"beta",
"emulators",
"pubsub",
"start",
f"--host-port=0.0.0.0:{PUBSUB_EMULATOR_PORT}",
f"--project={project}",
]
def _is_pubsub_responsive(service: ServiceContainer) -> bool:
try:
connection = socket.create_connection((service.host, service.port), timeout=1)
except OSError:
return False
connection.close()
return True
def _smoke_pubsub_emulator(
emulator_container: Container,
*,
project: str,
) -> None:
result = emulator_container.exec_run(
["bash", "-c", _PUBSUB_SMOKE_SCRIPT],
environment={
"CLOUDSDK_API_ENDPOINT_OVERRIDES_PUBSUB": f"http://localhost:{PUBSUB_EMULATOR_PORT}/",
"CLOUDSDK_AUTH_DISABLE_CREDENTIALS": "true",
"CLOUDSDK_CORE_PROJECT": project,
},
)
if result.exit_code != 0:
output = result.output.decode(errors="replace") if isinstance(result.output, bytes) else str(result.output)
msg = f"Pub/Sub emulator smoke check failed with exit code {result.exit_code}: {output[-2000:]}"
raise RuntimeError(msg)
@pytest.fixture(scope="session")
def pubsub_service(
container_service: ContainerService,
pubsub_image: str,
pubsub_project: str,
xdist_pubsub_isolation_level: XdistIsolationLevel,
) -> Generator[PubSubService, None, None]:
worker_id = get_xdist_worker_id()
container_name = "pubsub"
if xdist_pubsub_isolation_level == "server" and worker_id not in {None, "master"}:
container_name = f"{container_name}_{worker_id}"
with container_service.run(
image=pubsub_image,
command=_pubsub_start_command(pubsub_project),
name=container_name,
container_port=PUBSUB_EMULATOR_PORT,
wait_for_log="Server started",
check=_is_pubsub_responsive,
timeout=60,
transient=xdist_pubsub_isolation_level == "server",
) as service:
_smoke_pubsub_emulator(
service.container,
project=pubsub_project,
)
yield PubSubService(
container=service.container,
host=service.host,
port=service.port,
project=pubsub_project,
emulator_host=f"{service.host}:{service.port}",
)