Skip to content

Commit 2b8d21a

Browse files
committed
Fixed #370 -- added CLI tests for app sharing workflow.
1 parent e363b38 commit 2b8d21a

12 files changed

Lines changed: 191 additions & 209 deletions

File tree

.coveragerc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ omit =
33
*/venv/*
44
*/virtualenv/*
55
api/__init__.py
6-
api/tests/*
76
client/__init__.py
87
client/models.py
98
client/tests/__init__.py

api/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class FlavorAdmin(admin.ModelAdmin):
7373
admin.site.register(Flavor, FlavorAdmin)
7474

7575

76-
class FormationAdmin(GuardedModelAdmin):
76+
class FormationAdmin(admin.ModelAdmin):
7777
"""Set presentation options for :class:`~api.models.Formation` models
7878
in the Django admin.
7979
"""

api/models.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from django.dispatch import receiver
2121
from django.dispatch.dispatcher import Signal
2222
from django.utils.encoding import python_2_unicode_compatible
23+
from guardian.shortcuts import get_users_with_perms
2324
from json_field.fields import JSONField # @UnusedImport
2425

2526
from api import fields, tasks
@@ -174,7 +175,6 @@ class Formation(UuidAuditedModel):
174175
nodes = JSONField(default='{}', blank=True)
175176

176177
class Meta:
177-
permissions = (('use_formation', 'Can use formation'),)
178178
unique_together = (('owner', 'id'),)
179179

180180
def __str__(self):
@@ -519,10 +519,10 @@ def calculate(self):
519519
else:
520520
for n in self.formation.node_set.filter(layer__proxy=True):
521521
d['domains'].append(n.fqdn)
522-
# TODO: add proper sharing and access controls
523-
d['users'] = {}
524-
for u in (self.owner.username,):
525-
d['users'][u] = 'admin'
522+
# add proper sharing and access controls
523+
d['users'] = {self.owner.username: 'owner'}
524+
for u in (get_users_with_perms(self)):
525+
d['users'][u.username] = 'user'
526526
return d
527527

528528
def logs(self):
@@ -741,7 +741,7 @@ def push(cls, push):
741741
username = push.pop('username').split('_')[0]
742742
# retrieve the user and app instances
743743
user = User.objects.get(username=username)
744-
app = App.objects.get(owner=user, id=push.pop('app'))
744+
app = App.objects.get(id=push.pop('app'))
745745
# merge the push with the required model instances
746746
push['owner'] = user
747747
push['app'] = app

api/serializers.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class ConfigSerializer(serializers.ModelSerializer):
9191
"""Serialize a :class:`~api.models.Config` model."""
9292

9393
owner = serializers.Field(source='owner.username')
94-
app = OwnerSlugRelatedField(slug_field='id')
94+
app = serializers.SlugRelatedField(slug_field='id')
9595
values = serializers.ModelField(
9696
model_field=models.Config()._meta.get_field('values'), required=False)
9797

@@ -105,7 +105,7 @@ class BuildSerializer(serializers.ModelSerializer):
105105
"""Serialize a :class:`~api.models.Build` model."""
106106

107107
owner = serializers.Field(source='owner.username')
108-
app = OwnerSlugRelatedField(slug_field='id')
108+
app = serializers.SlugRelatedField(slug_field='id')
109109

110110
class Meta:
111111
"""Metadata options for a :class:`BuildSerializer`."""
@@ -117,7 +117,7 @@ class ReleaseSerializer(serializers.ModelSerializer):
117117
"""Serialize a :class:`~api.models.Release` model."""
118118

119119
owner = serializers.Field(source='owner.username')
120-
app = OwnerSlugRelatedField(slug_field='id')
120+
app = serializers.SlugRelatedField(slug_field='id')
121121
config = serializers.SlugRelatedField(slug_field='uuid')
122122
build = serializers.SlugRelatedField(slug_field='uuid', required=False)
123123

api/tests/test_key.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
import os.path
1111

1212
from django.test import TestCase
13+
from django.test.utils import override_settings
1314

1415
from deis import settings
1516

1617

18+
@override_settings(CELERY_ALWAYS_EAGER=True)
1719
class KeyTest(TestCase):
1820

1921
"""Tests cloud provider credentials"""

api/tests/test_perm.py

Lines changed: 3 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import json
44

55
from django.test import TestCase
6+
from django.test.utils import override_settings
67

78

9+
@override_settings(CELERY_ALWAYS_EAGER=True)
810
class TestAdminPerms(TestCase):
911

1012
def test_first_signup(self):
@@ -132,6 +134,7 @@ def test_delete(self):
132134
self.assertNotIn('two', str(response.data['results']))
133135

134136

137+
@override_settings(CELERY_ALWAYS_EAGER=True)
135138
class TestAppPerms(TestCase):
136139

137140
fixtures = ['test_sharing.json']
@@ -215,120 +218,3 @@ def test_list(self):
215218
response = self.client.get(
216219
"/api/apps/{}/perms".format(app_id), content_type='application/json')
217220
self.assertEqual(response.data, {'users': ['autotest-2']})
218-
219-
220-
class TestFormationPerms(TestCase):
221-
222-
fixtures = ['test_sharing.json']
223-
224-
def setUp(self):
225-
self.assertTrue(
226-
self.client.login(username='autotest-1', password='password'))
227-
228-
def test_create(self):
229-
# check that user 1 sees her lone formation
230-
response = self.client.get('/api/formations')
231-
self.assertEqual(response.status_code, 200)
232-
self.assertEqual(len(response.data['results']), 1)
233-
formation_id = response.data['results'][0]['id']
234-
# check that user 2 can't see any formations
235-
self.assertTrue(
236-
self.client.login(username='autotest-2', password='password'))
237-
response = self.client.get('/api/formations')
238-
self.assertEqual(response.status_code, 200)
239-
self.assertEqual(len(response.data['results']), 0)
240-
# give user 2 permission to user 1's formation
241-
self.assertTrue(
242-
self.client.login(username='autotest-1', password='password'))
243-
url = '/api/formations/{formation_id}/perms'.format(**locals())
244-
body = {'username': 'autotest-2'}
245-
response = self.client.post(
246-
url, json.dumps(body), content_type='application/json')
247-
self.assertEqual(response.status_code, 201)
248-
# check that user 1 can see a formation
249-
self.assertTrue(
250-
self.client.login(username='autotest-2', password='password'))
251-
response = self.client.get('/api/formations')
252-
self.assertEqual(response.status_code, 200)
253-
self.assertEqual(len(response.data['results']), 1)
254-
self.assertEqual(response.data['results'][0]['id'], formation_id)
255-
# revoke user 2's permission to user 1's formation
256-
self.assertTrue(
257-
self.client.login(username='autotest-1', password='password'))
258-
username = 'autotest-2'
259-
url = '/api/formations/{formation_id}/perms/{username}/'.format(**locals())
260-
response = self.client.delete(url)
261-
self.assertEqual(response.status_code, 204)
262-
263-
def test_create_errors(self):
264-
response = self.client.get('/api/formations')
265-
formation_id = response.data['results'][0]['id']
266-
# try to give user 2 permission to user 1's formation as user 2
267-
self.assertTrue(
268-
self.client.login(username='autotest-2', password='password'))
269-
url = '/api/formations/{formation_id}/perms'.format(**locals())
270-
body = {'username': 'autotest-2'}
271-
response = self.client.post(
272-
url, json.dumps(body), content_type='application/json')
273-
self.assertEqual(response.status_code, 403)
274-
# try to give user 1 permission to user 1's formation as user 2
275-
url = '/api/formations/{formation_id}/perms'.format(**locals())
276-
body = {'username': 'autotest-1'}
277-
response = self.client.post(
278-
url, json.dumps(body), content_type='application/json')
279-
self.assertEqual(response.status_code, 403)
280-
281-
def test_delete(self):
282-
# give user 2 permission to user 1's formation
283-
response = self.client.get('/api/formations')
284-
formation_id = response.data['results'][0]['id']
285-
url = '/api/formations/{formation_id}/perms'.format(**locals())
286-
body = {'username': 'autotest-2'}
287-
response = self.client.post(
288-
url, json.dumps(body), content_type='application/json')
289-
self.assertEqual(response.status_code, 201)
290-
# check that user 1 can see a formation
291-
self.assertTrue(
292-
self.client.login(username='autotest-2', password='password'))
293-
response = self.client.get('/api/formations')
294-
self.assertEqual(response.status_code, 200)
295-
self.assertEqual(len(response.data['results']), 1)
296-
self.assertEqual(response.data['results'][0]['id'], formation_id)
297-
# revoke user 2's permission to user 1's formation
298-
self.assertTrue(
299-
self.client.login(username='autotest-1', password='password'))
300-
username = 'autotest-2'
301-
url = '/api/formations/{formation_id}/perms/{username}/'.format(**locals())
302-
response = self.client.delete(url)
303-
self.assertEqual(response.status_code, 204)
304-
# check that user 1 can't see any formations
305-
self.assertTrue(
306-
self.client.login(username='autotest-2', password='password'))
307-
response = self.client.get('/api/formations')
308-
self.assertEqual(response.status_code, 200)
309-
self.assertEqual(len(response.data['results']), 0)
310-
311-
def test_delete_errors(self):
312-
# revoke user 2's permission to user 1's formation
313-
response = self.client.get('/api/formations')
314-
formation_id = response.data['results'][0]['id']
315-
username = 'autotest-2'
316-
url = '/api/formations/{formation_id}/perms/{username}/'.format(**locals())
317-
response = self.client.delete(url)
318-
self.assertEqual(response.status_code, 404)
319-
320-
def test_list(self):
321-
# check that user 1 sees her lone formation
322-
response = self.client.get('/api/formations')
323-
self.assertEqual(response.status_code, 200)
324-
self.assertEqual(len(response.data['results']), 1)
325-
formation_id = response.data['results'][0]['id']
326-
# create a new object permission
327-
url = "/api/formations/{}/perms".format(formation_id)
328-
body = {'username': 'autotest-2'}
329-
response = self.client.post(url, json.dumps(body), content_type='application/json')
330-
self.assertEqual(response.status_code, 201)
331-
# list perms on the app
332-
response = self.client.get(
333-
"/api/formations/{}/perms".format(formation_id), content_type='application/json')
334-
self.assertEqual(response.data, {'users': ['autotest-2']})

api/urls.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -166,22 +166,6 @@
166166
:meth:`FormationViewSet.converge() <api.views.FormationViewSet.converge>`
167167
168168
169-
Formation Sharing
170-
-----------------
171-
172-
.. http:delete:: /api/formations/(string:id)/perms/(string:username)/
173-
174-
Destroy a formation permission by its `username`.
175-
176-
.. http:get:: /api/formations/(string:id)/perms/
177-
178-
List all permissions granted to this formation.
179-
180-
.. http:post:: /api/formations/(string:id)/perms/
181-
182-
Create a new formation permission.
183-
184-
185169
Applications
186170
============
187171
@@ -410,11 +394,6 @@
410394
views.FormationViewSet.as_view({'post': 'calculate'})),
411395
url(r'^formations/(?P<id>[-_\w]+)/converge/?',
412396
views.FormationViewSet.as_view({'post': 'converge'})),
413-
# formation sharing
414-
url(r'^formations/(?P<id>[-_\w]+)/perms/(?P<username>[-_\w]+)/?',
415-
views.FormationPermsViewSet.as_view({'delete': 'destroy'})),
416-
url(r'^formations/(?P<id>[-_\w]+)/perms/?',
417-
views.FormationPermsViewSet.as_view({'get': 'list', 'post': 'create'})),
418397
# formation base endpoint
419398
url(r'^formations/(?P<id>[-_\w]+)/?',
420399
views.FormationViewSet.as_view({

0 commit comments

Comments
 (0)