Files
wehub-resource-sync bf2343b7e4
Integration Tests - MySQL + Elasticsearch / Detect Changes (push) Has been cancelled
Integration Tests - MySQL + Elasticsearch / integration-tests-mysql-elasticsearch (push) Has been cancelled
Integration Tests - PostgreSQL + Elasticsearch + Redis / Detect Changes (push) Has been cancelled
Integration Tests - PostgreSQL + Elasticsearch + Redis / integration-tests-postgres-elasticsearch-redis (push) Has been cancelled
Integration Tests - PostgreSQL + OpenSearch / Detect Changes (push) Has been cancelled
Integration Tests - PostgreSQL + OpenSearch / integration-tests-postgres-opensearch (push) Has been cancelled
Java Checkstyle / java-checkstyle (push) Has been cancelled
Maven Collate Tests / maven-collate-ci (push) Has been cancelled
OpenMetadata Service Unit Tests / openmetadata-service-unit-tests-status (push) Has been cancelled
Publish Package to Maven Central Repository / publish-maven-packages (push) Has been cancelled
OpenMetadata Service Unit Tests / Detect Changes (push) Has been cancelled
OpenMetadata Service Unit Tests / openmetadata-service-unit-tests (push) Has been cancelled
OpenMetadata Service Unit Tests / k8s_operator-unit-tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:35:45 +08:00

494 lines
18 KiB
Python

