|
1 | 1 |
|
2 | 2 | import logging |
3 | 3 | import json |
| 4 | +import time |
| 5 | +from unittest import mock |
4 | 6 |
|
5 | | -from django.test import TestCase |
| 7 | +from django.test import TestCase, TransactionTestCase, tag |
6 | 8 | from django.urls import reverse |
7 | 9 | from django.contrib.auth.models import User, Group |
8 | 10 | from django.conf import settings |
9 | 11 | from rest_framework import status |
10 | 12 |
|
| 13 | +from celery.contrib.testing.worker import start_worker |
| 14 | +from core.celery import app as celery_app |
| 15 | +from core.celery import task_routes |
| 16 | + |
11 | 17 | from plugins.models import PluginMeta, Plugin, ComputeResource |
12 | 18 | from plugininstances.models import PluginInstance |
13 | 19 | from feeds.models import (Note, Tag, Tagging, Feed, FeedGroupPermission, |
14 | 20 | FeedUserPermission, Comment) |
| 21 | +from feeds import views |
15 | 22 |
|
16 | 23 |
|
17 | 24 | COMPUTE_RESOURCE_URL = settings.COMPUTE_RESOURCE_URL |
@@ -79,7 +86,75 @@ def setUp(self): |
79 | 86 | def tearDown(self): |
80 | 87 | # re-enable logging |
81 | 88 | logging.disable(logging.NOTSET) |
82 | | - |
| 89 | + |
| 90 | + |
| 91 | +class TasksViewTests(TransactionTestCase): |
| 92 | + |
| 93 | + @classmethod |
| 94 | + def setUpClass(cls): |
| 95 | + logging.disable(logging.WARNING) |
| 96 | + super().setUpClass() |
| 97 | + # route tasks to this worker by using the default 'celery' queue |
| 98 | + # that is exclusively used for the automated tests |
| 99 | + celery_app.conf.update(task_routes=None) |
| 100 | + cls.celery_worker = start_worker(celery_app, |
| 101 | + concurrency=1, |
| 102 | + perform_ping_check=False) |
| 103 | + cls.celery_worker.__enter__() |
| 104 | + |
| 105 | + @classmethod |
| 106 | + def tearDownClass(cls): |
| 107 | + super().tearDownClass() |
| 108 | + cls.celery_worker.__exit__(None, None, None) |
| 109 | + # reset routes to the original queues |
| 110 | + celery_app.conf.update(task_routes=task_routes) |
| 111 | + logging.disable(logging.NOTSET) |
| 112 | + |
| 113 | + def setUp(self): |
| 114 | + # create superuser chris (owner of root folders) |
| 115 | + self.chris_username = 'chris' |
| 116 | + self.chris_password = CHRIS_SUPERUSER_PASSWORD |
| 117 | + |
| 118 | + self.content_type = 'application/vnd.collection+json' |
| 119 | + |
| 120 | + self.username = 'foo' |
| 121 | + self.password = 'foopass' |
| 122 | + self.other_username = 'booo' |
| 123 | + self.other_password = 'booopass' |
| 124 | + |
| 125 | + self.plugin_name = "pacspull" |
| 126 | + self.plugin_type = "fs" |
| 127 | + self.plugin_parameters = {'mrn': {'type': 'string', 'optional': False}, |
| 128 | + 'img_type': {'type': 'string', 'optional': True}} |
| 129 | + self.feedname = "Feed1" |
| 130 | + |
| 131 | + (self.compute_resource, tf) = ComputeResource.objects.get_or_create( |
| 132 | + name="host", compute_url=COMPUTE_RESOURCE_URL) |
| 133 | + |
| 134 | + # create users |
| 135 | + other_user = User.objects.create_user(username=self.other_username, |
| 136 | + password=self.other_password) |
| 137 | + user = User.objects.create_user(username=self.username, |
| 138 | + password=self.password) |
| 139 | + |
| 140 | + # assign predefined group |
| 141 | + all_grp = Group.objects.get(name='all_users') |
| 142 | + |
| 143 | + other_user.groups.set([all_grp]) |
| 144 | + user.groups.set([all_grp]) |
| 145 | + |
| 146 | + # create plugin |
| 147 | + (pl_meta, tf) = PluginMeta.objects.get_or_create(name='pacspull', type='fs') |
| 148 | + (plugin, tf) = Plugin.objects.get_or_create(meta=pl_meta, version='0.1') |
| 149 | + plugin.compute_resources.set([self.compute_resource]) |
| 150 | + plugin.save() |
| 151 | + |
| 152 | + # create a feed by creating a "fs" plugin instance |
| 153 | + pl_inst = PluginInstance.objects.create(plugin=plugin, owner=user, title='test', |
| 154 | + compute_resource= |
| 155 | + plugin.compute_resources.all()[0]) |
| 156 | + pl_inst.feed.name = self.feedname |
| 157 | + pl_inst.feed.save() |
83 | 158 |
|
84 | 159 | class NoteDetailViewTests(ViewTests): |
85 | 160 | """ |
@@ -224,7 +299,7 @@ def test_feed_list_query_search_from_other_users_not_listed(self): |
224 | 299 | self.assertNotContains(response, "Feed2") |
225 | 300 |
|
226 | 301 |
|
227 | | -class FeedDetailViewTests(ViewTests): |
| 302 | +class FeedDetailViewTests(TasksViewTests): |
228 | 303 | """ |
229 | 304 | Test the feed-detail view. |
230 | 305 | """ |
@@ -274,8 +349,24 @@ def test_feed_update_failure_access_denied(self): |
274 | 349 |
|
275 | 350 | def test_feed_delete_success(self): |
276 | 351 | self.client.login(username=self.username, password=self.password) |
| 352 | + |
| 353 | + with mock.patch.object(views.delete_feed, 'delay', |
| 354 | + return_value=None) as delay_mock: |
| 355 | + response = self.client.delete(self.read_update_delete_url) |
| 356 | + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) |
| 357 | + |
| 358 | + # check that the delete_feed task was called with appropriate args |
| 359 | + delay_mock.assert_called_with(response.data['id']) |
| 360 | + |
| 361 | + @tag('integration') |
| 362 | + def test_integration_feed_delete_success(self): |
| 363 | + self.client.login(username=self.username, password=self.password) |
277 | 364 | response = self.client.delete(self.read_update_delete_url) |
278 | | - self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) |
| 365 | + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) |
| 366 | + |
| 367 | + for _ in range(10): |
| 368 | + time.sleep(3) |
| 369 | + if Feed.objects.count() == 0: break |
279 | 370 | self.assertEqual(Feed.objects.count(), 0) |
280 | 371 |
|
281 | 372 | def test_feed_delete_failure_unauthenticated(self): |
|
0 commit comments