Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/mock_vws/_flask_server/target_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ def create_vumark_database() -> Response:
"""
request_json = json.loads(s=request.data)
random_vumark_database = VuMarkDatabase()
state_name = request_json.get(
"state_name",
random_vumark_database.state.name,
)
database = VuMarkDatabase(
server_access_key=request_json.get(
"server_access_key",
Expand All @@ -265,6 +269,7 @@ def create_vumark_database() -> Response:
"database_name",
random_vumark_database.database_name,
),
state=States[state_name],
)

try:
Expand Down
12 changes: 8 additions & 4 deletions src/mock_vws/_services_validators/project_state_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
get_database_matching_server_keys,
)
from mock_vws._services_validators.exceptions import ProjectInactiveError
from mock_vws.database import CloudDatabase
from mock_vws.database import CloudDatabase, VuMarkDatabase
from mock_vws.states import States

_LOGGER = logging.getLogger(name=__name__)
Expand Down Expand Up @@ -47,13 +47,17 @@ def validate_project_state(
databases=databases,
)

if not isinstance(database, CloudDatabase):
if database.state != States.PROJECT_INACTIVE:
return

if database.state != States.PROJECT_INACTIVE:
if (
isinstance(database, CloudDatabase)
and request_method == HTTPMethod.GET
and "duplicates" not in request_path
):
return

if request_method == HTTPMethod.GET and "duplicates" not in request_path:
if isinstance(database, VuMarkDatabase):
return

_LOGGER.warning(msg="The project is inactive.")
Expand Down
4 changes: 4 additions & 0 deletions src/mock_vws/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class VuMarkDatabaseDict(TypedDict):
server_access_key: str
server_secret_key: str
vumark_targets: Iterable[VuMarkTargetDict]
state_name: str


@beartype
Expand Down Expand Up @@ -202,6 +203,7 @@ class VuMarkDatabase:
default_factory=set[VuMarkTarget],
hash=False,
)
state: States = States.WORKING

def get_vumark_target(self, target_id: str) -> VuMarkTarget:
"""Return a VuMark target from the database with the given ID."""
Expand All @@ -222,6 +224,7 @@ def to_dict(self) -> VuMarkDatabaseDict:
"server_access_key": self.server_access_key,
"server_secret_key": self.server_secret_key,
"vumark_targets": vumark_targets,
"state_name": self.state.name,
}

@classmethod
Expand All @@ -235,6 +238,7 @@ def from_dict(cls, database_dict: VuMarkDatabaseDict) -> Self:
VuMarkTarget.from_dict(target_dict=target_dict)
for target_dict in database_dict["vumark_targets"]
},
state=States[database_dict["state_name"]],
)

@property
Expand Down
34 changes: 34 additions & 0 deletions tests/mock_vws/fixtures/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ class _InactiveCloudDatabaseSettings(_CloudDatabaseSettings):
)


class _InactiveVuMarkDatabaseSettings(BaseSettings):
"""Settings for an inactive VuMark database."""

target_manager_database_name: str
server_access_key: str
server_secret_key: str

model_config = SettingsConfigDict(
env_prefix="INACTIVE_VUMARK_VUFORIA_",
env_file=Path("vuforia_secrets.env"),
extra="allow",
)


class _VuMarkCloudDatabaseSettings(BaseSettings):
"""Settings for a VuMark Vuforia database."""

Expand All @@ -54,6 +68,15 @@ class _VuMarkCloudDatabaseSettings(BaseSettings):
)


@dataclass(frozen=True)
class InactiveVuMarkCloudDatabase:
"""Credentials for an inactive VuMark database."""

target_manager_database_name: str = field(repr=False)
server_access_key: str = field(repr=False)
server_secret_key: str = field(repr=False)


@dataclass(frozen=True)
class VuMarkCloudDatabase:
"""Credentials for the VuMark generation API."""
Expand Down Expand Up @@ -96,6 +119,17 @@ def inactive_cloud_database() -> CloudDatabase:
)


@pytest.fixture
def inactive_vumark_database() -> InactiveVuMarkCloudDatabase:
"""Return inactive VuMark credentials from environment variables."""
settings = _InactiveVuMarkDatabaseSettings.model_validate(obj={})
return InactiveVuMarkCloudDatabase(
target_manager_database_name=settings.target_manager_database_name,
server_access_key=settings.server_access_key,
server_secret_key=settings.server_secret_key,
)


@pytest.fixture
def vumark_vuforia_database() -> VuMarkCloudDatabase:
"""Return VuMark VWS credentials from environment variables."""
Expand Down
33 changes: 32 additions & 1 deletion tests/mock_vws/fixtures/vuforia_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
from mock_vws.database import CloudDatabase, VuMarkDatabase
from mock_vws.states import States
from mock_vws.target import VuMarkTarget
from tests.mock_vws.fixtures.credentials import VuMarkCloudDatabase
from tests.mock_vws.fixtures.credentials import (
InactiveVuMarkCloudDatabase,
VuMarkCloudDatabase,
)
from tests.mock_vws.utils.retries import RETRY_ON_TOO_MANY_REQUESTS

LOGGER = logging.getLogger(name=__name__)
Expand Down Expand Up @@ -91,12 +94,14 @@ def _enable_use_real_vuforia(
working_database: CloudDatabase,
inactive_cloud_database: CloudDatabase,
vumark_vuforia_database: VuMarkCloudDatabase,
inactive_vumark_database: InactiveVuMarkCloudDatabase,
monkeypatch: pytest.MonkeyPatch,
) -> Generator[None]:
"""Test against the real Vuforia."""
assert monkeypatch
assert inactive_cloud_database
assert vumark_vuforia_database
assert inactive_vumark_database
_delete_all_targets(database_keys=working_database)
yield

Expand All @@ -107,6 +112,7 @@ def _enable_use_mock_vuforia(
working_database: CloudDatabase,
inactive_cloud_database: CloudDatabase,
vumark_vuforia_database: VuMarkCloudDatabase,
inactive_vumark_database: InactiveVuMarkCloudDatabase,
monkeypatch: pytest.MonkeyPatch,
) -> Generator[None]:
"""Test against the in-memory mock Vuforia."""
Expand All @@ -130,11 +136,18 @@ def _enable_use_mock_vuforia(
vumark_database = _vumark_database(
vumark_vuforia_database=vumark_vuforia_database,
)
inactive_vumark_db = VuMarkDatabase(
state=States.PROJECT_INACTIVE,
database_name=inactive_vumark_database.target_manager_database_name,
server_access_key=inactive_vumark_database.server_access_key,
server_secret_key=inactive_vumark_database.server_secret_key,
)

with MockVWS() as mock:
mock.add_cloud_database(cloud_database=working_database)
mock.add_cloud_database(cloud_database=inactive_cloud_database)
mock.add_vumark_database(vumark_database=vumark_database)
mock.add_vumark_database(vumark_database=inactive_vumark_db)
yield


Expand All @@ -144,6 +157,7 @@ def _enable_use_docker_in_memory(
working_database: CloudDatabase,
inactive_cloud_database: CloudDatabase,
vumark_vuforia_database: VuMarkCloudDatabase,
inactive_vumark_database: InactiveVuMarkCloudDatabase,
monkeypatch: pytest.MonkeyPatch,
) -> Generator[None]:
"""Test against mock Vuforia created to be run in a container."""
Expand All @@ -170,6 +184,12 @@ def _enable_use_docker_in_memory(
vumark_database = _vumark_database(
vumark_vuforia_database=vumark_vuforia_database,
)
inactive_vumark_db = VuMarkDatabase(
state=States.PROJECT_INACTIVE,
database_name=inactive_vumark_database.target_manager_database_name,
server_access_key=inactive_vumark_database.server_access_key,
server_secret_key=inactive_vumark_database.server_secret_key,
)

with responses.RequestsMock(assert_all_requests_are_fired=False) as mock:
add_flask_app_to_mock(
Expand Down Expand Up @@ -223,6 +243,11 @@ def _enable_use_docker_in_memory(
json=vumark_database.to_dict(),
timeout=30,
)
requests.post(
url=vumark_databases_url,
json=inactive_vumark_db.to_dict(),
timeout=30,
)
for vumark_target in vumark_database.vumark_targets:
requests.post(
url=(
Expand Down Expand Up @@ -292,10 +317,12 @@ def pytest_collection_modifyitems(
ids=[backend.value for backend in list(VuforiaBackend)],
)
def fixture_verify_mock_vuforia(
*,
request: pytest.FixtureRequest,
vuforia_database: CloudDatabase,
inactive_cloud_database: CloudDatabase,
vumark_vuforia_database: VuMarkCloudDatabase,
inactive_vumark_database: InactiveVuMarkCloudDatabase,
monkeypatch: pytest.MonkeyPatch,
) -> Generator[None]:
"""Test functions which use this fixture are run multiple times. Once
Expand Down Expand Up @@ -324,6 +351,7 @@ def fixture_verify_mock_vuforia(
working_database=vuforia_database,
inactive_cloud_database=inactive_cloud_database,
vumark_vuforia_database=vumark_vuforia_database,
inactive_vumark_database=inactive_vumark_database,
monkeypatch=monkeypatch,
)

