Skip to content

Commit 2511954

Browse files
authored
Merge pull request #2033 from codalab/dataset_api
Tests - datasets api delete tests added
2 parents 90cfc91 + d277af0 commit 2511954

File tree

2 files changed

+94
-7
lines changed

2 files changed

+94
-7
lines changed

src/apps/api/tests/test_datasets.py

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33
from django.test import TestCase
44
from rest_framework.test import APITestCase
55
from datasets.models import Data
6-
from factories import UserFactory, DataFactory
6+
from factories import (
7+
UserFactory,
8+
DataFactory,
9+
CompetitionFactory,
10+
PhaseFactory,
11+
TaskFactory,
12+
SubmissionFactory
13+
)
714
from utils.data import pretty_bytes, gb_to_bytes
815
from unittest.mock import patch
916

@@ -306,3 +313,87 @@ def test_cannot_create_dataset_unauthenticated(self):
306313
'file_size': 1234,
307314
})
308315
self.assertEqual(resp.status_code, 403)
316+
317+
318+
class DatasetDeleteTests(APITestCase):
319+
def setUp(self):
320+
self.user = UserFactory(username='user', password='user')
321+
self.other_user = UserFactory(username='other', password='other')
322+
self.client.login(username='user', password='user')
323+
324+
self.dataset1 = DataFactory(created_by=self.user, name='dataset1')
325+
self.dataset2 = DataFactory(created_by=self.user, name='dataset2')
326+
self.other_dataset = DataFactory(created_by=self.other_user, name='other_dataset')
327+
328+
def test_delete_own_dataset_success(self):
329+
"""User can delete their own dataset."""
330+
url = reverse("data-detail", args=[self.dataset1.pk])
331+
resp = self.client.delete(url)
332+
self.assertEqual(resp.status_code, 204)
333+
self.assertFalse(Data.objects.filter(pk=self.dataset1.pk).exists())
334+
335+
def test_cannot_delete_others_dataset(self):
336+
"""User cannot delete someone else’s dataset."""
337+
url = reverse("data-detail", args=[self.other_dataset.pk])
338+
resp = self.client.delete(url)
339+
self.assertEqual(resp.status_code, 404)
340+
self.assertTrue(Data.objects.filter(pk=self.other_dataset.pk).exists())
341+
342+
def test_cannot_delete_dataset_in_use(self):
343+
"""If dataset is in use by a competition, it cannot be deleted."""
344+
# Set up in use dataset
345+
in_use_dataset = DataFactory(type=Data.INPUT_DATA, created_by=self.user, name="in_use_dataset")
346+
task = TaskFactory(input_data=in_use_dataset)
347+
phase = PhaseFactory()
348+
phase.tasks.add(task)
349+
competition = CompetitionFactory(created_by=self.user)
350+
competition.phases.set([phase])
351+
352+
url = reverse("data-detail", args=[in_use_dataset.pk])
353+
resp = self.client.delete(url)
354+
355+
self.assertEqual(resp.status_code, 400)
356+
self.assertEqual(resp.data["error"], "Cannot delete dataset: dataset is in use")
357+
self.assertTrue(Data.objects.filter(pk=in_use_dataset.pk).exists())
358+
359+
def test_bulk_delete_success(self):
360+
"""Multiple datasets deleted successfully."""
361+
ids = [self.dataset1.pk, self.dataset2.pk]
362+
resp = self.client.post(reverse("data-delete-many"), ids, format="json")
363+
self.assertEqual(resp.status_code, 200)
364+
self.assertEqual(resp.data["detail"], "Datasets deleted successfully")
365+
self.assertFalse(Data.objects.filter(pk__in=ids).exists())
366+
367+
def test_bulk_delete_with_errors(self):
368+
"""Bulk delete should fail entirely if one dataset is not deletable."""
369+
# include one dataset from another user
370+
ids = [self.dataset1.pk, self.other_dataset.pk]
371+
resp = self.client.post(reverse("data-delete-many"), ids, format="json")
372+
373+
# Since one dataset is not deletable, expect a 400 response
374+
self.assertEqual(resp.status_code, 400)
375+
self.assertIn("other_dataset", resp.data)
376+
self.assertEqual(resp.data["other_dataset"], "Cannot delete a dataset that is not yours")
377+
378+
# None should be deleted since the operation failed
379+
self.assertTrue(Data.objects.filter(pk=self.dataset1.pk).exists())
380+
self.assertTrue(Data.objects.filter(pk=self.other_dataset.pk).exists())
381+
382+
def test_cannot_delete_dataset_associated_with_a_submission_in_competition(self):
383+
"""If a dataset is a submission linked to a competition phase, it cannot be deleted."""
384+
# Setup a submission dataset
385+
phase = PhaseFactory()
386+
competition = CompetitionFactory(created_by=self.user)
387+
competition.phases.set([phase])
388+
submission_dataset = DataFactory(type=Data.SUBMISSION, created_by=self.user, name="submission_dataset")
389+
SubmissionFactory(owner=self.user, phase=phase, data=submission_dataset)
390+
391+
url = reverse("data-detail", args=[submission_dataset.pk])
392+
resp = self.client.delete(url)
393+
394+
self.assertEqual(resp.status_code, 400)
395+
self.assertEqual(
396+
resp.data["error"],
397+
"Cannot delete submission: submission belongs to an existing competition. Please visit the competition and delete your submission from there."
398+
)
399+
self.assertTrue(Data.objects.filter(pk=submission_dataset.pk).exists())

src/apps/api/views/datasets.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,13 @@ def create(self, request, *args, **kwargs):
144144
return Response(context, status=status.HTTP_201_CREATED, headers=headers)
145145

146146
def destroy(self, request, *args, **kwargs):
147-
# TODO: Confirm this has a test
148-
instance = self.get_object()
149-
150-
error = self.check_delete_permissions(request, instance)
151-
147+
dataset = self.get_object()
148+
error = self.check_delete_permissions(request, dataset)
152149
if error:
153150
return Response(
154151
{'error': error},
155152
status=status.HTTP_400_BAD_REQUEST
156153
)
157-
158154
return super().destroy(request, *args, **kwargs)
159155

160156
@action(detail=False, methods=('POST',))

0 commit comments

Comments
 (0)