pytest-databases 0.4.1__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/.pre-commit-config.yaml +1 -1
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/Makefile +6 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/PKG-INFO +5 -2
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/README.md +1 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/pyproject.toml +15 -18
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/__init__.py +11 -24
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/alloydb_omni.py +46 -14
- pytest_databases-0.6.0/src/pytest_databases/docker/azure_blob.py +187 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/bigquery.py +52 -20
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/cockroachdb.py +44 -12
- pytest_databases-0.6.0/src/pytest_databases/docker/docker-compose.azurite.yml +9 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/dragonfly.py +41 -10
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/elastic_search.py +62 -27
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/keydb.py +42 -10
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/mariadb.py +55 -22
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/mssql.py +57 -24
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/mysql.py +71 -36
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/oracle.py +65 -31
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/postgres.py +87 -50
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/redis.py +42 -10
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/spanner.py +48 -16
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/conftest.py +1 -1
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_alloydb_omni.py +2 -2
- pytest_databases-0.6.0/tests/docker/test_azure_blob.py +35 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_bigquery.py +4 -4
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_cockroachdb.py +4 -2
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_dragonfly.py +2 -2
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_elasticsearch.py +14 -14
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_keydb.py +2 -2
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_mariadb.py +4 -4
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_mssql.py +6 -6
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_mysql.py +8 -8
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_oracle.py +8 -4
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_postgres.py +12 -12
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_redis.py +2 -2
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/test_spanner.py +2 -2
- pytest_databases-0.4.1/requirements/requirements-dev.txt +0 -497
- pytest_databases-0.4.1/requirements/requirements-docs.txt +0 -405
- pytest_databases-0.4.1/requirements/requirements.txt +0 -13
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/.gitignore +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/.sourcery.yaml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/.vscode/launch.json +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/.vscode/settings.json +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/CODEOWNERS +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/CONTRIBUTING.rst +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/LICENSE +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/scripts/__init__.py +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/scripts/build_docs.py +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/scripts/convert_docs.sh +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/sonar-project.properties +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/__init__.py +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/__metadata__.py +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.alloydb-omni.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.bigquery.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.cockroachdb.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.dragonfly.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.elasticsearch.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.keydb.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.mariadb.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.mssql.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.mysql.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.oracle.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.postgres.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.redis.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/docker-compose.spanner.yml +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/helpers.py +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/py.typed +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/__init__.py +0 -0
- {pytest_databases-0.4.1 → pytest_databases-0.6.0}/tests/docker/__init__.py +0 -0
|
@@ -19,7 +19,7 @@ repos:
|
|
|
19
19
|
|
|
20
20
|
# Ruff replaces black, flake8, autoflake and isort
|
|
21
21
|
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
|
22
|
-
rev: "v0.4.
|
|
22
|
+
rev: "v0.4.5" # make sure this is always consistent with hatch configs
|
|
23
23
|
hooks:
|
|
24
24
|
- id: ruff
|
|
25
25
|
args: [--config, ./pyproject.toml]
|
|
@@ -111,6 +111,12 @@ lint: ## Runs pre-commit hooks; includes ruff linting, codespell, bl
|
|
|
111
111
|
|
|
112
112
|
.PHONY: test
|
|
113
113
|
test: ## Run the tests
|
|
114
|
+
@echo "=> Running test cases"
|
|
115
|
+
@hatch run +py=3.12 test:cov
|
|
116
|
+
@echo "=> Tests complete"
|
|
117
|
+
|
|
118
|
+
.PHONY: test-all
|
|
119
|
+
test-all: ## Run the tests for all python versions
|
|
114
120
|
@echo "=> Running test cases"
|
|
115
121
|
@hatch run test:cov
|
|
116
122
|
@echo "=> Tests complete"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: pytest-databases
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Reusable database fixtures for any and all databases.
|
|
5
5
|
Project-URL: Documentation, https://github.com/litestar-org/pytest-databases#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/litestar-org/pytest-databases/issues
|
|
@@ -20,6 +20,8 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
|
20
20
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
21
21
|
Requires-Python: >=3.8
|
|
22
22
|
Requires-Dist: pytest
|
|
23
|
+
Provides-Extra: azure-storage
|
|
24
|
+
Requires-Dist: azure-storage-blob; extra == 'azure-storage'
|
|
23
25
|
Provides-Extra: bigquery
|
|
24
26
|
Requires-Dist: google-cloud-bigquery; extra == 'bigquery'
|
|
25
27
|
Provides-Extra: cockroachdb
|
|
@@ -94,6 +96,7 @@ It is designed to offer pre-configured testing setups for many different types a
|
|
|
94
96
|
- **Dragonfly**: Latest server
|
|
95
97
|
- **KeyDB**: Latest server
|
|
96
98
|
- **Elasticsearch**: Version 7 and 8 are available
|
|
99
|
+
- **Azure blob storage**: Via azurite
|
|
97
100
|
|
|
98
101
|
## Contributing
|
|
99
102
|
|
|
@@ -44,6 +44,7 @@ It is designed to offer pre-configured testing setups for many different types a
|
|
|
44
44
|
- **Dragonfly**: Latest server
|
|
45
45
|
- **KeyDB**: Latest server
|
|
46
46
|
- **Elasticsearch**: Version 7 and 8 are available
|
|
47
|
+
- **Azure blob storage**: Via azurite
|
|
47
48
|
|
|
48
49
|
## Contributing
|
|
49
50
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[build-system]
|
|
2
2
|
build-backend = "hatchling.build"
|
|
3
|
-
requires = ["hatchling"
|
|
3
|
+
requires = ["hatchling"]
|
|
4
4
|
|
|
5
5
|
####################
|
|
6
6
|
# Project Metadata #
|
|
@@ -12,7 +12,7 @@ license = "MIT"
|
|
|
12
12
|
name = "pytest-databases"
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
requires-python = ">=3.8"
|
|
15
|
-
version = "0.
|
|
15
|
+
version = "0.6.0"
|
|
16
16
|
#
|
|
17
17
|
authors = [{ name = "Cody Fincher", email = "cody.fincher@gmail.com" }]
|
|
18
18
|
keywords = [
|
|
@@ -52,6 +52,7 @@ Issues = "https://github.com/litestar-org/pytest-databases/issues"
|
|
|
52
52
|
Source = "https://github.com/litestar-org/pytest-databases"
|
|
53
53
|
|
|
54
54
|
[project.optional-dependencies]
|
|
55
|
+
azure-storage = ["azure-storage-blob"]
|
|
55
56
|
bigquery = ["google-cloud-bigquery"]
|
|
56
57
|
cockroachdb = ["psycopg"]
|
|
57
58
|
dragonfly = ["redis"]
|
|
@@ -80,14 +81,8 @@ exclude = ["/.github", "/docs"]
|
|
|
80
81
|
|
|
81
82
|
# Default environment with production dependencies
|
|
82
83
|
[tool.hatch.envs.default]
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
pip-compile-hashes = false
|
|
86
|
-
pip-compile-installer = "uv"
|
|
87
|
-
pip-compile-resolver = "uv"
|
|
88
|
-
python = "3.11"
|
|
89
|
-
requires = ["hatch-pip-compile"]
|
|
90
|
-
type = "pip-compile"
|
|
84
|
+
installer = "uv"
|
|
85
|
+
python = "3.12"
|
|
91
86
|
|
|
92
87
|
[tool.hatch.envs.default.scripts]
|
|
93
88
|
upgrade-all = "PIP_COMPILE_UPGRADE=1 hatch env run --env {env_name} -- python --version"
|
|
@@ -119,6 +114,7 @@ features = [
|
|
|
119
114
|
"elasticsearch7",
|
|
120
115
|
"elasticsearch8",
|
|
121
116
|
"bigquery",
|
|
117
|
+
"azure-storage",
|
|
122
118
|
]
|
|
123
119
|
template = "default"
|
|
124
120
|
type = "virtual"
|
|
@@ -178,11 +174,9 @@ features = [
|
|
|
178
174
|
"elasticsearch8",
|
|
179
175
|
"bigquery",
|
|
180
176
|
]
|
|
181
|
-
lock-filename = "requirements/requirements-docs.txt"
|
|
182
|
-
pip-compile-constraint = "default"
|
|
183
177
|
python = "3.11"
|
|
184
|
-
template = "
|
|
185
|
-
type = "
|
|
178
|
+
template = "default"
|
|
179
|
+
type = "virtual"
|
|
186
180
|
|
|
187
181
|
[tool.hatch.envs.docs.env-vars]
|
|
188
182
|
PYTHONPATH = "."
|
|
@@ -250,12 +244,10 @@ features = [
|
|
|
250
244
|
"elasticsearch8",
|
|
251
245
|
"bigquery",
|
|
252
246
|
]
|
|
253
|
-
lock-filename = "requirements/requirements-dev.txt"
|
|
254
247
|
path = ".venv/"
|
|
255
|
-
pip-compile-constraint = "docs"
|
|
256
248
|
python = "3.11"
|
|
257
249
|
template = "docs"
|
|
258
|
-
type = "
|
|
250
|
+
type = "virtual"
|
|
259
251
|
|
|
260
252
|
|
|
261
253
|
# Lint environment
|
|
@@ -291,6 +283,7 @@ features = [
|
|
|
291
283
|
]
|
|
292
284
|
python = "3.11"
|
|
293
285
|
template = "docs"
|
|
286
|
+
type = "virtual"
|
|
294
287
|
|
|
295
288
|
[tool.hatch.envs.lint.scripts]
|
|
296
289
|
check = ["style", "typing"]
|
|
@@ -596,7 +589,11 @@ line-length = 120
|
|
|
596
589
|
|
|
597
590
|
[tool.pytest.ini_options]
|
|
598
591
|
addopts = "--dist loadfile -n 2 -ra -q --doctest-glob='*.md'"
|
|
599
|
-
filterwarnings = [
|
|
592
|
+
filterwarnings = [
|
|
593
|
+
"ignore::DeprecationWarning:pkg_resources",
|
|
594
|
+
"ignore::DeprecationWarning:xdist.*",
|
|
595
|
+
"ignore::DeprecationWarning:importlib._bootstrap",
|
|
596
|
+
]
|
|
600
597
|
markers = [
|
|
601
598
|
"mysql: MySQL Tests",
|
|
602
599
|
"postgres: Postgres Tests",
|
|
@@ -29,7 +29,7 @@ import re
|
|
|
29
29
|
import subprocess # noqa: S404
|
|
30
30
|
import sys
|
|
31
31
|
import timeit
|
|
32
|
-
from typing import TYPE_CHECKING, Any, Callable
|
|
32
|
+
from typing import TYPE_CHECKING, Any, Callable, Iterable
|
|
33
33
|
|
|
34
34
|
import pytest
|
|
35
35
|
|
|
@@ -72,7 +72,12 @@ COMPOSE_PROJECT_NAME: str = f"pytest-databases-{simple_string_hash(__file__)}"
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
class DockerServiceRegistry:
|
|
75
|
-
def __init__(
|
|
75
|
+
def __init__(
|
|
76
|
+
self,
|
|
77
|
+
worker_id: str,
|
|
78
|
+
compose_project_name: str = COMPOSE_PROJECT_NAME,
|
|
79
|
+
before_start: Iterable[Callable[[], Any]] | None = None,
|
|
80
|
+
) -> None:
|
|
76
81
|
self._running_services: set[str] = set()
|
|
77
82
|
self.docker_ip = self._get_docker_ip()
|
|
78
83
|
self._base_command = ["docker-compose"] if USE_LEGACY_DOCKER_COMPOSE else ["docker", "compose"]
|
|
@@ -82,6 +87,7 @@ class DockerServiceRegistry:
|
|
|
82
87
|
f"--project-name={compose_project_name}-{worker_id}",
|
|
83
88
|
],
|
|
84
89
|
)
|
|
90
|
+
self._before_start = list(before_start) if before_start else []
|
|
85
91
|
|
|
86
92
|
@staticmethod
|
|
87
93
|
def _get_docker_ip() -> str:
|
|
@@ -109,6 +115,9 @@ class DockerServiceRegistry:
|
|
|
109
115
|
pause: float = 0.1,
|
|
110
116
|
**kwargs: Any,
|
|
111
117
|
) -> None:
|
|
118
|
+
for before_start in self._before_start:
|
|
119
|
+
before_start()
|
|
120
|
+
|
|
112
121
|
if SKIP_DOCKER_COMPOSE:
|
|
113
122
|
self._running_services.add(name)
|
|
114
123
|
if name not in self._running_services:
|
|
@@ -130,25 +139,3 @@ class DockerServiceRegistry:
|
|
|
130
139
|
def down(self) -> None:
|
|
131
140
|
if not SKIP_DOCKER_COMPOSE:
|
|
132
141
|
self.run_command("down", "-t", "10")
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
@pytest.fixture(scope="session")
|
|
136
|
-
def compose_project_name() -> str:
|
|
137
|
-
return os.environ.get("COMPOSE_PROJECT_NAME", COMPOSE_PROJECT_NAME)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
@pytest.fixture(scope="session")
|
|
141
|
-
def docker_services(compose_project_name: str, worker_id: str = "main") -> Generator[DockerServiceRegistry, None, None]:
|
|
142
|
-
if os.getenv("GITHUB_ACTIONS") == "true" and sys.platform != "linux":
|
|
143
|
-
pytest.skip("Docker not available on this platform")
|
|
144
|
-
|
|
145
|
-
registry = DockerServiceRegistry(worker_id, compose_project_name=compose_project_name)
|
|
146
|
-
try:
|
|
147
|
-
yield registry
|
|
148
|
-
finally:
|
|
149
|
-
registry.down()
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
@pytest.fixture(scope="session")
|
|
153
|
-
def docker_ip(docker_services: DockerServiceRegistry) -> str:
|
|
154
|
-
return docker_services.docker_ip
|
{pytest_databases-0.4.1 → pytest_databases-0.6.0}/src/pytest_databases/docker/alloydb_omni.py
RENAMED
|
@@ -24,14 +24,21 @@
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
26
|
import os
|
|
27
|
+
import sys
|
|
27
28
|
from pathlib import Path
|
|
28
|
-
from typing import TYPE_CHECKING
|
|
29
|
+
from typing import TYPE_CHECKING, AsyncGenerator
|
|
29
30
|
|
|
30
31
|
import asyncpg
|
|
31
32
|
import pytest
|
|
32
33
|
|
|
34
|
+
from pytest_databases.docker import DockerServiceRegistry
|
|
35
|
+
from pytest_databases.helpers import simple_string_hash
|
|
36
|
+
|
|
33
37
|
if TYPE_CHECKING:
|
|
34
|
-
from
|
|
38
|
+
from collections.abc import Generator
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
COMPOSE_PROJECT_NAME: str = f"pytest-databases-alloydb-{simple_string_hash(__file__)}"
|
|
35
42
|
|
|
36
43
|
|
|
37
44
|
async def alloydb_omni_responsive(host: str, port: int, user: str, password: str, database: str) -> bool:
|
|
@@ -53,54 +60,78 @@ async def alloydb_omni_responsive(host: str, port: int, user: str, password: str
|
|
|
53
60
|
await conn.close()
|
|
54
61
|
|
|
55
62
|
|
|
56
|
-
@pytest.fixture()
|
|
63
|
+
@pytest.fixture(scope="session")
|
|
64
|
+
def alloydb_compose_project_name() -> str:
|
|
65
|
+
return os.environ.get("COMPOSE_PROJECT_NAME", COMPOSE_PROJECT_NAME)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@pytest.fixture(autouse=False, scope="session")
|
|
69
|
+
def alloydb_docker_services(
|
|
70
|
+
alloydb_compose_project_name: str, worker_id: str = "main"
|
|
71
|
+
) -> Generator[DockerServiceRegistry, None, None]:
|
|
72
|
+
if os.getenv("GITHUB_ACTIONS") == "true" and sys.platform != "linux":
|
|
73
|
+
pytest.skip("Docker not available on this platform")
|
|
74
|
+
|
|
75
|
+
registry = DockerServiceRegistry(worker_id, compose_project_name=alloydb_compose_project_name)
|
|
76
|
+
try:
|
|
77
|
+
yield registry
|
|
78
|
+
finally:
|
|
79
|
+
registry.down()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@pytest.fixture(scope="session")
|
|
57
83
|
def postgres_user() -> str:
|
|
58
84
|
return "postgres"
|
|
59
85
|
|
|
60
86
|
|
|
61
|
-
@pytest.fixture()
|
|
87
|
+
@pytest.fixture(scope="session")
|
|
62
88
|
def postgres_password() -> str:
|
|
63
89
|
return "super-secret"
|
|
64
90
|
|
|
65
91
|
|
|
66
|
-
@pytest.fixture()
|
|
92
|
+
@pytest.fixture(scope="session")
|
|
67
93
|
def postgres_database() -> str:
|
|
68
94
|
return "postgres"
|
|
69
95
|
|
|
70
96
|
|
|
71
|
-
@pytest.fixture()
|
|
97
|
+
@pytest.fixture(scope="session")
|
|
72
98
|
def alloydb_omni_port() -> int:
|
|
73
99
|
return 5420
|
|
74
100
|
|
|
75
101
|
|
|
76
|
-
@pytest.fixture()
|
|
102
|
+
@pytest.fixture(scope="session")
|
|
77
103
|
def default_alloydb_omni_service_name() -> str:
|
|
78
104
|
return "alloydb"
|
|
79
105
|
|
|
80
106
|
|
|
81
107
|
@pytest.fixture(scope="session")
|
|
82
|
-
def
|
|
108
|
+
def alloydb_docker_compose_files() -> list[Path]:
|
|
83
109
|
return [Path(Path(__file__).parent / "docker-compose.alloydb-omni.yml")]
|
|
84
110
|
|
|
85
111
|
|
|
112
|
+
@pytest.fixture(scope="session")
|
|
113
|
+
def alloydb_docker_ip(alloydb_docker_services: DockerServiceRegistry) -> str:
|
|
114
|
+
return alloydb_docker_services.docker_ip
|
|
115
|
+
|
|
116
|
+
|
|
86
117
|
# alias to the latest
|
|
87
|
-
@pytest.fixture(autouse=False)
|
|
118
|
+
@pytest.fixture(autouse=False, scope="session")
|
|
88
119
|
async def alloydb_omni_service(
|
|
89
|
-
|
|
120
|
+
alloydb_docker_services: DockerServiceRegistry,
|
|
90
121
|
default_alloydb_omni_service_name: str,
|
|
91
|
-
|
|
122
|
+
alloydb_docker_compose_files: list[Path],
|
|
92
123
|
alloydb_omni_port: int,
|
|
93
124
|
postgres_database: str,
|
|
94
125
|
postgres_user: str,
|
|
95
126
|
postgres_password: str,
|
|
96
|
-
) -> None:
|
|
127
|
+
) -> AsyncGenerator[None, None]:
|
|
97
128
|
os.environ["POSTGRES_PASSWORD"] = postgres_password
|
|
98
129
|
os.environ["POSTGRES_USER"] = postgres_user
|
|
99
130
|
os.environ["POSTGRES_DATABASE"] = postgres_database
|
|
100
131
|
os.environ[f"{default_alloydb_omni_service_name.upper()}_PORT"] = str(alloydb_omni_port)
|
|
101
|
-
await
|
|
132
|
+
await alloydb_docker_services.start(
|
|
102
133
|
name=default_alloydb_omni_service_name,
|
|
103
|
-
docker_compose_files=
|
|
134
|
+
docker_compose_files=alloydb_docker_compose_files,
|
|
104
135
|
timeout=45,
|
|
105
136
|
pause=1,
|
|
106
137
|
check=alloydb_omni_responsive,
|
|
@@ -109,3 +140,4 @@ async def alloydb_omni_service(
|
|
|
109
140
|
user=postgres_user,
|
|
110
141
|
password=postgres_password,
|
|
111
142
|
)
|
|
143
|
+
yield
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2024 Litestar
|
|
4
|
+
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import secrets
|
|
27
|
+
import subprocess # noqa: S404
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
from typing import AsyncGenerator, Generator
|
|
30
|
+
|
|
31
|
+
import pytest
|
|
32
|
+
from azure.storage.blob import ContainerClient
|
|
33
|
+
from azure.storage.blob.aio import ContainerClient as AsyncContainerClient
|
|
34
|
+
|
|
35
|
+
from pytest_databases.docker import DockerServiceRegistry
|
|
36
|
+
from pytest_databases.helpers import simple_string_hash
|
|
37
|
+
|
|
38
|
+
COMPOSE_PROJECT_NAME: str = f"pytest-databases-azure-blob-{simple_string_hash(__file__)}"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _get_container_ids(compose_file_name: str) -> list[str]:
|
|
42
|
+
proc = subprocess.run(
|
|
43
|
+
[ # noqa: S607
|
|
44
|
+
"docker",
|
|
45
|
+
"container",
|
|
46
|
+
"ls",
|
|
47
|
+
f"--filter=label=com.docker.compose.project.config_files={compose_file_name}",
|
|
48
|
+
"--format=json",
|
|
49
|
+
],
|
|
50
|
+
capture_output=True,
|
|
51
|
+
text=True,
|
|
52
|
+
check=True,
|
|
53
|
+
)
|
|
54
|
+
return [json.loads(line)["ID"] for line in proc.stdout.splitlines()]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _get_container_logs(compose_file_name: str) -> str:
|
|
58
|
+
logs = ""
|
|
59
|
+
for container_id in _get_container_ids(compose_file_name):
|
|
60
|
+
stdout = subprocess.run(
|
|
61
|
+
["docker", "logs", container_id], # noqa: S607
|
|
62
|
+
capture_output=True,
|
|
63
|
+
text=True,
|
|
64
|
+
check=True,
|
|
65
|
+
).stdout
|
|
66
|
+
logs += stdout
|
|
67
|
+
return logs
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@pytest.fixture(scope="session")
|
|
71
|
+
def azure_blob_compose_project_name() -> str:
|
|
72
|
+
return os.environ.get("COMPOSE_PROJECT_NAME", COMPOSE_PROJECT_NAME)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@pytest.fixture(scope="session")
|
|
76
|
+
def azure_blob_service_startup_delay() -> int:
|
|
77
|
+
return 1
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@pytest.fixture(scope="session")
|
|
81
|
+
def azure_blob_docker_services(
|
|
82
|
+
azure_blob_compose_project_name: str,
|
|
83
|
+
azure_blob_service_startup_delay: int,
|
|
84
|
+
worker_id: str = "main",
|
|
85
|
+
) -> Generator[DockerServiceRegistry, None, None]:
|
|
86
|
+
registry = DockerServiceRegistry(
|
|
87
|
+
worker_id,
|
|
88
|
+
compose_project_name=azure_blob_compose_project_name,
|
|
89
|
+
)
|
|
90
|
+
try:
|
|
91
|
+
yield registry
|
|
92
|
+
finally:
|
|
93
|
+
registry.down()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@pytest.fixture(scope="session")
|
|
97
|
+
def azure_blob_connection_string() -> str:
|
|
98
|
+
return "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@pytest.fixture(scope="session")
|
|
102
|
+
def azure_blob_account_name() -> str:
|
|
103
|
+
return "devstoreaccount1"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@pytest.fixture(scope="session")
|
|
107
|
+
def azure_blob_account_key() -> str:
|
|
108
|
+
return "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@pytest.fixture(scope="session")
|
|
112
|
+
def azure_blob_account_url() -> str:
|
|
113
|
+
return "http://127.0.0.1:10000/devstoreaccount1"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@pytest.fixture(scope="session")
|
|
117
|
+
def azure_blob_port() -> int:
|
|
118
|
+
return 10000
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@pytest.fixture(scope="session")
|
|
122
|
+
def azure_blob_docker_compose_files() -> list[Path]:
|
|
123
|
+
return [Path(Path(__file__).parent / "docker-compose.azurite.yml")]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@pytest.fixture(scope="session")
|
|
127
|
+
def default_azure_blob_redis_service_name() -> str:
|
|
128
|
+
return "azurite"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@pytest.fixture(scope="session")
|
|
132
|
+
def azure_blob_docker_ip(azure_blob_docker_services: DockerServiceRegistry) -> str:
|
|
133
|
+
return azure_blob_docker_services.docker_ip
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@pytest.fixture(scope="session")
|
|
137
|
+
def azure_blob_default_container_name() -> str:
|
|
138
|
+
return secrets.token_hex(4)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@pytest.fixture(scope="session")
|
|
142
|
+
def azure_blob_container_client(
|
|
143
|
+
azure_blob_connection_string: str,
|
|
144
|
+
azure_blob_default_container_name: str,
|
|
145
|
+
azure_blob_service: None,
|
|
146
|
+
) -> Generator[ContainerClient, None, None]:
|
|
147
|
+
with ContainerClient.from_connection_string(
|
|
148
|
+
azure_blob_connection_string, container_name=azure_blob_default_container_name
|
|
149
|
+
) as container_client:
|
|
150
|
+
yield container_client
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@pytest.fixture(scope="session")
|
|
154
|
+
async def azure_blob_async_container_client(
|
|
155
|
+
azure_blob_connection_string: str, azure_blob_default_container_name: str
|
|
156
|
+
) -> AsyncGenerator[AsyncContainerClient, None]:
|
|
157
|
+
async with AsyncContainerClient.from_connection_string(
|
|
158
|
+
azure_blob_connection_string, container_name=azure_blob_default_container_name
|
|
159
|
+
) as container_client:
|
|
160
|
+
yield container_client
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@pytest.fixture(autouse=False, scope="session")
|
|
164
|
+
async def azure_blob_service(
|
|
165
|
+
azure_blob_docker_services: DockerServiceRegistry,
|
|
166
|
+
default_azure_blob_redis_service_name: str,
|
|
167
|
+
azure_blob_docker_compose_files: list[Path],
|
|
168
|
+
azure_blob_connection_string: str,
|
|
169
|
+
azure_blob_port: int,
|
|
170
|
+
azure_blob_default_container_name: str,
|
|
171
|
+
) -> AsyncGenerator[None, None]:
|
|
172
|
+
os.environ["AZURE_BLOB_PORT"] = str(azure_blob_port)
|
|
173
|
+
|
|
174
|
+
def azurite_responsive(host: str, port: int) -> bool:
|
|
175
|
+
# because azurite has a bug where it will hang for a long time if you make a
|
|
176
|
+
# request against it before it has completed startup we can't ping it, so we're
|
|
177
|
+
# inspecting the container logs instead
|
|
178
|
+
logs = _get_container_logs(str(azure_blob_docker_compose_files[0].absolute()))
|
|
179
|
+
return "Azurite Blob service successfully listens on" in logs
|
|
180
|
+
|
|
181
|
+
await azure_blob_docker_services.start(
|
|
182
|
+
name=default_azure_blob_redis_service_name,
|
|
183
|
+
docker_compose_files=azure_blob_docker_compose_files,
|
|
184
|
+
check=azurite_responsive,
|
|
185
|
+
port=azure_blob_port,
|
|
186
|
+
)
|
|
187
|
+
yield
|
|
@@ -24,16 +24,23 @@
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
26
|
import os
|
|
27
|
+
import sys
|
|
27
28
|
from pathlib import Path
|
|
28
|
-
from typing import TYPE_CHECKING
|
|
29
|
+
from typing import TYPE_CHECKING, AsyncGenerator
|
|
29
30
|
|
|
30
31
|
import pytest
|
|
31
32
|
from google.api_core.client_options import ClientOptions
|
|
32
33
|
from google.auth.credentials import AnonymousCredentials, Credentials
|
|
33
34
|
from google.cloud import bigquery
|
|
34
35
|
|
|
36
|
+
from pytest_databases.docker import DockerServiceRegistry
|
|
37
|
+
from pytest_databases.helpers import simple_string_hash
|
|
38
|
+
|
|
35
39
|
if TYPE_CHECKING:
|
|
36
|
-
from
|
|
40
|
+
from collections.abc import Generator
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
COMPOSE_PROJECT_NAME: str = f"pytest-databases-bigquery-{simple_string_hash(__file__)}"
|
|
37
44
|
|
|
38
45
|
|
|
39
46
|
async def bigquery_responsive(
|
|
@@ -57,43 +64,57 @@ async def bigquery_responsive(
|
|
|
57
64
|
return False
|
|
58
65
|
|
|
59
66
|
|
|
60
|
-
@pytest.fixture
|
|
67
|
+
@pytest.fixture(scope="session")
|
|
68
|
+
def bigquery_compose_project_name() -> str:
|
|
69
|
+
return os.environ.get("COMPOSE_PROJECT_NAME", COMPOSE_PROJECT_NAME)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@pytest.fixture(autouse=False, scope="session")
|
|
73
|
+
def bigquery_docker_services(
|
|
74
|
+
bigquery_compose_project_name: str, worker_id: str = "main"
|
|
75
|
+
) -> Generator[DockerServiceRegistry, None, None]:
|
|
76
|
+
if os.getenv("GITHUB_ACTIONS") == "true" and sys.platform != "linux":
|
|
77
|
+
pytest.skip("Docker not available on this platform")
|
|
78
|
+
|
|
79
|
+
registry = DockerServiceRegistry(worker_id, compose_project_name=bigquery_compose_project_name)
|
|
80
|
+
try:
|
|
81
|
+
yield registry
|
|
82
|
+
finally:
|
|
83
|
+
registry.down()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@pytest.fixture(scope="session")
|
|
61
87
|
def bigquery_port() -> int:
|
|
62
88
|
return 9051
|
|
63
89
|
|
|
64
90
|
|
|
65
|
-
@pytest.fixture
|
|
91
|
+
@pytest.fixture(scope="session")
|
|
66
92
|
def bigquery_grpc_port() -> int:
|
|
67
93
|
return 9061
|
|
68
94
|
|
|
69
95
|
|
|
70
|
-
@pytest.fixture
|
|
71
|
-
def bigquery_endpoint(docker_ip: str, bigquery_port: int) -> str:
|
|
72
|
-
return f"http://{docker_ip}:{bigquery_port}"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
@pytest.fixture
|
|
96
|
+
@pytest.fixture(scope="session")
|
|
76
97
|
def bigquery_dataset() -> str:
|
|
77
98
|
return "test-dataset"
|
|
78
99
|
|
|
79
100
|
|
|
80
|
-
@pytest.fixture
|
|
101
|
+
@pytest.fixture(scope="session")
|
|
81
102
|
def bigquery_project() -> str:
|
|
82
103
|
return "emulator-test-project"
|
|
83
104
|
|
|
84
105
|
|
|
85
|
-
@pytest.fixture()
|
|
106
|
+
@pytest.fixture(scope="session")
|
|
86
107
|
def bigquery_client_options(bigquery_endpoint: str) -> ClientOptions:
|
|
87
108
|
return ClientOptions(api_endpoint=bigquery_endpoint)
|
|
88
109
|
|
|
89
110
|
|
|
90
|
-
@pytest.fixture
|
|
111
|
+
@pytest.fixture(scope="session")
|
|
91
112
|
def bigquery_credentials() -> Credentials:
|
|
92
113
|
return AnonymousCredentials()
|
|
93
114
|
|
|
94
115
|
|
|
95
116
|
@pytest.fixture(scope="session")
|
|
96
|
-
def
|
|
117
|
+
def bigquery_docker_compose_files() -> list[Path]:
|
|
97
118
|
return [Path(Path(__file__).parent / "docker-compose.bigquery.yml")]
|
|
98
119
|
|
|
99
120
|
|
|
@@ -102,11 +123,21 @@ def default_bigquery_service_name() -> str:
|
|
|
102
123
|
return "bigquery"
|
|
103
124
|
|
|
104
125
|
|
|
105
|
-
@pytest.fixture(
|
|
126
|
+
@pytest.fixture(scope="session")
|
|
127
|
+
def bigquery_docker_ip(bigquery_docker_services: DockerServiceRegistry) -> str:
|
|
128
|
+
return bigquery_docker_services.docker_ip
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@pytest.fixture(scope="session")
|
|
132
|
+
def bigquery_endpoint(bigquery_docker_ip: str, bigquery_port: int) -> str:
|
|
133
|
+
return f"http://{bigquery_docker_ip}:{bigquery_port}"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@pytest.fixture(autouse=False, scope="session")
|
|
106
137
|
async def bigquery_service(
|
|
107
|
-
|
|
138
|
+
bigquery_docker_services: DockerServiceRegistry,
|
|
108
139
|
default_bigquery_service_name: str,
|
|
109
|
-
|
|
140
|
+
bigquery_docker_compose_files: list[Path],
|
|
110
141
|
bigquery_port: int,
|
|
111
142
|
bigquery_grpc_port: int,
|
|
112
143
|
bigquery_endpoint: str,
|
|
@@ -114,15 +145,15 @@ async def bigquery_service(
|
|
|
114
145
|
bigquery_project: str,
|
|
115
146
|
bigquery_credentials: Credentials,
|
|
116
147
|
bigquery_client_options: ClientOptions,
|
|
117
|
-
) -> None:
|
|
148
|
+
) -> AsyncGenerator[None, None]:
|
|
118
149
|
os.environ["BIGQUERY_ENDPOINT"] = bigquery_endpoint
|
|
119
150
|
os.environ["BIGQUERY_DATASET"] = bigquery_dataset
|
|
120
151
|
os.environ["BIGQUERY_PORT"] = str(bigquery_port)
|
|
121
152
|
os.environ["BIGQUERY_GRPC_PORT"] = str(bigquery_grpc_port)
|
|
122
153
|
os.environ["GOOGLE_CLOUD_PROJECT"] = bigquery_project
|
|
123
|
-
await
|
|
154
|
+
await bigquery_docker_services.start(
|
|
124
155
|
name=default_bigquery_service_name,
|
|
125
|
-
docker_compose_files=
|
|
156
|
+
docker_compose_files=bigquery_docker_compose_files,
|
|
126
157
|
timeout=60,
|
|
127
158
|
check=bigquery_responsive,
|
|
128
159
|
bigquery_endpoint=bigquery_endpoint,
|
|
@@ -131,3 +162,4 @@ async def bigquery_service(
|
|
|
131
162
|
bigquery_credentials=bigquery_credentials,
|
|
132
163
|
bigquery_client_options=bigquery_client_options,
|
|
133
164
|
)
|
|
165
|
+
yield
|