Merge ~r00ta/maas:refactoring-baserepository-interface into maas:master

Proposed by Jacopo Rota
Status: Needs review
Proposed branch: ~r00ta/maas:refactoring-baserepository-interface
Merge into: maas:master
Diff against target: 546 lines (+154/-72)
14 files modified
src/maasapiserver/common/db/sequences.py (+4/-0)
src/maasapiserver/v3/db/base.py (+10/-4)
src/maasapiserver/v3/db/bmc.py (+5/-3)
src/maasapiserver/v3/db/machines.py (+5/-3)
src/maasapiserver/v3/db/nodes.py (+5/-3)
src/maasapiserver/v3/db/resource_pools.py (+14/-15)
src/maasapiserver/v3/db/users.py (+5/-3)
src/maasapiserver/v3/db/vmcluster.py (+5/-3)
src/maasapiserver/v3/db/zones.py (+16/-13)
src/maasapiserver/v3/services/resource_pools.py (+10/-2)
src/maasapiserver/v3/services/zones.py (+11/-1)
src/tests/maasapiserver/v3/db/test_resource_pools.py (+20/-13)
src/tests/maasapiserver/v3/db/test_zones.py (+17/-8)
src/tests/maasapiserver/v3/services/test_resource_pools.py (+27/-1)
Reviewer Review Type Date Requested Status
Javier Fuentes Needs Information
MAAS Lander Needs Fixing
Review via email: mp+464818@code.launchpad.net

Commit message

refactoring: improve BaseRepository interface removing dependencies from the request models

Description of the change

This MP aims to remove the dependency from the request models from the db layer.

Since the ID of the resources comes from the undelying database sequence, we can retrieve the value from the service in order to properly build the model that the repository has to store.

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b refactoring-baserepository-interface lp:~r00ta/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 1de447f43e4367f1eb9e0c0cef2c57e70136f670

review: Approve
Revision history for this message
Jacopo Rota (r00ta) wrote :

jenkins: !test

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b refactoring-baserepository-interface lp:~r00ta/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/5507/console
COMMIT: 1de447f43e4367f1eb9e0c0cef2c57e70136f670

review: Needs Fixing
Revision history for this message
Wyatt Rees (wyattrees) wrote :

jenkins: !test

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b refactoring-baserepository-interface lp:~r00ta/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/5508/console
COMMIT: 1de447f43e4367f1eb9e0c0cef2c57e70136f670

review: Needs Fixing
Revision history for this message
Javier Fuentes (javier-fs) wrote :

I left a few questions :)

review: Needs Information
Revision history for this message
Javier Fuentes (javier-fs) :

Unmerged commits

1de447f... by Jacopo Rota

