Skip to content

Commit

Permalink
Return only latest artefacts to frontend (#27)
Browse files Browse the repository at this point in the history
* Fix the get_artefacts_by_family_name function

* Return only latest artefacts to frontend

* Fix style issues

* Use groupby from itertools and check family name

* Add test_families

* Fix style issues
  • Loading branch information
nadzyah authored Jun 19, 2023
1 parent ca8a4d6 commit 62809eb
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 5 deletions.
17 changes: 17 additions & 0 deletions backend/test_observer/controllers/families/families.py
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

0 comments on commit 62809eb

Please sign in to comment.