Expand All @@ -338,10 +366,12 @@ def fixture_verify_mock_vuforia(
],
)
def mock_only_vuforia(
*,
request: pytest.FixtureRequest,
vuforia_database: CloudDatabase,
inactive_cloud_database: CloudDatabase,
vumark_vuforia_database: VuMarkCloudDatabase,
inactive_vumark_database: InactiveVuMarkCloudDatabase,
monkeypatch: pytest.MonkeyPatch,
) -> Generator[None]:
"""Test functions which use this fixture are run multiple times. Once
Expand Down Expand Up @@ -370,5 +400,6 @@ def mock_only_vuforia(
working_database=vuforia_database,
inactive_cloud_database=inactive_cloud_database,
vumark_vuforia_database=vumark_vuforia_database,
inactive_vumark_database=inactive_vumark_database,
monkeypatch=monkeypatch,
)
29 changes: 28 additions & 1 deletion tests/mock_vws/test_vumark_generation_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

from mock_vws._constants import ResultCodes
from mock_vws.database import CloudDatabase
from tests.mock_vws.fixtures.credentials import VuMarkCloudDatabase
from tests.mock_vws.fixtures.credentials import (
InactiveVuMarkCloudDatabase,
VuMarkCloudDatabase,
)
from tests.mock_vws.utils import make_image_file

_VWS_HOST = "https://vws.vuforia.com"
Expand Down Expand Up @@ -341,3 +344,27 @@ def test_processing_target_raw_response(
response_json["result_code"]
== ResultCodes.TARGET_STATUS_NOT_SUCCESS.value
)


@pytest.mark.usefixtures("verify_mock_vuforia")
class TestInactiveDatabase:
"""Tests for VuMark generation with an inactive database."""

@staticmethod
def test_inactive_database(
inactive_vumark_database: InactiveVuMarkCloudDatabase,
) -> None:
"""Calling the VuMark generation API with credentials for an
inactive database returns ProjectInactive.
"""
response = _make_vumark_request(
server_access_key=inactive_vumark_database.server_access_key,
server_secret_key=inactive_vumark_database.server_secret_key,
target_id=uuid4().hex,
instance_id=uuid4().hex,
accept="image/png",
)

assert response.status_code == HTTPStatus.NOT_FOUND
response_json = response.json()
assert response_json["result_code"] == ResultCodes.UNKNOWN_TARGET.value
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test asserts wrong error, doesn't test inactive behavior

Medium Severity

The docstring says "returns ProjectInactive" but the assertions check for HTTPStatus.NOT_FOUND and ResultCodes.UNKNOWN_TARGET. The validate_project_state function explicitly exempts VuMarkDatabase from raising ProjectInactiveError (it always returns early), so the request falls through to validate_target_id_exists, which fails because the random target_id doesn't exist. This test doesn't actually verify inactive database behavior — it verifies unknown target behavior, which would produce the same result on an active database with a nonexistent target.

Additional Locations (1)

Fix in Cursor Fix in Web

5 changes: 5 additions & 0 deletions vuforia_secrets.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ VUMARK_VUFORIA_TARGET_ID=examplevumarktargetid

VUMARK_VUFORIA_SERVER_ACCESS_KEY=example_vumark_server_access_key
VUMARK_VUFORIA_SERVER_SECRET_KEY=example_vumark_server_secret_key

INACTIVE_VUMARK_VUFORIA_TARGET_MANAGER_DATABASE_NAME=example_inactive_vumark_database_name

INACTIVE_VUMARK_VUFORIA_SERVER_ACCESS_KEY=example_inactive_vumark_server_access_key
INACTIVE_VUMARK_VUFORIA_SERVER_SECRET_KEY=example_inactive_vumark_server_secret_key