added integration tests and repository pattern for image, model and visual communication DTOs
Code Quality Pipeline / Check Code (pull_request) Failing after 3m21s

This commit is contained in:
brian
2025-02-28 22:24:52 +00:00
parent ac6a305da8
commit 090a1cd8bb
45 changed files with 2630 additions and 0 deletions
@@ -0,0 +1,444 @@
"""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(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()
@@ -0,0 +1,156 @@
"""Integration tests for ImageRepository class."""
import numpy as np
import pytest
from PIL import Image
from shared.repositories import ImageData, ImageRepository
def same_image(
img_a: Image.Image,
img_b: Image.Image,
) -> bool:
"""Check if two images contain the same data."""
assert isinstance(img_a, Image.Image)
assert isinstance(img_b, Image.Image)
# check if images have a comparable number of channels
if img_a.getbands() != img_b.getbands():
return False
# calculate pixel difference between images
img_a_arr = np.asarray(img_a)
img_b_arr = np.asarray(img_b)
diff = np.subtract(img_a_arr, img_b_arr)
if np.sum(diff) != 0:
return False
return True
def same_image_data(
data_a: ImageData,
data_b: ImageData,
) -> bool:
"""Check if two ImageData-objects contain the same data."""
assert isinstance(data_a, ImageData)
assert isinstance(data_b, ImageData)
# compare names
if data_a.name != data_b.name:
return False
# compare images
if not same_image(data_a.image, data_b.image):
return False
return True
def test_should_have_context_handler():
"""Test that class has a working context handler implemented."""
# ACT
with ImageRepository() as repo:
# ASSERT
assert repo.connected()
def test_should_get_image_data(
image_repo: ImageRepository,
image_data_in_minio: ImageData,
):
"""Test getting image data."""
# ARRANGE
image_name = image_data_in_minio.name
# ACT
received_image_data = image_repo.get_data(image_name)
# ASSERT
assert received_image_data is not None
assert isinstance(received_image_data, ImageData)
assert same_image_data(image_data_in_minio, received_image_data)
def test_should_get_none_when_no_image_data(
image_repo: ImageRepository,
image_data: ImageData,
):
"""Test getting None when no data is available."""
# ARRANGE
image_name = image_data.name
# ACT
received_image_data = image_repo.get_data(image_name)
# ASSERT
assert received_image_data is None
def test_should_delete_image_data(
image_repo: ImageRepository,
image_data_in_minio: ImageData,
):
"""Test deleting image data."""
# ARRANGE
image_name = image_data_in_minio.name
# ACT
image_repo.remove_data(image_name)
received_image_data = image_repo.get_data(image_name)
# ASSERT
assert received_image_data is None
def test_should_put_image_data(
image_repo: ImageRepository,
image_data: ImageData,
):
"""Test putting image data."""
# ARRANGE
image_name = image_data.name
# ACT
image_repo.put_data(image_data)
received_image_data = image_repo.get_data(image_name)
# ASSERT
assert received_image_data is not None
assert same_image_data(image_data, received_image_data)
def test_should_update_image_data(
image_repo: ImageRepository,
image_data_in_minio: ImageData,
):
"""Test updating image data."""
# ARRANGE
updated_image_data = image_data_in_minio.model_copy(
update={
'image': Image.new(mode='RGB', size=(480, 480), color='white'),
},
)
image_name = updated_image_data.name
# ACT
image_repo.put_data(updated_image_data)
received_image_data = image_repo.get_data(image_name)
# ASSERT
assert not same_image_data(image_data_in_minio, updated_image_data)
assert received_image_data is not None
assert same_image_data(updated_image_data, received_image_data)
def test_should_list_names(
image_repo: ImageRepository,
image_data_in_minio: ImageData,
):
"""Test get all image names."""
# ARRANGE
updated_image_data = image_data_in_minio.model_copy(
update={
'name': 'updated-test-image',
},
)
image_repo.put_data(updated_image_data)
expected_name_list = [
image_data_in_minio.name,
updated_image_data.name,
]
# ACT
name_list = image_repo.list_names()
# ASSERT
assert len(name_list) == 2
for name in name_list:
assert name in expected_name_list
if __name__ == '__main__':
pytest.main(['-s', '-v', __file__])
@@ -0,0 +1,133 @@
"""Integration tests related to Minio implementation."""
import logging
import os
from io import BytesIO
from pathlib import Path
import pytest
from shared.repositories.src.implementations import MinioImplementation
def same_data(
data_a: BytesIO,
data_b: BytesIO,
) -> bool:
"""Check if two BytesIO-objects contain the same data."""
assert isinstance(data_a, BytesIO)
assert isinstance(data_b, BytesIO)
# prepare for being read
data_a.seek(0)
data_b.seek(0)
# convert to bytes
data_a_bytes = data_a.read()
data_b_bytes = data_b.read()
# compare size
if len(data_a_bytes) != len(data_b_bytes):
logging.error(
'data has different length: %s and %s',
len(data_a_bytes),
len(data_b_bytes),
)
return False
# compare content
if data_a_bytes != data_b_bytes:
logging.error('data has different bytes')
return False
return True
def test_should_connect_to_minio():
"""Test connection to Minio."""
# ARRANGE
client = MinioImplementation()
# ACT
client.connect()
# ASSERT
assert client.connected()
client.close()
def test_should_have_context_handler():
"""Test that class has a working context handler implemented."""
# ACT
with MinioImplementation() as client:
# ASSERT
assert client.connected()
def test_should_get_data(
minio_client: MinioImplementation,
buffer_in_minio: tuple[Path, BytesIO],
):
"""Test getting data from Minio."""
# ARRANGE
path, buffer = buffer_in_minio
# ACT
received_buffer = minio_client._get(path)
# ASSERT
assert received_buffer is not None
assert same_data(received_buffer, buffer)
def test_should_get_none_when_no_data(
minio_client: MinioImplementation,
):
"""Test getting None when no data is available in Minio."""
# ARRANGE
nonexistent_path = Path('nonexistent-object-name')
# ACT
received_buffer = minio_client._get(nonexistent_path)
# ASSERT
assert received_buffer is None
def test_should_delete_data(
minio_client: MinioImplementation,
buffer_in_minio: tuple[Path, BytesIO],
):
"""Test deleting data from Minio."""
# ARRANGE
path, _ = buffer_in_minio
# ACT
minio_client._delete(path)
# ASSERT
received_buffer = minio_client._get(path)
assert received_buffer is None
def test_should_put_data(
minio_client: MinioImplementation,
buffer: BytesIO,
):
"""Test putting data in Minio."""
# ARRANGE
path = Path(os.getenv('MINIO_OBJECT_NAME', default=''))
# ACT
minio_client._put(path, buffer)
received_buffer = minio_client._get(path)
# ASSERT
assert received_buffer is not None
assert same_data(received_buffer, buffer)
def test_should_update_data(
minio_client: MinioImplementation,
buffer_in_minio: tuple[Path, BytesIO],
):
"""Test updating data in Minio."""
# ARRANGE
path, buffer = buffer_in_minio
updated_buffer = BytesIO(buffer.getvalue() + b'extra data')
# ACT
minio_client._put(path, updated_buffer)
received_buffer = minio_client._get(path)
# ASSERT
assert not same_data(updated_buffer, buffer)
assert received_buffer is not None
assert same_data(received_buffer, updated_buffer)
if __name__ == '__main__':
pytest.main(['-s', '-v', __file__])
@@ -0,0 +1,136 @@
"""Integration tests for ModelRepository class."""
from io import BytesIO
import pytest
from shared.repositories import ModelData, ModelRepository
def same_buffer(
buffer_a: BytesIO,
buffer_b: BytesIO,
) -> bool:
"""Check if 2 buffers contain the same data."""
assert isinstance(buffer_a, BytesIO)
assert isinstance(buffer_b, BytesIO)
# read buffers
a_values = buffer_a.getvalue()
b_values = buffer_b.getvalue()
# compare length of buffers
if len(a_values) != len(b_values):
return False
# compare content of buffers
if a_values != b_values:
return False
return True
def same_model_data(
data_a: ModelData,
data_b: ModelData,
) -> bool:
"""Check if to ModelData-objects contain the same data."""
assert isinstance(data_a, ModelData)
assert isinstance(data_b, ModelData)
# compare names
if data_a.buffer_checksum != data_b.buffer_checksum:
return False
# compare buffer
if not same_buffer(data_a.buffer, data_b.buffer):
return False
return True
def test_should_have_context_handler():
"""Test that class has a working context handler implemented."""
# ACT
with ModelRepository() as repo:
# ASSERT
assert repo.connected()
def test_should_get_model_data(
model_repo: ModelRepository,
model_data_in_minio: ModelData,
):
"""Test getting model data."""
# ARRANGE
object_name = ModelRepository._build_object_name(model_data_in_minio)
# ACT
received_model_data = model_repo.get_data(object_name)
# ASSERT
assert received_model_data is not None
assert isinstance(received_model_data, ModelData)
assert same_model_data(model_data_in_minio, received_model_data)
def test_should_get_none_when_no_model_data(
model_repo: ModelRepository,
model_data: ModelData,
):
"""Test getting None whne no data is available."""
# ARRANGE
object_name = ModelRepository._build_object_name(model_data)
# ACT
received_model_data = model_repo.get_data(object_name)
# ASSERT
assert received_model_data is None
def test_should_delete_model_data(
model_repo: ModelRepository,
model_data_in_minio: ModelData,
):
"""Test deleting model data."""
# ARRANGE
object_name = ModelRepository._build_object_name(model_data_in_minio)
# ACT
model_repo.remove_data(object_name)
received_model_data = model_repo.get_data(object_name)
# ASSERT
assert received_model_data is None
def test_should_put_model_data(
model_repo: ModelRepository,
model_data: ModelData,
):
"""Test putting model data."""
# ARRANGE
object_name = ModelRepository._build_object_name(model_data)
# ACT
model_repo.put_data(model_data)
received_model_data = model_repo.get_data(object_name)
# ASSERT
assert received_model_data is not None
assert same_model_data(model_data, received_model_data)
def test_should_list_names(
model_repo: ModelRepository,
model_data_in_minio: ModelData,
):
"""Test get all model names."""
# ARRANGE
new_buffer_checksum = ModelData.calculate_checksum(model_data_in_minio.buffer)
updated_model_data = model_data_in_minio.model_copy(
update={
'buffer_checksum': new_buffer_checksum,
},
)
model_repo.put_data(updated_model_data)
expected_name_list = [
ModelRepository._build_object_name(model_data_in_minio),
ModelRepository._build_object_name(updated_model_data),
]
# ACT
name_list = model_repo.list_names()
# ASSERT
assert len(name_list) == 2
for name in name_list:
assert name in expected_name_list
if __name__ == '__main__':
pytest.main(['-s', '-v', __file__])
@@ -0,0 +1,113 @@
"""Integration tests related to Mongo implementation."""
import pytest
from shared.repositories.src.implementations import MongoImplementation
def test_should_connect_mongo():
"""Test connecting to Mongo."""
# ARRANGE
client = MongoImplementation()
# ACT
client.connect()
# ASSERT
assert client.connected()
client.close()
def test_should_have_context_handler():
"""Test that class has a working context handler implemented."""
# ACT
with MongoImplementation() as client:
# ASSERT
assert client.connected()
def test_should_get_data(
mongo_client: MongoImplementation,
dictionary_in_mongo: dict,
):
"""Test getting data from mongo."""
# ARRANGE
name = dictionary_in_mongo['name']
query = {'name': name}
# ACT
received_dictionary = mongo_client._get(query)
# ASSERT
assert received_dictionary is not None
assert isinstance(received_dictionary, dict)
assert received_dictionary == dictionary_in_mongo
def test_should_get_none_when_no_data(
mongo_client: MongoImplementation,
dictionary: dict,
):
"""Test getting None when no data is available in mongo."""
# ARRANGE
name = dictionary['name']
query = {'name': name}
# ACT
received_dictionary = mongo_client._get(query)
# ASSERT
assert received_dictionary is None
def test_should_delete_data(
mongo_client: MongoImplementation,
dictionary_in_mongo: dict,
):
"""Test deleting data from mongo."""
# ARRANGE
name = dictionary_in_mongo['name']
query = {'name': name}
# ACT
mongo_client._delete(query)
received_dictionary = mongo_client._get(query)
# ASSERT
assert received_dictionary is None
def test_should_save_data(
mongo_client: MongoImplementation,
dictionary: dict,
):
"""Test saving data to mongo."""
# ARRANGE
name = dictionary['name']
query = {'name': name}
# ACT
mongo_client._save(
data=dictionary,
query=query,
)
# ASSERT
received_dictionary = mongo_client._get(query)
assert received_dictionary is not None
assert isinstance(received_dictionary, dict)
assert received_dictionary == dictionary
def test_should_update_data(
mongo_client: MongoImplementation,
dictionary_in_mongo: dict,
):
"""Test updating data in mongo."""
# ARRANGE
name = dictionary_in_mongo['name']
query = {'name': name}
# ACT
dictionary_in_mongo['str-key'] = 'updated-value'
mongo_client._save(
data=dictionary_in_mongo,
query=query,
)
# ASSERT
received_dictionary = mongo_client._get(query)
assert received_dictionary is not None
assert received_dictionary == dictionary_in_mongo
if __name__ == '__main__':
pytest.main(['-s', '-v', __file__])
@@ -0,0 +1,125 @@
"""Integration tests for VisualCommunicationRepository class."""
import pytest
from shared.repositories import (
VisualCommunicationData,
VisualCommunicationRepository,
VisualCommunicationValues,
)
def test_should_have_context_handler():
"""Test that class has a working context handler implemented."""
# ACT
with VisualCommunicationRepository() as repo:
# ASSERT
assert repo.connected()
def test_should_get_visual_communication_data(
visual_communication_repo: VisualCommunicationRepository,
visual_communication_data_in_mongo: VisualCommunicationData,
):
"""Test getting visual communication data."""
# ARRANGE
name = visual_communication_data_in_mongo.name
# ACT
received_visual_communication_data = visual_communication_repo.get_data(name)
# ASSERT
assert received_visual_communication_data is not None
assert isinstance(received_visual_communication_data, VisualCommunicationData)
assert received_visual_communication_data == visual_communication_data_in_mongo
def test_should_get_none_when_no_visual_communication_data(
visual_communication_repo: VisualCommunicationRepository,
visual_communication_data: VisualCommunicationData,
):
"""Test getting None when no data is available."""
# ARRANGE
name = visual_communication_data.name
# ACT
received_visual_communication_data = visual_communication_repo.get_data(name)
# ASSERT
assert received_visual_communication_data is None
def test_should_delete_image_data(
visual_communication_repo: VisualCommunicationRepository,
visual_communication_data_in_mongo: VisualCommunicationData,
):
"""Test deleting visual communication data."""
# ARRANGE
name = visual_communication_data_in_mongo.name
# ACT
visual_communication_repo.remove_data(name)
received_visual_communication_data = visual_communication_repo.get_data(name)
# ASSERT
assert received_visual_communication_data is None
def test_should_put_visual_communication_data(
visual_communication_repo: VisualCommunicationRepository,
visual_communication_data: VisualCommunicationData,
):
"""Test putting visual communication data."""
# ARRANGE
name = visual_communication_data.name
# ACT
visual_communication_repo.put_data(visual_communication_data)
received_visual_communication_data = visual_communication_repo.get_data(name)
# ASSERT
assert received_visual_communication_data is not None
assert isinstance(received_visual_communication_data, VisualCommunicationData)
assert received_visual_communication_data == visual_communication_data
def test_should_update_visual_communication_data(
visual_communication_repo: VisualCommunicationRepository,
visual_communication_data_in_mongo: VisualCommunicationData,
):
"""Test updating visual communication data."""
# ARRANGE
name = visual_communication_data_in_mongo.name
updated_annotation = VisualCommunicationValues.from_random()
updated_visual_communication = VisualCommunicationData(
name=name,
annotation=updated_annotation,
)
# ACT
visual_communication_repo.put_data(updated_visual_communication)
received_visual_communication_data = visual_communication_repo.get_data(name)
# ASSERT
assert received_visual_communication_data is not None
assert isinstance(received_visual_communication_data, VisualCommunicationData)
assert received_visual_communication_data == updated_visual_communication
def test_should_list_names(
visual_communication_repo: VisualCommunicationRepository,
visual_communication_data_in_mongo: VisualCommunicationData,
):
"""Test listing names of all documents."""
# ARRANGE
name = 'test-visual-communication-2'
annotation = VisualCommunicationValues.from_random()
second_visual_communication = VisualCommunicationData(
name=name,
annotation=annotation,
)
visual_communication_repo.put_data(second_visual_communication)
expected_name_list = [
visual_communication_data_in_mongo.name,
second_visual_communication.name,
]
# ACT
name_list = visual_communication_repo.list_names()
# ASSERT
assert len(name_list) == 2
for name in name_list:
assert name in expected_name_list
if __name__ == '__main__':
pytest.main(['-s', '-v', __file__])