Skip to content

Commit 35dfa58

Browse files
committed
Fix delete ElasticSearch index of FileMetadata and add its tests
1 parent 6a28d88 commit 35dfa58

File tree

4 files changed

+148
-12
lines changed

4 files changed

+148
-12
lines changed

addons/metadata/models.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -532,17 +532,6 @@ class FileMetadata(BaseModel):
532532
on_delete=models.CASCADE,
533533
)
534534

535-
@classmethod
536-
def load(cls, project_id, path, select_for_update=False):
537-
try:
538-
if select_for_update:
539-
return cls.objects.filter(project__id=project_id, path=path, deleted__isnull=True) \
540-
.select_for_update().get()
541-
else:
542-
return cls.objects.get(project__id=project_id, path=path, deleted__isnull=True)
543-
except cls.DoesNotExist:
544-
return None
545-
546535
@property
547536
def _id(self):
548537
path_id = self.path.replace('/', '_')

addons/metadata/tests/conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,12 @@
88
def override_settings():
99
"""Override settings for the test environment.
1010
"""
11+
# First call the parent override_settings to ensure Celery is configured
12+
from framework.celery_tasks import app as celery_app
13+
celery_app.conf.update({
14+
'task_always_eager': True,
15+
'task_eager_propagates': True,
16+
})
17+
18+
# Then set metadata-specific settings
1119
website_settings.ENABLE_PRIVATE_SEARCH = True
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# -*- coding: utf-8 -*-
2+
import pytest
3+
from unittest import mock
4+
from framework.auth.core import Auth
5+
from osf_tests.factories import ProjectFactory, UserFactory
6+
from addons.metadata.models import FileMetadata
7+
from tests.base import OsfTestCase
8+
from tests.utils import run_celery_tasks
9+
import website.search.search as search
10+
from website.search import elastic_search
11+
from website.search.util import build_query
12+
13+
14+
def query_metadata(term):
15+
results = search.search(build_query(term), index=elastic_search.INDEX, ext=True, private=True)
16+
return results
17+
18+
19+
@pytest.mark.enable_search
20+
@pytest.mark.enable_enqueue_task
21+
@mock.patch('addons.metadata.models.sync_metadata_asset_pool.apply_async')
22+
class TestFileMetadataSearch(OsfTestCase):
23+
24+
def setUp(self, mock_sync_task=None):
25+
super(TestFileMetadataSearch, self).setUp()
26+
search.delete_index(elastic_search.INDEX)
27+
search.create_index(elastic_search.INDEX)
28+
29+
def test_file_metadata_created_and_searchable(self, _mock_sync_task):
30+
with run_celery_tasks():
31+
user = UserFactory()
32+
project = ProjectFactory(creator=user, is_public=True)
33+
auth = Auth(user)
34+
metadata_addon = project.get_or_add_addon('metadata', auth=auth)
35+
metadata_addon.save()
36+
37+
osfstorage_addon = project.get_addon('osfstorage')
38+
root_node = osfstorage_addon.get_root()
39+
file_node = root_node.append_file('test_file.txt')
40+
file_node.save()
41+
42+
unique_search_term = 'created_metadata_test_12345'
43+
FileMetadata.objects.create(
44+
project=metadata_addon,
45+
creator=user,
46+
user=user,
47+
path='osfstorage/test_file.txt',
48+
hash='abc123',
49+
folder=False,
50+
metadata='{"items": [{"active": true, "schema": "test_schema", "data": {"title": {"value": "' + unique_search_term + '"}}}]}',
51+
)
52+
53+
results = query_metadata(unique_search_term)
54+
assert len(results['results']) == 1
55+
assert any(
56+
result.get('category') == 'metadata' and unique_search_term in result.get('text', '')
57+
for result in results['results']
58+
)
59+
60+
def test_file_metadata_updated_and_searchable(self, _mock_sync_task):
61+
with run_celery_tasks():
62+
user = UserFactory()
63+
project = ProjectFactory(creator=user, is_public=True)
64+
auth = Auth(user)
65+
metadata_addon = project.get_or_add_addon('metadata', auth=auth)
66+
metadata_addon.save()
67+
68+
osfstorage_addon = project.get_addon('osfstorage')
69+
root_node = osfstorage_addon.get_root()
70+
file_node = root_node.append_file('updatable_file.txt')
71+
file_node.save()
72+
73+
initial_search_term = 'initial_content_67890'
74+
file_metadata = FileMetadata.objects.create(
75+
project=metadata_addon,
76+
creator=user,
77+
user=user,
78+
path='osfstorage/updatable_file.txt',
79+
hash='def456',
80+
folder=False,
81+
metadata='{"items": [{"active": true, "schema": "test_schema", "data": {"title": {"value": "' + initial_search_term + '"}}}]}',
82+
)
83+
84+
updated_search_term = 'updated_content_54321'
85+
file_metadata.metadata = '{"items": [{"active": true, "schema": "test_schema", "data": {"title": {"value": "' + updated_search_term + '"}}}]}'
86+
file_metadata.save()
87+
88+
results = query_metadata(updated_search_term)
89+
assert len(results['results']) == 1
90+
assert any(
91+
result.get('category') == 'metadata' and updated_search_term in result.get('text', '')
92+
for result in results['results']
93+
)
94+
95+
# Test that the old content is no longer found
96+
old_results = query_metadata(initial_search_term)
97+
assert len(old_results['results']) == 0
98+
99+
def test_file_metadata_deleted_and_not_searchable(self, _mock_sync_task):
100+
with run_celery_tasks():
101+
user = UserFactory()
102+
project = ProjectFactory(creator=user, is_public=True)
103+
auth = Auth(user)
104+
metadata_addon = project.get_or_add_addon('metadata', auth=auth)
105+
metadata_addon.save()
106+
107+
osfstorage_addon = project.get_addon('osfstorage')
108+
root_node = osfstorage_addon.get_root()
109+
file_node = root_node.append_file('deletable_file.txt')
110+
file_node.save()
111+
112+
delete_test_term = 'delete_test_content_99999'
113+
file_metadata = FileMetadata.objects.create(
114+
project=metadata_addon,
115+
creator=user,
116+
user=user,
117+
path='osfstorage/deletable_file.txt',
118+
hash='delete123',
119+
folder=False,
120+
metadata='{"items": [{"active": true, "schema": "test_schema", "data": {"title": {"value": "' + delete_test_term + '"}}}]}',
121+
)
122+
123+
# Verify the metadata can be found before deletion
124+
pre_delete_results = query_metadata(delete_test_term)
125+
assert len(pre_delete_results['results']) == 1
126+
assert any(
127+
result.get('category') == 'metadata' and delete_test_term in result.get('text', '')
128+
for result in pre_delete_results['results']
129+
)
130+
131+
with run_celery_tasks():
132+
# Use the same deletion method as the actual API
133+
metadata_addon.delete_file_metadata(file_metadata.path, auth=auth)
134+
135+
post_delete_results = query_metadata(delete_test_term)
136+
assert len(post_delete_results['results']) == 0

website/search/elastic_search.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,10 @@ def update_user_async(self, user_id, index=None):
719719
@celery_app.task(bind=True, max_retries=5, default_retry_delay=60)
720720
def update_file_metadata_async(self, project_id, path, index=None, bulk=False):
721721
FileMetadata = apps.get_model(f'addons_{METADATA_SHORT_NAME}.FileMetadata')
722-
file_metadata = FileMetadata.load(project_id=project_id, path=path)
722+
try:
723+
file_metadata = FileMetadata.objects.get(project__id=project_id, path=path)
724+
except FileMetadata.DoesNotExist:
725+
return
723726
try:
724727
update_file_metadata(file_metadata=file_metadata, index=index, bulk=bulk)
725728
except Exception as exc:

0 commit comments

Comments
 (0)