Merge ~lloydwaltersj/maas:machine-get into maas:master
- Git
- lp:~lloydwaltersj/maas
- machine-get
- Merge into master
Status: | Merged |
---|---|
Approved by: | Jacopo Rota |
Approved revision: | e9658ae891d0e3ad8ee318a95530eecf1969d1ec |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~lloydwaltersj/maas:machine-get |
Merge into: | maas:master |
Diff against target: |
540 lines (+436/-0) 12 files modified
src/maasapiserver/v3/api/handlers/__init__.py (+2/-0) src/maasapiserver/v3/api/handlers/machines.py (+44/-0) src/maasapiserver/v3/api/models/requests/machines.py (+6/-0) src/maasapiserver/v3/api/models/responses/machines.py (+48/-0) src/maasapiserver/v3/db/machines.py (+90/-0) src/maasapiserver/v3/models/machines.py (+48/-0) src/maasapiserver/v3/services/__init__.py (+3/-0) src/maasapiserver/v3/services/machines.py (+26/-0) src/tests/fixtures/factories/machines.py (+29/-0) src/tests/fixtures/factories/node.py (+2/-0) src/tests/maasapiserver/v3/api/test_machines.py (+87/-0) src/tests/maasapiserver/v3/db/test_machines.py (+51/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jacopo Rota | Approve | ||
MAAS Lander | Approve | ||
Review via email: mp+463595@code.launchpad.net |
Commit message
MAASENG-2951: Add v3 api /machines GET
Description of the change
- 9cad4f4... by Jack Lloyd-Walters
-
join with other tables
- b31ceb6... by Jack Lloyd-Walters
-
fix fixtures
- 0cd96ca... by Jack Lloyd-Walters
-
linting
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b machine-get lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: FAILED
LOG: http://
COMMIT: 0cd96ca0d0e6daa
- b016757... by Jack Lloyd-Walters
-
linting
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b machine-get lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: FAILED
LOG: http://
COMMIT: b016757ec7e4773
- 9f56aee... by Jack Lloyd-Walters
-
ensure fixtures have data
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b machine-get lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: SUCCESS
COMMIT: 9f56aee146f0ae0
Jacopo Rota (r00ta) wrote : | # |
It looks good to me, I have just a small question
- e9658ae... by Jack Lloyd-Walters
-
fix according to feedback
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b machine-get lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: SUCCESS
COMMIT: e9658ae891d0e3a
Preview Diff
1 | diff --git a/src/maasapiserver/v3/api/handlers/__init__.py b/src/maasapiserver/v3/api/handlers/__init__.py |
2 | index e28615e..865492c 100644 |
3 | --- a/src/maasapiserver/v3/api/handlers/__init__.py |
4 | +++ b/src/maasapiserver/v3/api/handlers/__init__.py |
5 | @@ -1,5 +1,6 @@ |
6 | from maasapiserver.common.api.base import API |
7 | from maasapiserver.v3.api.handlers.auth import AuthHandler |
8 | +from maasapiserver.v3.api.handlers.machines import MachinesHandler |
9 | from maasapiserver.v3.api.handlers.resource_pools import ResourcePoolHandler |
10 | from maasapiserver.v3.api.handlers.root import RootHandler |
11 | from maasapiserver.v3.api.handlers.zones import ZonesHandler |
12 | @@ -12,5 +13,6 @@ APIv3 = API( |
13 | ZonesHandler(), |
14 | ResourcePoolHandler(), |
15 | AuthHandler(), |
16 | + MachinesHandler(), |
17 | ], |
18 | ) |
19 | diff --git a/src/maasapiserver/v3/api/handlers/machines.py b/src/maasapiserver/v3/api/handlers/machines.py |
20 | new file mode 100644 |
21 | index 0000000..13a2761 |
22 | --- /dev/null |
23 | +++ b/src/maasapiserver/v3/api/handlers/machines.py |
24 | @@ -0,0 +1,44 @@ |
25 | +from fastapi import Depends, Response |
26 | + |
27 | +from maasapiserver.common.api.base import Handler, handler |
28 | +from maasapiserver.common.api.models.responses.errors import ( |
29 | + ValidationErrorBodyResponse, |
30 | +) |
31 | +from maasapiserver.v3.api import services |
32 | +from maasapiserver.v3.api.models.requests.query import PaginationParams |
33 | +from maasapiserver.v3.api.models.responses.machines import MachinesListResponse |
34 | +from maasapiserver.v3.constants import EXTERNAL_V3_API_PREFIX |
35 | +from maasapiserver.v3.services import ServiceCollectionV3 |
36 | + |
37 | + |
38 | +class MachinesHandler(Handler): |
39 | + """Machines API handler.""" |
40 | + |
41 | + TAGS = ["Machines"] |
42 | + |
43 | + @handler( |
44 | + path="/machines", |
45 | + methods=["GET"], |
46 | + tags=TAGS, |
47 | + responses={ |
48 | + 200: { |
49 | + "model": MachinesListResponse, |
50 | + }, |
51 | + 422: {"model": ValidationErrorBodyResponse}, |
52 | + }, |
53 | + response_model_exclude_none=True, |
54 | + status_code=200, |
55 | + ) |
56 | + async def list_machines( |
57 | + self, |
58 | + pagination_params: PaginationParams = Depends(), |
59 | + services: ServiceCollectionV3 = Depends(services), |
60 | + ) -> Response: |
61 | + machines = await services.machines.list(pagination_params) |
62 | + return MachinesListResponse( |
63 | + items=[ |
64 | + machine.to_response(f"{EXTERNAL_V3_API_PREFIX}/machines") |
65 | + for machine in machines.items |
66 | + ], |
67 | + total=machines.total, |
68 | + ) |
69 | diff --git a/src/maasapiserver/v3/api/models/requests/machines.py b/src/maasapiserver/v3/api/models/requests/machines.py |
70 | new file mode 100644 |
71 | index 0000000..54aac9d |
72 | --- /dev/null |
73 | +++ b/src/maasapiserver/v3/api/models/requests/machines.py |
74 | @@ -0,0 +1,6 @@ |
75 | +from maasapiserver.v3.api.models.requests.base import NamedBaseModel |
76 | + |
77 | + |
78 | +class MachineRequest(NamedBaseModel): |
79 | + # TODO |
80 | + pass |
81 | diff --git a/src/maasapiserver/v3/api/models/responses/machines.py b/src/maasapiserver/v3/api/models/responses/machines.py |
82 | new file mode 100644 |
83 | index 0000000..038b133 |
84 | --- /dev/null |
85 | +++ b/src/maasapiserver/v3/api/models/responses/machines.py |
86 | @@ -0,0 +1,48 @@ |
87 | +from enum import Enum |
88 | + |
89 | +from maasapiserver.v3.api.models.responses.base import ( |
90 | + BaseHal, |
91 | + HalResponse, |
92 | + PaginatedResponse, |
93 | +) |
94 | +from maasserver.enum import NODE_STATUS_CHOICES |
95 | +from provisioningserver.drivers.pod.lxd import LXDPodDriver |
96 | +from provisioningserver.drivers.pod.virsh import VirshPodDriver |
97 | +from provisioningserver.drivers.power.registry import power_drivers |
98 | + |
99 | +MachineStatusEnum = Enum( |
100 | + "MachineStatus", |
101 | + dict({str(name).lower(): int(code) for code, name in NODE_STATUS_CHOICES}), |
102 | +) |
103 | +PowerTypeEnum = Enum( |
104 | + "PowerType", |
105 | + dict( |
106 | + { |
107 | + str(driver.name).lower(): str(driver.name).lower() |
108 | + for driver in power_drivers + [LXDPodDriver(), VirshPodDriver()] |
109 | + } |
110 | + ), |
111 | +) |
112 | + |
113 | + |
114 | +class MachineResponse(HalResponse[BaseHal]): |
115 | + kind = "Machine" |
116 | + id: int |
117 | + system_id: str |
118 | + description: str |
119 | + owner: str |
120 | + cpu_speed_MHz: int |
121 | + memory_MiB: int |
122 | + osystem: str |
123 | + architecture: str |
124 | + distro_series: str |
125 | + hwe_kernel: str |
126 | + locked: bool |
127 | + cpu_count: int |
128 | + status: MachineStatusEnum |
129 | + power_type: PowerTypeEnum |
130 | + fqdn: str |
131 | + |
132 | + |
133 | +class MachinesListResponse(PaginatedResponse[MachineResponse]): |
134 | + kind = "MachinesList" |
135 | diff --git a/src/maasapiserver/v3/db/machines.py b/src/maasapiserver/v3/db/machines.py |
136 | new file mode 100644 |
137 | index 0000000..f17ddad |
138 | --- /dev/null |
139 | +++ b/src/maasapiserver/v3/db/machines.py |
140 | @@ -0,0 +1,90 @@ |
141 | +from typing import Any |
142 | + |
143 | +from sqlalchemy import desc, select, Select |
144 | +from sqlalchemy.sql.expression import func |
145 | +from sqlalchemy.sql.functions import count |
146 | +from sqlalchemy.sql.operators import eq |
147 | + |
148 | +from maasapiserver.common.db.tables import ( |
149 | + BMCTable, |
150 | + DomainTable, |
151 | + NodeTable, |
152 | + UserTable, |
153 | +) |
154 | +from maasapiserver.v3.api.models.requests.machines import MachineRequest |
155 | +from maasapiserver.v3.api.models.requests.query import PaginationParams |
156 | +from maasapiserver.v3.db.base import BaseRepository |
157 | +from maasapiserver.v3.models.base import ListResult |
158 | +from maasapiserver.v3.models.machines import Machine |
159 | + |
160 | + |
161 | +class MachinesRepository(BaseRepository[Machine, MachineRequest]): |
162 | + async def create(self, request: MachineRequest) -> Machine: |
163 | + raise Exception("Not implemented yet.") |
164 | + |
165 | + async def find_by_id(self, id: int) -> Machine | None: |
166 | + raise Exception("Not implemented yet.") |
167 | + |
168 | + async def list( |
169 | + self, pagination_params: PaginationParams |
170 | + ) -> ListResult[Machine]: |
171 | + total_stmt = select(count()).select_from(NodeTable) |
172 | + total = (await self.connection.execute(total_stmt)).scalar() |
173 | + |
174 | + stmt = ( |
175 | + self._select_all_statement() |
176 | + .order_by(desc(NodeTable.c.id)) |
177 | + .offset((pagination_params.page - 1) * pagination_params.size) |
178 | + .limit(pagination_params.size) |
179 | + ) |
180 | + |
181 | + result = await self.connection.execute(stmt) |
182 | + return ListResult[Machine]( |
183 | + items=[Machine(**row._asdict()) for row in result.all()], |
184 | + total=total, |
185 | + ) |
186 | + |
187 | + async def update(self, resource: Machine) -> Machine: |
188 | + raise Exception("Not implemented yet.") |
189 | + |
190 | + async def delete(self, id: int) -> None: |
191 | + raise Exception("Not implemented yet.") |
192 | + |
193 | + def _select_all_statement(self) -> Select[Any]: |
194 | + return ( |
195 | + select( |
196 | + NodeTable.c.id, |
197 | + NodeTable.c.system_id, |
198 | + NodeTable.c.created, |
199 | + NodeTable.c.updated, |
200 | + func.coalesce(UserTable.c.username, "").label("owner"), |
201 | + NodeTable.c.description, |
202 | + NodeTable.c.cpu_speed, |
203 | + NodeTable.c.memory, |
204 | + NodeTable.c.osystem, |
205 | + NodeTable.c.architecture, |
206 | + NodeTable.c.distro_series, |
207 | + NodeTable.c.hwe_kernel, |
208 | + NodeTable.c.locked, |
209 | + NodeTable.c.cpu_count, |
210 | + NodeTable.c.status, |
211 | + BMCTable.c.power_type, |
212 | + func.concat( |
213 | + NodeTable.c.hostname, ".", DomainTable.c.name |
214 | + ).label("fqdn"), |
215 | + ) |
216 | + .select_from(NodeTable) |
217 | + .join( |
218 | + DomainTable, |
219 | + eq(DomainTable.c.id, NodeTable.c.domain_id), |
220 | + isouter=True, |
221 | + ) |
222 | + .join( |
223 | + UserTable, |
224 | + eq(UserTable.c.id, NodeTable.c.owner_id), |
225 | + isouter=True, |
226 | + ) |
227 | + .join( |
228 | + BMCTable, eq(BMCTable.c.id, NodeTable.c.bmc_id), isouter=True |
229 | + ) |
230 | + ) |
231 | diff --git a/src/maasapiserver/v3/models/machines.py b/src/maasapiserver/v3/models/machines.py |
232 | new file mode 100644 |
233 | index 0000000..8b89862 |
234 | --- /dev/null |
235 | +++ b/src/maasapiserver/v3/models/machines.py |
236 | @@ -0,0 +1,48 @@ |
237 | +from maasapiserver.v3.api.models.responses.base import BaseHal, BaseHref |
238 | +from maasapiserver.v3.api.models.responses.machines import ( |
239 | + MachineResponse, |
240 | + MachineStatusEnum, |
241 | + PowerTypeEnum, |
242 | +) |
243 | +from maasapiserver.v3.models.base import MaasTimestampedBaseModel |
244 | + |
245 | + |
246 | +class Machine(MaasTimestampedBaseModel): |
247 | + system_id: str |
248 | + description: str |
249 | + owner: str |
250 | + cpu_speed: int |
251 | + memory: int |
252 | + osystem: str |
253 | + architecture: str |
254 | + distro_series: str |
255 | + hwe_kernel: str |
256 | + locked: bool |
257 | + cpu_count: int |
258 | + status: MachineStatusEnum |
259 | + power_type: PowerTypeEnum |
260 | + fqdn: str |
261 | + |
262 | + def to_response(self, self_base_hyperlink: str) -> MachineResponse: |
263 | + return MachineResponse( |
264 | + id=self.id, |
265 | + system_id=self.system_id, |
266 | + description=self.description, |
267 | + owner=self.owner, |
268 | + cpu_speed_MHz=self.cpu_speed, |
269 | + memory_MiB=self.memory, |
270 | + osystem=self.osystem, |
271 | + architecture=self.architecture, |
272 | + distro_series=self.distro_series, |
273 | + hwe_kernel=self.hwe_kernel, |
274 | + locked=self.locked, |
275 | + cpu_count=self.cpu_count, |
276 | + status=self.status, |
277 | + power_type=self.power_type, |
278 | + fqdn=self.fqdn, |
279 | + hal_links=BaseHal( |
280 | + self=BaseHref( |
281 | + href=f"{self_base_hyperlink.rstrip('/')}/{self.id}" |
282 | + ) |
283 | + ), |
284 | + ) |
285 | diff --git a/src/maasapiserver/v3/services/__init__.py b/src/maasapiserver/v3/services/__init__.py |
286 | index 2eac400..51628e0 100644 |
287 | --- a/src/maasapiserver/v3/services/__init__.py |
288 | +++ b/src/maasapiserver/v3/services/__init__.py |
289 | @@ -3,6 +3,7 @@ from sqlalchemy.ext.asyncio import AsyncConnection |
290 | from maasapiserver.v3.services.auth import AuthService |
291 | from maasapiserver.v3.services.bmc import BmcService |
292 | from maasapiserver.v3.services.configurations import ConfigurationsService |
293 | +from maasapiserver.v3.services.machines import MachinesService |
294 | from maasapiserver.v3.services.nodes import NodesService |
295 | from maasapiserver.v3.services.resource_pools import ResourcePoolsService |
296 | from maasapiserver.v3.services.secrets import ( |
297 | @@ -25,6 +26,7 @@ class ServiceCollectionV3: |
298 | configurations: ConfigurationsService |
299 | resource_pools: ResourcePoolsService |
300 | auth: AuthService |
301 | + machines: MachinesService |
302 | |
303 | @classmethod |
304 | async def produce( |
305 | @@ -51,4 +53,5 @@ class ServiceCollectionV3: |
306 | bmc_service=services.bmc, |
307 | ) |
308 | services.resource_pools = ResourcePoolsService(connection=connection) |
309 | + services.machines = MachinesService(connection=connection) |
310 | return services |
311 | diff --git a/src/maasapiserver/v3/services/machines.py b/src/maasapiserver/v3/services/machines.py |
312 | new file mode 100644 |
313 | index 0000000..171ec23 |
314 | --- /dev/null |
315 | +++ b/src/maasapiserver/v3/services/machines.py |
316 | @@ -0,0 +1,26 @@ |
317 | +from sqlalchemy.ext.asyncio import AsyncConnection |
318 | + |
319 | +from maasapiserver.common.services._base import Service |
320 | +from maasapiserver.v3.api.models.requests.query import PaginationParams |
321 | +from maasapiserver.v3.db.machines import MachinesRepository |
322 | +from maasapiserver.v3.models.base import ListResult |
323 | +from maasapiserver.v3.models.machines import Machine |
324 | + |
325 | + |
326 | +class MachinesService(Service): |
327 | + def __init__( |
328 | + self, |
329 | + connection: AsyncConnection, |
330 | + machines_repository: MachinesRepository | None = None, |
331 | + ): |
332 | + super().__init__(connection) |
333 | + self.machines_repository = ( |
334 | + machines_repository |
335 | + if machines_repository |
336 | + else MachinesRepository(connection) |
337 | + ) |
338 | + |
339 | + async def list( |
340 | + self, pagination_params: PaginationParams |
341 | + ) -> ListResult[Machine]: |
342 | + return await self.machines_repository.list(pagination_params) |
343 | diff --git a/src/tests/fixtures/factories/machines.py b/src/tests/fixtures/factories/machines.py |
344 | new file mode 100644 |
345 | index 0000000..235dba6 |
346 | --- /dev/null |
347 | +++ b/src/tests/fixtures/factories/machines.py |
348 | @@ -0,0 +1,29 @@ |
349 | +from typing import Any |
350 | + |
351 | +from maasapiserver.v3.api.models.responses.machines import PowerTypeEnum |
352 | +from maasapiserver.v3.models.bmc import Bmc |
353 | +from maasapiserver.v3.models.machines import Machine |
354 | +from maasapiserver.v3.models.users import User |
355 | +from tests.fixtures.factories.node import create_test_machine_entry |
356 | +from tests.maasapiserver.fixtures.db import Fixture |
357 | + |
358 | + |
359 | +async def create_test_machine( |
360 | + fixture: Fixture, bmc: Bmc, user: User, **extra_details: Any |
361 | +) -> Machine: |
362 | + created_machine = await create_test_machine_entry( |
363 | + fixture, |
364 | + bmc_id=bmc.id, |
365 | + owner_id=user.id, |
366 | + osystem="ubuntu", |
367 | + distro_series="jammy", |
368 | + archtecture="amd64", |
369 | + hwe_kernel="hwe-22.04", |
370 | + **extra_details, |
371 | + ) |
372 | + created_machine["owner"] = user.username |
373 | + created_machine["power_type"] = PowerTypeEnum.virsh.name |
374 | + created_machine["fqdn"] = f"{created_machine['hostname']}." |
375 | + return Machine( |
376 | + **created_machine, |
377 | + ) |
378 | diff --git a/src/tests/fixtures/factories/node.py b/src/tests/fixtures/factories/node.py |
379 | index 6798f13..7cfeaff 100644 |
380 | --- a/src/tests/fixtures/factories/node.py |
381 | +++ b/src/tests/fixtures/factories/node.py |
382 | @@ -74,6 +74,8 @@ async def _create_test_node_entry( |
383 | "last_applied_storage_layout": "flat", |
384 | "enable_hw_sync": False, |
385 | "node_type": node_type, |
386 | + "architecture": "", |
387 | + "hwe_kernel": "", |
388 | } |
389 | node.update(extra_details) |
390 | [created_node] = await fixture.create( |
391 | diff --git a/src/tests/maasapiserver/v3/api/test_machines.py b/src/tests/maasapiserver/v3/api/test_machines.py |
392 | new file mode 100644 |
393 | index 0000000..d40da3d |
394 | --- /dev/null |
395 | +++ b/src/tests/maasapiserver/v3/api/test_machines.py |
396 | @@ -0,0 +1,87 @@ |
397 | +from httpx import AsyncClient |
398 | +import pytest |
399 | + |
400 | +from maasapiserver.common.api.models.responses.errors import ErrorBodyResponse |
401 | +from maasapiserver.v3.api.models.responses.machines import MachinesListResponse |
402 | +from maasapiserver.v3.constants import EXTERNAL_V3_API_PREFIX |
403 | +from maasapiserver.v3.models.machines import Machine |
404 | +from tests.fixtures.factories.bmc import create_test_bmc |
405 | +from tests.fixtures.factories.machines import create_test_machine |
406 | +from tests.fixtures.factories.user import create_test_user |
407 | +from tests.maasapiserver.fixtures.db import Fixture |
408 | + |
409 | + |
410 | +@pytest.mark.usefixtures("ensuremaasdb") |
411 | +@pytest.mark.asyncio |
412 | +class TestMachinesApi: |
413 | + def _assert_machine_in_list( |
414 | + self, machine: Machine, machines_response: MachinesListResponse |
415 | + ) -> None: |
416 | + machine_response = next( |
417 | + filter( |
418 | + lambda machine_response: machine.id == machine_response.id, |
419 | + machines_response.items, |
420 | + ) |
421 | + ) |
422 | + assert machine.id == machine_response.id |
423 | + assert ( |
424 | + machine.to_response(f"{EXTERNAL_V3_API_PREFIX}/machines") |
425 | + == machine_response |
426 | + ) |
427 | + |
428 | + @pytest.mark.parametrize("machines_size", range(0, 10)) |
429 | + async def test_list_parameters_200( |
430 | + self, |
431 | + api_client: AsyncClient, |
432 | + fixture: Fixture, |
433 | + machines_size: int, |
434 | + ) -> None: |
435 | + bmc = await create_test_bmc(fixture) |
436 | + user = await create_test_user(fixture) |
437 | + created_machines = [ |
438 | + ( |
439 | + await create_test_machine( |
440 | + fixture, description=str(i), bmc=bmc, user=user |
441 | + ) |
442 | + ) |
443 | + for i in range(0, machines_size) |
444 | + ] |
445 | + |
446 | + response = await api_client.get("/api/v3/machines") |
447 | + assert response.status_code == 200 |
448 | + |
449 | + machines_response = MachinesListResponse(**response.json()) |
450 | + assert machines_response.kind == "MachinesList" |
451 | + assert machines_response.total == machines_size |
452 | + assert len(machines_response.items) == machines_size |
453 | + for machine in created_machines: |
454 | + self._assert_machine_in_list(machine, machines_response) |
455 | + |
456 | + for page in range(1, machines_size // 2): |
457 | + response = await api_client.get( |
458 | + f"/api/v3/machines?page={page}&size=2" |
459 | + ) |
460 | + assert response.status_code == 200 |
461 | + machines_response = MachinesListResponse(**response.json()) |
462 | + assert machines_response.kind == "MachinesList" |
463 | + assert machines_response.total == machines_size |
464 | + assert ( |
465 | + len(machines_response.items) == 2 |
466 | + if page != machines_size // 2 |
467 | + else (machines_size % 2 or 2) |
468 | + ) |
469 | + |
470 | + @pytest.mark.parametrize( |
471 | + "page,size", [(1, 0), (0, 1), (-1, -1), (1, 1001)] |
472 | + ) |
473 | + async def test_list_422( |
474 | + self, page: int, size: int, api_client: AsyncClient |
475 | + ) -> None: |
476 | + response = await api_client.get( |
477 | + f"/api/v3/machines?page={page}&size={size}" |
478 | + ) |
479 | + assert response.status_code == 422 |
480 | + |
481 | + error_response = ErrorBodyResponse(**response.json()) |
482 | + assert error_response.kind == "Error" |
483 | + assert error_response.code == 422 |
484 | diff --git a/src/tests/maasapiserver/v3/db/test_machines.py b/src/tests/maasapiserver/v3/db/test_machines.py |
485 | new file mode 100644 |
486 | index 0000000..b079c63 |
487 | --- /dev/null |
488 | +++ b/src/tests/maasapiserver/v3/db/test_machines.py |
489 | @@ -0,0 +1,51 @@ |
490 | +from math import ceil |
491 | + |
492 | +import pytest |
493 | +from sqlalchemy.ext.asyncio import AsyncConnection |
494 | + |
495 | +from maasapiserver.v3.api.models.requests.query import PaginationParams |
496 | +from maasapiserver.v3.db.machines import MachinesRepository |
497 | +from tests.fixtures.factories.bmc import create_test_bmc |
498 | +from tests.fixtures.factories.machines import create_test_machine |
499 | +from tests.fixtures.factories.user import create_test_user |
500 | +from tests.maasapiserver.fixtures.db import Fixture |
501 | + |
502 | + |
503 | +@pytest.mark.usefixtures("ensuremaasdb") |
504 | +@pytest.mark.asyncio |
505 | +class TestMachinesRepository: |
506 | + @pytest.mark.parametrize("page_size", range(1, 12)) |
507 | + async def test_list( |
508 | + self, page_size: int, db_connection: AsyncConnection, fixture: Fixture |
509 | + ) -> None: |
510 | + bmc = await create_test_bmc(fixture) |
511 | + user = await create_test_user(fixture) |
512 | + |
513 | + machine_count = 10 |
514 | + machines_repository = MachinesRepository(db_connection) |
515 | + created_machines = [ |
516 | + ( |
517 | + await create_test_machine( |
518 | + fixture, description=str(i), bmc=bmc, user=user |
519 | + ) |
520 | + ) |
521 | + for i in range(0, machine_count) |
522 | + ][::-1] |
523 | + total_pages = ceil(machine_count / page_size) |
524 | + for page in range(1, total_pages + 1): |
525 | + machines_result = await machines_repository.list( |
526 | + PaginationParams(size=page_size, page=page) |
527 | + ) |
528 | + assert machines_result.total == machine_count |
529 | + assert total_pages == ceil(machines_result.total / page_size) |
530 | + if page == total_pages: # last page may have fewer elements |
531 | + assert len(machines_result.items) == ( |
532 | + page_size |
533 | + - ((total_pages * page_size) % machines_result.total) |
534 | + ) |
535 | + else: |
536 | + assert len(machines_result.items) == page_size |
537 | + for machine in created_machines[ |
538 | + ((page - 1) * page_size) : ((page * page_size)) |
539 | + ]: |
540 | + assert machine in machines_result.items |
UNIT TESTS
-b machine-get lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: FAILED maas-ci. internal: 8080/job/ maas-tester/ 5205/console 9f4e2b42dd9f6e3 639476e794
LOG: http://
COMMIT: 8e84d91472ad210