Skip to content

Commit 555a2d1

Browse files
adamtheturtleclaudepre-commit-ci-lite[bot]
authored
Add test for inactive database in VuMark API (#3003)
* Add test for inactive database in VuMark generation API This test verifies that calling the VuMark generation endpoint with credentials from an inactive database returns a ProjectInactive error. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Move inactive database test to existing test file Avoids duplicating _make_vumark_request by placing TestInactiveDatabase in test_vumark_generation_api.py where the helper already exists. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * [pre-commit.ci lite] apply automatic fixes * Use verify_mock_vuforia for inactive database test Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Use inactive VuMark database fixture for TestInactiveDatabase Add state support to VuMarkDatabase, add InactiveVuMarkCloudDatabase fixture using INACTIVE_VUMARK_VUFORIA_* env vars, and update project_state_validators to raise ProjectInactiveError for inactive VuMark databases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Use keyword-only args in fixture functions to fix too-many-positional-arguments Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix inactive VuMark database to return UnknownTarget (404) not ProjectInactive Real Vuforia returns 404 UnknownTarget for inactive VuMark databases on the generation endpoint, not 403 ProjectInactive. Skip the project-inactive check for VuMarkDatabase so target validation runs and returns the correct response. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add INACTIVE_VUMARK_VUFORIA_* to vuforia_secrets.env.example Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent be00f28 commit 555a2d1

7 files changed

Lines changed: 116 additions & 6 deletions

File tree

src/mock_vws/_flask_server/target_manager.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ def create_vumark_database() -> Response:
252252
"""
253253
request_json = json.loads(s=request.data)
254254
random_vumark_database = VuMarkDatabase()
255+
state_name = request_json.get(
256+
"state_name",
257+
random_vumark_database.state.name,
258+
)
255259
database = VuMarkDatabase(
256260
server_access_key=request_json.get(
257261
"server_access_key",
@@ -265,6 +269,7 @@ def create_vumark_database() -> Response:
265269
"database_name",
266270
random_vumark_database.database_name,
267271
),
272+
state=States[state_name],
268273
)
269274

270275
try:

src/mock_vws/_services_validators/project_state_validators.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
get_database_matching_server_keys,
1212
)
1313
from mock_vws._services_validators.exceptions import ProjectInactiveError
14-
from mock_vws.database import CloudDatabase
14+
from mock_vws.database import CloudDatabase, VuMarkDatabase
1515
from mock_vws.states import States
1616

1717
_LOGGER = logging.getLogger(name=__name__)
@@ -47,13 +47,17 @@ def validate_project_state(
4747
databases=databases,
4848
)
4949

50-
if not isinstance(database, CloudDatabase):
50+
if database.state != States.PROJECT_INACTIVE:
5151
return
5252

53-
if database.state != States.PROJECT_INACTIVE:
53+
if (
54+
isinstance(database, CloudDatabase)
55+
and request_method == HTTPMethod.GET
56+
and "duplicates" not in request_path
57+
):
5458
return
5559

56-
if request_method == HTTPMethod.GET and "duplicates" not in request_path:
60+
if isinstance(database, VuMarkDatabase):
5761
return
5862

5963
_LOGGER.warning(msg="The project is inactive.")

src/mock_vws/database.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class VuMarkDatabaseDict(TypedDict):
4040
server_access_key: str
4141
server_secret_key: str
4242
vumark_targets: Iterable[VuMarkTargetDict]
43+
state_name: str
4344

4445

4546
@beartype
@@ -202,6 +203,7 @@ class VuMarkDatabase:
202203
default_factory=set[VuMarkTarget],
203204
hash=False,
204205
)
206+
state: States = States.WORKING
205207

206208
def get_vumark_target(self, target_id: str) -> VuMarkTarget:
207209
"""Return a VuMark target from the database with the given ID."""
@@ -222,6 +224,7 @@ def to_dict(self) -> VuMarkDatabaseDict:
222224
"server_access_key": self.server_access_key,
223225
"server_secret_key": self.server_secret_key,
224226
"vumark_targets": vumark_targets,
227+
"state_name": self.state.name,
225228
}
226229

227230
@classmethod
@@ -235,6 +238,7 @@ def from_dict(cls, database_dict: VuMarkDatabaseDict) -> Self:
235238
VuMarkTarget.from_dict(target_dict=target_dict)
236239
for target_dict in database_dict["vumark_targets"]
237240
},
241+
state=States[database_dict["state_name"]],
238242
)
239243

240244
@property

tests/mock_vws/fixtures/credentials.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@ class _InactiveCloudDatabaseSettings(_CloudDatabaseSettings):
3838
)
3939

4040

41+
class _InactiveVuMarkDatabaseSettings(BaseSettings):
42+
"""Settings for an inactive VuMark database."""
43+
44+
target_manager_database_name: str
45+
server_access_key: str
46+
server_secret_key: str
47+
48+
model_config = SettingsConfigDict(
49+
env_prefix="INACTIVE_VUMARK_VUFORIA_",
50+
env_file=Path("vuforia_secrets.env"),
51+
extra="allow",
52+
)
53+
54+
4155
class _VuMarkCloudDatabaseSettings(BaseSettings):
4256
"""Settings for a VuMark Vuforia database."""
4357

@@ -54,6 +68,15 @@ class _VuMarkCloudDatabaseSettings(BaseSettings):
5468
)
5569

5670

71+
@dataclass(frozen=True)
72+
class InactiveVuMarkCloudDatabase:
73+
"""Credentials for an inactive VuMark database."""
74+
75+
target_manager_database_name: str = field(repr=False)
76+
server_access_key: str = field(repr=False)
77+
server_secret_key: str = field(repr=False)
78+
79+
5780
@dataclass(frozen=True)
5881
class VuMarkCloudDatabase:
5982
"""Credentials for the VuMark generation API."""
@@ -96,6 +119,17 @@ def inactive_cloud_database() -> CloudDatabase:
96119
)
97120

98121

122+
@pytest.fixture
123+
def inactive_vumark_database() -> InactiveVuMarkCloudDatabase:
124+
"""Return inactive VuMark credentials from environment variables."""
125+
settings = _InactiveVuMarkDatabaseSettings.model_validate(obj={})
126+
return InactiveVuMarkCloudDatabase(
127+
target_manager_database_name=settings.target_manager_database_name,
128+
server_access_key=settings.server_access_key,
129+
server_secret_key=settings.server_secret_key,
130+
)
131+
132+
99133
@pytest.fixture
100134
def vumark_vuforia_database() -> VuMarkCloudDatabase:
101135
"""Return VuMark VWS credentials from environment variables."""

tests/mock_vws/fixtures/vuforia_backends.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
from mock_vws.database import CloudDatabase, VuMarkDatabase
2323
from mock_vws.states import States
2424
from mock_vws.target import VuMarkTarget
25-
from tests.mock_vws.fixtures.credentials import VuMarkCloudDatabase
25+
from tests.mock_vws.fixtures.credentials import (
26+
InactiveVuMarkCloudDatabase,
27+
VuMarkCloudDatabase,
28+
)
2629
from tests.mock_vws.utils.retries import RETRY_ON_TOO_MANY_REQUESTS
2730

2831
LOGGER = logging.getLogger(name=__name__)
@@ -91,12 +94,14 @@ def _enable_use_real_vuforia(
9194
working_database: CloudDatabase,
9295
inactive_cloud_database: CloudDatabase,
9396
vumark_vuforia_database: VuMarkCloudDatabase,
97+
inactive_vumark_database: InactiveVuMarkCloudDatabase,
9498
monkeypatch: pytest.MonkeyPatch,
9599
) -> Generator[None]:
96100
"""Test against the real Vuforia."""
97101
assert monkeypatch
98102
assert inactive_cloud_database
99103
assert vumark_vuforia_database
104+
assert inactive_vumark_database
100105
_delete_all_targets(database_keys=working_database)
101106
yield
102107

@@ -107,6 +112,7 @@ def _enable_use_mock_vuforia(
107112
working_database: CloudDatabase,
108113
inactive_cloud_database: CloudDatabase,
109114
vumark_vuforia_database: VuMarkCloudDatabase,
115+
inactive_vumark_database: InactiveVuMarkCloudDatabase,
110116
monkeypatch: pytest.MonkeyPatch,
111117
) -> Generator[None]:
112118
"""Test against the in-memory mock Vuforia."""
@@ -130,11 +136,18 @@ def _enable_use_mock_vuforia(
130136
vumark_database = _vumark_database(
131137
vumark_vuforia_database=vumark_vuforia_database,
132138
)
139+
inactive_vumark_db = VuMarkDatabase(
140+
state=States.PROJECT_INACTIVE,
141+
database_name=inactive_vumark_database.target_manager_database_name,
142+
server_access_key=inactive_vumark_database.server_access_key,
143+
server_secret_key=inactive_vumark_database.server_secret_key,
144+
)
133145

134146
with MockVWS() as mock:
135147
mock.add_cloud_database(cloud_database=working_database)
136148
mock.add_cloud_database(cloud_database=inactive_cloud_database)
137149
mock.add_vumark_database(vumark_database=vumark_database)
150+
mock.add_vumark_database(vumark_database=inactive_vumark_db)
138151
yield
139152

140153

@@ -144,6 +157,7 @@ def _enable_use_docker_in_memory(
144157
working_database: CloudDatabase,
145158
inactive_cloud_database: CloudDatabase,
146159
vumark_vuforia_database: VuMarkCloudDatabase,
160+
inactive_vumark_database: InactiveVuMarkCloudDatabase,
147161
monkeypatch: pytest.MonkeyPatch,
148162
) -> Generator[None]:
149163
"""Test against mock Vuforia created to be run in a container."""
@@ -170,6 +184,12 @@ def _enable_use_docker_in_memory(
170184
vumark_database = _vumark_database(
171185
vumark_vuforia_database=vumark_vuforia_database,
172186
)
187+
inactive_vumark_db = VuMarkDatabase(
188+
state=States.PROJECT_INACTIVE,
189+
database_name=inactive_vumark_database.target_manager_database_name,
190+
server_access_key=inactive_vumark_database.server_access_key,
191+
server_secret_key=inactive_vumark_database.server_secret_key,
192+
)
173193

174194
with responses.RequestsMock(assert_all_requests_are_fired=False) as mock:
175195
add_flask_app_to_mock(
@@ -223,6 +243,11 @@ def _enable_use_docker_in_memory(
223243
json=vumark_database.to_dict(),
224244
timeout=30,
225245
)
246+
requests.post(
247+
url=vumark_databases_url,
248+
json=inactive_vumark_db.to_dict(),
249+
timeout=30,
250+
)
226251
for vumark_target in vumark_database.vumark_targets:
227252
requests.post(
228253
url=(
@@ -292,10 +317,12 @@ def pytest_collection_modifyitems(
292317
ids=[backend.value for backend in list(VuforiaBackend)],
293318
)
294319
def fixture_verify_mock_vuforia(
320+
*,
295321
request: pytest.FixtureRequest,
296322
vuforia_database: CloudDatabase,
297323
inactive_cloud_database: CloudDatabase,
298324
vumark_vuforia_database: VuMarkCloudDatabase,
325+
inactive_vumark_database: InactiveVuMarkCloudDatabase,
299326
monkeypatch: pytest.MonkeyPatch,
300327
) -> Generator[None]:
301328
"""Test functions which use this fixture are run multiple times. Once
@@ -324,6 +351,7 @@ def fixture_verify_mock_vuforia(
324351
working_database=vuforia_database,
325352
inactive_cloud_database=inactive_cloud_database,
326353
vumark_vuforia_database=vumark_vuforia_database,
354+
inactive_vumark_database=inactive_vumark_database,
327355
monkeypatch=monkeypatch,
328356
)
329357

@@ -338,10 +366,12 @@ def fixture_verify_mock_vuforia(
338366
],
339367
)
340368
def mock_only_vuforia(
369+
*,
341370
request: pytest.FixtureRequest,
342371
vuforia_database: CloudDatabase,
343372
inactive_cloud_database: CloudDatabase,
344373
vumark_vuforia_database: VuMarkCloudDatabase,
374+
inactive_vumark_database: InactiveVuMarkCloudDatabase,
345375
monkeypatch: pytest.MonkeyPatch,
346376
) -> Generator[None]:
347377
"""Test functions which use this fixture are run multiple times. Once
@@ -370,5 +400,6 @@ def mock_only_vuforia(
370400
working_database=vuforia_database,
371401
inactive_cloud_database=inactive_cloud_database,
372402
vumark_vuforia_database=vumark_vuforia_database,
403+
inactive_vumark_database=inactive_vumark_database,
373404
monkeypatch=monkeypatch,
374405
)

tests/mock_vws/test_vumark_generation_api.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818

1919
from mock_vws._constants import ResultCodes
2020
from mock_vws.database import CloudDatabase
21-
from tests.mock_vws.fixtures.credentials import VuMarkCloudDatabase
21+
from tests.mock_vws.fixtures.credentials import (
22+
InactiveVuMarkCloudDatabase,
23+
VuMarkCloudDatabase,
24+
)
2225
from tests.mock_vws.utils import make_image_file
2326

2427
_VWS_HOST = "https://vws.vuforia.com"
@@ -341,3 +344,27 @@ def test_processing_target_raw_response(
341344
response_json["result_code"]
342345
== ResultCodes.TARGET_STATUS_NOT_SUCCESS.value
343346
)
347+
348+
349+
@pytest.mark.usefixtures("verify_mock_vuforia")
350+
class TestInactiveDatabase:
351+
"""Tests for VuMark generation with an inactive database."""
352+
353+
@staticmethod
354+
def test_inactive_database(
355+
inactive_vumark_database: InactiveVuMarkCloudDatabase,
356+
) -> None:
357+
"""Calling the VuMark generation API with credentials for an
358+
inactive database returns ProjectInactive.
359+
"""
360+
response = _make_vumark_request(
361+
server_access_key=inactive_vumark_database.server_access_key,
362+
server_secret_key=inactive_vumark_database.server_secret_key,
363+
target_id=uuid4().hex,
364+
instance_id=uuid4().hex,
365+
accept="image/png",
366+
)
367+
368+
assert response.status_code == HTTPStatus.NOT_FOUND
369+
response_json = response.json()
370+
assert response_json["result_code"] == ResultCodes.UNKNOWN_TARGET.value

vuforia_secrets.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,8 @@ VUMARK_VUFORIA_TARGET_ID=examplevumarktargetid
1919

2020
VUMARK_VUFORIA_SERVER_ACCESS_KEY=example_vumark_server_access_key
2121
VUMARK_VUFORIA_SERVER_SECRET_KEY=example_vumark_server_secret_key
22+
23+
INACTIVE_VUMARK_VUFORIA_TARGET_MANAGER_DATABASE_NAME=example_inactive_vumark_database_name
24+
25+
INACTIVE_VUMARK_VUFORIA_SERVER_ACCESS_KEY=example_inactive_vumark_server_access_key
26+
INACTIVE_VUMARK_VUFORIA_SERVER_SECRET_KEY=example_inactive_vumark_server_secret_key

0 commit comments

Comments
 (0)