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

Return only latest artefacts to frontend #27

Merged
merged 6 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
17 changes: 17 additions & 0 deletions backend/test_observer/controllers/families/families.py
nadzyah marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Copyright 2023 Canonical Ltd.
# All rights reserved.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Expand All @@ -10,10 +13,16 @@
# Nadzeya Hutsko <[email protected]>
# Omar Abou Selo <[email protected]>


from itertools import groupby


from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from test_observer.data_access.models import Family
from test_observer.data_access.models_enums import FamilyName
from test_observer.data_access.setup import get_db
from test_observer.data_access.repository import get_artefacts_by_family_name

from .models import FamilyDTO

Expand All @@ -27,5 +36,13 @@ def read_family(family_name: str, db: Session = Depends(get_db)):
if family is None:
raise HTTPException(status_code=404, detail="Family not found")

family_name_enum_value = FamilyName(family_name)
latest_artefacts = get_artefacts_by_family_name(db, family_name_enum_value)

stage_artefact_dict = groupby(latest_artefacts, lambda art: art.stage)

for stage, artefacts in stage_artefact_dict:
stage.artefacts = list(artefacts)

family.stages = sorted(family.stages, key=lambda x: x.position)
return family
2 changes: 2 additions & 0 deletions backend/test_observer/data_access/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ def get_artefacts_by_family_name(
Artefact.source,
func.max(Artefact.created_at).label("max_created"),
)
.join(Stage)
.filter(Stage.family.has(Family.name == family_name))
.group_by(Artefact.stage_id, Artefact.name, Artefact.source)
.subquery()
)
Expand Down
3 changes: 1 addition & 2 deletions backend/test_observer/external_apis/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ def get_deb_version(self, debname: str) -> str | None:
pkg_ver = re.search("Version: (.+)", pkg)
if pkg_name and pkg_ver:
# Periods in json keys are bad, convert them to _
pkg_name_key = pkg_name.group(1).replace(".", "_")
json_data[pkg_name_key] = pkg_ver.group(1)
json_data[pkg_name.group(1)] = pkg_ver.group(1)
return json_data.get(debname)

def _create_download_and_extract_filepaths(self) -> None:
Expand Down
89 changes: 89 additions & 0 deletions backend/tests/controllers/families/test_families.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Copyright 2023 Canonical Ltd.
# All rights reserved.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Written by:
# Nadzeya Hutsko <[email protected]>


from datetime import datetime, timedelta
from random import randint

from fastapi.testclient import TestClient
from sqlalchemy.orm import Session

from tests.helpers import create_artefact


def test_retreive_family(db_session: Session, test_client: TestClient):
"""
We should get json for a specific family with its stages and artefacts
"""
# Arrange
artefact_name_stage_pair = [
("core20", "edge", datetime.utcnow()),
("oem-jammy", "proposed", datetime.utcnow()),
("core20", "edge", datetime.utcnow() - timedelta(days=10)),
("core20", "beta", datetime.utcnow() - timedelta(days=20)),
]
artefacts = []
for name, stage, created_at in artefact_name_stage_pair:
artefacts.append(
create_artefact(
db_session,
stage,
name=name,
created_at=created_at,
version=str(randint(1, 100)),
)
)
snap_stage = artefacts[0].stage

# Act
response = test_client.get("/v1/families/snap")

# Assert
assert response.json() == {
"id": snap_stage.family_id,
"name": snap_stage.family.name,
"stages": [
{
"id": 1,
"name": "edge",
"artefacts": [
{
"id": artefacts[0].id,
"name": artefacts[0].name,
"version": artefacts[0].version,
"source": artefacts[0].source,
}
],
},
{
"id": 2,
"name": "beta",
"artefacts": [
{
"id": artefacts[-1].id,
"name": artefacts[-1].name,
"version": artefacts[-1].version,
"source": artefacts[-1].source,
}
],
},
{"id": 3, "name": "candidate", "artefacts": []},
{"id": 4, "name": "stable", "artefacts": []},
],
}
5 changes: 3 additions & 2 deletions backend/tests/data_access/test_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,15 @@ def test_get_artefacts_by_family_name(db_session: Session):


def test_get_artefacts_by_family_name_latest(db_session: Session):
"""We should get a only latest artefacts in each stage"""
"""We should get a only latest artefacts in each stage for the specified family"""
# Arrange
artefact_name_stage_pair = [
("core20", "edge", datetime.utcnow()),
("oem-jammy", "proposed", datetime.utcnow()),
("core20", "edge", datetime.utcnow() - timedelta(days=10)),
("core20", "beta", datetime.utcnow() - timedelta(days=20)),
]
expected_artefacts = {artefact_name_stage_pair[0], artefact_name_stage_pair[2]}
expected_artefacts = {artefact_name_stage_pair[0], artefact_name_stage_pair[-1]}

for name, stage, created_at in artefact_name_stage_pair:
create_artefact(
Expand Down
2 changes: 1 addition & 1 deletion backend/tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from test_observer.data_access.models_enums import FamilyName


def create_artefact(db_session: Session, stage_name: str, **kwargs):
def create_artefact(db_session: Session, stage_name: str, **kwargs) -> Artefact:
"""Create a dummy artefact"""
stage = db_session.query(Stage).filter(Stage.name == stage_name).first()
artefact = Artefact(
Expand Down