mirror of
https://github.com/ansible/awx.git
synced 2024-11-01 08:21:15 +03:00
398 lines
17 KiB
Python
398 lines
17 KiB
Python
# FIXME: do not use ResourceTestCase
|
|
|
|
"""
|
|
This file demonstrates two different styles of tests (one doctest and one
|
|
unittest). These will both pass when you run "manage.py test".
|
|
|
|
Replace these with more appropriate tests for your application.
|
|
"""
|
|
|
|
|
|
import datetime
|
|
import json
|
|
|
|
from django.contrib.auth.models import User as DjangoUser
|
|
import django.test
|
|
from django.test.client import Client
|
|
from lib.main.models import *
|
|
|
|
class BaseTest(django.test.TestCase):
|
|
|
|
def make_user(self, username, password, super_user=False):
|
|
django_user = None
|
|
if super_user:
|
|
django_user = DjangoUser.objects.create_superuser(username, "%s@example.com", password)
|
|
else:
|
|
django_user = DjangoUser.objects.create_user(username, "%s@example.com", password)
|
|
return django_user
|
|
|
|
def make_organizations(self, created_by, count=1):
|
|
results = []
|
|
for x in range(0, count):
|
|
results.append(Organization.objects.create(
|
|
name="org%s" % x,
|
|
description="org%s" % x,
|
|
created_by=created_by
|
|
))
|
|
return results
|
|
|
|
def make_projects(self, created_by, count=1):
|
|
results = []
|
|
for x in range(0, count):
|
|
results.append(Project.objects.create(
|
|
name="proj%s" % x,
|
|
description="proj%s" % x,
|
|
scm_type='git',
|
|
default_playbook='foo.yml',
|
|
local_repository='/checkout',
|
|
created_by=created_by
|
|
))
|
|
return results
|
|
|
|
def check_pagination_and_size(self, data, desired_count, previous=None, next=None):
|
|
self.assertEquals(data['previous'], previous)
|
|
self.assertEquals(data['next'], next)
|
|
|
|
def setup_users(self):
|
|
# Create a user.
|
|
self.super_username = 'admin'
|
|
self.super_password = 'admin'
|
|
self.normal_username = 'normal'
|
|
self.normal_password = 'normal'
|
|
self.other_username = 'other'
|
|
self.other_password = 'other'
|
|
|
|
self.super_django_user = self.make_user(self.super_username, self.super_password, super_user=True)
|
|
self.normal_django_user = self.make_user(self.normal_username, self.normal_password, super_user=False)
|
|
self.other_django_user = self.make_user(self.other_username, self.other_password, super_user=False)
|
|
|
|
def get_super_credentials(self):
|
|
return (self.super_username, self.super_password)
|
|
|
|
def get_normal_credentials(self):
|
|
return (self.normal_username, self.normal_password)
|
|
|
|
def get_other_credentials(self):
|
|
return (self.other_username, self.other_password)
|
|
|
|
def get_invalid_credentials(self):
|
|
return ('random', 'combination')
|
|
|
|
def _generic_rest(self, url, data=None, expect=204, auth=None, method=None):
|
|
assert method is not None
|
|
method = method.lower()
|
|
if method not in [ 'get', 'delete' ]:
|
|
assert data is not None
|
|
client = Client()
|
|
if auth:
|
|
client.login(username=auth[0], password=auth[1])
|
|
method = getattr(client,method)
|
|
response = None
|
|
if data is not None:
|
|
response = method(url, json.dumps(data), 'application/json')
|
|
else:
|
|
response = method(url)
|
|
|
|
if response.status_code == 500 and expect != 500:
|
|
assert False, "Failed: %s" % response.content
|
|
if expect is not None:
|
|
assert response.status_code == expect, "expected status %s, got %s for url=%s as auth=%s: %s" % (expect, response.status_code, url, auth, response.content)
|
|
if response.status_code not in [ 202, 204, 400, 409 ]:
|
|
# no JSON responses in these at least for now, 400/409 should probably return some (FIXME)
|
|
return json.loads(response.content)
|
|
else:
|
|
return None
|
|
|
|
def get(self, url, expect=200, auth=None):
|
|
return self._generic_rest(url, data=None, expect=expect, auth=auth, method='get')
|
|
|
|
def post(self, url, data, expect=204, auth=None):
|
|
return self._generic_rest(url, data=data, expect=expect, auth=auth, method='post')
|
|
|
|
def put(self, url, data, expect=200, auth=None):
|
|
return self._generic_rest(url, data=data, expect=expect, auth=auth, method='put')
|
|
|
|
def delete(self, url, expect=201, auth=None):
|
|
return self._generic_rest(url, data=None, expect=expect, auth=auth, method='delete')
|
|
|
|
def get_urls(self, collection_url, auth=None):
|
|
# TODO: this test helper function doesn't support pagination
|
|
data = self.get(collection_url, expect=200, auth=auth)
|
|
return [item['url'] for item in data['results']]
|
|
|
|
|
|
class OrganizationsTest(BaseTest):
|
|
|
|
def collection(self):
|
|
return '/api/v1/organizations/'
|
|
|
|
def setUp(self):
|
|
self.setup_users()
|
|
|
|
self.organizations = self.make_organizations(self.super_django_user, 10)
|
|
self.projects = self.make_projects(self.normal_django_user, 10)
|
|
|
|
# add projects to organizations in a more or less arbitrary way
|
|
for project in self.projects[0:2]:
|
|
self.organizations[0].projects.add(project)
|
|
for project in self.projects[3:8]:
|
|
self.organizations[1].projects.add(project)
|
|
for project in self.projects[9:10]:
|
|
self.organizations[2].projects.add(project)
|
|
self.organizations[0].projects.add(self.projects[-1])
|
|
self.organizations[9].projects.add(self.projects[-2])
|
|
|
|
# get the URL for various organization records
|
|
self.a_detail_url = "%s%s" % (self.collection(), self.organizations[0].pk)
|
|
self.b_detail_url = "%s%s" % (self.collection(), self.organizations[1].pk)
|
|
self.c_detail_url = "%s%s" % (self.collection(), self.organizations[2].pk)
|
|
|
|
# configuration:
|
|
# admin_user is an admin and regular user in all organizations
|
|
# other_user is all organizations
|
|
# normal_user is a user in organization 0, and an admin of organization 1
|
|
|
|
for x in self.organizations:
|
|
# NOTE: superuser does not have to be explicitly added to admin group
|
|
# x.admins.add(self.super_django_user)
|
|
x.users.add(self.super_django_user)
|
|
|
|
self.organizations[0].users.add(self.normal_django_user)
|
|
self.organizations[1].admins.add(self.normal_django_user)
|
|
|
|
def test_get_list(self):
|
|
|
|
# no credentials == 401
|
|
self.get(self.collection(), expect=401)
|
|
|
|
# wrong credentials == 401
|
|
self.get(self.collection(), expect=401, auth=self.get_invalid_credentials())
|
|
|
|
# superuser credentials == 200, full list
|
|
data = self.get(self.collection(), expect=200, auth=self.get_super_credentials())
|
|
self.check_pagination_and_size(data, 10, previous=None, next=None)
|
|
[self.assertTrue(key in data['results'][0]) for key in ['name', 'description', 'url', 'creation_date', 'id' ]]
|
|
|
|
# check that the related URL functionality works
|
|
related = data['results'][0]['related']
|
|
for x in [ 'audit_trail', 'projects', 'users', 'admins', 'tags' ]:
|
|
self.assertTrue(x in related and related[x].endswith("/%s/" % x), "looking for %s in related" % x)
|
|
|
|
# normal credentials == 200, get only organizations that I am actually added to (there are 2)
|
|
data = self.get(self.collection(), expect=200, auth=self.get_normal_credentials())
|
|
self.check_pagination_and_size(data, 2, previous=None, next=None)
|
|
|
|
# no admin rights? get empty list
|
|
data = self.get(self.collection(), expect=200, auth=self.get_other_credentials())
|
|
self.check_pagination_and_size(data, 0, previous=None, next=None)
|
|
|
|
def test_get_item(self):
|
|
|
|
# first get all the URLs
|
|
data = self.get(self.collection(), expect=200, auth=self.get_super_credentials())
|
|
urls = [item['url'] for item in data['results']]
|
|
|
|
# make sure super user can fetch records
|
|
data = self.get(urls[0], expect=200, auth=self.get_super_credentials())
|
|
[self.assertTrue(key in data) for key in ['name', 'description', 'url' ]]
|
|
|
|
# make sure invalid user cannot
|
|
data = self.get(urls[0], expect=401, auth=self.get_invalid_credentials())
|
|
|
|
# normal user should be able to get org 0 and org 1 but not org 9 (as he's not a user or admin of it)
|
|
data = self.get(urls[0], expect=200, auth=self.get_normal_credentials())
|
|
data = self.get(urls[1], expect=200, auth=self.get_normal_credentials())
|
|
data = self.get(urls[9], expect=403, auth=self.get_normal_credentials())
|
|
|
|
# other user isn't a user or admin of anything, and similarly can't get in
|
|
data = self.get(urls[0], expect=403, auth=self.get_other_credentials())
|
|
|
|
def test_get_item_subobjects_projects(self):
|
|
|
|
# first get all the orgs
|
|
orgs = self.get(self.collection(), expect=200, auth=self.get_super_credentials())
|
|
|
|
# find projects attached to the first org
|
|
projects0_url = orgs['results'][0]['related']['projects']
|
|
projects1_url = orgs['results'][1]['related']['projects']
|
|
projects9_url = orgs['results'][9]['related']['projects']
|
|
|
|
self.get(projects0_url, expect=401, auth=None)
|
|
self.get(projects0_url, expect=401, auth=self.get_invalid_credentials())
|
|
|
|
# normal user is just a member of the first org, but can't see any projects yet
|
|
projects0a = self.get(projects0_url, expect=200, auth=self.get_normal_credentials())
|
|
self.assertEquals(projects0a['count'], 0)
|
|
|
|
# however in the second org, he's an admin and should see all of them
|
|
projects1a = self.get(projects1_url, expect=200, auth=self.get_normal_credentials())
|
|
self.assertEquals(projects1a['count'], 5)
|
|
projects1b = self.get(projects1_url, expect=200, auth=self.get_other_credentials())
|
|
self.assertEquals(projects1b['count'], 0)
|
|
|
|
# superuser should be able to read anything
|
|
projects9a = self.get(projects9_url, expect=200, auth=self.get_super_credentials())
|
|
self.assertEquals(projects9a['count'], 1)
|
|
|
|
|
|
def test_get_item_subobjects_users(self):
|
|
pass
|
|
|
|
def test_get_item_subobjects_admins(self):
|
|
pass
|
|
|
|
def test_get_item_subobjects_tags(self):
|
|
pass
|
|
|
|
def test_get_item_subobjects_audit_trail(self):
|
|
pass
|
|
|
|
def test_post_item(self):
|
|
|
|
new_org = dict(name='magic test org', description='8675309')
|
|
|
|
# need to be a valid user
|
|
self.post(self.collection(), new_org, expect=401, auth=None)
|
|
self.post(self.collection(), new_org, expect=401, auth=self.get_invalid_credentials())
|
|
|
|
# only super users can create organizations
|
|
self.post(self.collection(), new_org, expect=403, auth=self.get_normal_credentials())
|
|
self.post(self.collection(), new_org, expect=403, auth=self.get_other_credentials())
|
|
data1 = self.post(self.collection(), new_org, expect=201, auth=self.get_super_credentials())
|
|
|
|
# duplicate post results in 400
|
|
data2 = self.post(self.collection(), new_org, expect=400, auth=self.get_super_credentials())
|
|
|
|
# look at what we got back from the post, make sure we added an org
|
|
self.assertTrue(data1['url'].endswith("/11/"))
|
|
|
|
def test_post_item_subobjects_projects(self):
|
|
|
|
# first get all the orgs
|
|
orgs = self.get(self.collection(), expect=200, auth=self.get_super_credentials())
|
|
|
|
# find projects attached to the first org
|
|
projects0_url = orgs['results'][0]['related']['projects']
|
|
projects7_url = orgs['results'][1]['related']['projects']
|
|
|
|
# get all the projects on the first org
|
|
projects0 = self.get(projects0_url, expect=200, auth=self.get_super_credentials())
|
|
a_project = projects0['results'][-1]
|
|
|
|
# attempt to add the project to the 7th org and see what happens
|
|
self.post(projects7_url, a_project, expect=204, auth=self.get_super_credentials())
|
|
projects1 = self.get(projects0_url, expect=200, auth=self.get_super_credentials())
|
|
self.assertEquals(projects1['count'], 3)
|
|
|
|
# make sure we can't add the project again (should generate a conflict error)
|
|
self.post(projects7_url, a_project, expect=409, auth=self.get_super_credentials())
|
|
projects7 = self.get(projects7_url, expect=200, auth=self.get_super_credentials())
|
|
self.assertEquals(projects7['count'], 6)
|
|
|
|
# make sure adding a project that does not exist, or a missing pk field, results in a 400
|
|
self.post(projects7_url, dict(id=99999), expect=400, auth=self.get_super_credentials())
|
|
self.post(projects7_url, dict(asdf=1234), expect=400, auth=self.get_super_credentials())
|
|
|
|
# test that by posting a pk + disassociate: True we can remove a relationship
|
|
a_project['disassociate'] = True
|
|
self.post(projects7_url, a_project, expect=204, auth=self.get_super_credentials())
|
|
projects7 = self.get(projects7_url, expect=200, auth=self.get_super_credentials())
|
|
self.assertEquals(projects7['count'], 5)
|
|
|
|
# FIXME: need to add tests for associating and disassocating from a non-priveledged acct
|
|
|
|
def test_post_item_subobjects_users(self):
|
|
pass
|
|
|
|
def test_post_item_subobjects_admins(self):
|
|
pass
|
|
|
|
def test_post_item_subobjects_tags(self):
|
|
pass
|
|
|
|
def test_post_item_subobjects_audit_trail(self):
|
|
pass
|
|
|
|
def test_put_item(self):
|
|
|
|
# first get some urls and data to put back to them
|
|
urls = self.get_urls(self.collection(), auth=self.get_super_credentials())
|
|
data0 = self.get(urls[0], expect=200, auth=self.get_super_credentials())
|
|
data1 = self.get(urls[1], expect=200, auth=self.get_super_credentials())
|
|
|
|
# test that an unauthenticated user cannot do a put
|
|
new_data1 = data1.copy()
|
|
new_data1['description'] = 'updated description'
|
|
self.put(urls[0], new_data1, expect=401, auth=None)
|
|
self.put(urls[0], new_data1, expect=401, auth=self.get_invalid_credentials())
|
|
|
|
# user normal is an admin of org 0 and a member of org 1 so should be able to put only org 1
|
|
self.put(urls[0], new_data1, expect=403, auth=self.get_normal_credentials())
|
|
put_result = self.put(urls[1], new_data1, expect=200, auth=self.get_normal_credentials())
|
|
|
|
# FIXME: test the contents of the put returned object
|
|
|
|
# get back org 1 and see if it changed
|
|
get_result = self.get(urls[1], expect=200, auth=self.get_normal_credentials())
|
|
self.assertEquals(get_result['description'], 'updated description')
|
|
|
|
# super user can also put even though they aren't added to the org users or admins list
|
|
self.put(urls[1], new_data1, expect=200, auth=self.get_super_credentials())
|
|
|
|
# make sure posting to this URL is not supported
|
|
self.post(urls[1], new_data1, expect=405, auth=self.get_super_credentials())
|
|
|
|
def test_put_item_subobjects_projects(self):
|
|
|
|
# any attempt to put a subobject should be a 405, edit the actual resource or POST with 'disassociate' to delete
|
|
# this is against a collection URL anyway, so we really need not repeat this test for other object types
|
|
# as a PUT against a collection doesn't make much sense.
|
|
|
|
orgs = self.get(self.collection(), expect=200, auth=self.get_super_credentials())
|
|
projects0_url = orgs['results'][0]['related']['projects']
|
|
sub_projects = self.get(projects0_url, expect=200, auth=self.get_super_credentials())
|
|
self.assertEquals(sub_projects['count'], 3)
|
|
first_sub_project = sub_projects['results'][0]
|
|
self.put(projects0_url, first_sub_project, expect=405, auth=self.get_super_credentials())
|
|
|
|
def test_put_item_subobjects_users(self):
|
|
pass
|
|
|
|
def test_put_item_subobjects_admins(self):
|
|
pass
|
|
|
|
def test_delete_item(self):
|
|
|
|
# first get some urls
|
|
urls = self.get_urls(self.collection(), auth=self.get_super_credentials())
|
|
urldata1 = self.get(urls[1], auth=self.get_super_credentials())
|
|
|
|
# check authentication -- admins of the org and superusers can delete objects only
|
|
self.delete(urls[0], expect=401, auth=None)
|
|
self.delete(urls[0], expect=401, auth=self.get_invalid_credentials())
|
|
self.delete(urls[8], expect=403, auth=self.get_normal_credentials())
|
|
self.delete(urls[1], expect=204, auth=self.get_normal_credentials())
|
|
self.delete(urls[0], expect=204, auth=self.get_super_credentials())
|
|
|
|
# check that when we have deleted an object it comes back 404 via GET
|
|
# but that it's still in the database as inactive
|
|
self.get(urls[1], expect=404, auth=self.get_normal_credentials())
|
|
org1 = Organization.objects.get(pk=urldata1['id'])
|
|
self.assertEquals(org1.active, False)
|
|
|
|
# also check that DELETE on the collection doesn't work
|
|
self.delete(self.collection(), expect=405, auth=self.get_super_credentials())
|
|
|
|
def test_delete_item_subobjects_projects(self):
|
|
# TODO: make sure this is covered in the POST test with a disassociate example
|
|
pass
|
|
|
|
def test_delete_item_subobjects_users(self):
|
|
# TODO: make sure this is covered in the POST test with a disassociate example
|
|
pass
|
|
|
|
def test_delete_item_subobjects_admins(self):
|
|
# TODO: make sure this is covered in the POST test with a disassociate example
|
|
pass
|
|
|