Skip to content

Commit faf5456

Browse files
authored
Destroy documentation (#3413)
* implement documentation deletes * implement remove_by_prefix on warehouse.packaging.interfaces:IFileStorage * wire up documentation delete task * tests for destroy documentation task * add tests for manage.project.destroy_docs and manage.project.documentation * review feedback: remove stray flush
1 parent 48d4e68 commit faf5456

File tree

19 files changed

+514
-26
lines changed

19 files changed

+514
-26
lines changed

dev/environment

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ CAMO_KEY="insecure camo key"
2020

2121
DOCS_URL="https://pythonhosted.org/{project}/"
2222

23-
FILES_BACKEND=warehouse.packaging.services.LocalFileStorage path=/var/opt/warehouse/packages/ url=http://files.example.com/packages/{path}
23+
FILES_BACKEND=warehouse.packaging.services.LocalFileStorage path=/var/opt/warehouse/packages/ url=http://files.example.com/packages/{path} name=files
24+
DOCS_BACKEND=warehouse.packaging.services.LocalFileStorage path=/var/opt/warehouse/docs/ name=docs
2425

2526
MAIL_HOST=smtp
2627
MAIL_PORT=2525

tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ def app_config(database):
117117
"ratelimit.url": "memory://",
118118
"elasticsearch.url": "https://localhost/warehouse",
119119
"files.backend": "warehouse.packaging.services.LocalFileStorage",
120+
"docs.backend": "warehouse.packaging.services.LocalFileStorage",
120121
"files.url": "http://localhost:7000/",
121122
"sessions.secret": "123456",
122123
"sessions.url": "redis://localhost:0/",

tests/unit/forklift/test_legacy.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,13 +1196,15 @@ def storage_service_store(path, file_path, *, meta):
11961196

11971197
storage_service = pretend.stub(store=storage_service_store)
11981198
db_request.find_service = pretend.call_recorder(
1199-
lambda svc: storage_service
1199+
lambda svc, name=None: storage_service
12001200
)
12011201

12021202
resp = legacy.file_upload(db_request)
12031203

12041204
assert resp.status_code == 200
1205-
assert db_request.find_service.calls == [pretend.call(IFileStorage)]
1205+
assert db_request.find_service.calls == [
1206+
pretend.call(IFileStorage, name="files"),
1207+
]
12061208
assert len(storage_service.store.calls) == 2 if has_signature else 1
12071209
assert storage_service.store.calls[0] == pretend.call(
12081210
"/".join([
@@ -2110,7 +2112,7 @@ def storage_service_store(path, file_path, *, meta):
21102112

21112113
storage_service = pretend.stub(store=storage_service_store)
21122114
db_request.find_service = pretend.call_recorder(
2113-
lambda svc: storage_service
2115+
lambda svc, name=None: storage_service
21142116
)
21152117

21162118
monkeypatch.setattr(
@@ -2121,7 +2123,9 @@ def storage_service_store(path, file_path, *, meta):
21212123
resp = legacy.file_upload(db_request)
21222124

21232125
assert resp.status_code == 200
2124-
assert db_request.find_service.calls == [pretend.call(IFileStorage)]
2126+
assert db_request.find_service.calls == [
2127+
pretend.call(IFileStorage, name="files"),
2128+
]
21252129
assert storage_service.store.calls == [
21262130
pretend.call(
21272131
"/".join([
@@ -2218,7 +2222,7 @@ def storage_service_store(path, file_path, *, meta):
22182222

22192223
storage_service = pretend.stub(store=storage_service_store)
22202224
db_request.find_service = pretend.call_recorder(
2221-
lambda svc: storage_service
2225+
lambda svc, name=None: storage_service
22222226
)
22232227

22242228
monkeypatch.setattr(
@@ -2229,7 +2233,9 @@ def storage_service_store(path, file_path, *, meta):
22292233
resp = legacy.file_upload(db_request)
22302234

22312235
assert resp.status_code == 200
2232-
assert db_request.find_service.calls == [pretend.call(IFileStorage)]
2236+
assert db_request.find_service.calls == [
2237+
pretend.call(IFileStorage, name="files"),
2238+
]
22332239
assert storage_service.store.calls == [
22342240
pretend.call(
22352241
"/".join([
@@ -2315,7 +2321,7 @@ def storage_service_store(path, file_path, *, meta):
23152321
assert fp.read() == b"A fake file."
23162322

23172323
storage_service = pretend.stub(store=storage_service_store)
2318-
db_request.find_service = lambda svc: storage_service
2324+
db_request.find_service = lambda svc, name=None: storage_service
23192325

23202326
monkeypatch.setattr(
23212327
legacy,
@@ -2361,7 +2367,7 @@ def storage_service_store(path, file_path, *, meta):
23612367
assert fp.read() == b"A fake file."
23622368

23632369
storage_service = pretend.stub(store=storage_service_store)
2364-
db_request.find_service = lambda svc: storage_service
2370+
db_request.find_service = lambda svc, name=None: storage_service
23652371

23662372
monkeypatch.setattr(
23672373
legacy,
@@ -2463,7 +2469,7 @@ def test_upload_succeeds_creates_release(self, pyramid_config, db_request):
24632469
])
24642470

24652471
storage_service = pretend.stub(store=lambda path, filepath, meta: None)
2466-
db_request.find_service = lambda svc: storage_service
2472+
db_request.find_service = lambda svc, name=None: storage_service
24672473

24682474
resp = legacy.file_upload(db_request)
24692475

@@ -2554,7 +2560,7 @@ def test_equivalent_version_one_release(self, pyramid_config, db_request):
25542560
})
25552561

25562562
storage_service = pretend.stub(store=lambda path, filepath, meta: None)
2557-
db_request.find_service = lambda svc: storage_service
2563+
db_request.find_service = lambda svc, name=None: storage_service
25582564

25592565
resp = legacy.file_upload(db_request)
25602566

@@ -2601,7 +2607,7 @@ def test_equivalent_canonical_versions(self, pyramid_config, db_request):
26012607
})
26022608

26032609
storage_service = pretend.stub(store=lambda path, filepath, meta: None)
2604-
db_request.find_service = lambda svc: storage_service
2610+
db_request.find_service = lambda svc, name=None: storage_service
26052611

26062612
legacy.file_upload(db_request)
26072613

@@ -2631,7 +2637,7 @@ def test_upload_succeeds_creates_project(self, pyramid_config, db_request):
26312637
})
26322638

26332639
storage_service = pretend.stub(store=lambda path, filepath, meta: None)
2634-
db_request.find_service = lambda svc: storage_service
2640+
db_request.find_service = lambda svc, name=None: storage_service
26352641
db_request.remote_addr = "10.10.10.10"
26362642

26372643
resp = legacy.file_upload(db_request)
@@ -2733,7 +2739,7 @@ def test_upload_requires_verified_email(self, pyramid_config, db_request,
27332739
})
27342740

27352741
storage_service = pretend.stub(store=lambda path, filepath, meta: None)
2736-
db_request.find_service = lambda svc: storage_service
2742+
db_request.find_service = lambda svc, name=None: storage_service
27372743
db_request.remote_addr = "10.10.10.10"
27382744

27392745
if expected_success:
@@ -2777,7 +2783,7 @@ def test_upload_purges_legacy(self, pyramid_config, db_request,
27772783
})
27782784

27792785
storage_service = pretend.stub(store=lambda path, filepath, meta: None)
2780-
db_request.find_service = lambda svc: storage_service
2786+
db_request.find_service = lambda svc, name=None: storage_service
27812787
db_request.remote_addr = "10.10.10.10"
27822788

27832789
tm = pretend.stub(
@@ -2873,7 +2879,7 @@ def test_autohides_old_releases(self, pyramid_config, db_request):
28732879
])
28742880

28752881
storage_service = pretend.stub(store=lambda path, filepath, meta: None)
2876-
db_request.find_service = lambda svc: storage_service
2882+
db_request.find_service = lambda svc, name=None: storage_service
28772883

28782884
resp = legacy.file_upload(db_request)
28792885

@@ -2954,7 +2960,7 @@ def test_doesnt_autohides_old_releases(self, pyramid_config, db_request):
29542960
])
29552961

29562962
storage_service = pretend.stub(store=lambda path, filepath, meta: None)
2957-
db_request.find_service = lambda svc: storage_service
2963+
db_request.find_service = lambda svc, name=None: storage_service
29582964

29592965
resp = legacy.file_upload(db_request)
29602966

tests/unit/manage/test_views.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from warehouse.manage import views
2424
from warehouse.accounts.interfaces import IUserService
2525
from warehouse.packaging.models import JournalEntry, Project, Role, User
26+
from warehouse.utils.project import remove_documentation
2627

2728
from ...common.db.accounts import EmailFactory
2829
from ...common.db.packaging import (
@@ -830,6 +831,105 @@ def test_delete_project(self, db_request):
830831
.filter(Project.name == "foo").count())
831832

832833

834+
class TestManageProjectDocumentation:
835+
836+
def test_manage_project_documentation(self):
837+
request = pretend.stub()
838+
project = pretend.stub()
839+
840+
assert views.manage_project_documentation(project, request) == {
841+
"project": project,
842+
}
843+
844+
def test_destroy_project_docs_no_confirm(self):
845+
project = pretend.stub(normalized_name='foo')
846+
request = pretend.stub(
847+
POST={},
848+
session=pretend.stub(
849+
flash=pretend.call_recorder(lambda *a, **kw: None),
850+
),
851+
route_path=lambda *a, **kw: "/foo/bar/",
852+
)
853+
854+
with pytest.raises(HTTPSeeOther) as exc:
855+
views.destroy_project_docs(project, request)
856+
assert exc.value.status_code == 303
857+
assert exc.value.headers["Location"] == "/foo/bar/"
858+
859+
assert request.session.flash.calls == [
860+
pretend.call("Must confirm the request.", queue="error"),
861+
]
862+
863+
def test_destroy_project_docs_wrong_confirm(self):
864+
project = pretend.stub(normalized_name='foo')
865+
request = pretend.stub(
866+
POST={"confirm_project_name": "bar"},
867+
session=pretend.stub(
868+
flash=pretend.call_recorder(lambda *a, **kw: None),
869+
),
870+
route_path=lambda *a, **kw: "/foo/bar/",
871+
)
872+
873+
with pytest.raises(HTTPSeeOther) as exc:
874+
views.destroy_project_docs(project, request)
875+
assert exc.value.status_code == 303
876+
assert exc.value.headers["Location"] == "/foo/bar/"
877+
878+
assert request.session.flash.calls == [
879+
pretend.call(
880+
"Could not delete project - 'bar' is not the same as 'foo'",
881+
queue="error"
882+
),
883+
]
884+
885+
def test_destroy_project_docs(self, db_request):
886+
project = ProjectFactory.create(name="foo")
887+
remove_documentation_recorder = pretend.stub(
888+
delay=pretend.call_recorder(
889+
lambda *a, **kw: None
890+
)
891+
)
892+
task = pretend.call_recorder(
893+
lambda *a, **kw: remove_documentation_recorder
894+
)
895+
896+
db_request.route_path = pretend.call_recorder(
897+
lambda *a, **kw: "/the-redirect"
898+
)
899+
db_request.session = pretend.stub(
900+
flash=pretend.call_recorder(lambda *a, **kw: None),
901+
)
902+
db_request.POST["confirm_project_name"] = project.normalized_name
903+
db_request.user = UserFactory.create()
904+
db_request.remote_addr = "192.168.1.1"
905+
db_request.task = task
906+
907+
result = views.destroy_project_docs(project, db_request)
908+
909+
assert task.calls == [
910+
pretend.call(remove_documentation)
911+
]
912+
913+
assert remove_documentation_recorder.delay.calls == [
914+
pretend.call(project.name)
915+
]
916+
917+
assert db_request.session.flash.calls == [
918+
pretend.call(
919+
"Successfully deleted docs for project 'foo'.",
920+
queue="success"
921+
),
922+
]
923+
assert db_request.route_path.calls == [
924+
pretend.call('manage.project.documentation', project_name='foo'),
925+
]
926+
assert isinstance(result, HTTPSeeOther)
927+
assert result.headers["Location"] == "/the-redirect"
928+
assert not (db_request.db.query(Project)
929+
.filter(Project.name == "foo")
930+
.first().has_docs)
931+
932+
833933
class TestManageProjectReleases:
834934

835935
def test_manage_project_releases(self):

tests/unit/packaging/test_init.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@ def key_factory(keystring, iterate_on=None):
3434
config = pretend.stub(
3535
maybe_dotted=lambda dotted: storage_class,
3636
register_service_factory=pretend.call_recorder(
37-
lambda factory, iface: None,
37+
lambda factory, iface, name=None: None,
3838
),
3939
registry=pretend.stub(
4040
settings={
4141
"files.backend": "foo.bar",
42+
"docs.backend": "wu.tang",
4243
},
4344
),
4445
register_origin_cache_keys=pretend.call_recorder(lambda c, **kw: None),
@@ -50,7 +51,8 @@ def key_factory(keystring, iterate_on=None):
5051
packaging.includeme(config)
5152

5253
assert config.register_service_factory.calls == [
53-
pretend.call(storage_class.create_service, IFileStorage),
54+
pretend.call(storage_class.create_service, IFileStorage, name='files'),
55+
pretend.call(storage_class.create_service, IFileStorage, name='docs'),
5456
]
5557
assert config.register_origin_cache_keys.calls == [
5658
pretend.call(

0 commit comments

Comments
 (0)