# Copyright 2025 Collate
# Licensed under the Collate Community License, Version 1.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# https://github.com/open-metadata/OpenMetadata/blob/main/ingestion/LICENSE
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
OpenMetadata high-level API REST API test
Tests for ApiService, APICollection, and APIEndpoint entities
"""
from copy import deepcopy
import pytest
from metadata.generated.schema.api.data.createAPICollection import (
CreateAPICollectionRequest,
)
from metadata.generated.schema.api.data.createAPIEndpoint import (
CreateAPIEndpointRequest,
)
from metadata.generated.schema.api.services.createApiService import (
CreateApiServiceRequest,
)
from metadata.generated.schema.entity.data.apiCollection import APICollection
from metadata.generated.schema.entity.data.apiEndpoint import (
APIEndpoint,
ApiRequestMethod,
)
from metadata.generated.schema.entity.services.apiService import (
ApiConnection,
ApiService,
ApiServiceType,
)
from metadata.generated.schema.entity.services.connections.api.openAPISchemaURL import (
OpenAPISchemaURL,
)
from metadata.generated.schema.entity.services.connections.api.restConnection import (
RestConnection,
RestType,
)
from metadata.generated.schema.type.basic import EntityName
from metadata.generated.schema.type.entityReference import EntityReference
from metadata.generated.schema.type.entityReferenceList import EntityReferenceList
from ..conftest import _safe_delete # noqa: TID252
from ..integration_base import generate_name # noqa: TID252
@pytest.fixture(scope="module")
def api_service(metadata):
"""Module-scoped ApiService for REST API tests."""
service_name = generate_name()
service_request = CreateApiServiceRequest(
name=service_name,
serviceType=ApiServiceType.Rest,
connection=ApiConnection(
config=RestConnection(
openAPISchemaConnection=OpenAPISchemaURL(
openAPISchemaURL="https://petstore.swagger.io/v2/swagger.json"
),
type=RestType.Rest,
)
),
)
service_entity = metadata.create_or_update(data=service_request)
yield service_entity
_safe_delete(
metadata,
entity=ApiService,
entity_id=service_entity.id,
recursive=True,
hard_delete=True,
)
@pytest.fixture(scope="module")
def rest_user(metadata):
"""User for REST API ownership tests."""
from metadata.generated.schema.api.teams.createUser import CreateUserRequest
from metadata.generated.schema.entity.teams.user import User
user_name = generate_name()
user = metadata.create_or_update(
data=CreateUserRequest(name=user_name, email=f"{user_name.root}@user.com"),
)
yield user
metadata.delete(entity=User, entity_id=user.id, hard_delete=True)
@pytest.fixture(scope="module")
def rest_owners(rest_user):
"""Owner reference list for REST API tests."""
return EntityReferenceList(
root=[
EntityReference(
id=rest_user.id,
type="user",
fullyQualifiedName=rest_user.fullyQualifiedName.root,
)
]
)
@pytest.fixture(scope="module")
def service_request(api_service):
"""Recreatable service request matching the existing service."""
return CreateApiServiceRequest(
name=api_service.name,
serviceType=ApiServiceType.Rest,
connection=ApiConnection(
config=RestConnection(
openAPISchemaConnection=OpenAPISchemaURL(
openAPISchemaURL="https://petstore.swagger.io/v2/swagger.json"
),
type=RestType.Rest,
)
),
)
@pytest.fixture(scope="module")
def collection_request(api_service):
"""CreateAPICollectionRequest for the module's service."""
return CreateAPICollectionRequest(
name="test-collection",
service=api_service.fullyQualifiedName,
endpointURL="https://petstore.swagger.io/v2/pet",
)
@pytest.fixture(scope="module")
def api_collection(metadata, collection_request):
"""Module-scoped APICollection entity."""
return metadata.create_or_update(data=collection_request)
@pytest.fixture(scope="module")
def endpoint_request(api_collection):
"""CreateAPIEndpointRequest for the module's collection."""
return CreateAPIEndpointRequest(
name="test-endpoint",
apiCollection=api_collection.fullyQualifiedName,
endpointURL="https://petstore.swagger.io/v2/pet/{petId}",
requestMethod=ApiRequestMethod.GET,
)
class TestOMetaRestAPI:
"""
REST API integration tests.
Tests CRUD operations for ApiService, APICollection, and APIEndpoint.
Uses fixtures from conftest:
- metadata: OpenMetadata client (session scope)
"""
@pytest.mark.order(1)
def test_create_api_collection(self, metadata, api_service, api_collection, collection_request):
"""
We can create an APICollection and we receive it back as Entity
"""
res = metadata.create_or_update(data=collection_request)
assert res.name == collection_request.name
assert res.service.id == api_service.id
assert res.owners is None or res.owners == EntityReferenceList(root=[])
@pytest.mark.order(2)
def test_create_api_endpoint(self, metadata, api_service, api_collection, endpoint_request):
"""
We can create an APIEndpoint and we receive it back as Entity
"""
res = metadata.create_or_update(data=endpoint_request)
assert res.name == endpoint_request.name
assert res.apiCollection.id == api_collection.id
assert res.requestMethod == ApiRequestMethod.GET
assert res.owners is None or res.owners == EntityReferenceList(root=[])
@pytest.mark.order(3)
def test_create_api_service(self, metadata, api_service, service_request):
"""
We can create an ApiService and we receive it back as Entity
"""
res = metadata.create_or_update(data=service_request)
assert res.name == service_request.name
assert res.serviceType == service_request.serviceType
assert res.owners is None or res.owners == EntityReferenceList(root=[])
@pytest.mark.order(4)
def test_delete_api_collection(self, metadata, api_service):
"""
We can delete an APICollection by ID
"""
delete_collection = CreateAPICollectionRequest(
name=generate_name(),
service=api_service.fullyQualifiedName,
endpointURL="https://petstore.swagger.io/v2/user",
)
created = metadata.create_or_update(data=delete_collection)
res_name = metadata.get_by_name(entity=APICollection, fqn=created.fullyQualifiedName)
res_id = metadata.get_by_id(entity=APICollection, entity_id=res_name.id)
metadata.delete(entity=APICollection, entity_id=str(res_id.id.root))
res = metadata.list_entities(entity=APICollection)
assert not next(
iter(ent for ent in res.entities if ent.fullyQualifiedName == created.fullyQualifiedName),
None,
)
@pytest.mark.order(5)
def test_delete_api_endpoint(self, metadata, api_collection):
"""
We can delete an APIEndpoint by ID
"""
delete_endpoint = CreateAPIEndpointRequest(
name=generate_name(),
apiCollection=api_collection.fullyQualifiedName,
endpointURL="https://petstore.swagger.io/v2/pet/{petId}/delete",
requestMethod=ApiRequestMethod.DELETE,
)
endpoint_res = metadata.create_or_update(data=delete_endpoint)
res_name = metadata.get_by_name(entity=APIEndpoint, fqn=endpoint_res.fullyQualifiedName)
res_id = metadata.get_by_id(entity=APIEndpoint, entity_id=res_name.id)
metadata.delete(entity=APIEndpoint, entity_id=str(res_id.id.root))
res = metadata.list_entities(entity=APIEndpoint)
assert not next(
iter(ent for ent in res.entities if ent.fullyQualifiedName == endpoint_res.fullyQualifiedName),
None,
)
@pytest.mark.order(6)
def test_delete_api_service(self, metadata):
"""
We can delete an ApiService by ID
"""
delete_service = CreateApiServiceRequest(
name=generate_name(),
serviceType=ApiServiceType.Rest,
connection=ApiConnection(
config=RestConnection(
openAPISchemaConnection=OpenAPISchemaURL(
openAPISchemaURL="https://petstore.swagger.io/v2/swagger.json"
),
type=RestType.Rest,
)
),
)
created = metadata.create_or_update(data=delete_service)
res_name = metadata.get_by_name(entity=ApiService, fqn=delete_service.name)
res_id = metadata.get_by_id(entity=ApiService, entity_id=res_name.id)
metadata.delete(entity=ApiService, entity_id=str(res_id.id.root))
res = metadata.list_entities(entity=ApiService)
assert not next(
iter(ent for ent in res.entities if ent.fullyQualifiedName == created.fullyQualifiedName),
None,
)
@pytest.mark.order(7)
def test_get_api_collection_id(self, metadata, api_collection, collection_request):
"""
We can fetch an APICollection by ID and get it back as Entity
"""
metadata.create_or_update(data=collection_request)
res_name = metadata.get_by_name(entity=APICollection, fqn=api_collection.fullyQualifiedName)
res = metadata.get_by_id(entity=APICollection, entity_id=str(res_name.id.root))
assert res_name.id == res.id
@pytest.mark.order(8)
def test_get_api_collection_name(self, metadata, api_collection, collection_request):
"""
We can fetch an APICollection by name and get it back as Entity
"""
metadata.create_or_update(data=collection_request)
res = metadata.get_by_name(entity=APICollection, fqn=api_collection.fullyQualifiedName)
assert res.name == api_collection.name
nullable_res = metadata.get_by_name(entity=APICollection, fqn="something.made.up")
assert nullable_res is None
@pytest.mark.order(9)
def test_get_api_endpoint_id(self, metadata, api_collection):
"""
We can fetch an APIEndpoint by ID and get it back as Entity
"""
endpoint_request = CreateAPIEndpointRequest(
name="test-endpoint-get-id",
apiCollection=api_collection.fullyQualifiedName,
endpointURL="https://petstore.swagger.io/v2/pet/{petId}",
requestMethod=ApiRequestMethod.GET,
)
endpoint_res = metadata.create_or_update(data=endpoint_request)
res_name = metadata.get_by_name(entity=APIEndpoint, fqn=endpoint_res.fullyQualifiedName)
res = metadata.get_by_id(entity=APIEndpoint, entity_id=str(res_name.id.root))
assert res_name.id == res.id
@pytest.mark.order(10)
def test_get_api_endpoint_name(self, metadata, api_collection):
"""
We can fetch an APIEndpoint by name and get it back as Entity
"""
endpoint_request = CreateAPIEndpointRequest(
name="test-endpoint-get-name",
apiCollection=api_collection.fullyQualifiedName,
endpointURL="https://petstore.swagger.io/v2/pet/{petId}",
requestMethod=ApiRequestMethod.GET,
)
endpoint_res = metadata.create_or_update(data=endpoint_request)
res = metadata.get_by_name(entity=APIEndpoint, fqn=endpoint_res.fullyQualifiedName)
assert res.name == endpoint_res.name
nullable_res = metadata.get_by_name(entity=APIEndpoint, fqn="something.made.up")
assert nullable_res is None
@pytest.mark.order(11)
def test_get_entity_ref_api_collection(self, metadata, api_collection, collection_request):
"""
test get EntityReference for APICollection
"""
res = metadata.create_or_update(data=collection_request)
entity_ref = metadata.get_entity_reference(entity=APICollection, fqn=res.fullyQualifiedName)
assert res.id == entity_ref.id
@pytest.mark.order(12)
def test_get_entity_ref_api_endpoint(self, metadata, api_collection, endpoint_request):
"""
test get EntityReference for APIEndpoint
"""
res = metadata.create_or_update(data=endpoint_request)
entity_ref = metadata.get_entity_reference(entity=APIEndpoint, fqn=res.fullyQualifiedName)
assert res.id == entity_ref.id
@pytest.mark.order(13)
def test_get_entity_ref_api_service(self, metadata, api_service, service_request):
"""
test get EntityReference for ApiService
"""
res = metadata.create_or_update(data=service_request)
entity_ref = metadata.get_entity_reference(entity=ApiService, fqn=res.fullyQualifiedName)
assert res.id == entity_ref.id
@pytest.mark.order(14)
def test_list_all_and_paginate_collections(self, metadata, api_service, collection_request):
"""
Validate generator utility to fetch all APICollections
"""
fake_create = deepcopy(collection_request)
for i in range(0, 5): # noqa: PIE808
fake_create.name = EntityName(collection_request.name.root + str(i))
metadata.create_or_update(data=fake_create)
all_entities = metadata.list_all_entities(entity=APICollection, limit=2)
assert len(list(all_entities)) >= 5
entity_list = metadata.list_entities(entity=APICollection, limit=2)
assert len(entity_list.entities) == 2
if entity_list.after:
after_entity_list = metadata.list_entities(entity=APICollection, limit=2, after=entity_list.after)
assert len(after_entity_list.entities) == 2
@pytest.mark.order(15)
def test_list_api_collections(self, metadata, api_service, api_collection, collection_request):
"""
We can list all our APICollections
"""
metadata.create_or_update(data=collection_request)
res = metadata.list_entities(
entity=APICollection,
params={"service": api_service.name.root},
)
data = next(
iter(ent for ent in res.entities if ent.name == api_collection.name),
None,
)
assert data
@pytest.mark.order(16)
def test_list_api_endpoints(self, metadata, api_collection, endpoint_request):
"""
We can list all our APIEndpoints
"""
metadata.create_or_update(data=endpoint_request)
res = metadata.list_entities(
entity=APIEndpoint,
params={"apiCollection": api_collection.fullyQualifiedName.root},
)
data = next(
iter(ent for ent in res.entities if ent.name == endpoint_request.name),
None,
)
assert data
@pytest.mark.order(17)
def test_list_api_services(self, metadata, api_service, service_request):
"""
We can list all our ApiServices
"""
metadata.create_or_update(data=service_request)
res = metadata.list_entities(entity=ApiService)
data = next(
iter(ent for ent in res.entities if ent.name == service_request.name),
None,
)
assert data
@pytest.mark.order(18)
def test_update_api_collection(self, metadata, api_collection, collection_request, rest_user, rest_owners):
"""
Updating it properly changes its properties
"""
res_create = metadata.create_or_update(data=collection_request)
updated = collection_request.model_dump(exclude_unset=True)
updated["owners"] = rest_owners
updated_entity = CreateAPICollectionRequest(**updated)
res = metadata.create_or_update(data=updated_entity)
assert res.name == updated_entity.name
assert res_create.id == res.id
assert res.owners.root[0].id == rest_user.id
@pytest.mark.order(19)
def test_update_api_endpoint(self, metadata, api_collection, endpoint_request, rest_user, rest_owners):
"""
Updating it properly changes its properties
"""
res_create = metadata.create_or_update(data=endpoint_request)
updated = endpoint_request.model_dump(exclude_unset=True)
updated["owners"] = rest_owners
updated_entity = CreateAPIEndpointRequest(**updated)
res = metadata.create_or_update(data=updated_entity)
assert res.name == updated_entity.name
assert res_create.id == res.id
assert res.owners.root[0].id == rest_user.id
@pytest.mark.order(20)
def test_update_api_service(self, metadata, api_service, service_request, rest_user, rest_owners):
"""
Updating it properly changes its properties
"""
res_create = metadata.create_or_update(data=service_request)
updated = service_request.model_dump(exclude_unset=True)
updated["owners"] = rest_owners
updated_entity = CreateApiServiceRequest(**updated)
res = metadata.create_or_update(data=updated_entity)
assert res.name == updated_entity.name
assert res_create.id == res.id
assert res.owners.root[0].id == rest_user.id