Skip to content

Commit 6f63248

Browse files
authored
Delete imported files when deactivating version (#10684)
* Delete imported files when deactivating version Closes #10682 * Remove dead code We aren't using this, and tests were failing because of the storage class being overridden by other tests.
1 parent 9c6ade2 commit 6f63248

File tree

7 files changed

+70
-95
lines changed

7 files changed

+70
-95
lines changed

readthedocs/api/v3/tests/test_versions.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
import django_dynamic_fixture as fixture
44
from django.test import override_settings
55
from django.urls import reverse
6+
from django_dynamic_fixture import get
67

78
from readthedocs.builds.constants import EXTERNAL, TAG
89
from readthedocs.builds.models import Version
9-
from readthedocs.projects.models import Project
10+
from readthedocs.projects.models import HTMLFile, Project
1011

1112
from .mixins import APIEndpointMixin
1213

@@ -266,12 +267,33 @@ def test_activate_version(self, clean_project_resources, trigger_build):
266267
trigger_build.assert_called_once()
267268

268269
@mock.patch("readthedocs.builds.models.trigger_build")
269-
@mock.patch("readthedocs.projects.tasks.utils.clean_project_resources")
270-
def test_deactivate_version(self, clean_project_resources, trigger_build):
270+
@mock.patch("readthedocs.projects.tasks.search.remove_search_indexes")
271+
@mock.patch("readthedocs.projects.tasks.utils.remove_build_storage_paths")
272+
def test_deactivate_version(
273+
self, remove_build_storage_paths, remove_search_indexes, trigger_build
274+
):
275+
another_version = get(Version, project=self.project, active=True)
276+
get(
277+
HTMLFile,
278+
project=self.project,
279+
version=another_version,
280+
name="index.html",
281+
path="index.html",
282+
)
283+
get(
284+
HTMLFile,
285+
project=self.project,
286+
version=self.version,
287+
name="index.html",
288+
path="index.html",
289+
)
290+
271291
self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
272292
data = {"active": False}
273293
self.assertTrue(self.version.active)
274294
self.assertTrue(self.version.built)
295+
self.assertTrue(another_version.imported_files.exists())
296+
self.assertTrue(self.version.imported_files.exists())
275297
response = self.client.patch(
276298
reverse(
277299
"projects-versions-detail",
@@ -286,7 +308,10 @@ def test_deactivate_version(self, clean_project_resources, trigger_build):
286308
self.version.refresh_from_db()
287309
self.assertFalse(self.version.active)
288310
self.assertFalse(self.version.built)
289-
clean_project_resources.assert_called_once()
311+
self.assertFalse(self.version.imported_files.exists())
312+
self.assertTrue(another_version.imported_files.exists())
313+
remove_build_storage_paths.delay.assert_called_once()
314+
remove_search_indexes.delay.assert_called_once()
290315
trigger_build.assert_not_called()
291316

292317
def test_projects_version_external(self):

readthedocs/builds/models.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,11 @@ def clean_resources(self):
422422
"""
423423
Remove all resources from this version.
424424
425-
This includes removing files from storage,
426-
and removing its search index.
425+
This includes:
426+
427+
- Files from storage
428+
- Search index
429+
- Imported files
427430
"""
428431
from readthedocs.projects.tasks.utils import clean_project_resources
429432

readthedocs/projects/models.py

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@
5454

5555
from .constants import (
5656
DOWNLOADABLE_MEDIA_TYPES,
57-
MEDIA_TYPE_EPUB,
58-
MEDIA_TYPE_HTMLZIP,
59-
MEDIA_TYPE_PDF,
6057
MEDIA_TYPES,
6158
)
6259

@@ -851,34 +848,6 @@ def has_good_build(self):
851848
return self._good_build
852849
return self.builds(manager=INTERNAL).filter(success=True).exists()
853850

854-
def has_media(self, type_, version_slug=LATEST, version_type=None):
855-
storage_path = self.get_storage_path(
856-
type_=type_, version_slug=version_slug,
857-
version_type=version_type
858-
)
859-
return build_media_storage.exists(storage_path)
860-
861-
def has_pdf(self, version_slug=LATEST, version_type=None):
862-
return self.has_media(
863-
MEDIA_TYPE_PDF,
864-
version_slug=version_slug,
865-
version_type=version_type
866-
)
867-
868-
def has_epub(self, version_slug=LATEST, version_type=None):
869-
return self.has_media(
870-
MEDIA_TYPE_EPUB,
871-
version_slug=version_slug,
872-
version_type=version_type
873-
)
874-
875-
def has_htmlzip(self, version_slug=LATEST, version_type=None):
876-
return self.has_media(
877-
MEDIA_TYPE_HTMLZIP,
878-
version_slug=version_slug,
879-
version_type=version_type
880-
)
881-
882851
def vcs_repo(
883852
self,
884853
environment,

readthedocs/projects/tasks/utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def clean_project_resources(project, version=None):
6767
6868
- Artifacts from storage.
6969
- Search indexes from ES.
70+
- Imported files.
7071
7172
:param version: Version instance. If isn't given,
7273
all resources of `project` will be deleted.
@@ -90,6 +91,12 @@ def clean_project_resources(project, version=None):
9091
version_slug=version.slug if version else None,
9192
)
9293

94+
# Remove imported files
95+
if version:
96+
version.imported_files.all().delete()
97+
else:
98+
project.imported_files.all().delete()
99+
93100

94101
@app.task()
95102
def finish_inactive_builds():

readthedocs/rtd_tests/mocks/paths.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
"""Context managers to patch os.path.exists calls."""
22
import os
3-
import re
43
from unittest import mock
54

65

7-
def fake_paths(check, target="exists"):
6+
def fake_paths(check):
87
"""
98
Usage:
109
@@ -23,7 +22,7 @@ def patched_exists(path):
2322
return original_exists(path)
2423
return result
2524

26-
return mock.patch.object(os.path, target, patched_exists)
25+
return mock.patch.object(os.path, "exists", patched_exists)
2726

2827

2928
def fake_paths_lookup(path_dict):
@@ -40,22 +39,3 @@ def check(path):
4039
return path_dict.get(path, None)
4140

4241
return fake_paths(check)
43-
44-
45-
def fake_paths_by_regex(pattern, target="exists", exists=True):
46-
r"""
47-
Usage:
48-
49-
>>> with fake_paths_by_regex('\.pdf$', target="lexists"):
50-
... assert os.path.exists('my.pdf') == True
51-
>>> with fake_paths_by_regex('\.pdf$', target="lexists", exists=False):
52-
... assert os.path.exists('my.pdf') == False
53-
"""
54-
regex = re.compile(pattern)
55-
56-
def check(path):
57-
if regex.search(path):
58-
return exists
59-
return None
60-
61-
return fake_paths(check, target)

readthedocs/rtd_tests/tests/test_build_forms.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from readthedocs.builds.forms import VersionForm
99
from readthedocs.builds.models import Version
1010
from readthedocs.projects.constants import PRIVATE, PUBLIC
11-
from readthedocs.projects.models import Project
11+
from readthedocs.projects.models import HTMLFile, Project
1212

1313

1414
class TestVersionForm(TestCase):
@@ -90,15 +90,31 @@ def test_can_update_privacy_level(self):
9090
self.assertEqual(version.privacy_level, PRIVATE)
9191

9292
@mock.patch("readthedocs.builds.models.trigger_build", mock.MagicMock())
93-
@mock.patch("readthedocs.projects.tasks.utils.clean_project_resources")
93+
@mock.patch("readthedocs.projects.tasks.search.remove_search_indexes")
94+
@mock.patch("readthedocs.projects.tasks.utils.remove_build_storage_paths")
9495
def test_resources_are_deleted_when_version_is_inactive(
95-
self, clean_project_resources
96+
self, remove_build_storage_paths, remove_search_indexes
9697
):
9798
version = get(
9899
Version,
99100
project=self.project,
100101
active=True,
101102
)
103+
another_version = get(Version, project=self.project, active=True)
104+
get(
105+
HTMLFile,
106+
project=self.project,
107+
version=version,
108+
name="index.html",
109+
path="index.html",
110+
)
111+
get(
112+
HTMLFile,
113+
project=self.project,
114+
version=another_version,
115+
name="index.html",
116+
path="index.html",
117+
)
102118

103119
url = reverse(
104120
"project_version_detail", args=(version.project.slug, version.slug)
@@ -114,7 +130,10 @@ def test_resources_are_deleted_when_version_is_inactive(
114130
},
115131
)
116132
self.assertEqual(r.status_code, 302)
117-
clean_project_resources.assert_not_called()
133+
remove_build_storage_paths.delay.assert_not_called()
134+
remove_search_indexes.delay.assert_not_called()
135+
self.assertTrue(version.imported_files.exists())
136+
self.assertTrue(another_version.imported_files.exists())
118137

119138
r = self.client.post(
120139
url,
@@ -124,4 +143,7 @@ def test_resources_are_deleted_when_version_is_inactive(
124143
},
125144
)
126145
self.assertEqual(r.status_code, 302)
127-
clean_project_resources.assert_called_once()
146+
remove_build_storage_paths.delay.assert_called_once()
147+
remove_search_indexes.delay.assert_called_once()
148+
self.assertFalse(version.imported_files.exists())
149+
self.assertTrue(another_version.imported_files.exists())

readthedocs/rtd_tests/tests/test_project.py

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
from readthedocs.projects.exceptions import ProjectConfigurationError
3434
from readthedocs.projects.models import Project
3535
from readthedocs.projects.tasks.utils import finish_inactive_builds
36-
from readthedocs.rtd_tests.mocks.paths import fake_paths_by_regex
3736

3837

3938
class ProjectMixin:
@@ -63,36 +62,6 @@ def test_subprojects(self):
6362
self.assertEqual(r.status_code, 200)
6463
self.assertEqual(resp['subprojects'][0]['id'], 23)
6564

66-
def test_has_pdf(self):
67-
# The project has a pdf if the PDF file exists on disk.
68-
with fake_paths_by_regex(r"\.pdf$", target="lexists"):
69-
self.assertTrue(self.pip.has_pdf(LATEST))
70-
71-
# The project has no pdf if there is no file on disk.
72-
with fake_paths_by_regex(r"\.pdf$", target="lexists", exists=False):
73-
self.assertFalse(self.pip.has_pdf(LATEST))
74-
75-
def test_has_pdf_with_pdf_build_disabled(self):
76-
# The project doesn't depend on `enable_pdf_build`
77-
self.pip.enable_pdf_build = False
78-
with fake_paths_by_regex(r"\.pdf$", target="lexists"):
79-
self.assertTrue(self.pip.has_pdf(LATEST))
80-
81-
def test_has_epub(self):
82-
# The project has a epub if the PDF file exists on disk.
83-
with fake_paths_by_regex(r"\.epub$", target="lexists"):
84-
self.assertTrue(self.pip.has_epub(LATEST))
85-
86-
# The project has no epub if there is no file on disk.
87-
with fake_paths_by_regex(r"\.epub$", target="lexists", exists=False):
88-
self.assertFalse(self.pip.has_epub(LATEST))
89-
90-
def test_has_epub_with_epub_build_disabled(self):
91-
# The project doesn't depend on `enable_epub_build`
92-
self.pip.enable_epub_build = False
93-
with fake_paths_by_regex(r"\.epub$", target="lexists"):
94-
self.assertTrue(self.pip.has_epub(LATEST))
95-
9665
@patch('readthedocs.projects.models.Project.find')
9766
def test_conf_file_found(self, find_method):
9867
find_method.return_value = [

0 commit comments

Comments
 (0)