|
21 | 21 |
|
22 | 22 | from tests.common.db.oidc import GitHubPublisherFactory
|
23 | 23 | from warehouse.admin.views import projects as views
|
| 24 | +from warehouse.observations.models import ObservationKind |
24 | 25 | from warehouse.packaging.models import Project, Role
|
25 | 26 | from warehouse.packaging.tasks import update_release_description
|
26 | 27 | from warehouse.search.tasks import reindex_project
|
27 | 28 |
|
28 | 29 | from ....common.db.accounts import UserFactory
|
| 30 | +from ....common.db.observations import ObserverFactory |
29 | 31 | from ....common.db.packaging import (
|
30 | 32 | JournalEntryFactory,
|
31 | 33 | ProjectFactory,
|
| 34 | + ProjectObservationFactory, |
32 | 35 | ReleaseFactory,
|
33 | 36 | RoleFactory,
|
34 | 37 | )
|
@@ -101,6 +104,8 @@ def test_gets_project(self, db_request):
|
101 | 104 | "MAX_PROJECT_SIZE": views.MAX_PROJECT_SIZE,
|
102 | 105 | "ONE_GB": views.ONE_GB,
|
103 | 106 | "UPLOAD_LIMIT_CAP": views.UPLOAD_LIMIT_CAP,
|
| 107 | + "observation_kinds": ObservationKind, |
| 108 | + "observations": [], |
104 | 109 | }
|
105 | 110 |
|
106 | 111 | def test_non_normalized_name(self, db_request):
|
@@ -128,6 +133,8 @@ def test_gets_release(self, db_request):
|
128 | 133 | assert views.release_detail(release, db_request) == {
|
129 | 134 | "release": release,
|
130 | 135 | "journals": journals,
|
| 136 | + "observation_kinds": ObservationKind, |
| 137 | + "observations": [], |
131 | 138 | }
|
132 | 139 |
|
133 | 140 | def test_release_render(self, db_request):
|
@@ -157,6 +164,80 @@ def test_release_render(self, db_request):
|
157 | 164 | ]
|
158 | 165 |
|
159 | 166 |
|
| 167 | +class TestReleaseAddObservation: |
| 168 | + def test_add_observation(self, db_request): |
| 169 | + release = ReleaseFactory.create() |
| 170 | + user = UserFactory.create() |
| 171 | + db_request.route_path = pretend.call_recorder( |
| 172 | + lambda *a, **kw: "/admin/projects/" |
| 173 | + ) |
| 174 | + db_request.matchdict["project_name"] = release.project.normalized_name |
| 175 | + db_request.POST["kind"] = ObservationKind.IsSpam.value[0] |
| 176 | + db_request.POST["summary"] = "This is a summary" |
| 177 | + db_request.user = user |
| 178 | + |
| 179 | + views.add_release_observation(release, db_request) |
| 180 | + |
| 181 | + assert len(release.observations) == 1 |
| 182 | + |
| 183 | + def test_no_kind_errors(self): |
| 184 | + release = pretend.stub( |
| 185 | + project=pretend.stub(name="foo", normalized_name="foo"), version="1.0" |
| 186 | + ) |
| 187 | + request = pretend.stub( |
| 188 | + POST={}, |
| 189 | + session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)), |
| 190 | + route_path=lambda *a, **kw: "/foo/bar/", |
| 191 | + ) |
| 192 | + |
| 193 | + with pytest.raises(HTTPSeeOther) as exc: |
| 194 | + views.add_release_observation(release, request) |
| 195 | + assert exc.value.status_code == 303 |
| 196 | + assert exc.value.headers["Location"] == "/foo/bar/" |
| 197 | + |
| 198 | + assert request.session.flash.calls == [ |
| 199 | + pretend.call("Provide a kind", queue="error") |
| 200 | + ] |
| 201 | + |
| 202 | + def test_invalid_kind_errors(self): |
| 203 | + release = pretend.stub( |
| 204 | + project=pretend.stub(name="foo", normalized_name="foo"), version="1.0" |
| 205 | + ) |
| 206 | + request = pretend.stub( |
| 207 | + POST={"kind": "not a valid kind"}, |
| 208 | + session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)), |
| 209 | + route_path=lambda *a, **kw: "/foo/bar/", |
| 210 | + ) |
| 211 | + |
| 212 | + with pytest.raises(HTTPSeeOther) as exc: |
| 213 | + views.add_release_observation(release, request) |
| 214 | + assert exc.value.status_code == 303 |
| 215 | + assert exc.value.headers["Location"] == "/foo/bar/" |
| 216 | + |
| 217 | + assert request.session.flash.calls == [ |
| 218 | + pretend.call("Invalid kind", queue="error") |
| 219 | + ] |
| 220 | + |
| 221 | + def test_no_summary_errors(self): |
| 222 | + release = pretend.stub( |
| 223 | + project=pretend.stub(name="foo", normalized_name="foo"), version="1.0" |
| 224 | + ) |
| 225 | + request = pretend.stub( |
| 226 | + POST={"kind": ObservationKind.IsSpam.value[0]}, |
| 227 | + session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)), |
| 228 | + route_path=lambda *a, **kw: "/foo/bar/", |
| 229 | + ) |
| 230 | + |
| 231 | + with pytest.raises(HTTPSeeOther) as exc: |
| 232 | + views.add_release_observation(release, request) |
| 233 | + assert exc.value.status_code == 303 |
| 234 | + assert exc.value.headers["Location"] == "/foo/bar/" |
| 235 | + |
| 236 | + assert request.session.flash.calls == [ |
| 237 | + pretend.call("Provide a summary", queue="error") |
| 238 | + ] |
| 239 | + |
| 240 | + |
160 | 241 | class TestProjectReleasesList:
|
161 | 242 | def test_no_query(self, db_request):
|
162 | 243 | project = ProjectFactory.create()
|
@@ -347,6 +428,117 @@ def test_non_normalized_name(self, db_request):
|
347 | 428 | views.journals_list(project, db_request)
|
348 | 429 |
|
349 | 430 |
|
| 431 | +class TestProjectObservationsList: |
| 432 | + def test_with_page(self, db_request): |
| 433 | + observer = ObserverFactory.create() |
| 434 | + UserFactory.create(observer=observer) |
| 435 | + project = ProjectFactory.create() |
| 436 | + observations = ProjectObservationFactory.create_batch( |
| 437 | + size=30, related=project, observer=observer |
| 438 | + ) |
| 439 | + |
| 440 | + db_request.matchdict["project_name"] = project.normalized_name |
| 441 | + db_request.GET["page"] = "2" |
| 442 | + result = views.project_observations_list(project, db_request) |
| 443 | + |
| 444 | + assert result == { |
| 445 | + "observations": observations[25:], |
| 446 | + "project": project, |
| 447 | + } |
| 448 | + |
| 449 | + def test_with_invalid_page(self, db_request): |
| 450 | + project = ProjectFactory.create() |
| 451 | + db_request.matchdict["project_name"] = project.normalized_name |
| 452 | + db_request.GET["page"] = "not an integer" |
| 453 | + |
| 454 | + with pytest.raises(HTTPBadRequest): |
| 455 | + views.project_observations_list(project, db_request) |
| 456 | + |
| 457 | + |
| 458 | +class TestProjectAddObservation: |
| 459 | + def test_add_observation(self, db_request): |
| 460 | + project = ProjectFactory.create() |
| 461 | + observer = ObserverFactory.create() |
| 462 | + user = UserFactory.create(observer=observer) |
| 463 | + db_request.route_path = pretend.call_recorder( |
| 464 | + lambda *a, **kw: "/admin/projects/" |
| 465 | + ) |
| 466 | + db_request.matchdict["project_name"] = project.normalized_name |
| 467 | + db_request.POST["kind"] = ObservationKind.IsSpam.value[0] |
| 468 | + db_request.POST["summary"] = "This is a summary" |
| 469 | + db_request.user = user |
| 470 | + |
| 471 | + views.add_project_observation(project, db_request) |
| 472 | + |
| 473 | + assert len(project.observations) == 1 |
| 474 | + |
| 475 | + def test_no_user_observer(self, db_request): |
| 476 | + project = ProjectFactory.create() |
| 477 | + user = UserFactory.create() |
| 478 | + db_request.route_path = pretend.call_recorder( |
| 479 | + lambda *a, **kw: "/admin/projects/" |
| 480 | + ) |
| 481 | + db_request.matchdict["project_name"] = project.normalized_name |
| 482 | + db_request.POST["kind"] = ObservationKind.IsSpam.value[0] |
| 483 | + db_request.POST["summary"] = "This is a summary" |
| 484 | + db_request.user = user |
| 485 | + |
| 486 | + views.add_project_observation(project, db_request) |
| 487 | + |
| 488 | + assert len(project.observations) == 1 |
| 489 | + |
| 490 | + def test_no_kind_errors(self): |
| 491 | + project = pretend.stub(name="foo", normalized_name="foo") |
| 492 | + request = pretend.stub( |
| 493 | + POST={}, |
| 494 | + session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)), |
| 495 | + route_path=lambda *a, **kw: "/foo/bar/", |
| 496 | + ) |
| 497 | + |
| 498 | + with pytest.raises(HTTPSeeOther) as exc: |
| 499 | + views.add_project_observation(project, request) |
| 500 | + assert exc.value.status_code == 303 |
| 501 | + assert exc.value.headers["Location"] == "/foo/bar/" |
| 502 | + |
| 503 | + assert request.session.flash.calls == [ |
| 504 | + pretend.call("Provide a kind", queue="error") |
| 505 | + ] |
| 506 | + |
| 507 | + def test_invalid_kind_errors(self): |
| 508 | + project = pretend.stub(name="foo", normalized_name="foo") |
| 509 | + request = pretend.stub( |
| 510 | + POST={"kind": "not a valid kind"}, |
| 511 | + session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)), |
| 512 | + route_path=lambda *a, **kw: "/foo/bar/", |
| 513 | + ) |
| 514 | + |
| 515 | + with pytest.raises(HTTPSeeOther) as exc: |
| 516 | + views.add_project_observation(project, request) |
| 517 | + assert exc.value.status_code == 303 |
| 518 | + assert exc.value.headers["Location"] == "/foo/bar/" |
| 519 | + |
| 520 | + assert request.session.flash.calls == [ |
| 521 | + pretend.call("Invalid kind", queue="error") |
| 522 | + ] |
| 523 | + |
| 524 | + def test_no_summary_errors(self): |
| 525 | + project = pretend.stub(name="foo", normalized_name="foo") |
| 526 | + request = pretend.stub( |
| 527 | + POST={"kind": ObservationKind.IsSpam.value[0]}, |
| 528 | + session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)), |
| 529 | + route_path=lambda *a, **kw: "/foo/bar/", |
| 530 | + ) |
| 531 | + |
| 532 | + with pytest.raises(HTTPSeeOther) as exc: |
| 533 | + views.add_project_observation(project, request) |
| 534 | + assert exc.value.status_code == 303 |
| 535 | + assert exc.value.headers["Location"] == "/foo/bar/" |
| 536 | + |
| 537 | + assert request.session.flash.calls == [ |
| 538 | + pretend.call("Provide a summary", queue="error") |
| 539 | + ] |
| 540 | + |
| 541 | + |
350 | 542 | class TestProjectSetTotalSizeLimit:
|
351 | 543 | def test_sets_total_size_limitwith_integer(self, db_request):
|
352 | 544 | project = ProjectFactory.create(name="foo")
|
|
0 commit comments