Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add(tests for store) #132

Merged
merged 17 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from 8 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
2 changes: 0 additions & 2 deletions genotype_api/database/base_handler.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from dataclasses import dataclass
from typing import Type

from sqlalchemy.orm import Session, Query, DeclarativeBase

from genotype_api.database.models import Analysis, Sample


Expand Down
16 changes: 10 additions & 6 deletions genotype_api/database/crud/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

ChrOertlin marked this conversation as resolved.
Show resolved Hide resolved

from genotype_api.database.base_handler import BaseHandler
from genotype_api.database.models import Analysis, Plate, Sample, User, SNP
from genotype_api.database.models import Analysis, Plate, Sample, User, SNP, Genotype
from genotype_api.dto.user import UserRequest
from genotype_api.exceptions import SampleExistsError

Expand Down Expand Up @@ -42,14 +42,18 @@ def create_analyses_samples(self, analyses: list[Analysis]) -> list[Sample]:
if not self.session.query(Sample).filter(Sample.id == analysis.sample_id).one_or_none()
]

def create_user(self, user: UserRequest) -> User:
db_user = User(email=user.email, name=user.name)
self.session.add(db_user)
def create_user(self, user: User) -> User:
self.session.add(user)
self.session.commit()
self.session.refresh(db_user)
return db_user
self.session.refresh(user)
return user
ChrOertlin marked this conversation as resolved.
Show resolved Hide resolved

def create_snps(self, snps: list[SNP]) -> list[SNP]:
self.session.add_all(snps)
self.session.commit()
return snps

def create_genotype(self, genotype: Genotype) -> Genotype:
self.session.add(genotype)
self.session.commit()
return genotype
15 changes: 2 additions & 13 deletions genotype_api/database/crud/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,6 @@ class ReadHandler(BaseHandler):
def get_analyses_from_plate(self, plate_id: int) -> list[Analysis]:
return self.session.query(Analysis).filter(Analysis.plate_id == plate_id).all()

def get_analysis_by_type_sample(
self,
sample_id: str,
analysis_type: str,
) -> Analysis | None:
return (
self.session.query(Analysis)
.filter(Analysis.sample_id == sample_id, Analysis.type == analysis_type)
.first()
)

def get_analysis_by_id(self, analysis_id: int) -> Analysis:
return self.session.query(Analysis).filter(Analysis.id == analysis_id).first()

Expand Down Expand Up @@ -130,7 +119,7 @@ def _get_samples(query: Query, sample_id: str) -> Query:
"""Returns a query for samples containing the given sample_id."""
return query.filter(Sample.id.contains(sample_id))

def get_sample(self, sample_id: str) -> Sample:
def get_sample_by_id(self, sample_id: str) -> Sample:
return self.session.query(Sample).filter(Sample.id == sample_id).first()

