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
MAAS Lander Needs Fixing
MAAS Maintainers Pending
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

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
1diff --git a/src/maasapiserver/common/db/sequences.py b/src/maasapiserver/common/db/sequences.py
2new file mode 100644
3index 0000000..963a7c6
4--- /dev/null
5+++ b/src/maasapiserver/common/db/sequences.py
6@@ -0,0 +1,4 @@
7+from sqlalchemy import Sequence
8+
9+ZoneIdSequence = Sequence("maasserver_zone_id_seq")
10+ResourcePoolIdSequence = Sequence("maasserver_resourcepool_id_seq")
11diff --git a/src/maasapiserver/v3/db/base.py b/src/maasapiserver/v3/db/base.py
12index 21ff3cf..26cea78 100644
13--- a/src/maasapiserver/v3/db/base.py
14+++ b/src/maasapiserver/v3/db/base.py
15@@ -8,15 +8,21 @@ from maasapiserver.v3.models.base import ListResult
16
17 T = TypeVar("T")
18
19-K = TypeVar("K")
20
21-
22-class BaseRepository(ABC, Generic[T, K]):
23+class BaseRepository(ABC, Generic[T]):
24 def __init__(self, connection: AsyncConnection):
25 self.connection = connection
26
27 @abstractmethod
28- async def create(self, request: K) -> T:
29+ async def get_next_id(self) -> int:
30+ """
31+ Get the next ID for a new resource. Usually, this is useful because the ID comes from a sequence defined in the
32+ database.
33+ """
34+ pass
35+
36+ @abstractmethod
37+ async def create(self, request: T) -> T:
38 pass
39
40 @abstractmethod
41diff --git a/src/maasapiserver/v3/db/bmc.py b/src/maasapiserver/v3/db/bmc.py
42index 7dee695..df07a0a 100644
43--- a/src/maasapiserver/v3/db/bmc.py
44+++ b/src/maasapiserver/v3/db/bmc.py
45@@ -2,15 +2,17 @@ from sqlalchemy import update
46 from sqlalchemy.sql.operators import eq
47
48 from maasapiserver.common.db.tables import BMCTable
49-from maasapiserver.v3.api.models.requests.bmc import BmcRequest
50 from maasapiserver.v3.api.models.requests.query import PaginationParams
51 from maasapiserver.v3.db.base import BaseRepository
52 from maasapiserver.v3.models.base import ListResult
53 from maasapiserver.v3.models.bmc import Bmc
54
55
56-class BmcRepository(BaseRepository[Bmc, BmcRequest]):
57- async def create(self, request: BmcRequest) -> Bmc:
58+class BmcRepository(BaseRepository[Bmc]):
59+ async def get_next_id(self) -> int:
60+ raise Exception("Not implemented yet.")
61+
62+ async def create(self, resource: Bmc) -> Bmc:
63 raise Exception("Not implemented yet.")
64
65 async def find_by_id(self, id: int) -> Bmc | None:
66diff --git a/src/maasapiserver/v3/db/machines.py b/src/maasapiserver/v3/db/machines.py
67index 3002fb5..85205aa 100644
68--- a/src/maasapiserver/v3/db/machines.py
69+++ b/src/maasapiserver/v3/db/machines.py
70@@ -11,7 +11,6 @@ from maasapiserver.common.db.tables import (
71 NodeTable,
72 UserTable,
73 )
74-from maasapiserver.v3.api.models.requests.machines import MachineRequest
75 from maasapiserver.v3.api.models.requests.query import PaginationParams
76 from maasapiserver.v3.db.base import BaseRepository
77 from maasapiserver.v3.models.base import ListResult
78@@ -19,8 +18,11 @@ from maasapiserver.v3.models.machines import Machine
79 from maasserver.enum import NODE_TYPE
80
81
82-class MachinesRepository(BaseRepository[Machine, MachineRequest]):
83- async def create(self, request: MachineRequest) -> Machine:
84+class MachinesRepository(BaseRepository[Machine]):
85+ async def get_next_id(self) -> int:
86+ raise Exception("Not implemented yet.")
87+
88+ async def create(self, machine: Machine) -> Machine:
89 raise Exception("Not implemented yet.")
90
91 async def find_by_id(self, id: int) -> Machine | None:
92diff --git a/src/maasapiserver/v3/db/nodes.py b/src/maasapiserver/v3/db/nodes.py
93index 2686a7a..1bf1b71 100644
94--- a/src/maasapiserver/v3/db/nodes.py
95+++ b/src/maasapiserver/v3/db/nodes.py
96@@ -2,15 +2,17 @@ from sqlalchemy import update
97 from sqlalchemy.sql.operators import eq
98
99 from maasapiserver.common.db.tables import NodeTable
100-from maasapiserver.v3.api.models.requests.nodes import NodeRequest
101 from maasapiserver.v3.api.models.requests.query import PaginationParams
102 from maasapiserver.v3.db.base import BaseRepository
103 from maasapiserver.v3.models.base import ListResult
104 from maasapiserver.v3.models.nodes import Node
105
106
107-class NodesRepository(BaseRepository[Node, NodeRequest]):
108- async def create(self, request: NodeRequest) -> Node:
109+class NodesRepository(BaseRepository[Node]):
110+ async def get_next_id(self) -> int:
111+ raise Exception("Not implemented yet.")
112+
113+ async def create(self, resource: Node) -> Node:
114 raise Exception("Not implemented yet.")
115
116 async def find_by_id(self, id: int) -> Node | None:
117diff --git a/src/maasapiserver/v3/db/resource_pools.py b/src/maasapiserver/v3/db/resource_pools.py
118index 33640ae..525847b 100644
119--- a/src/maasapiserver/v3/db/resource_pools.py
120+++ b/src/maasapiserver/v3/db/resource_pools.py
121@@ -6,6 +6,7 @@ from sqlalchemy.exc import IntegrityError
122 from sqlalchemy.sql.functions import count
123 from sqlalchemy.sql.operators import eq
124
125+from maasapiserver.common.db.sequences import ResourcePoolIdSequence
126 from maasapiserver.common.db.tables import ResourcePoolTable
127 from maasapiserver.common.models.constants import (
128 UNIQUE_CONSTRAINT_VIOLATION_TYPE,
129@@ -15,9 +16,6 @@ from maasapiserver.common.models.exceptions import (
130 BaseExceptionDetail,
131 )
132 from maasapiserver.v3.api.models.requests.query import PaginationParams
133-from maasapiserver.v3.api.models.requests.resource_pools import (
134- ResourcePoolRequest,
135-)
136 from maasapiserver.v3.db.base import BaseRepository
137 from maasapiserver.v3.models.base import ListResult
138 from maasapiserver.v3.models.resource_pools import ResourcePool
139@@ -31,9 +29,11 @@ RESOURCE_POOLS_FIELDS = (
140 )
141
142
143-class ResourcePoolRepository(
144- BaseRepository[ResourcePool, ResourcePoolRequest]
145-):
146+class ResourcePoolRepository(BaseRepository[ResourcePool]):
147+ async def get_next_id(self) -> int:
148+ stmt = select(ResourcePoolIdSequence.next_value())
149+ return (await self.connection.execute(stmt)).scalar()
150+
151 async def find_by_id(self, id: int) -> Optional[ResourcePool]:
152 stmt = self._select_all_statement().where(
153 eq(ResourcePoolTable.c.id, id)
154@@ -43,24 +43,23 @@ class ResourcePoolRepository(
155 return ResourcePool(**resource_pools._asdict())
156 return None
157
158- async def create(self, request: ResourcePoolRequest) -> ResourcePool:
159- now = datetime.utcnow()
160+ async def create(self, resource_pool: ResourcePool) -> ResourcePool:
161 stmt = (
162 insert(ResourcePoolTable)
163 .returning(*RESOURCE_POOLS_FIELDS)
164 .values(
165- name=request.name,
166- description=request.description,
167- updated=now,
168- created=now,
169+ name=resource_pool.name,
170+ description=resource_pool.description,
171+ updated=resource_pool.updated,
172+ created=resource_pool.created,
173 )
174 )
175 try:
176 result = await self.connection.execute(stmt)
177 except IntegrityError:
178- self._raise_constraint_violation(request.name)
179- resource_pools = result.one()
180- return ResourcePool(**resource_pools._asdict())
181+ self._raise_constraint_violation(resource_pool.name)
182+ created_resource_pools = result.one()
183+ return ResourcePool(**created_resource_pools._asdict())
184
185 async def list(
186 self, pagination_params: PaginationParams
187diff --git a/src/maasapiserver/v3/db/users.py b/src/maasapiserver/v3/db/users.py
188index 573b790..097c475 100644
189--- a/src/maasapiserver/v3/db/users.py
190+++ b/src/maasapiserver/v3/db/users.py
191@@ -3,14 +3,16 @@ from sqlalchemy.sql.operators import eq
192
193 from maasapiserver.common.db.tables import UserTable
194 from maasapiserver.v3.api.models.requests.query import PaginationParams
195-from maasapiserver.v3.api.models.requests.users import UserRequest
196 from maasapiserver.v3.db.base import BaseRepository
197 from maasapiserver.v3.models.base import ListResult
198 from maasapiserver.v3.models.users import User
199
200
201-class UsersRepository(BaseRepository[User, UserRequest]):
202- async def create(self, request: UserRequest) -> User:
203+class UsersRepository(BaseRepository[User]):
204+ async def get_next_id(self) -> int:
205+ raise Exception("Not implemented yet.")
206+
207+ async def create(self, resource: User) -> User:
208 raise Exception("Not implemented yet.")
209
210 async def find_by_id(self, id: int) -> User | None:
211diff --git a/src/maasapiserver/v3/db/vmcluster.py b/src/maasapiserver/v3/db/vmcluster.py
212index b0a2bbf..9153d95 100644
213--- a/src/maasapiserver/v3/db/vmcluster.py
214+++ b/src/maasapiserver/v3/db/vmcluster.py
215@@ -3,14 +3,16 @@ from sqlalchemy.sql.operators import eq
216
217 from maasapiserver.common.db.tables import VmClusterTable
218 from maasapiserver.v3.api.models.requests.query import PaginationParams
219-from maasapiserver.v3.api.models.requests.vmcluster import VmClusterRequest
220 from maasapiserver.v3.db.base import BaseRepository
221 from maasapiserver.v3.models.base import ListResult
222 from maasapiserver.v3.models.vmcluster import VmCluster
223
224
225-class VmClustersRepository(BaseRepository[VmCluster, VmClusterRequest]):
226- async def create(self, request: VmClusterRequest) -> VmCluster:
227+class VmClustersRepository(BaseRepository[VmCluster]):
228+ async def get_next_id(self) -> int:
229+ raise Exception("Not implemented yet.")
230+
231+ async def create(self, resource: VmCluster) -> VmCluster:
232 raise Exception("Not implemented yet.")
233
234 async def find_by_id(self, id: int) -> VmCluster | None:
235diff --git a/src/maasapiserver/v3/db/zones.py b/src/maasapiserver/v3/db/zones.py
236index 5325896..417e553 100644
237--- a/src/maasapiserver/v3/db/zones.py
238+++ b/src/maasapiserver/v3/db/zones.py
239@@ -1,10 +1,10 @@
240-from datetime import datetime
241 from typing import Any
242
243 from sqlalchemy import delete, desc, insert, select, Select
244 from sqlalchemy.sql.functions import count
245 from sqlalchemy.sql.operators import eq
246
247+from maasapiserver.common.db.sequences import ZoneIdSequence
248 from maasapiserver.common.db.tables import DefaultResourceTable, ZoneTable
249 from maasapiserver.common.models.constants import (
250 UNIQUE_CONSTRAINT_VIOLATION_TYPE,
251@@ -14,18 +14,21 @@ from maasapiserver.common.models.exceptions import (
252 BaseExceptionDetail,
253 )
254 from maasapiserver.v3.api.models.requests.query import PaginationParams
255-from maasapiserver.v3.api.models.requests.zones import ZoneRequest
256 from maasapiserver.v3.db.base import BaseRepository
257 from maasapiserver.v3.models.base import ListResult
258 from maasapiserver.v3.models.zones import Zone
259
260
261-class ZonesRepository(BaseRepository[Zone, ZoneRequest]):
262- async def create(self, request: ZoneRequest) -> Zone:
263+class ZonesRepository(BaseRepository[Zone]):
264+ async def get_next_id(self) -> int:
265+ stmt = select(ZoneIdSequence.next_value())
266+ return (await self.connection.execute(stmt)).scalar()
267+
268+ async def create(self, zone: Zone) -> Zone:
269 check_integrity_stmt = (
270 select(ZoneTable.c.id)
271 .select_from(ZoneTable)
272- .where(eq(ZoneTable.c.name, request.name))
273+ .where(eq(ZoneTable.c.name, zone.name))
274 .limit(1)
275 )
276 existing_entity = (
277@@ -36,12 +39,11 @@ class ZonesRepository(BaseRepository[Zone, ZoneRequest]):
278 details=[
279 BaseExceptionDetail(
280 type=UNIQUE_CONSTRAINT_VIOLATION_TYPE,
281- message=f"An entity with name '{request.name}' already exists. Its id is '{existing_entity.id}'.",
282+ message=f"An entity with name '{zone.name}' already exists. Its id is '{existing_entity.id}'.",
283 )
284 ]
285 )
286
287- now = datetime.utcnow()
288 stmt = (
289 insert(ZoneTable)
290 .returning(
291@@ -52,15 +54,16 @@ class ZonesRepository(BaseRepository[Zone, ZoneRequest]):
292 ZoneTable.c.updated,
293 )
294 .values(
295- name=request.name,
296- description=request.description,
297- updated=now,
298- created=now,
299+ id=zone.id,
300+ name=zone.name,
301+ description=zone.description,
302+ updated=zone.updated,
303+ created=zone.created,
304 )
305 )
306 result = await self.connection.execute(stmt)
307- zone = result.one()
308- return Zone(**zone._asdict())
309+ created_zone = result.one()
310+ return Zone(**created_zone._asdict())
311
312 async def find_by_id(self, id: int) -> Zone | None:
313 stmt = self._select_all_statement().filter(eq(ZoneTable.c.id, id))
314diff --git a/src/maasapiserver/v3/services/resource_pools.py b/src/maasapiserver/v3/services/resource_pools.py
315index 6862bdc..4388b31 100644
316--- a/src/maasapiserver/v3/services/resource_pools.py
317+++ b/src/maasapiserver/v3/services/resource_pools.py
318@@ -1,3 +1,4 @@
319+from datetime import datetime
320 from typing import Optional
321
322 from sqlalchemy.ext.asyncio import AsyncConnection
323@@ -34,9 +35,16 @@ class ResourcePoolsService(Service):
324 async def create(
325 self, resource_pool_request: ResourcePoolRequest
326 ) -> ResourcePool:
327- return await self.resource_pools_repository.create(
328- resource_pool_request
329+ now = datetime.utcnow()
330+ resource_pool_id = await self.resource_pools_repository.get_next_id()
331+ resource_pool = ResourcePool(
332+ id=resource_pool_id,
333+ name=resource_pool_request.name,
334+ description=resource_pool_request.description,
335+ updated=now,
336+ created=now,
337 )
338+ return await self.resource_pools_repository.create(resource_pool)
339
340 async def get_by_id(self, id: int) -> Optional[ResourcePool]:
341 return await self.resource_pools_repository.find_by_id(id)
342diff --git a/src/maasapiserver/v3/services/zones.py b/src/maasapiserver/v3/services/zones.py
343index 8b6e5f3..f40f419 100644
344--- a/src/maasapiserver/v3/services/zones.py
345+++ b/src/maasapiserver/v3/services/zones.py
346@@ -1,3 +1,4 @@
347+from datetime import datetime
348 from typing import Optional
349
350 from sqlalchemy.ext.asyncio import AsyncConnection
351@@ -50,7 +51,16 @@ class ZonesService(Service):
352 )
353
354 async def create(self, zone_request: ZoneRequest) -> Zone:
355- return await self.zones_repository.create(zone_request)
356+ zone_id = await self.zones_repository.get_next_id()
357+ now = datetime.utcnow()
358+ zone = Zone(
359+ id=zone_id,
360+ name=zone_request.name,
361+ description=zone_request.description,
362+ updated=now,
363+ created=now,
364+ )
365+ return await self.zones_repository.create(zone)
366
367 async def get_by_id(self, id: int) -> Optional[Zone]:
368 return await self.zones_repository.find_by_id(id)
369diff --git a/src/tests/maasapiserver/v3/db/test_resource_pools.py b/src/tests/maasapiserver/v3/db/test_resource_pools.py
370index 6ad5feb..da0e994 100644
371--- a/src/tests/maasapiserver/v3/db/test_resource_pools.py
372+++ b/src/tests/maasapiserver/v3/db/test_resource_pools.py
373@@ -7,9 +7,6 @@ from sqlalchemy.orm.exc import NoResultFound
374
375 from maasapiserver.common.models.exceptions import AlreadyExistsException
376 from maasapiserver.v3.api.models.requests.query import PaginationParams
377-from maasapiserver.v3.api.models.requests.resource_pools import (
378- ResourcePoolRequest,
379-)
380 from maasapiserver.v3.db.resource_pools import ResourcePoolRepository
381 from maasapiserver.v3.models.resource_pools import ResourcePool
382 from tests.fixtures.factories.resource_pools import (
383@@ -22,35 +19,45 @@ from tests.maasapiserver.fixtures.db import Fixture
384 @pytest.mark.usefixtures("ensuremaasdb")
385 @pytest.mark.asyncio
386 class TestResourcePoolRepository:
387+ async def test_get_next_id(self, db_connection: AsyncConnection) -> None:
388+ resource_pools_repository = ResourcePoolRepository(db_connection)
389+ first = await resource_pools_repository.get_next_id()
390+ second = await resource_pools_repository.get_next_id()
391+ assert first < second
392+
393 async def test_create(self, db_connection: AsyncConnection) -> None:
394- now = datetime.utcnow()
395+ date = datetime.fromisocalendar(2024, 1, 1).astimezone(timezone.utc)
396 resource_pools_repository = ResourcePoolRepository(db_connection)
397 created_resource_pools = await resource_pools_repository.create(
398- ResourcePoolRequest(
399- name="my_resource_pool", description="my description"
400+ ResourcePool(
401+ id=2,
402+ name="my_resource_pool",
403+ description="my description",
404+ created=date,
405+ updated=date,
406 )
407 )
408 assert created_resource_pools.id
409 assert created_resource_pools.name == "my_resource_pool"
410 assert created_resource_pools.description == "my description"
411- assert created_resource_pools.created.astimezone(
412- timezone.utc
413- ) >= now.astimezone(timezone.utc)
414- assert created_resource_pools.updated.astimezone(
415- timezone.utc
416- ) >= now.astimezone(timezone.utc)
417+ assert created_resource_pools.created.astimezone(timezone.utc) == date
418+ assert created_resource_pools.updated.astimezone(timezone.utc) == date
419
420 async def test_create_duplicated(
421 self, db_connection: AsyncConnection, fixture: Fixture
422 ) -> None:
423+ date = datetime.fromisocalendar(2024, 1, 1).astimezone(timezone.utc)
424 resource_pools_repository = ResourcePoolRepository(db_connection)
425 created_resource_pools = await create_test_resource_pool(fixture)
426
427 with pytest.raises(AlreadyExistsException):
428 await resource_pools_repository.create(
429- ResourcePoolRequest(
430+ ResourcePool(
431+ id=3,
432 name=created_resource_pools.name,
433 description=created_resource_pools.description,
434+ created=date,
435+ updated=date,
436 )
437 )
438
439diff --git a/src/tests/maasapiserver/v3/db/test_zones.py b/src/tests/maasapiserver/v3/db/test_zones.py
440index 1104182..55367c9 100644
441--- a/src/tests/maasapiserver/v3/db/test_zones.py
442+++ b/src/tests/maasapiserver/v3/db/test_zones.py
443@@ -11,6 +11,7 @@ from maasapiserver.v3.api.models.requests.query import PaginationParams
444 from maasapiserver.v3.api.models.requests.zones import ZoneRequest
445 from maasapiserver.v3.constants import DEFAULT_ZONE_NAME
446 from maasapiserver.v3.db.zones import ZonesRepository
447+from maasapiserver.v3.models.zones import Zone
448 from tests.fixtures.factories.zone import create_test_zone
449 from tests.maasapiserver.fixtures.db import Fixture
450
451@@ -18,21 +19,29 @@ from tests.maasapiserver.fixtures.db import Fixture
452 @pytest.mark.usefixtures("ensuremaasdb")
453 @pytest.mark.asyncio
454 class TestZonesRepository:
455+ async def test_get_next_id(self, db_connection: AsyncConnection) -> None:
456+ zones_repository = ZonesRepository(db_connection)
457+ first = await zones_repository.get_next_id()
458+ second = await zones_repository.get_next_id()
459+ assert first < second
460+
461 async def test_create(self, db_connection: AsyncConnection) -> None:
462- now = datetime.utcnow()
463+ date = datetime.fromisocalendar(2024, 1, 1).astimezone(timezone.utc)
464 zones_repository = ZonesRepository(db_connection)
465 created_zone = await zones_repository.create(
466- ZoneRequest(name="my_zone", description="my description")
467+ Zone(
468+ id=2,
469+ name="my_zone",
470+ description="my description",
471+ created=date,
472+ updated=date,
473+ )
474 )
475 assert created_zone.id > 1
476 assert created_zone.name == "my_zone"
477 assert created_zone.description == "my description"
478- assert created_zone.created.astimezone(timezone.utc) >= now.astimezone(
479- timezone.utc
480- )
481- assert created_zone.updated.astimezone(timezone.utc) >= now.astimezone(
482- timezone.utc
483- )
484+ assert created_zone.created.astimezone(timezone.utc) == date
485+ assert created_zone.updated.astimezone(timezone.utc) == date
486
487 async def test_create_duplicated(
488 self, db_connection: AsyncConnection, fixture: Fixture
489diff --git a/src/tests/maasapiserver/v3/services/test_resource_pools.py b/src/tests/maasapiserver/v3/services/test_resource_pools.py
490index b3012a3..d3c5cbb 100644
491--- a/src/tests/maasapiserver/v3/services/test_resource_pools.py
492+++ b/src/tests/maasapiserver/v3/services/test_resource_pools.py
493@@ -1,4 +1,5 @@
494 from datetime import datetime
495+from typing import Any
496 from unittest.mock import AsyncMock, Mock
497
498 import pytest
499@@ -23,6 +24,24 @@ class TestResourcePoolsService:
500 async def test_create(
501 self, db_connection: AsyncConnection, fixture: Fixture
502 ) -> None:
503+ class ResourcePoolMatcher(ResourcePool):
504+ def __init__(self, **kwargs: Any) -> None:
505+ kwargs["created"] = datetime.now()
506+ kwargs["updated"] = datetime.now()
507+ super().__init__(**kwargs)
508+
509+ def __eq__(self, other: Any) -> bool:
510+ if not isinstance(other, ResourcePool):
511+ return False
512+ return (
513+ self.id == other.id
514+ and self.name == other.name
515+ and self.description == other.description
516+ and self.created >= other.created
517+ and self.updated # The matcher is created after the actual resource
518+ >= other.updated
519+ )
520+
521 now = datetime.utcnow()
522 resource_pool = ResourcePool(
523 id=1,
524@@ -35,6 +54,7 @@ class TestResourcePoolsService:
525 resource_pool_repository_mock.create = AsyncMock(
526 return_value=resource_pool
527 )
528+ resource_pool_repository_mock.get_next_id = AsyncMock(return_value=1)
529 resource_pools_service = ResourcePoolsService(
530 connection=db_connection,
531 resource_pools_repository=resource_pool_repository_mock,
532@@ -43,7 +63,13 @@ class TestResourcePoolsService:
533 name=resource_pool.name, description=resource_pool.description
534 )
535 created_resource_pool = await resource_pools_service.create(request)
536- resource_pool_repository_mock.create.assert_called_once_with(request)
537+ resource_pool_repository_mock.create.assert_called_once_with(
538+ ResourcePoolMatcher(
539+ id=1,
540+ name=resource_pool.name,
541+ description=resource_pool.description,
542+ )
543+ )
544 assert created_resource_pool is not None
545
546 async def test_list(

Subscribers

People subscribed via source and target branches