445 lines
12 KiB
Python
445 lines
12 KiB
Python
"""Integration tests configuration."""
|
|
|
|
import os
|
|
import random
|
|
from collections.abc import Iterator
|
|
from io import BytesIO
|
|
from pathlib import Path
|
|
|
|
import minio
|
|
import pytest
|
|
from PIL import Image
|
|
from pymongo import MongoClient
|
|
from testcontainers.minio import MinioContainer
|
|
from testcontainers.mongodb import MongoDbContainer
|
|
|
|
from model.src.models import VisualCommunicationModel
|
|
from shared.repositories import (
|
|
HexadecimalString,
|
|
ImageData,
|
|
ImageRepository,
|
|
ModelData,
|
|
ModelRepository,
|
|
VisualCommunicationData,
|
|
VisualCommunicationRepository,
|
|
VisualCommunicationValues,
|
|
)
|
|
from shared.repositories.src.implementations import (
|
|
MinioImplementation,
|
|
MongoImplementation,
|
|
)
|
|
|
|
# set random seed for reproducibility
|
|
random.seed(13)
|
|
|
|
# define test static variables
|
|
MINIO_PORT = 9000
|
|
MINIO_ACCESS_KEY = 'minioadmin'
|
|
MINIO_SECRET_KEY = 'minioadmin'
|
|
MONGO_PORT = 27017
|
|
MONGO_USERNAME = 'admin'
|
|
MONGO_PASSWORD = 'password'
|
|
|
|
env_var_map = {
|
|
'MINIO_ENDPOINT': f'localhost:{MINIO_PORT}', # updated when container is running
|
|
'MINIO_ACCESS_KEY': MINIO_ACCESS_KEY,
|
|
'MINIO_SECRET_KEY': MINIO_SECRET_KEY,
|
|
'MINIO_BUCKET_NAME': 'test-bucket',
|
|
'MINIO_OBJECT_NAME': 'test-object',
|
|
'MINIO_IMAGE_NAME': 'test-image',
|
|
'MONGO_ENDPOINT': (
|
|
f'mongodb://{MONGO_USERNAME}:{MONGO_PASSWORD}' f'@localhost:{MONGO_PORT}/'
|
|
), # updated when container is running
|
|
'MONGO_DB': 'test-db',
|
|
'MONGO_COLLECTION': 'test-collection',
|
|
}
|
|
container_map = {
|
|
'minio': MinioContainer(
|
|
port=MINIO_PORT,
|
|
access_key=MINIO_ACCESS_KEY,
|
|
secret_key=MINIO_SECRET_KEY,
|
|
),
|
|
'mongo': MongoDbContainer(
|
|
port=MONGO_PORT,
|
|
username=MONGO_USERNAME,
|
|
password=MONGO_PASSWORD,
|
|
dbname=env_var_map['MONGO_DB'],
|
|
),
|
|
}
|
|
|
|
|
|
@pytest.fixture(scope='session', autouse=True)
|
|
def setup_infrastructure(request: pytest.FixtureRequest) -> None:
|
|
"""Prepare infrastructure for integration test."""
|
|
# prepare infrastructure
|
|
for container in container_map.values():
|
|
container.start()
|
|
# update env var map
|
|
minio_host = container_map['minio'].get_container_host_ip()
|
|
minio_port = container_map['minio'].get_exposed_port(MINIO_PORT)
|
|
env_var_map['MINIO_ENDPOINT'] = f'{minio_host}:{minio_port}'
|
|
mongo_host = container_map['mongo'].get_container_host_ip()
|
|
mongo_port = container_map['mongo'].get_exposed_port(MONGO_PORT)
|
|
env_var_map['MONGO_ENDPOINT'] = (
|
|
f'mongodb://{MONGO_USERNAME}:{MONGO_PASSWORD}@{mongo_host}:{mongo_port}/'
|
|
)
|
|
|
|
# ensure cleanup
|
|
def cleanup_infrastructure():
|
|
for container in container_map.values():
|
|
container.stop()
|
|
|
|
request.addfinalizer(cleanup_infrastructure)
|
|
|
|
|
|
@pytest.fixture(scope='session', autouse=True)
|
|
def populate_env(
|
|
request: pytest.FixtureRequest,
|
|
setup_infrastructure,
|
|
) -> None:
|
|
"""Populate environment with variables used for testing."""
|
|
# update env
|
|
for key, val in env_var_map.items():
|
|
os.environ[key] = val
|
|
|
|
# ensure cleanup
|
|
def cleanup_env():
|
|
for key in env_var_map:
|
|
_ = os.environ.pop(key, default=None)
|
|
|
|
request.addfinalizer(cleanup_env)
|
|
|
|
|
|
@pytest.fixture(scope='session')
|
|
def raw_minio_client(
|
|
setup_infrastructure,
|
|
populate_env,
|
|
) -> Iterator[minio.Minio]:
|
|
"""Raw Minio client fixture."""
|
|
# prepare arguments
|
|
minio_endpoint = str(os.getenv('MINIO_ENDPOINT'))
|
|
minio_access_key = str(os.getenv('MINIO_ACCESS_KEY'))
|
|
minio_secret_key = str(os.getenv('MINIO_SECRET_KEY'))
|
|
minio_bucket_name = str(os.getenv('MINIO_BUCKET_NAME'))
|
|
# connect client
|
|
client = minio.Minio(
|
|
endpoint=minio_endpoint,
|
|
access_key=minio_access_key,
|
|
secret_key=minio_secret_key,
|
|
secure=False,
|
|
)
|
|
# ensure bucket exists
|
|
if not client.bucket_exists(bucket_name=minio_bucket_name):
|
|
client.make_bucket(bucket_name=minio_bucket_name)
|
|
# expose client
|
|
yield client
|
|
# cleanup
|
|
object_list = client.list_objects(minio_bucket_name, recursive=True)
|
|
for obj in object_list:
|
|
client.remove_object(
|
|
bucket_name=obj.bucket_name,
|
|
object_name=obj.object_name,
|
|
)
|
|
client.remove_bucket(minio_bucket_name)
|
|
|
|
|
|
@pytest.fixture
|
|
def minio_client(
|
|
setup_infrastructure,
|
|
populate_env,
|
|
) -> Iterator[MinioImplementation]:
|
|
"""MinioImplementation fixture."""
|
|
# instantiate and connect client
|
|
minio_client = MinioImplementation()
|
|
minio_client.connect()
|
|
# expose client
|
|
yield minio_client
|
|
# cleanup
|
|
object_name_list = minio_client._list_objects(Path('*'))
|
|
for name in object_name_list:
|
|
minio_client._delete(Path(name))
|
|
minio_client.close()
|
|
|
|
|
|
@pytest.fixture
|
|
def buffer() -> Iterator[BytesIO]:
|
|
"""Bytes buffer fixture."""
|
|
# generate reproducible random data
|
|
data = random.randbytes(n=2**21) # 2 MB
|
|
# convert data
|
|
buffer = BytesIO(data)
|
|
# expose buffer
|
|
yield buffer
|
|
|
|
|
|
@pytest.fixture
|
|
def buffer_in_minio(
|
|
raw_minio_client: minio.Minio,
|
|
buffer: BytesIO,
|
|
) -> Iterator[tuple[Path, BytesIO]]:
|
|
"""Buffer in Minio fixture."""
|
|
# prepare arguments
|
|
minio_bucket_name = str(os.getenv('MINIO_BUCKET_NAME'))
|
|
minio_object_name = str(os.getenv('MINIO_OBJECT_NAME'))
|
|
# prepare for saving
|
|
num_bytes = len(buffer.getvalue())
|
|
buffer.seek(0)
|
|
# put data in bucket
|
|
raw_minio_client.put_object(
|
|
bucket_name=minio_bucket_name,
|
|
object_name=minio_object_name,
|
|
length=num_bytes,
|
|
data=buffer,
|
|
)
|
|
# expose data
|
|
yield Path(minio_object_name), buffer
|
|
# cleanup
|
|
raw_minio_client.remove_object(
|
|
bucket_name=minio_bucket_name,
|
|
object_name=minio_object_name,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def image_data() -> Iterator[ImageData]:
|
|
"""Image data fixture."""
|
|
# prepare arguments
|
|
name = str(os.getenv('MINIO_IMAGE_NAME'))
|
|
image = Image.new(mode='RGB', size=(480, 480))
|
|
# instantiate data
|
|
image_data = ImageData(image=image, name=name)
|
|
# expose data
|
|
yield image_data
|
|
|
|
|
|
@pytest.fixture
|
|
def image_data_in_minio(
|
|
raw_minio_client: minio.Minio,
|
|
image_data: ImageData,
|
|
) -> Iterator[ImageData]:
|
|
"""Image data in Minio fixture."""
|
|
# prepare arguments
|
|
minio_bucket_name = str(os.getenv('MINIO_BUCKET_NAME'))
|
|
image_name = image_data.name
|
|
# build object path
|
|
object_path = ImageRepository._build_path(image_name)
|
|
# save image to buffer
|
|
buffer = BytesIO()
|
|
image_data.image.save(buffer, 'png')
|
|
# prepare for saving
|
|
num_bytes = len(buffer.getvalue())
|
|
buffer.seek(0)
|
|
# put data in bucket
|
|
raw_minio_client.put_object(
|
|
bucket_name=minio_bucket_name,
|
|
object_name=object_path.as_posix(),
|
|
length=num_bytes,
|
|
data=buffer,
|
|
)
|
|
# expose data
|
|
yield image_data
|
|
# cleanup
|
|
raw_minio_client.remove_object(
|
|
bucket_name=minio_bucket_name,
|
|
object_name=object_path.as_posix(),
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope='session')
|
|
def image_repo(
|
|
setup_infrastructure,
|
|
populate_env,
|
|
) -> Iterator[ImageRepository]:
|
|
"""Image repository fixture."""
|
|
repo = ImageRepository()
|
|
repo.connect()
|
|
yield repo
|
|
repo.close()
|
|
|
|
|
|
@pytest.fixture
|
|
def model_data() -> Iterator[ModelData]:
|
|
"""Model data fixture."""
|
|
# prepare arguments
|
|
vis_com_model = VisualCommunicationModel().to('cpu')
|
|
class_name = type(vis_com_model).__name__
|
|
buffer = ModelData.model_to_buffer(vis_com_model)
|
|
buffer_checksum = HexadecimalString('77dcab1769563654a6e24f92d40f29bd')
|
|
# instantiate data
|
|
model_data = ModelData(
|
|
buffer=buffer,
|
|
buffer_checksum=buffer_checksum,
|
|
class_name=class_name,
|
|
)
|
|
# expose model
|
|
yield model_data
|
|
|
|
|
|
@pytest.fixture
|
|
def model_data_in_minio(
|
|
raw_minio_client: minio.Minio,
|
|
model_data: ModelData,
|
|
) -> Iterator[ModelData]:
|
|
"""Model data in Minio fixture."""
|
|
# prepare arguments
|
|
minio_bucket_name = str(os.getenv('MINIO_BUCKET_NAME'))
|
|
object_name = ModelRepository._build_object_name(model_data)
|
|
buffer = model_data.buffer
|
|
# build object path
|
|
object_path = ModelRepository._prefix() / object_name
|
|
# prepare for saving
|
|
num_bytes = len(buffer.getvalue())
|
|
buffer.seek(0)
|
|
# put data in bucket
|
|
raw_minio_client.put_object(
|
|
bucket_name=minio_bucket_name,
|
|
object_name=object_path.as_posix(),
|
|
length=num_bytes,
|
|
data=buffer,
|
|
)
|
|
# expose data
|
|
yield model_data
|
|
# cleanup
|
|
raw_minio_client.remove_object(
|
|
bucket_name=minio_bucket_name,
|
|
object_name=object_path.as_posix(),
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope='session')
|
|
def model_repo(
|
|
setup_infrastructure,
|
|
populate_env,
|
|
) -> Iterator[ModelRepository]:
|
|
"""Model repository fixture."""
|
|
repo = ModelRepository()
|
|
repo.connect()
|
|
yield repo
|
|
repo.close()
|
|
|
|
|
|
@pytest.fixture
|
|
def raw_mongo_client(
|
|
setup_infrastructure,
|
|
populate_env,
|
|
) -> Iterator[MongoClient]:
|
|
"""Raw mongo client fixture."""
|
|
# prepare arguments
|
|
mongo_endpoint = str(os.getenv('MONGO_ENDPOINT'))
|
|
mongo_database = str(os.getenv('MONGO_DB'))
|
|
# connect client
|
|
client: MongoClient = MongoClient(mongo_endpoint)
|
|
_ = client[mongo_database]
|
|
# expose client
|
|
yield client
|
|
# cleanup
|
|
client.drop_database(mongo_database)
|
|
|
|
|
|
@pytest.fixture
|
|
def mongo_client(
|
|
setup_infrastructure,
|
|
populate_env,
|
|
) -> Iterator[MongoImplementation]:
|
|
"""MongoImplementation fixture."""
|
|
# instantiate and connect client
|
|
mongo_client = MongoImplementation()
|
|
mongo_client.connect()
|
|
# expose client
|
|
yield mongo_client
|
|
# cleanup
|
|
mongo_client._collection.drop()
|
|
mongo_client.close()
|
|
|
|
|
|
@pytest.fixture
|
|
def dictionary() -> Iterator[dict]:
|
|
"""Dictionary fixture."""
|
|
# prepare data
|
|
data = {
|
|
'name': 'test-dictionary',
|
|
'str_key': 'value',
|
|
'int_key': 100,
|
|
'float_key': 3.14,
|
|
'list_key': [1, 2, 3],
|
|
'dict_key': {
|
|
'nested_key': 'nested_value',
|
|
},
|
|
}
|
|
# expose data
|
|
yield data
|
|
|
|
|
|
@pytest.fixture
|
|
def dictionary_in_mongo(
|
|
raw_mongo_client: MongoClient,
|
|
dictionary: dict,
|
|
) -> Iterator[dict]:
|
|
"""Dictionary in Mongo fixture."""
|
|
# prepare arguments
|
|
database = str(os.getenv('MONGO_DB'))
|
|
collection = str(os.getenv('MONGO_COLLECTION'))
|
|
# save data
|
|
_ = raw_mongo_client[database][collection].insert_one(dictionary.copy())
|
|
# expose data
|
|
yield dictionary
|
|
# cleanup
|
|
raw_mongo_client[database][collection].delete_one(dictionary)
|
|
|
|
|
|
@pytest.fixture
|
|
def visual_communication_values() -> Iterator[VisualCommunicationValues]:
|
|
"""Visual communication values fixture."""
|
|
# instantiate with random values
|
|
visual_communication_values = VisualCommunicationValues.from_random()
|
|
# expose values
|
|
yield visual_communication_values
|
|
|
|
|
|
@pytest.fixture
|
|
def visual_communication_data(
|
|
visual_communication_values: VisualCommunicationValues,
|
|
) -> Iterator[VisualCommunicationData]:
|
|
"""Visual communication data fixture."""
|
|
# prepare arguments
|
|
name = 'test-visual-communication'
|
|
annotation = visual_communication_values
|
|
# instantiate data
|
|
visual_communication_data = VisualCommunicationData(
|
|
name=name,
|
|
annotation=annotation,
|
|
)
|
|
# expose data
|
|
yield visual_communication_data
|
|
|
|
|
|
@pytest.fixture
|
|
def visual_communication_data_in_mongo(
|
|
raw_mongo_client: MongoClient,
|
|
visual_communication_data: VisualCommunicationData,
|
|
) -> Iterator[VisualCommunicationData]:
|
|
"""Visual communication data in Mongo fixture."""
|
|
# prepare arguments
|
|
database = str(os.getenv('MONGO_DB'))
|
|
collection = str(os.getenv('MONGO_COLLECTION'))
|
|
# convert data
|
|
dictionary = visual_communication_data.model_dump(mode='dict')
|
|
# save data
|
|
_ = raw_mongo_client[database][collection].insert_one(dictionary.copy())
|
|
# expose data
|
|
yield visual_communication_data
|
|
# cleanup
|
|
raw_mongo_client[database][collection].delete_one(dictionary)
|
|
|
|
|
|
@pytest.fixture(scope='session')
|
|
def visual_communication_repo(
|
|
setup_infrastructure,
|
|
populate_env,
|
|
) -> Iterator[VisualCommunicationRepository]:
|
|
"""Visual communication repository fixture."""
|
|
repo = VisualCommunicationRepository()
|
|
repo.connect()
|
|
yield repo
|
|
repo.close()
|