def get_user_by_id(self, user_id: int) -> User:
Expand All @@ -145,7 +134,7 @@ def get_users_with_skip_and_limit(self, skip: int, limit: int) -> list[User]:
def check_analyses_objects(self, analyses: list[Analysis], analysis_type: Types) -> None:
"""Raising 400 if any analysis in the list already exist in the database"""
for analysis_obj in analyses:
existing_analysis = self.get_analysis_by_type_sample(
existing_analysis = self.get_analysis_by_type_and_sample_id(
sample_id=analysis_obj.sample_id,
analysis_type=analysis_type,
)
Expand Down
4 changes: 2 additions & 2 deletions genotype_api/database/crud/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def refresh_sample_status(
return sample

def update_sample_comment(self, sample_id: str, comment: str) -> Sample:
sample: Sample = self.get_sample(sample_id=sample_id)
sample: Sample = self.get_sample_by_id(sample_id=sample_id)
if not sample:
raise SampleNotFoundError
sample.comment = comment
Expand All @@ -38,7 +38,7 @@ def update_sample_comment(self, sample_id: str, comment: str) -> Sample:
return sample

def update_sample_status(self, sample_id: str, status: str | None) -> Sample:
sample: Sample = self.get_sample(sample_id=sample_id)
sample: Sample = self.get_sample_by_id(sample_id=sample_id)
if not sample:
raise SampleNotFoundError
sample.status = status
Expand Down
6 changes: 3 additions & 3 deletions genotype_api/services/endpoint_services/sample_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def _get_sample_response(self, sample: Sample) -> SampleResponse:
)

def get_sample(self, sample_id: str) -> SampleResponse:
sample: Sample = self.store.get_sample(sample_id=sample_id)
sample: Sample = self.store.get_sample_by_id(sample_id=sample_id)
if not sample:
raise SampleNotFoundError
if len(sample.analyses) == 2 and not sample.status:
Expand All @@ -82,13 +82,13 @@ def create_sample(self, sample_create: SampleCreate) -> None:
self.store.create_sample(sample=sample)

def delete_sample(self, sample_id: str) -> None:
sample: Sample = self.store.get_sample(sample_id=sample_id)
sample: Sample = self.store.get_sample_by_id(sample_id=sample_id)
for analysis in sample.analyses:
self.store.delete_analysis(analysis=analysis)
self.store.delete_sample(sample=sample)

def get_status_detail(self, sample_id: str) -> SampleDetail:
sample: Sample = self.store.get_sample(sample_id=sample_id)
sample: Sample = self.store.get_sample_by_id(sample_id=sample_id)
if len(sample.analyses) != 2:
return SampleDetail()
return MatchGenotypeService.check_sample(sample=sample)
Expand Down
3 changes: 2 additions & 1 deletion genotype_api/services/endpoint_services/user_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ def create_user(self, user: UserRequest):
existing_user: User = self.store.get_user_by_email(email=user.email)
if existing_user:
raise UserExistsError
new_user: User = self.store.create_user(user=user)
db_user = User(email=user.email, name=user.name)
new_user: User = self.store.create_user(user=db_user)
return self._create_user_response(new_user)

def get_users(self, skip: int, limit: int) -> list[UserResponse]:
Expand Down
50 changes: 50 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import pytest

from genotype_api.database.database import initialise_database, create_all_tables, drop_all_tables
from genotype_api.database.filter_models.plate_models import PlateSignOff
from genotype_api.database.filter_models.sample_models import SampleSexesUpdate
from genotype_api.database.models import User, Plate, SNP, Sample, Genotype, Analysis
from genotype_api.database.store import Store
from tests.store_helpers import StoreHelpers
Expand All @@ -17,6 +19,21 @@ def timestamp_now() -> datetime:
return datetime.datetime.now()


@pytest.fixture
def date_two_weeks_future() -> datetime.date:
return datetime.date.today() + datetime.timedelta(days=14)


@pytest.fixture
def date_yesterday() -> datetime:
return datetime.date.today() - datetime.timedelta(days=1)


@pytest.fixture
def date_tomorrow() -> datetime:
return datetime.date.today() + datetime.timedelta(days=1)


@pytest.fixture
def store() -> Generator[Store, None, None]:
"""Return a CG store."""
Expand Down Expand Up @@ -232,6 +249,39 @@ def base_store(
return store


@pytest.fixture
def unsigned_plate() -> Plate:
return Plate(
id=1,
plate_id="ID_1",
signed_by=None,
method_document=None,
method_version=None,
created_at=datetime.datetime.now(),
signed_at=None,
)


@pytest.fixture
def plate_sign_off() -> PlateSignOff:
return PlateSignOff(
user_id=1,
signed_at=datetime.datetime.now(),
method_document="mdoc",
method_version="mdoc_ver",
)


@pytest.fixture
def sample_sex_update(test_sample_id) -> SampleSexesUpdate:
return SampleSexesUpdate(
sample_id=test_sample_id,
sex="female",
genotype_sex="female",
sequence_sex="female",
)


@pytest.fixture(name="fixtures_dir")
def fixture_fixtures_dir() -> Path:
"""Return the path to fixtures dir."""
Expand Down
77 changes: 77 additions & 0 deletions tests/database/crud/test_create.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Module to test the create functionality of the genotype API CRUD."""

from genotype_api.database.models import Analysis, SNP, User, Genotype, Sample, Plate
from genotype_api.database.store import Store


def test_create_analysis(store: Store, test_analysis: Analysis):
# GIVEN an analysis and an empty store
ChrOertlin marked this conversation as resolved.
Show resolved Hide resolved

# WHEN creating the analysis
store.create_analysis(analysis=test_analysis)

# THEN the analysis is created
assert store._get_query(Analysis).all()[0]
diitaz93 marked this conversation as resolved.
Show resolved Hide resolved


def test_create_genotype(store: Store, test_genotype: Genotype):
# GIVEN a genotype and an empty store

# WHEN creating the genotype
store.create_genotype(genotype=test_genotype)

# THEN the genotype is created
assert store._get_query(Genotype).all()[0]


def test_create_snp(store: Store, test_snp: SNP):
# GIVEN a SNP and an empty store

# WHEN creating the SNP
store.create_snps(snps=[test_snp])

# THEN the SNP is created
assert store._get_query(SNP).all()[0]


def test_create_user(store: Store, test_user: User):
# GIVEN a user and an empty store

# WHEN creating the user
store.create_user(user=test_user)

# THEN the user is created
assert store._get_query(User).all()[0]


def test_create_sample(store: Store, test_sample: Sample):
# GIVEN a sample and an empty store

# WHEN creating the sample
store.create_sample(sample=test_sample)

# THEN the sample is created
assert store._get_query(Sample).all()[0]


def test_create_plate(store: Store, test_plate: Plate):
# GIVEN a plate and an empty store

# WHEN creating the plate
store.create_plate(plate=test_plate)

# THEN the plate is created
assert store._get_query(Plate).all()[0]


def test_create_analyses_samples(store: Store, test_analysis: Analysis):
# GIVEN an analysis in a store
store.create_analysis(test_analysis)
ChrOertlin marked this conversation as resolved.
Show resolved Hide resolved

# WHEN creating the analyses
store.create_analyses_samples(analyses=[test_analysis])

# THEN the samples are created
sample: Sample = store._get_query(Sample).all()[0]
assert sample
assert sample.id == test_analysis.sample_id
64 changes: 64 additions & 0 deletions tests/database/crud/test_delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""Module to test the delete functionality of the genotype API CRUD."""

from genotype_api.database.models import Analysis, Sample, User, Plate, SNP
from genotype_api.database.store import Store


def test_delete_analysis(base_store: Store, test_analysis: Analysis):
# GIVEN an analysis and a store with the analysis
assert base_store._get_query(Analysis).all()[0]
ChrOertlin marked this conversation as resolved.
Show resolved Hide resolved

# WHEN deleting the analysis
base_store.delete_analysis(analysis=test_analysis)

# THEN the analysis is deleted
for analysis in base_store._get_query(Analysis).all():
diitaz93 marked this conversation as resolved.
Show resolved Hide resolved
assert analysis != test_analysis


def test_delete_sample(base_store: Store, test_sample: Sample):
# GIVEN a sample and a store with the sample
assert base_store._get_query(Sample).all()[0]
ChrOertlin marked this conversation as resolved.
Show resolved Hide resolved

# WHEN deleting the sample
base_store.delete_sample(sample=test_sample)

# THEN the sample is deleted
for sample in base_store._get_query(Sample).all():
assert sample != test_sample


def test_delete_plate(base_store: Store, test_plate: Plate):
# GIVEN a plate and a store with the plate
assert base_store._get_query(Plate).all()[0]

# WHEN deleting the plate
base_store.delete_plate(plate=test_plate)

# THEN the plate is deleted
for plate in base_store._get_query(Plate).all():
assert plate != test_plate


def test_delete_user(base_store: Store, test_user: User):
# GIVEN a user and a store with the user
assert base_store._get_query(User).all()[0]

# WHEN deleting the user
base_store.delete_user(user=test_user)

# THEN the user is deleted
for user in base_store._get_query(User).all():
assert user != test_user


def test_delete_snps(base_store: Store, test_snp):
# GIVEN a SNP and a store with the SNP
assert base_store._get_query(SNP).all()[0]

# WHEN deleting the SNP
base_store.delete_snps()

# THEN the SNP is deleted
for snp in base_store._get_query(SNP).all():
assert snp != test_snp
Loading
Loading