Skip to content

Commit bf4db01

Browse files
authored
Merge branch 'main' into scc
2 parents 5660567 + 69a5123 commit bf4db01

File tree

6 files changed

+138
-107
lines changed

6 files changed

+138
-107
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ dependencies = [
5050
"pyyaml",
5151
"tenacity",
5252
"types-requests>=2.32.0.20241016",
53-
"schemathesis>=3.38.10",
53+
"schemathesis>=4.0.0a8",
5454
"requests",
5555
"pytest-asyncio",
5656
"syrupy",

pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ markers =
1515
slow: Mark tests which take more than 10 minutes as slow tests.
1616
pre_upgrade: Mark tests which should be run before upgrading the product.
1717
post_upgrade: Mark tests which should be run after upgrading the product.
18+
fuzzer: Mark tests that use fuzzing and are probably going to generate unanticipated failures.
1819

1920
# Model server
2021
modelmesh: Mark tests which are model mesh tests

tests/model_registry/conftest.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
from ocp_resources.deployment import Deployment
1313

1414
from ocp_resources.model_registry import ModelRegistry
15+
import schemathesis.schemas
16+
from schemathesis.specs.openapi.schemas import BaseOpenAPISchema
17+
from schemathesis.generation.stateful.state_machine import APIStateMachine
18+
from schemathesis.core.transport import Response
19+
from schemathesis.generation.case import Case
1520
from ocp_resources.resource import ResourceEditor
1621

1722
from pytest import FixtureRequest
@@ -44,6 +49,10 @@
4449

4550
@pytest.fixture(scope="class")
4651
def model_registry_namespace(request: FixtureRequest, admin_client: DynamicClient) -> Generator[Namespace, Any, Any]:
52+
# TODO: model_registry_namespace fixture should basically be doing this 1) check the ns exists, 2) it is in ACTIVE
53+
# state and return. But it should not create the ns. If DSC manages registriesNamespace, and namespace was not
54+
# created when mr is updated to Managed state, it would be a bug and we should catch it
55+
# To be handled in upcoming PR.
4756
with create_ns(
4857
name=request.param.get("namespace_name", MR_NAMESPACE),
4958
admin_client=admin_client,
@@ -301,11 +310,32 @@ def model_registry_instance_rest_endpoint(
301310

302311

303312
@pytest.fixture(scope="class")
304-
def generated_schema(model_registry_instance_rest_endpoint: str) -> Any:
305-
return schemathesis.from_uri(
306-
uri="https://raw.githubusercontent.com/kubeflow/model-registry/main/api/openapi/model-registry.yaml",
307-
base_url=f"https://{model_registry_instance_rest_endpoint}/",
313+
def generated_schema(model_registry_instance_rest_endpoint: str) -> BaseOpenAPISchema:
314+
schema = schemathesis.openapi.from_url(
315+
url="https://raw.githubusercontent.com/kubeflow/model-registry/main/api/openapi/model-registry.yaml"
308316
)
317+
schema.configure(base_url=f"https://{model_registry_instance_rest_endpoint}/")
318+
return schema
319+
320+
321+
@pytest.fixture
322+
def state_machine(generated_schema: BaseOpenAPISchema, current_client_token: str) -> APIStateMachine:
323+
BaseAPIWorkflow = generated_schema.as_state_machine()
324+
325+
class APIWorkflow(BaseAPIWorkflow): # type: ignore
326+
headers: dict[str, str]
327+
328+
def setup(self) -> None:
329+
self.headers = {"Authorization": f"Bearer {current_client_token}", "Content-Type": "application/json"}
330+
331+
# these kwargs are passed to requests.request()
332+
def get_call_kwargs(self, case: Case) -> dict[str, Any]:
333+
return {"verify": False, "headers": self.headers}
334+
335+
def after_call(self, response: Response, case: Case) -> None:
336+
LOGGER.info(f"{case.method} {case.path} -> {response.status_code}")
337+
338+
return APIWorkflow
309339

310340

311341
@pytest.fixture(scope="class")

tests/model_registry/test_rest_api.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44

55
LOGGER = get_logger(name=__name__)
66

7-
schema = schemathesis.from_pytest_fixture("generated_schema")
7+
schema = schemathesis.pytest.from_fixture("generated_schema")
88

99

10-
# TODO: This is a Stateless test due to how the openAPI spec is currently defined in upstream.
11-
# Once it is updated to support Stateful testing of the API we can enable this to run every time,
12-
# but for now having it run manually to check the existing failures is more than enough.
1310
@pytest.mark.skip(reason="Only run manually for now")
11+
@pytest.mark.fuzzer
1412
@schema.parametrize()
15-
def test_mr_api(case, current_client_token):
13+
def test_mr_api_stateless(case, current_client_token):
1614
case.headers["Authorization"] = f"Bearer {current_client_token}"
1715
case.headers["Content-Type"] = "application/json"
1816
case.call_and_validate(verify=False)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import pytest
2+
from simple_logger.logger import get_logger
3+
from tests.model_registry.constants import MR_NAMESPACE
4+
from utilities.constants import DscComponents
5+
6+
LOGGER = get_logger(name=__name__)
7+
8+
9+
@pytest.mark.fuzzer
10+
@pytest.mark.parametrize(
11+
"model_registry_namespace, updated_dsc_component_state_scope_class",
12+
[
13+
pytest.param(
14+
{"namespace_name": MR_NAMESPACE},
15+
{
16+
"component_patch": {
17+
DscComponents.MODELREGISTRY: {
18+
"managementState": DscComponents.ManagementState.MANAGED,
19+
"registriesNamespace": MR_NAMESPACE,
20+
},
21+
},
22+
},
23+
)
24+
],
25+
indirect=True,
26+
)
27+
@pytest.mark.usefixtures("model_registry_namespace", "updated_dsc_component_state_scope_class")
28+
class TestRestAPIStateful:
29+
def test_mr_api_stateful(self, state_machine):
30+
"""Launches stateful tests against the Model Registry API endpoints defined in its openAPI yaml spec file"""
31+
state_machine.run()

0 commit comments

Comments
 (0)