refactoring: improve BaseRepository interface removing dependencies from the request models

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasapiserver/common/db/sequences.py b/src/maasapiserver/common/db/sequences.py
0new file mode 1006440new file mode 100644
index 0000000..963a7c6
--- /dev/null
+++ b/src/maasapiserver/common/db/sequences.py
@@ -0,0 +1,4 @@
1from sqlalchemy import Sequence
2
3ZoneIdSequence = Sequence("maasserver_zone_id_seq")
4ResourcePoolIdSequence = Sequence("maasserver_resourcepool_id_seq")
diff --git a/src/maasapiserver/v3/db/base.py b/src/maasapiserver/v3/db/base.py
index 21ff3cf..26cea78 100644
--- a/src/maasapiserver/v3/db/base.py
+++ b/src/maasapiserver/v3/db/base.py
@@ -8,15 +8,21 @@ from maasapiserver.v3.models.base import ListResult
88
9T = TypeVar("T")9T = TypeVar("T")
1010
11K = TypeVar("K")
1211
1312class BaseRepository(ABC, Generic[T]):
14class BaseRepository(ABC, Generic[T, K]):
15 def __init__(self, connection: AsyncConnection):13 def __init__(self, connection: AsyncConnection):
16 self.connection = connection14 self.connection = connection
1715
18 @abstractmethod16 @abstractmethod
19 async def create(self, request: K) -> T:17 async def get_next_id(self) -> int:
18 """
19 Get the next ID for a new resource. Usually, this is useful because the ID comes from a sequence defined in the
20 database.
21 """
22 pass
23
24 @abstractmethod
25 async def create(self, request: T) -> T:
20 pass26 pass
2127
22 @abstractmethod28 @abstractmethod
diff --git a/src/maasapiserver/v3/db/bmc.py b/src/maasapiserver/v3/db/bmc.py
index 7dee695..df07a0a 100644
--- a/src/maasapiserver/v3/db/bmc.py
+++ b/src/maasapiserver/v3/db/bmc.py
@@ -2,15 +2,17 @@ from sqlalchemy import update
2from sqlalchemy.sql.operators import eq2from sqlalchemy.sql.operators import eq
33
4from maasapiserver.common.db.tables import BMCTable4from maasapiserver.common.db.tables import BMCTable
5from maasapiserver.v3.api.models.requests.bmc import BmcRequest
6from maasapiserver.v3.api.models.requests.query import PaginationParams5from maasapiserver.v3.api.models.requests.query import PaginationParams
7from maasapiserver.v3.db.base import BaseRepository6from maasapiserver.v3.db.base import BaseRepository
8from maasapiserver.v3.models.base import ListResult7from maasapiserver.v3.models.base import ListResult
9from maasapiserver.v3.models.bmc import Bmc8from maasapiserver.v3.models.bmc import Bmc
109
1110
12class BmcRepository(BaseRepository[Bmc, BmcRequest]):11class BmcRepository(BaseRepository[Bmc]):
13 async def create(self, request: BmcRequest) -> Bmc:12 async def get_next_id(self) -> int:
13 raise Exception("Not implemented yet.")
14
15 async def create(self, resource: Bmc) -> Bmc:
14 raise Exception("Not implemented yet.")16 raise Exception("Not implemented yet.")
1517
16 async def find_by_id(self, id: int) -> Bmc | None:18 async def find_by_id(self, id: int) -> Bmc | None:
diff --git a/src/maasapiserver/v3/db/machines.py b/src/maasapiserver/v3/db/machines.py
index 3002fb5..85205aa 100644
--- a/src/maasapiserver/v3/db/machines.py
+++ b/src/maasapiserver/v3/db/machines.py
@@ -11,7 +11,6 @@ from maasapiserver.common.db.tables import (
11 NodeTable,11 NodeTable,
12 UserTable,12 UserTable,
13)13)
14from maasapiserver.v3.api.models.requests.machines import MachineRequest
15from maasapiserver.v3.api.models.requests.query import PaginationParams14from maasapiserver.v3.api.models.requests.query import PaginationParams
16from maasapiserver.v3.db.base import BaseRepository15from maasapiserver.v3.db.base import BaseRepository
17from maasapiserver.v3.models.base import ListResult16from maasapiserver.v3.models.base import ListResult
@@ -19,8 +18,11 @@ from maasapiserver.v3.models.machines import Machine
19from maasserver.enum import NODE_TYPE18from maasserver.enum import NODE_TYPE
2019
2120
22class MachinesRepository(BaseRepository[Machine, MachineRequest]):21class MachinesRepository(BaseRepository[Machine]):
23 async def create(self, request: MachineRequest) -> Machine:22 async def get_next_id(self) -> int:
23 raise Exception("Not implemented yet.")
24
25 async def create(self, machine: Machine) -> Machine:
24 raise Exception("Not implemented yet.")26 raise Exception("Not implemented yet.")
2527
26 async def find_by_id(self, id: int) -> Machine | None:28 async def find_by_id(self, id: int) -> Machine | None:
diff --git a/src/maasapiserver/v3/db/nodes.py b/src/maasapiserver/v3/db/nodes.py
index 2686a7a..1bf1b71 100644
--- a/src/maasapiserver/v3/db/nodes.py
+++ b/src/maasapiserver/v3/db/nodes.py
@@ -2,15 +2,17 @@ from sqlalchemy import update
2from sqlalchemy.sql.operators import eq2from sqlalchemy.sql.operators import eq
33
4from maasapiserver.common.db.tables import NodeTable4from maasapiserver.common.db.tables import NodeTable
5from maasapiserver.v3.api.models.requests.nodes import NodeRequest
6from maasapiserver.v3.api.models.requests.query import PaginationParams5from maasapiserver.v3.api.models.requests.query import PaginationParams
7from maasapiserver.v3.db.base import BaseRepository6from maasapiserver.v3.db.base import BaseRepository
8from maasapiserver.v3.models.base import ListResult7from maasapiserver.v3.models.base import ListResult
9from maasapiserver.v3.models.nodes import Node8from maasapiserver.v3.models.nodes import Node
109
1110
12class NodesRepository(BaseRepository[Node, NodeRequest]):11class NodesRepository(BaseRepository[Node]):
13 async def create(self, request: NodeRequest) -> Node:12 async def get_next_id(self) -> int:
13 raise Exception("Not implemented yet.")
14
15 async def create(self, resource: Node) -> Node:
14 raise Exception("Not implemented yet.")16 raise Exception("Not implemented yet.")
1517
16 async def find_by_id(self, id: int) -> Node | None:18 async def find_by_id(self, id: int) -> Node | None:
diff --git a/src/maasapiserver/v3/db/resource_pools.py b/src/maasapiserver/v3/db/resource_pools.py
index 33640ae..525847b 100644
--- a/src/maasapiserver/v3/db/resource_pools.py
+++ b/src/maasapiserver/v3/db/resource_pools.py
@@ -6,6 +6,7 @@ from sqlalchemy.exc import IntegrityError
6from sqlalchemy.sql.functions import count6from sqlalchemy.sql.functions import count
7from sqlalchemy.sql.operators import eq7from sqlalchemy.sql.operators import eq
88
9from maasapiserver.common.db.sequences import ResourcePoolIdSequence
9from maasapiserver.common.db.tables import ResourcePoolTable10from maasapiserver.common.db.tables import ResourcePoolTable
10from maasapiserver.common.models.constants import (11from maasapiserver.common.models.constants import (
11 UNIQUE_CONSTRAINT_VIOLATION_TYPE,12 UNIQUE_CONSTRAINT_VIOLATION_TYPE,
@@ -15,9 +16,6 @@ from maasapiserver.common.models.exceptions import (
15 BaseExceptionDetail,16 BaseExceptionDetail,
16)17)
17from maasapiserver.v3.api.models.requests.query import PaginationParams18from maasapiserver.v3.api.models.requests.query import PaginationParams
18from maasapiserver.v3.api.models.requests.resource_pools import (
19 ResourcePoolRequest,
20)
21from maasapiserver.v3.db.base import BaseRepository19from maasapiserver.v3.db.base import BaseRepository
22from maasapiserver.v3.models.base import ListResult20from maasapiserver.v3.models.base import ListResult
23from maasapiserver.v3.models.resource_pools import ResourcePool21from maasapiserver.v3.models.resource_pools import ResourcePool
@@ -31,9 +29,11 @@ RESOURCE_POOLS_FIELDS = (
31)29)
3230
3331
34class ResourcePoolRepository(32class ResourcePoolRepository(BaseRepository[ResourcePool]):
35 BaseRepository[ResourcePool, ResourcePoolRequest]33 async def get_next_id(self) -> int:
36):34 stmt = select(ResourcePoolIdSequence.next_value())
35 return (await self.connection.execute(stmt)).scalar()
36
37 async def find_by_id(self, id: int) -> Optional[ResourcePool]:37 async def find_by_id(self, id: int) -> Optional[ResourcePool]:
38 stmt = self._select_all_statement().where(38 stmt = self._select_all_statement().where(
39 eq(ResourcePoolTable.c.id, id)39 eq(ResourcePoolTable.c.id, id)
@@ -43,24 +43,23 @@ class ResourcePoolRepository(
43 return ResourcePool(**resource_pools._asdict())43 return ResourcePool(**resource_pools._asdict())
44 return None44 return None
4545
46 async def create(self, request: ResourcePoolRequest) -> ResourcePool:46 async def create(self, resource_pool: ResourcePool) -> ResourcePool:
47 now = datetime.utcnow()
48 stmt = (47 stmt = (
49 insert(ResourcePoolTable)48 insert(ResourcePoolTable)
50 .returning(*RESOURCE_POOLS_FIELDS)49 .returning(*RESOURCE_POOLS_FIELDS)
51 .values(50 .values(
52 name=request.name,51 name=resource_pool.name,
53 description=request.description,52 description=resource_pool.description,
54 updated=now,53 updated=resource_pool.updated,
55 created=now,54 created=resource_pool.created,
56 )55 )
57 )56 )
58 try:57 try:
59 result = await self.connection.execute(stmt)58 result = await self.connection.execute(stmt)
60 except IntegrityError:59 except IntegrityError:
61 self._raise_constraint_violation(request.name)60 self._raise_constraint_violation(resource_pool.name)
62 resource_pools = result.one()61 created_resource_pools = result.one()
63 return ResourcePool(**resource_pools._asdict())62 return ResourcePool(**created_resource_pools._asdict())
6463
65 async def list(64 async def list(
66 self, pagination_params: PaginationParams65 self, pagination_params: PaginationParams
diff --git a/src/maasapiserver/v3/db/users.py b/src/maasapiserver/v3/db/users.py
index 573b790..097c475 100644
--- a/src/maasapiserver/v3/db/users.py
+++ b/src/maasapiserver/v3/db/users.py
@@ -3,14 +3,16 @@ from sqlalchemy.sql.operators import eq
33
4from maasapiserver.common.db.tables import UserTable4from maasapiserver.common.db.tables import UserTable
5from maasapiserver.v3.api.models.requests.query import PaginationParams5from maasapiserver.v3.api.models.requests.query import PaginationParams
6from maasapiserver.v3.api.models.requests.users import UserRequest
7from maasapiserver.v3.db.base import BaseRepository6from maasapiserver.v3.db.base import BaseRepository
8from maasapiserver.v3.models.base import ListResult7from maasapiserver.v3.models.base import ListResult
9from maasapiserver.v3.models.users import User8from maasapiserver.v3.models.users import User
109
1110
12class UsersRepository(BaseRepository[User, UserRequest]):11class UsersRepository(BaseRepository[User]):
13 async def create(self, request: UserRequest) -> User:12 async def get_next_id(self) -> int:
13 raise Exception("Not implemented yet.")
14
15 async def create(self, resource: User) -> User:
14 raise Exception("Not implemented yet.")16 raise Exception("Not implemented yet.")
1517
16 async def find_by_id(self, id: int) -> User | None:18 async def find_by_id(self, id: int) -> User | None:
diff --git a/src/maasapiserver/v3/db/vmcluster.py b/src/maasapiserver/v3/db/vmcluster.py
index b0a2bbf..9153d95 100644
--- a/src/maasapiserver/v3/db/vmcluster.py
+++ b/src/maasapiserver/v3/db/vmcluster.py
@@ -3,14 +3,16 @@ from sqlalchemy.sql.operators import eq
33
4from maasapiserver.common.db.tables import VmClusterTable4from maasapiserver.common.db.tables import VmClusterTable
5from maasapiserver.v3.api.models.requests.query import PaginationParams5from maasapiserver.v3.api.models.requests.query import PaginationParams
6from maasapiserver.v3.api.models.requests.vmcluster import VmClusterRequest
7from maasapiserver.v3.db.base import BaseRepository6from maasapiserver.v3.db.base import BaseRepository
8from maasapiserver.v3.models.base import ListResult7from maasapiserver.v3.models.base import ListResult
9from maasapiserver.v3.models.vmcluster import VmCluster8from maasapiserver.v3.models.vmcluster import VmCluster
109
1110
12class VmClustersRepository(BaseRepository[VmCluster, VmClusterRequest]):11class VmClustersRepository(BaseRepository[VmCluster]):
13 async def create(self, request: VmClusterRequest) -> VmCluster:12 async def get_next_id(self) -> int:
13 raise Exception("Not implemented yet.")
14
15 async def create(self, resource: VmCluster) -> VmCluster:
14 raise Exception("Not implemented yet.")16 raise Exception("Not implemented yet.")
1517
16 async def find_by_id(self, id: int) -> VmCluster | None:18 async def find_by_id(self, id: int) -> VmCluster | None:
diff --git a/src/maasapiserver/v3/db/zones.py b/src/maasapiserver/v3/db/zones.py
index 5325896..417e553 100644
--- a/src/maasapiserver/v3/db/zones.py
+++ b/src/maasapiserver/v3/db/zones.py
@@ -1,10 +1,10 @@
1from datetime import datetime
2from typing import Any1from typing import Any
32
4from sqlalchemy import delete, desc, insert, select, Select3from sqlalchemy import delete, desc, insert, select, Select
5from sqlalchemy.sql.functions import count4from sqlalchemy.sql.functions import count
6from sqlalchemy.sql.operators import eq5from sqlalchemy.sql.operators import eq
76
7from maasapiserver.common.db.sequences import ZoneIdSequence
8from maasapiserver.common.db.tables import DefaultResourceTable, ZoneTable8from maasapiserver.common.db.tables import DefaultResourceTable, ZoneTable
9from maasapiserver.common.models.constants import (9from maasapiserver.common.models.constants import (
10 UNIQUE_CONSTRAINT_VIOLATION_TYPE,10 UNIQUE_CONSTRAINT_VIOLATION_TYPE,
@@ -14,18 +14,21 @@ from maasapiserver.common.models.exceptions import (
14 BaseExceptionDetail,14 BaseExceptionDetail,
15)15)
16from maasapiserver.v3.api.models.requests.query import PaginationParams16from maasapiserver.v3.api.models.requests.query import PaginationParams
17from maasapiserver.v3.api.models.requests.zones import ZoneRequest
18from maasapiserver.v3.db.base import BaseRepository17from maasapiserver.v3.db.base import BaseRepository
19from maasapiserver.v3.models.base import ListResult18from maasapiserver.v3.models.base import ListResult
20from maasapiserver.v3.models.zones import Zone19from maasapiserver.v3.models.zones import Zone
2120
2221
23class ZonesRepository(BaseRepository[Zone, ZoneRequest]):22class ZonesRepository(BaseRepository[Zone]):
24 async def create(self, request: ZoneRequest) -> Zone:23 async def get_next_id(self) -> int:
24 stmt = select(ZoneIdSequence.next_value())
25 return (await self.connection.execute(stmt)).scalar()
26
27 async def create(self, zone: Zone) -> Zone:
25 check_integrity_stmt = (28 check_integrity_stmt = (
26 select(ZoneTable.c.id)29 select(ZoneTable.c.id)
27 .select_from(ZoneTable)30 .select_from(ZoneTable)
28 .where(eq(ZoneTable.c.name, request.name))31 .where(eq(ZoneTable.c.name, zone.name))
29 .limit(1)32 .limit(1)
30 )33 )
31 existing_entity = (34 existing_entity = (
@@ -36,12 +39,11 @@ class ZonesRepository(BaseRepository[Zone, ZoneRequest]):
36 details=[39 details=[
37 BaseExceptionDetail(40 BaseExceptionDetail(
38 type=UNIQUE_CONSTRAINT_VIOLATION_TYPE,41 type=UNIQUE_CONSTRAINT_VIOLATION_TYPE,
39 message=f"An entity with name '{request.name}' already exists. Its id is '{existing_entity.id}'.",42 message=f"An entity with name '{zone.name}' already exists. Its id is '{existing_entity.id}'.",
40 )43 )
41 ]44 ]
42 )45 )
4346
44 now = datetime.utcnow()
45 stmt = (47 stmt = (
46 insert(ZoneTable)48 insert(ZoneTable)
47 .returning(49 .returning(
@@ -52,15 +54,16 @@ class ZonesRepository(BaseRepository[Zone, ZoneRequest]):
52 ZoneTable.c.updated,54 ZoneTable.c.updated,
53 )55 )
54 .values(56 .values(
55 name=request.name,57 id=zone.id,
56 description=request.description,58 name=zone.name,
57 updated=now,59 description=zone.description,
58 created=now,60 updated=zone.updated,
61 created=zone.created,
59 )62 )
60 )63 )
61 result = await self.connection.execute(stmt)64 result = await self.connection.execute(stmt)
62 zone = result.one()65 created_zone = result.one()
63 return Zone(**zone._asdict())66 return Zone(**created_zone._asdict())
6467
65 async def find_by_id(self, id: int) -> Zone | None:68 async def find_by_id(self, id: int) -> Zone | None:
66 stmt = self._select_all_statement().filter(eq(ZoneTable.c.id, id))69 stmt = self._select_all_statement().filter(eq(ZoneTable.c.id, id))
diff --git a/src/maasapiserver/v3/services/resource_pools.py b/src/maasapiserver/v3/services/resource_pools.py
index 6862bdc..4388b31 100644
--- a/src/maasapiserver/v3/services/resource_pools.py
+++ b/src/maasapiserver/v3/services/resource_pools.py
@@ -1,3 +1,4 @@
1from datetime import datetime
1from typing import Optional2from typing import Optional
23
3from sqlalchemy.ext.asyncio import AsyncConnection4from sqlalchemy.ext.asyncio import AsyncConnection
@@ -34,9 +35,16 @@ class ResourcePoolsService(Service):
34 async def create(35 async def create(
35 self, resource_pool_request: ResourcePoolRequest36 self, resource_pool_request: ResourcePoolRequest
36 ) -> ResourcePool:37 ) -> ResourcePool:
37 return await self.resource_pools_repository.create(38 now = datetime.utcnow()
38 resource_pool_request39 resource_pool_id = await self.resource_pools_repository.get_next_id()
40 resource_pool = ResourcePool(
41 id=resource_pool_id,
42 name=resource_pool_request.name,
43 description=resource_pool_request.description,
44 updated=now,
45 created=now,
39 )46 )
47 return await self.resource_pools_repository.create(resource_pool)
4048
41 async def get_by_id(self, id: int) -> Optional[ResourcePool]:49 async def get_by_id(self, id: int) -> Optional[ResourcePool]:
42 return await self.resource_pools_repository.find_by_id(id)50 return await self.resource_pools_repository.find_by_id(id)
diff --git a/src/maasapiserver/v3/services/zones.py b/src/maasapiserver/v3/services/zones.py
index 8b6e5f3..f40f419 100644
--- a/src/maasapiserver/v3/services/zones.py
+++ b/src/maasapiserver/v3/services/zones.py
@@ -1,3 +1,4 @@
1from datetime import datetime
1from typing import Optional2from typing import Optional
23
3from sqlalchemy.ext.asyncio import AsyncConnection4from sqlalchemy.ext.asyncio import AsyncConnection
@@ -50,7 +51,16 @@ class ZonesService(Service):
50 )51 )
5152
52 async def create(self, zone_request: ZoneRequest) -> Zone:53 async def create(self, zone_request: ZoneRequest) -> Zone:
53 return await self.zones_repository.create(zone_request)54 zone_id = await self.zones_repository.get_next_id()
55 now = datetime.utcnow()
56 zone = Zone(
57 id=zone_id,
58 name=zone_request.name,
59 description=zone_request.description,
60 updated=now,
61 created=now,
62 )
63 return await self.zones_repository.create(zone)
5464
55 async def get_by_id(self, id: int) -> Optional[Zone]:65 async def get_by_id(self, id: int) -> Optional[Zone]:
56 return await self.zones_repository.find_by_id(id)66 return await self.zones_repository.find_by_id(id)
diff --git a/src/tests/maasapiserver/v3/db/test_resource_pools.py b/src/tests/maasapiserver/v3/db/test_resource_pools.py
index 6ad5feb..da0e994 100644
--- a/src/tests/maasapiserver/v3/db/test_resource_pools.py
+++ b/src/tests/maasapiserver/v3/db/test_resource_pools.py
@@ -7,9 +7,6 @@ from sqlalchemy.orm.exc import NoResultFound
77
8from maasapiserver.common.models.exceptions import AlreadyExistsException8from maasapiserver.common.models.exceptions import AlreadyExistsException
9from maasapiserver.v3.api.models.requests.query import PaginationParams9from maasapiserver.v3.api.models.requests.query import PaginationParams
10from maasapiserver.v3.api.models.requests.resource_pools import (
11 ResourcePoolRequest,
12)
13from maasapiserver.v3.db.resource_pools import ResourcePoolRepository10from maasapiserver.v3.db.resource_pools import ResourcePoolRepository
14from maasapiserver.v3.models.resource_pools import ResourcePool11from maasapiserver.v3.models.resource_pools import ResourcePool
15from tests.fixtures.factories.resource_pools import (12from tests.fixtures.factories.resource_pools import (
@@ -22,35 +19,45 @@ from tests.maasapiserver.fixtures.db import Fixture
22@pytest.mark.usefixtures("ensuremaasdb")19@pytest.mark.usefixtures("ensuremaasdb")
23@pytest.mark.asyncio20@pytest.mark.asyncio
24class TestResourcePoolRepository:21class TestResourcePoolRepository:
22 async def test_get_next_id(self, db_connection: AsyncConnection) -> None:
23 resource_pools_repository = ResourcePoolRepository(db_connection)
24 first = await resource_pools_repository.get_next_id()
25 second = await resource_pools_repository.get_next_id()
26 assert first < second
27
25 async def test_create(self, db_connection: AsyncConnection) -> None:28 async def test_create(self, db_connection: AsyncConnection) -> None:
26 now = datetime.utcnow()29 date = datetime.fromisocalendar(2024, 1, 1).astimezone(timezone.utc)
27 resource_pools_repository = ResourcePoolRepository(db_connection)30 resource_pools_repository = ResourcePoolRepository(db_connection)
28 created_resource_pools = await resource_pools_repository.create(31 created_resource_pools = await resource_pools_repository.create(
29 ResourcePoolRequest(32 ResourcePool(
30 name="my_resource_pool", description="my description"33 id=2,
34 name="my_resource_pool",
35 description="my description",
36 created=date,
37 updated=date,
31 )38 )
32 )39 )
33 assert created_resource_pools.id40 assert created_resource_pools.id
34 assert created_resource_pools.name == "my_resource_pool"41 assert created_resource_pools.name == "my_resource_pool"
35 assert created_resource_pools.description == "my description"42 assert created_resource_pools.description == "my description"
36 assert created_resource_pools.created.astimezone(43 assert created_resource_pools.created.astimezone(timezone.utc) == date
37 timezone.utc44 assert created_resource_pools.updated.astimezone(timezone.utc) == date
38 ) >= now.astimezone(timezone.utc)
39 assert created_resource_pools.updated.astimezone(
40 timezone.utc
41 ) >= now.astimezone(timezone.utc)
4245
43 async def test_create_duplicated(46 async def test_create_duplicated(
44 self, db_connection: AsyncConnection, fixture: Fixture47 self, db_connection: AsyncConnection, fixture: Fixture
45 ) -> None:48 ) -> None:
49 date = datetime.fromisocalendar(2024, 1, 1).astimezone(timezone.utc)
46 resource_pools_repository = ResourcePoolRepository(db_connection)50 resource_pools_repository = ResourcePoolRepository(db_connection)
47 created_resource_pools = await create_test_resource_pool(fixture)51 created_resource_pools = await create_test_resource_pool(fixture)
4852
49 with pytest.raises(AlreadyExistsException):53 with pytest.raises(AlreadyExistsException):
50 await resource_pools_repository.create(54 await resource_pools_repository.create(
51 ResourcePoolRequest(55 ResourcePool(
56 id=3,
52 name=created_resource_pools.name,57 name=created_resource_pools.name,
53 description=created_resource_pools.description,58 description=created_resource_pools.description,
59 created=date,
60 updated=date,
54 )61 )
55 )62 )
5663
diff --git a/src/tests/maasapiserver/v3/db/test_zones.py b/src/tests/maasapiserver/v3/db/test_zones.py
index 1104182..55367c9 100644
--- a/src/tests/maasapiserver/v3/db/test_zones.py
+++ b/src/tests/maasapiserver/v3/db/test_zones.py
@@ -11,6 +11,7 @@ from maasapiserver.v3.api.models.requests.query import PaginationParams
11from maasapiserver.v3.api.models.requests.zones import ZoneRequest11from maasapiserver.v3.api.models.requests.zones import ZoneRequest
12from maasapiserver.v3.constants import DEFAULT_ZONE_NAME12from maasapiserver.v3.constants import DEFAULT_ZONE_NAME
13from maasapiserver.v3.db.zones import ZonesRepository13from maasapiserver.v3.db.zones import ZonesRepository
14from maasapiserver.v3.models.zones import Zone
14from tests.fixtures.factories.zone import create_test_zone15from tests.fixtures.factories.zone import create_test_zone
15from tests.maasapiserver.fixtures.db import Fixture16from tests.maasapiserver.fixtures.db import Fixture
1617
@@ -18,21 +19,29 @@ from tests.maasapiserver.fixtures.db import Fixture
18@pytest.mark.usefixtures("ensuremaasdb")19@pytest.mark.usefixtures("ensuremaasdb")
19@pytest.mark.asyncio20@pytest.mark.asyncio
20class TestZonesRepository:21class TestZonesRepository:
22 async def test_get_next_id(self, db_connection: AsyncConnection) -> None:
23 zones_repository = ZonesRepository(db_connection)
24 first = await zones_repository.get_next_id()
25 second = await zones_repository.get_next_id()
26 assert first < second
27
21 async def test_create(self, db_connection: AsyncConnection) -> None:28 async def test_create(self, db_connection: AsyncConnection) -> None:
22 now = datetime.utcnow()29 date = datetime.fromisocalendar(2024, 1, 1).astimezone(timezone.utc)
23 zones_repository = ZonesRepository(db_connection)30 zones_repository = ZonesRepository(db_connection)
24 created_zone = await zones_repository.create(31 created_zone = await zones_repository.create(
25 ZoneRequest(name="my_zone", description="my description")32 Zone(
33 id=2,
34 name="my_zone",
35 description="my description",
36 created=date,
37 updated=date,
38 )
26 )39 )
27 assert created_zone.id > 140 assert created_zone.id > 1
28 assert created_zone.name == "my_zone"41 assert created_zone.name == "my_zone"
29 assert created_zone.description == "my description"42 assert created_zone.description == "my description"
30 assert created_zone.created.astimezone(timezone.utc) >= now.astimezone(43 assert created_zone.created.astimezone(timezone.utc) == date
31 timezone.utc44 assert created_zone.updated.astimezone(timezone.utc) == date
32 )
33 assert created_zone.updated.astimezone(timezone.utc) >= now.astimezone(
34 timezone.utc
35 )
3645
37 async def test_create_duplicated(46 async def test_create_duplicated(
38 self, db_connection: AsyncConnection, fixture: Fixture47 self, db_connection: AsyncConnection, fixture: Fixture
diff --git a/src/tests/maasapiserver/v3/services/test_resource_pools.py b/src/tests/maasapiserver/v3/services/test_resource_pools.py
index b3012a3..d3c5cbb 100644
--- a/src/tests/maasapiserver/v3/services/test_resource_pools.py
+++ b/src/tests/maasapiserver/v3/services/test_resource_pools.py
@@ -1,4 +1,5 @@
1from datetime import datetime1from datetime import datetime
2from typing import Any
2from unittest.mock import AsyncMock, Mock3from unittest.mock import AsyncMock, Mock
34
4import pytest5import pytest
@@ -23,6 +24,24 @@ class TestResourcePoolsService:
23 async def test_create(24 async def test_create(
24 self, db_connection: AsyncConnection, fixture: Fixture25 self, db_connection: AsyncConnection, fixture: Fixture
25 ) -> None:26 ) -> None:
27 class ResourcePoolMatcher(ResourcePool):
28 def __init__(self, **kwargs: Any) -> None:
29 kwargs["created"] = datetime.now()
30 kwargs["updated"] = datetime.now()
31 super().__init__(**kwargs)
32
33 def __eq__(self, other: Any) -> bool:
34 if not isinstance(other, ResourcePool):
35 return False
36 return (
37 self.id == other.id
38 and self.name == other.name
39 and self.description == other.description
40 and self.created >= other.created
41 and self.updated # The matcher is created after the actual resource
42 >= other.updated
43 )
44
26 now = datetime.utcnow()45 now = datetime.utcnow()
27 resource_pool = ResourcePool(46 resource_pool = ResourcePool(
28 id=1,47 id=1,
@@ -35,6 +54,7 @@ class TestResourcePoolsService:
35 resource_pool_repository_mock.create = AsyncMock(54 resource_pool_repository_mock.create = AsyncMock(
36 return_value=resource_pool55 return_value=resource_pool
37 )56 )
57 resource_pool_repository_mock.get_next_id = AsyncMock(return_value=1)
38 resource_pools_service = ResourcePoolsService(58 resource_pools_service = ResourcePoolsService(
39 connection=db_connection,59 connection=db_connection,
40 resource_pools_repository=resource_pool_repository_mock,60 resource_pools_repository=resource_pool_repository_mock,
@@ -43,7 +63,13 @@ class TestResourcePoolsService:
43 name=resource_pool.name, description=resource_pool.description63 name=resource_pool.name, description=resource_pool.description
44 )64 )
45 created_resource_pool = await resource_pools_service.create(request)65 created_resource_pool = await resource_pools_service.create(request)
46 resource_pool_repository_mock.create.assert_called_once_with(request)66 resource_pool_repository_mock.create.assert_called_once_with(
67 ResourcePoolMatcher(
68 id=1,
69 name=resource_pool.name,
70 description=resource_pool.description,
71 )
72 )
47 assert created_resource_pool is not None73 assert created_resource_pool is not None
4874
49 async def test_list(75 async def test_list(

Subscribers

People subscribed via source and target branches