|
| 1 | +import datetime |
1 | 2 | import textwrap |
2 | 3 | from functools import partial |
3 | 4 | from http import HTTPStatus |
|
7 | 8 | import pytest |
8 | 9 | from base import ViewTest |
9 | 10 | from django.urls import reverse |
| 11 | +from django.utils import timezone |
10 | 12 | from django.utils.functional import classproperty |
11 | 13 | from factories import ( |
12 | 14 | BackupPointFactory, |
@@ -167,6 +169,15 @@ def test_get_serialized_state(admin_client, item, monkeypatch): |
167 | 169 | assert resp.status_code == HTTPStatus.OK |
168 | 170 |
|
169 | 171 |
|
| 172 | +@pytest.mark.parametrize("query_params", [{}, {"sort": "test"}, {"sort": "-created"}]) |
| 173 | +@pytest.mark.django_db |
| 174 | +def test_device_results(admin_client, query_params): |
| 175 | + device = DeviceFactory() |
| 176 | + CompTestResultFactory(device=device) |
| 177 | + resp = admin_client.get(f"/dcim/devices/{device.pk}/results/", query_params) |
| 178 | + assert resp.status_code == HTTPStatus.OK |
| 179 | + |
| 180 | + |
170 | 181 | @pytest.mark.parametrize("query_params", [{}, {"sort": "device"}, {"sort": "-device"}]) |
171 | 182 | @pytest.mark.django_db |
172 | 183 | def test_report_devices(admin_client, query_params): |
@@ -263,35 +274,75 @@ def test_datasource_devices(admin_client): |
263 | 274 | assert resp.status_code == HTTPStatus.OK |
264 | 275 |
|
265 | 276 |
|
266 | | -class TestRunTests: |
267 | | - url = "/plugins/validity/tests/run/" |
| 277 | +class TestRunTestsView: |
| 278 | + """Covers RunTestsView (validity.views.script.RunTestsView).""" |
| 279 | + |
| 280 | + @staticmethod |
| 281 | + def _url(): |
| 282 | + return reverse("plugins:validity:compliancetest_run") |
268 | 283 |
|
269 | 284 | def test_get(self, admin_client): |
270 | | - resp = admin_client.get(self.url) |
| 285 | + resp = admin_client.get(self._url()) |
271 | 286 | assert resp.status_code == HTTPStatus.OK |
272 | 287 |
|
273 | 288 | @pytest.mark.parametrize( |
274 | 289 | "form_data, status_code, has_workers", |
275 | 290 | [ |
276 | 291 | ({}, HTTPStatus.FOUND, True), |
277 | 292 | ({}, HTTPStatus.OK, False), |
278 | | - ({"devices": [1, 2]}, HTTPStatus.OK, True), # devices do not exist |
| 293 | + ({"devices": [1, 2]}, HTTPStatus.OK, True), # devices do not exist — invalid choices |
279 | 294 | ], |
280 | 295 | ) |
281 | 296 | def test_post(self, admin_client, di, form_data, status_code, has_workers): |
282 | 297 | launcher = Mock(**{"has_workers": has_workers, "return_value.pk": 1}) |
283 | 298 | with di.override({dependencies.runtests_launcher: lambda: launcher}): |
284 | | - result = admin_client.post(self.url, form_data) |
| 299 | + result = admin_client.post(self._url(), form_data) |
285 | 300 | assert result.status_code == status_code |
286 | 301 | if status_code == HTTPStatus.FOUND: # if form is valid |
287 | 302 | launcher.assert_called_once() |
288 | 303 | assert isinstance(launcher.call_args.args[0], RunTestsParams) |
289 | 304 |
|
| 305 | + @pytest.mark.django_db |
| 306 | + def test_post_with_valid_devices(self, admin_client, di): |
| 307 | + d1, d2 = DeviceFactory(), DeviceFactory() |
| 308 | + launcher = Mock(has_workers=True, return_value=Mock(pk=1)) |
| 309 | + with di.override({dependencies.runtests_launcher: lambda: launcher}): |
| 310 | + resp = admin_client.post(self._url(), {"devices": [d1.pk, d2.pk]}) |
| 311 | + assert resp.status_code == HTTPStatus.FOUND |
| 312 | + launcher.assert_called_once() |
| 313 | + assert isinstance(launcher.call_args.args[0], RunTestsParams) |
| 314 | + |
290 | 315 |
|
291 | 316 | @pytest.mark.parametrize("job_factory", [RunTestsJobFactory, DSBackupJobFactory]) |
292 | | -def test_scriptresult(admin_client, job_factory): |
293 | | - job = job_factory(status="completed") |
294 | | - resp = admin_client.get(f"/plugins/validity/scripts/results/{job.pk}/") |
| 317 | +@pytest.mark.django_db |
| 318 | +def test_script_result_view_completed_job(admin_client, job_factory): |
| 319 | + """ |
| 320 | + Full GET for a finished job: ScriptResultView only builds the log table when ``job.completed`` |
| 321 | + (the *timestamp* field) is set — same as real jobs after ``terminate()``. ``status`` alone is not enough. |
| 322 | + """ |
| 323 | + completed_at = timezone.now() |
| 324 | + job = job_factory( |
| 325 | + status="completed", |
| 326 | + started=completed_at - datetime.timedelta(minutes=1), |
| 327 | + completed=completed_at, |
| 328 | + data={"output": "test output", "log": []}, |
| 329 | + ) |
| 330 | + assert job.completed, "need completion timestamp set or get_table is skipped (differs from browser)" |
| 331 | + |
| 332 | + url = reverse("plugins:validity:script_result", kwargs={"pk": job.pk}) |
| 333 | + resp = admin_client.get(url) |
| 334 | + assert resp.status_code == HTTPStatus.OK, getattr(resp, "content", b"")[:2000] |
| 335 | + |
| 336 | + |
| 337 | +@pytest.mark.parametrize("job_factory", [RunTestsJobFactory, DSBackupJobFactory]) |
| 338 | +@pytest.mark.django_db |
| 339 | +def test_script_result_view_incomplete_job(admin_client, job_factory): |
| 340 | + """Running job has no completion timestamp, so get_table is not used.""" |
| 341 | + job = job_factory(status="running", started=timezone.now()) |
| 342 | + assert not job.completed |
| 343 | + |
| 344 | + url = reverse("plugins:validity:script_result", kwargs={"pk": job.pk}) |
| 345 | + resp = admin_client.get(url) |
295 | 346 | assert resp.status_code == HTTPStatus.OK |
296 | 347 |
|
297 | 348 |
|
|
0 commit comments