diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f89a742 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM python:alpine + +MAINTAINER Anna Sudnitsyna +WORKDIR /usr/src/app + +COPY requirements.txt ./ + + + +RUN pip install --no-cache-dir -r requirements.txt +RUN pip install selenium +COPY . . + +#EXPOSE 8000 + +#ENTRYPOINT python3 manage.py runserver 0.0.0.0:8000 +ENTRYPOINT ls && python manage.py test tests.selenium.dashboard_test \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/test_inventory.json b/api/test_inventory.json new file mode 100644 index 0000000..7f7057d --- /dev/null +++ b/api/test_inventory.json @@ -0,0 +1 @@ +[{"model": "contenttypes.contenttype", "pk": 1, "fields": {"app_label": "admin", "model": "logentry"}}, {"model": "contenttypes.contenttype", "pk": 2, "fields": {"app_label": "auth", "model": "permission"}}, {"model": "contenttypes.contenttype", "pk": 3, "fields": {"app_label": "auth", "model": "group"}}, {"model": "contenttypes.contenttype", "pk": 4, "fields": {"app_label": "auth", "model": "user"}}, {"model": "contenttypes.contenttype", "pk": 5, "fields": {"app_label": "contenttypes", "model": "contenttype"}}, {"model": "contenttypes.contenttype", "pk": 6, "fields": {"app_label": "sessions", "model": "session"}}, {"model": "contenttypes.contenttype", "pk": 7, "fields": {"app_label": "api", "model": "child"}}, {"model": "contenttypes.contenttype", "pk": 8, "fields": {"app_label": "api", "model": "group"}}, {"model": "contenttypes.contenttype", "pk": 9, "fields": {"app_label": "api", "model": "host"}}, {"model": "contenttypes.contenttype", "pk": 10, "fields": {"app_label": "api", "model": "hostvariable"}}, {"model": "contenttypes.contenttype", "pk": 11, "fields": {"app_label": "api", "model": "inventory"}}, {"model": "contenttypes.contenttype", "pk": 12, "fields": {"app_label": "api", "model": "machine"}}, {"model": "contenttypes.contenttype", "pk": 13, "fields": {"app_label": "api", "model": "variable"}}, {"model": "contenttypes.contenttype", "pk": 14, "fields": {"app_label": "registration", "model": "activation"}}, {"model": "contenttypes.contenttype", "pk": 15, "fields": {"app_label": "registration", "model": "limits"}}, {"model": "contenttypes.contenttype", "pk": 16, "fields": {"app_label": "authtoken", "model": "inventorytoken"}}, {"model": "contenttypes.contenttype", "pk": 17, "fields": {"app_label": "authtoken", "model": "token"}}, {"model": "contenttypes.contenttype", "pk": 18, "fields": {"app_label": "social_django", "model": "association"}}, {"model": "contenttypes.contenttype", "pk": 19, "fields": {"app_label": "social_django", "model": "code"}}, {"model": "contenttypes.contenttype", "pk": 20, "fields": {"app_label": "social_django", "model": "nonce"}}, {"model": "contenttypes.contenttype", "pk": 21, "fields": {"app_label": "social_django", "model": "usersocialauth"}}, {"model": "contenttypes.contenttype", "pk": 22, "fields": {"app_label": "social_django", "model": "partial"}}, {"model": "api.group", "pk": 1, "fields": {"group": "test_gr", "inventory": 1}}, {"model": "api.group", "pk": 2, "fields": {"group": "child_gr", "inventory": 1}}, {"model": "api.variable", "pk": 1, "fields": {"variable": "test_var", "value": "dGVzdA==", "group": 1}}, {"model": "api.host", "pk": 1, "fields": {"group": 1, "host": 1}}, {"model": "api.child", "pk": 1, "fields": {"group": 1, "child": 2}}, {"model": "auth.permission", "pk": 1, "fields": {"name": "Can add log entry", "content_type": 1, "codename": "add_logentry"}}, {"model": "auth.permission", "pk": 2, "fields": {"name": "Can change log entry", "content_type": 1, "codename": "change_logentry"}}, {"model": "auth.permission", "pk": 3, "fields": {"name": "Can delete log entry", "content_type": 1, "codename": "delete_logentry"}}, {"model": "auth.permission", "pk": 4, "fields": {"name": "Can add permission", "content_type": 2, "codename": "add_permission"}}, {"model": "auth.permission", "pk": 5, "fields": {"name": "Can change permission", "content_type": 2, "codename": "change_permission"}}, {"model": "auth.permission", "pk": 6, "fields": {"name": "Can delete permission", "content_type": 2, "codename": "delete_permission"}}, {"model": "auth.permission", "pk": 7, "fields": {"name": "Can add group", "content_type": 3, "codename": "add_group"}}, {"model": "auth.permission", "pk": 8, "fields": {"name": "Can change group", "content_type": 3, "codename": "change_group"}}, {"model": "auth.permission", "pk": 9, "fields": {"name": "Can delete group", "content_type": 3, "codename": "delete_group"}}, {"model": "auth.permission", "pk": 10, "fields": {"name": "Can add user", "content_type": 4, "codename": "add_user"}}, {"model": "auth.permission", "pk": 11, "fields": {"name": "Can change user", "content_type": 4, "codename": "change_user"}}, {"model": "auth.permission", "pk": 12, "fields": {"name": "Can delete user", "content_type": 4, "codename": "delete_user"}}, {"model": "auth.permission", "pk": 13, "fields": {"name": "Can add content type", "content_type": 5, "codename": "add_contenttype"}}, {"model": "auth.permission", "pk": 14, "fields": {"name": "Can change content type", "content_type": 5, "codename": "change_contenttype"}}, {"model": "auth.permission", "pk": 15, "fields": {"name": "Can delete content type", "content_type": 5, "codename": "delete_contenttype"}}, {"model": "auth.permission", "pk": 16, "fields": {"name": "Can add session", "content_type": 6, "codename": "add_session"}}, {"model": "auth.permission", "pk": 17, "fields": {"name": "Can change session", "content_type": 6, "codename": "change_session"}}, {"model": "auth.permission", "pk": 18, "fields": {"name": "Can delete session", "content_type": 6, "codename": "delete_session"}}, {"model": "auth.permission", "pk": 19, "fields": {"name": "Can add child", "content_type": 7, "codename": "add_child"}}, {"model": "auth.permission", "pk": 20, "fields": {"name": "Can change child", "content_type": 7, "codename": "change_child"}}, {"model": "auth.permission", "pk": 21, "fields": {"name": "Can delete child", "content_type": 7, "codename": "delete_child"}}, {"model": "auth.permission", "pk": 22, "fields": {"name": "Can add group", "content_type": 8, "codename": "add_group"}}, {"model": "auth.permission", "pk": 23, "fields": {"name": "Can change group", "content_type": 8, "codename": "change_group"}}, {"model": "auth.permission", "pk": 24, "fields": {"name": "Can delete group", "content_type": 8, "codename": "delete_group"}}, {"model": "auth.permission", "pk": 25, "fields": {"name": "Can add host", "content_type": 9, "codename": "add_host"}}, {"model": "auth.permission", "pk": 26, "fields": {"name": "Can change host", "content_type": 9, "codename": "change_host"}}, {"model": "auth.permission", "pk": 27, "fields": {"name": "Can delete host", "content_type": 9, "codename": "delete_host"}}, {"model": "auth.permission", "pk": 28, "fields": {"name": "Can add host variable", "content_type": 10, "codename": "add_hostvariable"}}, {"model": "auth.permission", "pk": 29, "fields": {"name": "Can change host variable", "content_type": 10, "codename": "change_hostvariable"}}, {"model": "auth.permission", "pk": 30, "fields": {"name": "Can delete host variable", "content_type": 10, "codename": "delete_hostvariable"}}, {"model": "auth.permission", "pk": 31, "fields": {"name": "Can add inventory", "content_type": 11, "codename": "add_inventory"}}, {"model": "auth.permission", "pk": 32, "fields": {"name": "Can change inventory", "content_type": 11, "codename": "change_inventory"}}, {"model": "auth.permission", "pk": 33, "fields": {"name": "Can delete inventory", "content_type": 11, "codename": "delete_inventory"}}, {"model": "auth.permission", "pk": 34, "fields": {"name": "Can add machine", "content_type": 12, "codename": "add_machine"}}, {"model": "auth.permission", "pk": 35, "fields": {"name": "Can change machine", "content_type": 12, "codename": "change_machine"}}, {"model": "auth.permission", "pk": 36, "fields": {"name": "Can delete machine", "content_type": 12, "codename": "delete_machine"}}, {"model": "auth.permission", "pk": 37, "fields": {"name": "Can add variable", "content_type": 13, "codename": "add_variable"}}, {"model": "auth.permission", "pk": 38, "fields": {"name": "Can change variable", "content_type": 13, "codename": "change_variable"}}, {"model": "auth.permission", "pk": 39, "fields": {"name": "Can delete variable", "content_type": 13, "codename": "delete_variable"}}, {"model": "auth.permission", "pk": 40, "fields": {"name": "Can add activation", "content_type": 14, "codename": "add_activation"}}, {"model": "auth.permission", "pk": 41, "fields": {"name": "Can change activation", "content_type": 14, "codename": "change_activation"}}, {"model": "auth.permission", "pk": 42, "fields": {"name": "Can delete activation", "content_type": 14, "codename": "delete_activation"}}, {"model": "auth.permission", "pk": 43, "fields": {"name": "Can add limits", "content_type": 15, "codename": "add_limits"}}, {"model": "auth.permission", "pk": 44, "fields": {"name": "Can change limits", "content_type": 15, "codename": "change_limits"}}, {"model": "auth.permission", "pk": 45, "fields": {"name": "Can delete limits", "content_type": 15, "codename": "delete_limits"}}, {"model": "auth.permission", "pk": 46, "fields": {"name": "Can add inventory token", "content_type": 16, "codename": "add_inventorytoken"}}, {"model": "auth.permission", "pk": 47, "fields": {"name": "Can change inventory token", "content_type": 16, "codename": "change_inventorytoken"}}, {"model": "auth.permission", "pk": 48, "fields": {"name": "Can delete inventory token", "content_type": 16, "codename": "delete_inventorytoken"}}, {"model": "auth.permission", "pk": 49, "fields": {"name": "Can add Token", "content_type": 17, "codename": "add_token"}}, {"model": "auth.permission", "pk": 50, "fields": {"name": "Can change Token", "content_type": 17, "codename": "change_token"}}, {"model": "auth.permission", "pk": 51, "fields": {"name": "Can delete Token", "content_type": 17, "codename": "delete_token"}}, {"model": "auth.permission", "pk": 52, "fields": {"name": "Can add association", "content_type": 18, "codename": "add_association"}}, {"model": "auth.permission", "pk": 53, "fields": {"name": "Can change association", "content_type": 18, "codename": "change_association"}}, {"model": "auth.permission", "pk": 54, "fields": {"name": "Can delete association", "content_type": 18, "codename": "delete_association"}}, {"model": "auth.permission", "pk": 55, "fields": {"name": "Can add code", "content_type": 19, "codename": "add_code"}}, {"model": "auth.permission", "pk": 56, "fields": {"name": "Can change code", "content_type": 19, "codename": "change_code"}}, {"model": "auth.permission", "pk": 57, "fields": {"name": "Can delete code", "content_type": 19, "codename": "delete_code"}}, {"model": "auth.permission", "pk": 58, "fields": {"name": "Can add nonce", "content_type": 20, "codename": "add_nonce"}}, {"model": "auth.permission", "pk": 59, "fields": {"name": "Can change nonce", "content_type": 20, "codename": "change_nonce"}}, {"model": "auth.permission", "pk": 60, "fields": {"name": "Can delete nonce", "content_type": 20, "codename": "delete_nonce"}}, {"model": "auth.permission", "pk": 61, "fields": {"name": "Can add user social auth", "content_type": 21, "codename": "add_usersocialauth"}}, {"model": "auth.permission", "pk": 62, "fields": {"name": "Can change user social auth", "content_type": 21, "codename": "change_usersocialauth"}}, {"model": "auth.permission", "pk": 63, "fields": {"name": "Can delete user social auth", "content_type": 21, "codename": "delete_usersocialauth"}}, {"model": "auth.permission", "pk": 64, "fields": {"name": "Can add partial", "content_type": 22, "codename": "add_partial"}}, {"model": "auth.permission", "pk": 65, "fields": {"name": "Can change partial", "content_type": 22, "codename": "change_partial"}}, {"model": "auth.permission", "pk": 66, "fields": {"name": "Can delete partial", "content_type": 22, "codename": "delete_partial"}}, {"model": "auth.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$36000$gFiBQjvOOzJ4$CYfwrgZKOUGOdc1TEel3FC0mjTu+7j/b+CNAuf7VTYo=", "last_login": "2018-06-30T11:40:58.519Z", "is_superuser": false, "username": "tester", "first_name": "", "last_name": "", "email": "sudnitsina@gmail.com", "is_staff": false, "is_active": true, "date_joined": "2018-06-30T09:47:19.813Z", "groups": [], "user_permissions": []}}, {"model": "api.inventory", "pk": 1, "fields": {"inventory": "test_inv", "user": 1}}, {"model": "api.machine", "pk": 1, "fields": {"machine": "test.test", "user": 1}}, {"model": "registration.activation", "pk": 1, "fields": {"activation_key": "095977dfa12b05e908a4f2b4cc3edfa63411b1f0ce1ec4604e7e3ab0f72703e4", "created_date": "2018-06-30T09:47:23.919Z"}}, {"model": "registration.limits", "pk": 1, "fields": {"inventories_number": 3}}, {"model": "authtoken.token", "pk": "790cb216be621e8b2e7c064e21f9f4fb020808071176655f9df1ac713f643d21", "fields": {"user": 1, "created": "2018-06-30T11:41:11.470Z"}}, {"model": "authtoken.inventorytoken", "pk": "ed6b741898abbcf2d4b0eb5dee0778d38a0b9f0b4af543e3b9c43710a44ee080", "fields": {"user": 1, "description": "test_inv_token", "created_date": "2018-06-30T11:41:25.181Z", "inventory": [1]}}] \ No newline at end of file diff --git a/api/tests_api.py b/api/tests_api.py new file mode 100644 index 0000000..41b4d0f --- /dev/null +++ b/api/tests_api.py @@ -0,0 +1,422 @@ +from django.test import TestCase, TransactionTestCase +from django.urls import reverse +from authtoken.models import * +from api.models import * +from django.contrib.auth.models import User +import json +from django.db import transaction +from api.ini_serializer import ini + + + +class NotFoundTest(TestCase): + def test_not_api(self): + url = '/n/a' + response = self.client.get(url) + self.assertEquals(response.status_code, 404) + + +class TokenTestBase(TestCase): + def setUp(self): + self.u = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') + self.inventory = Inventory.objects.create(inventory='inv_in_scope', user=self.u) + self.token = InventoryToken.objects.create(user=self.u, description='test_scoped_token') + self.token.inventory.add(self.inventory) + self.admin_token = Token.objects.create(user=self.u) + + +class InventoryTest(TokenTestBase): + inv_name = 'test_inventory' + + def test_create_admin_token(self): + url = reverse('inventory_details', args=[self.inv_name]) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"ADD","details":"inv"}') + + def test_create_scoped_token(self): + url = reverse('inventory_details', args=[self.inv_name]) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.status_code, 404) + self.assertJSONEqual(response.content.decode(), '{"detail":"Not found."}') + + def test_get_admin_token(self): + url = reverse('inventory_details', args=[self.inventory]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key} ) + self.assertJSONEqual( + response.content.decode(), + '{"all":{"hosts":[],"children":[],"vars":{"inventory_name":"inv_in_scope"}}}') + + def test_get_scoped_token(self): + # inv in scope: return inv + url = reverse('inventory_details', args=[self.inventory]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertJSONEqual( + response.content.decode(), + '{"all":{"hosts":[],"children":[],"vars":{"inventory_name":"inv_in_scope"}}}') + # inv doesnt exist: return "doesnt exist" + url = reverse('inventory_details', args=[self.inv_name]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertJSONEqual(response.content.decode(), '{"detail":"Not found."}') + # inv not in scope: return {"detail":"Acess denied"} + Inventory.objects.create(inventory='inv_not_in_scope', user=self.u) + url = reverse('inventory_details', args=['inv_not_in_scope']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertJSONEqual(response.content.decode(), '{"detail":"Acess denied"}') + + def test_delete_admin_token(self): + url = reverse('inventory_details', args=[self.inventory]) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertJSONEqual(response.content.decode(), '{"status":"DELETE","details":"inventory"}') + # inv doesnt exist: return "doesnt exist" + url = reverse('inventory_details', args=[self.inv_name]) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertEquals(response.content.decode(), '{"detail":"Not found."}') + + def test_delete_scoped_token(self): + # inv not in scope doesnt exist: return {"detail":"Not found."} + url = reverse('inventory_details', args=[self.inv_name]) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertJSONEqual(response.content.decode(), '{"detail":"Not found."}') + # inv not in scope: return {"detail":"Not found."} + Inventory.objects.create(inventory = self.inv_name, user=self.u) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + # get list of inv + url = reverse('inventory_list') + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertListEqual(json.loads(response.content.decode()), ["inv_in_scope", "test_inventory"]) + # inv in scope: return {"status":"DELETE","details":"inventory"} + url = reverse('inventory_details', args=[self.inventory]) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertJSONEqual(response.content.decode(), '{"status":"DELETE","details":"inventory"}') + # get list of inv + url = reverse('inventory_list') + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertEquals(response.content.decode(), '["test_inventory"]') + + def test_limit(self): + def create_inv(name): + url = reverse('inventory_details', args=[name]) + return self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + for i in range(4): + r = create_inv('inv_%s' % i) + self.assertEquals(r.content.decode(), '"inventories limit exceeded"') + + def test_already_exist(self): + name = 'some_name' + url = reverse('inventory_details', args=[name]) + self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + r = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertEquals(r.content.decode(), '"already exists"') + + + +class MachineTest(TokenTestBase): + def test_create_delete_scoped_token(self): + """ + create machine - True + get list of machines - True + """ + url = reverse('machine', args=['test_machine']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + url = reverse('machine') + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEqual(response.content.decode(), '["test_machine"]') + url = reverse('machine', args=['test_machine']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + url = reverse('machine') + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEqual(response.content.decode(), '[]') + + +class GroupTest(TokenTestBase): + def setUp(self): + super(GroupTest, self).setUp() + Group.objects.create(inventory=self.inventory, group='test_group_to_delete') + + def test_create_admin_token(self): + url = reverse('group_details', args=[self.inventory, 'test_group']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + url = reverse('group_list', args=[self.inventory]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertListEqual(json.loads(response.content.decode()), ["test_group", "test_group_to_delete"]) + + def test_create_scoped_token(self): + # valid token + url = reverse('group_details', args=[self.inventory, 'test_group']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + url = reverse('group_list', args=[self.inventory]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertListEqual(json.loads(response.content.decode()), ["test_group", "test_group_to_delete"]) + # invalid token + token = InventoryToken.objects.create(user=self.u, description='test_scoped_token1') + url = reverse('group_details', args=[self.inventory, 'test_group1']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': token.token}) + self.assertJSONEqual(response.content.decode(), '{"detail":"Acess denied"}') + + def test_delete_admin_token(self): + url = reverse('group_details', args=[self.inventory, 'test_group_to_delete']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '{"status":"DELETE","details":"group"}') + url = reverse('group_list', args=[self.inventory]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertEquals(response.content.decode(), '[]') + + def test_delete_scoped_token(self): + # invalid token + token = InventoryToken.objects.create(user=self.u, description='test_scoped_token1') + url = reverse('group_details', args=[self.inventory, 'test_group_to_delete']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': token.token}) + self.assertJSONEqual(response.content.decode(), '{"detail":"Acess denied"}') + url = reverse('group_details', args=[self.inventory, 'test_group_to_delete']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '{"status":"DELETE","details":"group"}') + url = reverse('group_list', args=[self.inventory]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '[]') + + def test_delete_doesnt_exist(self): + url = reverse('group_details', args=[self.inventory, 'not_exist']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '{"detail":"Not found."}') + + +class VariableTest(TokenTestBase): + def setUp(self): + super(VariableTest, self).setUp() + self.group = Group.objects.create(inventory=self.inventory, group='test_group') + + def test_create_scoped_token(self): + url = reverse('vars_details', args=[self.inventory, self.group, 'test_var']) + response = self.client.put(url, data='test_val', **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '{"status":"ADD","details":"var"}') + """check var""" + url = reverse('vars_list', args=[self.inventory, self.group]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '["test_var"]') + url = reverse('vars_details', args=[self.inventory, self.group, 'test_var']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '"test_val"') + """delete vars""" + url = reverse('vars_details', args=[self.inventory, self.group, 'test_var']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '{"status":"DELETE","details":"var"}') + url = reverse('vars_list', args=[self.inventory, self.group]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '[]') + + +class HostTest(TokenTestBase): + def setUp(self): + super(HostTest, self).setUp() + self.group = Group.objects.create(inventory=self.inventory, group='test_group') + self.machine = Machine.objects.create(machine='mach', user=self.u) + mach = Machine.objects.create(machine='test_duplicate_machine', user=self.u) + Host.objects.create(group=self.group, host=mach) + + def test_create_scoped_token(self): + """create host""" + url = reverse('host', args=[self.inventory, self.group, self.machine]) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '{"status":"ADD","details":"host"}') + """check hosts""" + url = reverse('host', args=[self.inventory, self.group]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertListEqual(json.loads(response.content.decode()), ["mach","test_duplicate_machine"]) + """delete host""" + url = reverse('host', args=[self.inventory, self.group, self.machine]) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '{"status":"DELETE","details":"host"}') + """check hosts""" + url = reverse('host', args=[self.inventory, self.group]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '["test_duplicate_machine"]') + + def test_duplicates_creation(self): + url = reverse('host', args=[self.inventory, self.group, 'test_duplicate_machine']) + with transaction.atomic(): + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '"already exists"') + url = reverse('host', args=[self.inventory, 'test_group']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '["test_duplicate_machine"]') + # Django’s TestCase class wraps each test in a transaction for performance reasons. + + +class ChildTest(TokenTestBase): + def setUp(self): + super(ChildTest, self).setUp() + self.parent_group = Group.objects.create(inventory=self.inventory, group='parent') + self.child_group = Group.objects.create(inventory=self.inventory, group='child') + self.duplicate = Group.objects.create(inventory=self.inventory, group='duplicate_child') + self.duplicate_child = Child.objects.create(group=self.parent_group, child=self.duplicate) + + def test_general_scoped_token(self): + """create child""" + url = reverse('child', args=[self.inventory, self.parent_group, self.child_group]) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '{"status":"ADD","details":"child"}') + """check child""" + url = reverse('child', args=[self.inventory, self.parent_group]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertListEqual(json.loads(response.content), ["child", "duplicate_child"]) + """delete child""" + url = reverse('child', args=[self.inventory, self.parent_group, self.child_group]) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '{"status":"DELETE","details":"child"}') + """check child""" + url = reverse('child', args=[self.inventory, self.parent_group]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '["duplicate_child"]') + """assign group to itself as a child""" + url = reverse('child', args=[self.inventory, self.parent_group, self.parent_group]) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEquals(response.content.decode(), '"group can\'t be a child of itself"') + + +class GeneralTest(TestCase): + def setUp(self): + u = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') + Token.objects.create(user=u) + + def test_scoped_token(self): + """create new inv, check availability with scoped token""" + inv_name = "django_test_inv" + u = User.objects.get(username='john') + inventory = Inventory.objects.create(inventory=inv_name, user = u) + token = InventoryToken.objects.create(user=u, description='test_token') + token.inventory.add(inventory) + self.assertTrue(token) + self.assertListEqual(list(token.inventory.all()), list(Inventory.objects.all())) + new_group = Group.objects.create(inventory=inventory, group='test_group') + """check group list availability with scoped token""" + url = reverse('group_list', args=[inventory]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': token.token}) + self.assertEquals(response.status_code, 200) + """create new inv, check availability with token not containing this inv in scope""" + inventory2 = Inventory.objects.create(inventory = 'inv_name2', user = u) + url = reverse('group_list', args=[inventory2]) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': token.token}) + self.assertEqual(response.content.decode(), '{"detail":"Acess denied"}') + """check availability with non-existent token""" + token = InventoryToken(token='123') + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': token.token}) + self.assertEqual(response.content.decode(), '{"detail":"No such user"}') + + +class Upload(TokenTestBase): + inventory_data = """{"group2": {}, + "group1": { + "vars": {"234": "234"}, + "hosts": ["1.com", "two.com"], + "children": ["group2"] + }, + "group3": {}, + "_meta" : { + "hostvars" : { + "1.com" : { + "sensu_address": "10.128.13.118", + "sensu_bind": "127.0.0.1" + } + } + } + }""" + + def test_inventory_upload(self): + dict1 = json.loads(self.inventory_data) + inv_name = 'uploaded_inventory' + # inv_name='groupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroupgroup' + url = reverse('inventory_details', args=[inv_name]) + # no token + response = self.client.put(url, data=self.inventory_data) + self.assertEqual( + response.content.decode(), + '{"detail":"Authentication credentials were not provided."}' + ) + # invalid token + token = InventoryToken(token='123') + response = self.client.put(url, data=self.inventory_data, **{'HTTP_X_AUTH_TOKEN': token.token}) + self.assertEqual(response.content.decode(), '{"detail":"No such user"}') + # valid admin Token + token = Token.objects.get(user=self.u) + response = self.client.put(url, data=self.inventory_data, **{'HTTP_X_AUTH_TOKEN': token.key}) + self.assertEqual(response.content.decode(), 'done') + # check groups uploaded + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': token.key}) + dict2 = json.loads(response.content.decode()) + l1 = list(dict1.keys()) + ['all', '_meta'] + self.assertSetEqual(set(l1), set(dict2.keys())) + + # additional test for dashboard + url = reverse('upload') + form_data = {"inv_name": 'test_upl', "uploaded": self.inventory_data} + self.client.force_login(self.u) + response = self.client.post(url, form_data) + self.assertEqual(response.content.decode(), 'done') + # check groups uploaded + url = reverse('inventory_details', args=['test_upl']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': token.key}) + dict2 = json.loads(response.content.decode()) + l1 = list(dict1.keys()) + ['all', '_meta'] + self.assertSetEqual(set(l1), set(dict2.keys())) + + def test_upload_ini(self): + # valid admin Token + inv_name = 'uploaded_inventory' + token = Token.objects.get(user=self.u) + url = reverse('inventory_details', args=[inv_name]) + response = self.client.put(url, data=ini, **{'HTTP_X_AUTH_TOKEN': token.key}) + self.assertEqual(response.content.decode(), 'done') # TODO: check if uploaded correctly + + +# class ScopedToken(TransactionTestCase): +# def setUp(self): +# self.u = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') +# self.inventory = Inventory.objects.create(inventory = 'inv_name', user = self.u) +# self.token = InventoryToken.objects.create(user=self.u, description='test_scoped_token') +# self.token.inventory.add(self.inventory) +# self.machine = Machine.objects.create(user = self.u, machine='test_duplicate_machine') +# self.group = Group.objects.create(inventory=self.inventory, group='test_duplicate_group') +# self.host = Host.objects.create(group=self.group, host=self.machine) + + +class CharsTest(TokenTestBase): + def test_group(self): + my_name = "group.group" + url = '/api/inventory/' + str(self.inventory) + '/groups/' + my_name + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertEqual(response.content.decode(), '{"detail":"bad request"}') + url = '/api/inventory/' + str(self.inventory) + '/groups/' + my_name + '/' + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertEqual(response.content.decode(), '{"detail":"bad request"}') + url = '/api/inventory/' + str(self.inventory) + '/groups/' + my_name + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.admin_token.key}) + self.assertEqual(response.content.decode(), '{"detail":"Not found."}') + + def test_vars(self): + group = Group.objects.create(inventory=self.inventory, group="test_group") + my_var = 'test%var' + url = '/api/inventory/' + str(self.inventory) + '/groups/' + str(group) + '/vars/' + my_var + '/' + response = self.client.put(url, data='test_val', **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEqual(response.content.decode(), '{"detail":"bad request"}') + """check var""" + url = '/api/inventory/' + str(self.inventory) + '/groups/' + str(group) + '/vars' + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertJSONEqual(response.content.decode(), '[]') + url = '/api/inventory/' + str(self.inventory) + '/groups/' + str(group) + '/vars/' + my_var + '/' + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertJSONEqual(response.content.decode(), '{"detail":"Not found."}') + + def test_host_vars(self): + my_var = 'test;var' + mach = Machine.objects.create(user=self.u, machine="test_mach") + url = '/api/inventory/' + str(self.inventory) + '/host/' + str(mach) + '/host_vars/' + my_var + response = self.client.put(url, data='test_val', **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEqual(response.content.decode(), '{"detail":"bad request"}') + self.assertEqual(response.status_code, 400) + url = '/api/inventory/' + str(self.inventory) + '/host/' + str(mach) + '/host_vars/' + my_var + '/' + response = self.client.put(url, data='test_val', **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEqual(response.content.decode(), '{"detail":"bad request"}') + url = '/api/inventory/' + str(self.inventory) + '/host/' + str(mach) + '/host_vars/' + 'normal_var' + '/' + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': self.token.token}) + self.assertEqual(response.content.decode(), '{"detail":"Not found."}') diff --git a/api/tests_ini.py b/api/tests_ini.py new file mode 100644 index 0000000..40ef375 --- /dev/null +++ b/api/tests_ini.py @@ -0,0 +1,63 @@ +from unittest import TestCase + +from api import ini_serializer + +EXPECTED_RESULT={ + "_meta": { + "hostvars": { + "host1": { + "123": "45632", + "567": "890", + "port": "45632" + }, + "host2": { + "a": "b" + }, + "host4": { + "ansible_ssh_port": "2233" + } + } + }, + "atlanta": { + "hosts": [ + "host1", + "host2" + ] + }, + "raleigh": { + "hosts": [ + "host1", + "host4", + "host3" + ] + }, + "southeast": { + "children": [ + "atlanta", + "raleigh" + ], + "vars": { + "some_server": "foo.southeast.example.com", + "halon_system_timeout": "30", + "self_destruct_countdown": "60", + "escape_pods": "2" + } + }, + "usa": { + "children": [ + "southeast", + "northeast" + ] + } +} + + +class INITest(TestCase): + def test_conversion(self): + result = ini_serializer.serializer(ini_serializer.ini) + self.assertDictEqual(result, EXPECTED_RESULT) + + def test_invalid_data(self): + data = "123" + with self.assertRaises(ValueError): + ini_serializer.serializer(data) diff --git a/api/tests_models.py b/api/tests_models.py new file mode 100644 index 0000000..3172063 --- /dev/null +++ b/api/tests_models.py @@ -0,0 +1,67 @@ +from django.contrib.auth.models import User +from django.test import TestCase + +from api import models + + +class MachineTest(TestCase): + def test_init(self): + obj = models.Machine(machine="my_machine") + self.assertEqual(str(obj), "my_machine") + +class InventoryTest(TestCase): + def test_init(self): + obj = models.Inventory(inventory="my_inv") + self.assertEqual(str(obj), "my_inv") + + +class GroupTest(TestCase): + def test_init(self): + obj = models.Group(group="my_group") + self.assertEqual(str(obj), "my_group") + + +class VariableTest(TestCase): + def test_init(self): + obj = models.Variable(variable="my_var", value="my_val") + self.assertEqual(str(obj), "my_var") + +class HostTest(TestCase): + def test_init(self): + mach = models.Machine(machine="my_machine") + obj = models.Host(host=mach) + self.assertEqual(str(obj), "my_machine") + + +class ChildTest(TestCase): + def test_init(self): + parent = models.Group(group="p_group") + child = models.Group(group="c_group") + obj = models.Child(group=parent, child=child) + self.assertEqual(str(obj), "c_group") + + +class HostVariableTest(TestCase): + def test_init(self): + obj = models.HostVariable(variable="my_var", value="my_val") + self.assertEqual(str(obj), "my_var") + + +class InventorySaveTest(TestCase): + def setUp(self): + + self.user = User(username="tester") + self.user.save() + + def test_inventory(self): + + + inv = models.Inventory(inventory="saved_inventory", user=self.user) + inv.save() + self.assertTrue(models.Inventory.objects.filter(inventory="saved_inventory", user=self.user).exists()) + + def test_inv_limit_error(self): + with self.assertRaises(models.LimitError): + for i in range(4): + inv = models.Inventory(inventory=str(i), user=self.user) + inv.save() diff --git a/api/tests_views.py b/api/tests_views.py new file mode 100644 index 0000000..8beef9b --- /dev/null +++ b/api/tests_views.py @@ -0,0 +1,311 @@ +from django.test import TestCase, TransactionTestCase +from django.urls import reverse +from authtoken.models import * +from api.models import * +from django.contrib.auth.models import User +import json +from django.db import transaction +from api.ini_serializer import ini +import time + +TOKEN = "790cb216be621e8b2e7c064e21f9f4fb020808071176655f9df1ac713f643d21" +INVENTORY = '{"test_gr": {"vars": {"test_var": "test"}, "hosts": ["test.test"], "children": ["child_gr"]}, "child_gr": {"vars": {}, "hosts": [], "children": []}, "all": {"vars": {"inventory_name": "test_inv"}, "hosts": [], "children": []}}' + + +class NotFoundTest(TestCase): + fixtures = ["tests/api/test_inventory.json"] + + def test_not_api(self): + url = "/n/a" + response = self.client.get(url) + self.assertEquals(response.status_code, 404) + + def test_api_get(self): + url = "/api/n/a" + response = self.client.get(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.status_code, 404) + self.assertEqual(response.content.decode(), '{"detail":"Not found."}') + + def test_api_put(self): + url = "/api/n/a" + response = self.client.put(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.status_code, 400) + self.assertEqual(response.content.decode(), '{"detail":"bad request"}') + +class InventoryTest(TestCase): + fixtures = ["tests/api/test_inventory.json"] + + def test_list(self): + url = reverse("inventory_list") + print(url) + response = self.client.get(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.content.decode(), '["test_inv"]') + + def test_json(self): + url = reverse("inventory_details", args=["test_inv"]) + response = self.client.get(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertJSONEqual(response.content.decode(), INVENTORY) + + def test_create(self): + url = reverse("inventory_details", args=["created_inv"]) + response = self.client.put(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"ADD","details":"inv"}') + self.assertTrue(Inventory.objects.filter(inventory="created_inv").exists()) + + def test_create_error(self): + url = reverse("inventory_details", args=["test_inv"]) + response = self.client.put(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '"already exists"') # TODO check if " are needed + + def test_delete(self): + url = reverse("inventory_details", args=["test_inv"]) + response = self.client.delete(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"DELETE","details":"inventory"}') # TODO change datails for different actions, inv or inventory for all + self.assertFalse(Inventory.objects.filter(inventory="test_inv").exists()) + + def test_upload(self): + url = reverse('inventory_details', args=["upl_inv1"]) + self.client.delete(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + response = self.client.put(url, data=INVENTORY, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEqual(response.content.decode(), 'done') + + def test_upload_error(self): + url = reverse('inventory_details', args=["upl_inv1"]) + response = self.client.put(url, data='string', **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), 'invalid data') + data = '{"test_gr": {"hosts": "string"}}' + response = self.client.put(url, data=data, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), 'hosts should be list') + + +class GroupTest(TestCase): + fixtures = ["tests/api/test_inventory.json"] + # url = reverse("group_list", args=["test_inv"]) + + def test_list(self): + url = reverse("group_list", args=["test_inv"]) + response = self.client.get(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.content.decode(), '["child_gr", "test_gr"]') + + def test_create(self): + url = reverse("group_details", args=["test_inv", "created_group"]) + response = self.client.put(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"ADD","details":"group"}') + self.assertTrue(Group.objects.filter(group="created_group").exists()) + + def test_create_error(self): + url = reverse("group_details", args=["test_inv", "test_gr"]) + response = self.client.put(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '"already exists"') + + def test_delete(self): + url = reverse("group_details", args=["test_inv", "test_gr"]) + response = self.client.delete(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"DELETE","details":"group"}') + self.assertFalse(Group.objects.filter(group="test_gr").exists()) + + def test_delete_error(self): + url = reverse("group_details", args=["test_inv", "not_exist"]) + response = self.client.delete(url, **{"HTTP_X_AUTH_TOKEN": TOKEN}) + self.assertEquals(response.status_code, 404) + self.assertEqual(response.content.decode(), '{"detail":"Not found."}') + + +class MachineTest(TestCase): + fixtures = ["tests/api/test_inventory.json"] + + def test_list(self): + url = reverse('machine') + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEqual(response.content.decode(), '["test.test"]') + + def test_create(self): + url = reverse('machine', args=['create.test']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"ADD","details":"machine"}') + self.assertTrue(Machine.objects.filter(machine="create.test").exists()) + + def test_create_error(self): + url = reverse('machine', args=['test.test']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '"already exists"') + + def test_delete(self): + url = reverse('machine', args=['test.test']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"DELETE","details":"machine"}') + self.assertFalse(Machine.objects.filter(machine="create.test").exists()) + + def test_delete_error(self): + url = reverse('machine', args=['not_exist.test']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 404) + self.assertEqual(response.content.decode(), '{"detail":"Not found."}') + + +class HostTest(TestCase): + fixtures = ["tests/api/test_inventory.json"] + + def test_list(self): + url = reverse('host', args=['test_inv', 'test_gr']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '["test.test"]') + + def test_create(self): + url = reverse('host', args=['test_inv', 'child_gr', 'test.test']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"ADD","details":"host"}') + self.assertTrue(Host.objects.filter(host=Machine.objects.get(machine="test.test"), + group=Group.objects.filter(group="child_gr").exists())) + + def test_create_error(self): + url = reverse('host', args=['test_inv', 'child_gr', 'not_exist.test']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 404) + self.assertJSONEqual(response.content.decode(), '{"detail":"Not found."}') + + url = reverse('host', args=['test_inv', 'test_gr', 'test.test']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '"already exists"') + + def test_delete(self): + url = reverse('host', args=['test_inv', 'test_gr', 'test.test']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"DELETE","details":"host"}') + self.assertFalse(Host.objects.filter(host=Machine.objects.get(machine="test.test"), + group=Group.objects.filter(group="child_gr").exists())) + + +class ChildTest(TestCase): + fixtures = ["tests/api/test_inventory.json"] + + def test_list(self): + url = reverse('child', args=['test_inv', 'test_gr']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '["child_gr"]') + + def test_create(self): + url = reverse('child', args=['test_inv', 'child_gr', 'test_gr']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"ADD","details":"child"}') + self.assertTrue(Host.objects.filter(host=Machine.objects.get(machine="test.test"), + group=Group.objects.filter(group="child_gr").exists())) + + def test_create_404(self): + url = reverse('child', args=['test_inv', 'child_gr', 'some_gr']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 404) + self.assertJSONEqual(response.content.decode(), '{"detail":"Not found."}') + + def test_create_error(self): + url = reverse('child', args=['test_inv', 'child_gr', 'child_gr']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEquals(response.content.decode(), '"group can\'t be a child of itself"') + + def test_delete(self): + url = reverse('child', args=['test_inv', 'test_gr', 'child_gr']) + response = self.client.delete(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"DELETE","details":"child"}') + self.assertFalse(Child.objects.filter(group=Group.objects.get(group="test_gr"), + child=Group.objects.get(group="child_gr")).exists()) + + +class VariableTest(TestCase): + fixtures = ["tests/api/test_inventory.json"] + + def test_crud(self): + # put + url = reverse('vars_details', args=['test_inv', 'child_gr', 'test_var']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"ADD","details":"var"}') + + # put - error data + url = reverse('vars_details', args=['test_inv', 'test_gr', 'test_var']) + response = self.client.put(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '"already exists"') + + # get list + url = reverse('vars_list', args=['test_inv', 'test_gr']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '["test_var"]') + + # post + url = reverse('vars_details', args=['test_inv', 'test_gr', 'test_var']) + response = self.client.post(url, data="changed_val", content_type="application/json", + **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertJSONEqual(response.content.decode(), '{"status":"UPDATE","details":"var"}') + + # get value + url = reverse('vars_details', args=['test_inv', 'test_gr', 'test_var']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '"changed_val"') + + # delete + url = reverse('vars_details', args=['test_inv', 'test_gr', 'test_var']) + response = self.client.delete(url, data='test_val', **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '{"status":"DELETE","details":"var"}') + + +class HostVariableTest(TestCase): + fixtures = ["tests/api/test_inventory.json"] + + def test_crud(self): + # put + url = reverse('hostvars_details', args=['test_inv', 'test.test', 'test_hostvar']) + response = self.client.put(url, data='test_val', **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertJSONEqual(response.content.decode(), '{"status":"ADD","details":"hostvar"}') + + # put - error data + url = reverse('hostvars_details', args=['test_inv', 'test.test', 'test_hostvar']) + response = self.client.put(url, data='test_val', **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '"already exists"') + + # post + url = reverse('hostvars_details', args=['test_inv', 'test.test', 'test_hostvar']) + response = self.client.post(url, data="changed_val", content_type="application/json", + **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertJSONEqual(response.content.decode(), '{"status":"UPDATE","details":"hostvar"}') + + # get list + url = reverse('hostvars_list', args=['test_inv', 'test.test']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '["test_hostvar"]') + + # get value + url = reverse('hostvars_details', args=['test_inv', 'test.test', 'test_hostvar']) + response = self.client.get(url, **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '"changed_val"') + + # delete + url = reverse('hostvars_details', args=['test_inv', 'test.test', 'test_hostvar']) + response = self.client.delete(url, data='test_val', **{'HTTP_X_AUTH_TOKEN': TOKEN}) + self.assertEquals(response.status_code, 200) + self.assertEqual(response.content.decode(), '{"status":"DELETE","details":"hostvar"}') diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d2d8ac3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +version: '2' + +services: + web: + build: + context: ../ + dockerfile: tests/Dockerfile + expose: + - "8000" + depends_on: + - selenium + selenium: + image: selenium/standalone-chrome diff --git a/postman/Inventory_API.postman_environment.json b/postman/Inventory_API.postman_environment.json new file mode 100644 index 0000000..b81c599 --- /dev/null +++ b/postman/Inventory_API.postman_environment.json @@ -0,0 +1,27 @@ +{ + "id": "d4e23e5f-8d9d-4dd4-afdf-f15954e40875", + "name": "Inventory API", + "values": [ + { + "key": "url", + "value": "http://127.0.0.1:8000", + "enabled": true, + "type": "text" + }, + { + "key": "token", + "value": "efefc75ba5efdebb9b5090662d35ffbc952b11b5b4bd48625fde5c9794af72c2", + "enabled": true, + "type": "text" + }, + { + "key": "inv", + "value": "my_inv", + "enabled": true, + "type": "text" + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2018-06-26T13:37:31.232Z", + "_postman_exported_using": "Postman/6.1.3" +} \ No newline at end of file diff --git a/postman/inventory.postman_collection.json b/postman/inventory.postman_collection.json new file mode 100644 index 0000000..09415de --- /dev/null +++ b/postman/inventory.postman_collection.json @@ -0,0 +1,878 @@ +{ + "info": { + "_postman_id": "3bf6d521-6003-49a8-902c-f8f7c190610d", + "name": "inventory", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "delete inventory Copy", + "event": [ + { + "listen": "test", + "script": { + "id": "4fecac5d-bd31-49df-bdab-d56b1a4cfb65", + "type": "text/javascript", + "exec": [ + "// postman.clearEnvironmentVariable(\"inv\");", + "", + "tests[\"status code is 200\"] == responseCode.code === 200;", + "var jsonData = JSON.parse(responseBody);", + "tests['json'] = jsonData[\"status\"] == \"DELETE\"; jsonData[\"details\"] == \"inventory\";" + ] + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/{{inv}}", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "{{inv}}" + ] + } + }, + "response": [] + }, + { + "name": "create inventory", + "event": [ + { + "listen": "test", + "script": { + "id": "661c9fbf-3f52-4256-9220-8d32cbfda581", + "type": "text/javascript", + "exec": [ + "//postman.clearEnvironmentVariable(\"inv\");", + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "tests[\"status code is 200\"] == responseCode.code === 200;" + ] + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{url}}/api/inventory/{{inv}}", + "host": [ + "{{url}}" + ], + "path": [ + "api", + "inventory", + "{{inv}}" + ] + } + }, + "response": [] + }, + { + "name": "inventory", + "event": [ + { + "listen": "test", + "script": { + "id": "86d4831a-6fca-40c1-ab71-e88615c0e4fe", + "type": "text/javascript", + "exec": [ + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "", + "var jsonData = JSON.parse(responseBody);", + "", + "tests['json'] = responseBody.indexOf(postman.getEnvironmentVariable(\"inv\")) !== -1;", + "tests[\"content type\"] = postman.getResponseHeader('Content-Type') === 'application/json';", + "", + "//postman.setEnvironmentVariable(\"inv\", jsonData);", + "tests[\"Body is object\"] = typeof jsonData == \"object\";", + "", + "" + ] + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{url}}/api/inventories", + "host": [ + "{{url}}" + ], + "path": [ + "api", + "inventories" + ] + } + }, + "response": [] + }, + { + "name": "group create", + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/{{inv}}/groups/first_group", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "{{inv}}", + "groups", + "first_group" + ] + } + }, + "response": [] + }, + { + "name": "group create child", + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/my_inv/groups/my_child", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "my_child" + ] + } + }, + "response": [] + }, + { + "name": "groups", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{url}}/api/inventory/my_inv/groups/", + "host": [ + "{{url}}" + ], + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "" + ] + } + }, + "response": [] + }, + { + "name": "vars create", + "event": [ + { + "listen": "test", + "script": { + "id": "da5ac7be-0908-4d8f-9f44-5ccc79342c27", + "type": "text/javascript", + "exec": [ + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "", + "tests[\"response\"] = responseBody.has(\"details\");", + "tests[\"response\"] = responseBody.has(\"status\");", + "", + "var jsonData = JSON.parse(responseBody);", + "tests['json'] = jsonData[\"details\"] == \"var\";", + "tests['json'] = jsonData[\"status\"] == \"ADD\";" + ] + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/my_inv/groups/first_group/vars/my_var", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "first_group", + "vars", + "my_var" + ] + } + }, + "response": [] + }, + { + "name": "vars", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/my_inv/groups/first_group/vars", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "first_group", + "vars" + ] + } + }, + "response": [] + }, + { + "name": "vars del", + "event": [ + { + "listen": "test", + "script": { + "id": "f6d31c41-d654-44fa-93fc-3162c495af87", + "type": "text/javascript", + "exec": [ + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "", + "tests[\"response\"] = responseBody.has(\"details\");", + "tests[\"response\"] = responseBody.has(\"status\");", + "", + "var jsonData = JSON.parse(responseBody);", + "tests['json'] = jsonData[\"details\"] == \"var\";", + "tests['json'] = jsonData[\"status\"] == \"DELETE\";" + ] + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/my_inv/groups/first_group/vars/my_var", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "first_group", + "vars", + "my_var" + ] + } + }, + "response": [] + }, + { + "name": "children create", + "event": [ + { + "listen": "test", + "script": { + "id": "78e0f95f-2727-41d7-a919-be694b4716c4", + "type": "text/javascript", + "exec": [ + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "", + "tests[\"response\"] = responseBody.has(\"details\");", + "tests[\"response\"] = responseBody.has(\"status\");", + "", + "var jsonData = JSON.parse(responseBody);", + "tests['json'] = jsonData[\"details\"] == \"child\";", + "tests['json'] = jsonData[\"status\"] == \"ADD\";" + ] + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/my_inv/groups/first_group/children/my_child", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "first_group", + "children", + "my_child" + ] + } + }, + "response": [] + }, + { + "name": "children", + "event": [ + { + "listen": "test", + "script": { + "id": "d3923c09-9f3d-44c6-ab76-5c799bad421f", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/my_inv/groups/first_group/children", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "first_group", + "children" + ] + } + }, + "response": [] + }, + { + "name": "hosts create", + "event": [ + { + "listen": "test", + "script": { + "id": "040fd106-e290-4c49-86ee-fb1dd3c24dfd", + "type": "text/javascript", + "exec": [ + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "", + "tests[\"response\"] = responseBody.has(\"detail\");", + "", + "var jsonData = JSON.parse(responseBody);", + "tests['json'] = jsonData[\"detail\"] == \"Not found.\";" + ] + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/my_inv/groups/first_group/hosts/my_host", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "first_group", + "hosts", + "my_host" + ] + } + }, + "response": [] + }, + { + "name": "machine create", + "event": [ + { + "listen": "test", + "script": { + "id": "6c3f2287-161c-42b3-9280-c10cfd2aa9af", + "type": "text/javascript", + "exec": [ + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "", + "var jsonData = JSON.parse(responseBody);", + "tests['json'] = jsonData[\"status\"] == \"ADD\"; jsonData[\"details\"] == \"machine\"; " + ] + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/machines/my_machine", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "machines", + "my_machine" + ] + } + }, + "response": [] + }, + { + "name": "hosts create successfully", + "event": [ + { + "listen": "test", + "script": { + "id": "c73220fb-c363-4672-bb25-2d171c4f204f", + "type": "text/javascript", + "exec": [ + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "", + "var jsonData = JSON.parse(responseBody);", + "tests['json'] = jsonData[\"status\"] == \"ADD\"; jsonData[\"details\"] == \"host\"; " + ] + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/my_inv/groups/first_group/hosts/my_machine", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "first_group", + "hosts", + "my_machine" + ] + } + }, + "response": [] + }, + { + "name": "hosts", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/my_inv/groups/first_group/hosts", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "my_inv", + "groups", + "first_group", + "hosts" + ] + } + }, + "response": [] + }, + { + "name": "machine delete", + "event": [ + { + "listen": "test", + "script": { + "id": "1c568b7f-6f0b-472f-9a4b-e33404b7db3a", + "type": "text/javascript", + "exec": [ + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "", + "var jsonData = JSON.parse(responseBody);", + "tests['response'] = jsonData[\"status\"] == \"DELETE\"; jsonData[\"details\"] == \"machine\"; ", + "", + "" + ] + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{url}}/api/machines/my_machine", + "host": [ + "{{url}}" + ], + "path": [ + "api", + "machines", + "my_machine" + ] + } + }, + "response": [] + }, + { + "name": "get inventory json", + "event": [ + { + "listen": "test", + "script": { + "id": "80ef89ad-c979-4fdf-941a-ae9bce482c44", + "type": "text/javascript", + "exec": [ + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "tests[\"status code is 200\"] == responseCode.code === 200;", + "var jsonData = JSON.parse(responseBody);", + "tests[\"Response contains 'all'\"] = responseBody.has(\"all\");" + ] + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{url}}/api/inventory/my_inv", + "host": [ + "{{url}}" + ], + "path": [ + "api", + "inventory", + "my_inv" + ] + } + }, + "response": [] + }, + { + "name": "delete inventory", + "event": [ + { + "listen": "test", + "script": { + "id": "4fecac5d-bd31-49df-bdab-d56b1a4cfb65", + "type": "text/javascript", + "exec": [ + "// postman.clearEnvironmentVariable(\"inv\");", + "", + "tests[\"status code is 200\"] == responseCode.code === 200;", + "var jsonData = JSON.parse(responseBody);", + "tests['json'] = jsonData[\"status\"] == \"DELETE\"; jsonData[\"details\"] == \"inventory\";" + ] + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/inventory/{{inv}}", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "inventory", + "{{inv}}" + ] + } + }, + "response": [] + }, + { + "name": "upload inventory", + "event": [ + { + "listen": "test", + "script": { + "id": "26ce0c85-61e2-42f5-a0ad-b18420c0a589", + "type": "text/javascript", + "exec": [ + "//postman.clearEnvironmentVariable(\"inv\");", + "tests[\"Response time is less than 200ms\"] = responseTime < 200;", + "tests[\"status code is 200\"] == responseCode.code === 200;", + "", + "", + "// var jsonData = JSON.parse(responseBody);", + "tests['json'] =responseBody == \"done\";" + ] + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Auth-Token", + "value": "{{token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\"group2\": {},\r\n \"group1\": {\r\n \"vars\": {\"234\": \"{\\\"myvar\\\": \\\"ttttt\\\", \\\"o\\\": [1,2,3], \\\"j\\\": {}}\"},\r\n \"hosts\": [\"1.com\", \"two.com\", 3],\r\n \"children\": [\"group2\"]\r\n },\r\n \"group3\": {},\r\n \"_meta\" : {\r\n \"hostvars\" : {\r\n \"1.com\" : {\r\n \"sensu_address\": \"10.128.13.118\",\r\n \"sensu_bind\": {\"127.0.0.1\": \"ololo\"}\r\n }\r\n }\r\n }\r\n }" + }, + "url": { + "raw": "{{url}}/api/inventory/{{inv}}", + "host": [ + "{{url}}" + ], + "path": [ + "api", + "inventory", + "{{inv}}" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/random_inventory_generator.py b/random_inventory_generator.py new file mode 100644 index 0000000..c23b30a --- /dev/null +++ b/random_inventory_generator.py @@ -0,0 +1,30 @@ +import random +import string +import json + + +def inventory_generator(): + data = {"_meta": {"hostvars": {}}} + + def rnd_string(): return ''.join(random.choices( + string.ascii_letters + string.digits, k=10)) + hosts = [rnd_string() for i in range(500)] + + for i in range(200): + data[rnd_string()] = {"vars": {rnd_string(): rnd_string() for i in range(10)}, + "hosts": [random.choice(hosts) for i in range(10)]} + for i in range(200): + data["_meta"]["hostvars"] = { + random.choice(hosts): { + rnd_string(): rnd_string() for i in range(10)}for i in range(10)} + + data = json.dumps(data, indent=4) + # with open("big_json.txt", "a") as f: + # for i in data: + # f.write(i) + f = open("big_json111.txt", 'w') + f.write(data) + f.close() + + +inventory_generator() diff --git a/selenium/__init__.py b/selenium/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/selenium/dashboard_test.py b/selenium/dashboard_test.py new file mode 100644 index 0000000..7bc3970 --- /dev/null +++ b/selenium/dashboard_test.py @@ -0,0 +1,169 @@ +import time + +from django.contrib.staticfiles.testing import StaticLiveServerTestCase +# from selenium.webdriver.chrome.webdriver import WebDriver +from selenium.webdriver.firefox.webdriver import WebDriver +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.common.by import By +from api.models import Inventory +from selenium.webdriver.support import expected_conditions as EC + +from selenium import webdriver +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities + +import os +import socket + +# os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = '0.0.0.0:80' + +class DashboardSeleniumTests(StaticLiveServerTestCase): + fixtures = ["tests/selenium/user.json"] + # live_server_url = 'localhost' + # live_server_url = 'http://{}:8000'.format( + # socket.gethostbyname(socket.gethostname()) + # ) + # host = socket.gethostbyname(socket.gethostname()) + host = 'web' + + @classmethod + def setUpClass(cls): + super().setUpClass() + # cls.selenium = WebDriver() + # cls.selenium.implicitly_wait(1) + # cls.selenium.maximize_window() + capabilities = DesiredCapabilities.CHROME.copy() + # + + cls.selenium = webdriver.Remote( + command_executor="http://selenium:4444/wd/hub", + desired_capabilities=capabilities + ) + cls.selenium.implicitly_wait(1) + + @classmethod + def tearDownClass(cls): + cls.selenium.quit() + super().tearDownClass() + + def test_workflow(self): + wait = 0.5 + self.selenium.get('%s%s' % (self.live_server_url, '/dashboard/')) + print(self.live_server_url) + self.selenium.save_screenshot('screen.png') + print('done??') + # self.assertEqual(self.selenium.current_url, '%s%s' % (self.live_server_url, '/login/?next=/dashboard/')) + + name = self.selenium.find_element_by_xpath('//*[@id="id_username"]') + name.send_keys("tester") + password = self.selenium.find_element_by_xpath('//*[@id="id_password"]') + password.send_keys("tester123") + button = self.selenium.find_element_by_xpath('//*[@id="login"]') + button.click() + + # create inv + self.selenium.find_element_by_xpath('//*[@id="addInv"]').click() + self.selenium.find_element_by_css_selector('input[type="text"]').send_keys("tester123", Keys.RETURN) + # WebDriverWait(self.selenium, 10).until( + # lambda driver: self.selenium.find_element_by_xpath('//*[@id="ui-id-1"]/li/div[contains(text(), "tester123")]') + # ) + # i = [] + # while len(i) == 0: + # i = Inventory.objects.filter(inventory='tester123') + # print(i) + + time.sleep(wait) + + # select inv + self.selenium.find_element_by_css_selector('#eb div.ui-widget a span').click() + # time.sleep(100) + self.selenium.find_element_by_xpath('//*[@id="ui-id-1"]/li/div[contains(text(), "tester123")]').click() + + # create gr + time.sleep(wait) + self.selenium.find_element_by_xpath('//*[@id="addGr"]').click() + self.selenium.find_element_by_css_selector('input[type="text"]').send_keys("test_group", Keys.RETURN) + + # select gr + time.sleep(wait) + elem = self.selenium.find_element_by_css_selector('#sidepanel div.ui-widget a span') + elem.click() + # self.selenium.find_element_by_css_selector('#sidepanel div.ui-widget a span').click() + time.sleep(wait) + self.selenium.find_element_by_xpath('//*[ @ id = "ui-id-{}"]/li/div[contains(text(), "test_group")]'.format(2)).click() + # except Exception as e: + # print(e) + # time.sleep(wait) + + # create mach + self.selenium.find_element_by_xpath('//*[@id="eb"]/div[1]/a').click() + time.sleep(wait) + self.selenium.find_element_by_xpath('//*[@id="modal_content"]/h2/button').click() + # time.sleep(wait) + self.selenium.find_element_by_css_selector('#machform input[type="text"]').send_keys("test_mach", Keys.RETURN) + # WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath('//*[@id="modal_content"]/a')) + # time.sleep(wait) + time.sleep(1) + self.selenium.find_element_by_xpath('//*[@id="modal_content"]/a').click() + time.sleep(wait) + + # create var + self.selenium.find_element_by_css_selector('#vars > button.plus').click() + # time.sleep(wait) + self.selenium.find_element_by_css_selector('#vars input[name="newVar"]').send_keys("test_var", Keys.RETURN) + # time.sleep(wait) + # self.selenium.find_element_by_css_selector('#vars input[name="newVal"]').send_keys("test_val") + time.sleep(wait) + # TODO add value + + # create host + self.selenium.find_element_by_css_selector('#hosts > button.plus').click() + self.selenium.find_element_by_css_selector('#hostform a span').click() + time.sleep(wait) + self.selenium.find_element_by_css_selector('ul.ui-menu:nth-of-type(3) li div').click() + # self.selenium.find_element_by_xpath('//*ul[3]/li/div[contains(text(), "test_mach")]').click() + # time.sleep(wait) + self.selenium.find_element_by_css_selector('#hostform button').click() + + # create gr + # time.sleep(wait) + self.selenium.find_element_by_xpath('//*[@id="addGr"]').click() + self.selenium.find_element_by_css_selector('input[type="text"]').send_keys("test_child", Keys.RETURN) + + # create child + time.sleep(1) + self.selenium.find_element_by_css_selector('#groups > button.plus').click() + + self.selenium.find_element_by_css_selector('#child a span').click() + time.sleep(wait) + self.selenium.find_element_by_css_selector('ul.ui-menu:nth-of-type(3) li div').click() + # self.selenium.find_element_by_xpath('//*[@id="ui-id-18"]/li/div[contains(text(), "test_child")]').click() + # time.sleep(wait) + self.selenium.find_element_by_css_selector('#child button').click() + time.sleep(wait) + + # del child + self.selenium.find_element_by_xpath('//*[@id="groups"]/table/tbody/tr/td[2]/a').click() + + # del host + self.selenium.find_element_by_xpath('//*[@id="hosts"]/table/tbody/tr/td[2]/a').click() + + # del var + self.selenium.find_element_by_xpath('//*[@id="vars"]/table/tbody/tr/td[3]/a').click() + + # del gr + time.sleep(wait) + self.selenium.find_element_by_xpath('//*[@id="delGr"]').click() + + # del inv + time.sleep(wait) + self.selenium.find_element_by_xpath('//*[@id="delInv"]').click() + time.sleep(wait) + + # del mach + self.selenium.find_element_by_xpath('//*[@id="eb"]/div[1]/a').click() + time.sleep(wait) + self.selenium.find_element_by_xpath('//*[@id="modal_content"]/table/tbody/tr[1]/td[2]/button').click() + time.sleep(wait) + self.selenium.find_element_by_xpath('//*[@id="modal_content"]/a').click() + time.sleep(wait) diff --git a/selenium/registration_test.py b/selenium/registration_test.py new file mode 100644 index 0000000..875b1aa --- /dev/null +++ b/selenium/registration_test.py @@ -0,0 +1,46 @@ +from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from selenium.webdriver.firefox.webdriver import WebDriver +from selenium.webdriver.common.keys import Keys +from django.core import mail +from django.contrib.auth.models import User +from registration.models import Activation +from django.urls import reverse +import time + +class MySeleniumTests(StaticLiveServerTestCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.selenium = WebDriver() + cls.selenium.implicitly_wait(10) + cls.selenium.maximize_window() + + @classmethod + def tearDownClass(cls): + cls.selenium.quit() + super().tearDownClass() + + def test_login(self): + self.selenium.get('%s%s' % (self.live_server_url, '/registration/')) + elem = self.selenium.find_element_by_name("username") + elem.send_keys("test_user") + elem = self.selenium.find_element_by_name("email") + elem.send_keys("test_user@test.ru") + elem = self.selenium.find_element_by_name("password1") + elem.send_keys("qwerty123") + elem = self.selenium.find_element_by_name("password2") + elem.send_keys("qwerty123", Keys.RETURN) + time.sleep(1) + user = User.objects.get(username="test_user") + self.assertEqual(str(user), "test_user") + key = Activation.objects.all()[0] + act_url = key.get_absolute_url() + # print(mail.outbox[0].body) + self.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].subject, "Deplodock. Завершение регистрации.") + self.assertEqual(mail.outbox[0].to[0], "test_user@test.ru") + self.assertRegexpMatches(mail.outbox[0].body, key.activation_key) + self.selenium.get('%s%s' % (self.live_server_url, act_url)) + text = self.selenium.find_element_by_tag_name("body").text + self.assertEqual(text, "%s, ваш аккаунт активирован. Перейти в личный кабинет" % user) diff --git a/selenium/user.json b/selenium/user.json new file mode 100644 index 0000000..3915eba --- /dev/null +++ b/selenium/user.json @@ -0,0 +1,3 @@ +[ + {"model": "auth.user", "pk": 1, "fields": {"username": "tester", "password": "pbkdf2_sha256$100000$AJu3FQOhiYtW$WoGIroWBGo14YXEwFkU3yDhN0Uq8f6rc6e2kiHUg5B0=", "email": "tester@gmail.com"}} +] \ No newline at end of file diff --git a/trials/__init__.py b/trials/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/trials/get_random_secret.py b/trials/get_random_secret.py new file mode 100644 index 0000000..16d014e --- /dev/null +++ b/trials/get_random_secret.py @@ -0,0 +1,17 @@ +import random + + +def get_random_string(length=12, + allowed_chars='abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'): + return ''.join(random.choice(allowed_chars) for i in range(length)) + + +def get_random_secret_key(): + """ + Return a 50 character random string usable as a SECRET_KEY setting value. + """ + chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)' + return get_random_string(50, chars) + +print(get_random_secret_key()) \ No newline at end of file diff --git a/trials/my_test.py b/trials/my_test.py new file mode 100644 index 0000000..58e44d1 --- /dev/null +++ b/trials/my_test.py @@ -0,0 +1,72 @@ +from __future__ import unicode_literals + +from django.core.urlresolvers import reverse +from django.test import TestCase +from api.models import Inventory, Group +from django.contrib.auth.models import User +import time +from django.db import transaction + + +class ProductivityTest(TestCase): + fixtures = ["tests/selenium/user.json"] + + def test_massive_creation_base(self): + start = time.time() + user = User.objects.all()[0] + inventory = Inventory(user=user, inventory='inv') + inventory.save() + for i in range(20000): + group = Group(inventory=inventory, group="group_{}".format(i)) + group.save() + + time_is = time.time() - start + print("base: ", time_is) + + # @transaction.atomic + def test_transaction(self): + start = time.time() + user = User.objects.all()[0] + inventory = Inventory(user=user, inventory='inv') + inventory.save() + with transaction.atomic(): + for i in range(20000): + group = Group(inventory=inventory, group="group_{}".format(i)) + group.clean_fields(exclude=['id', 'inventory']) + # group.setattr(f.attname, f.clean(raw_value, self)) + # for i in group._meta.fields: + # print(i.name) + group.save() + + time_is = time.time() - start + print("transaction_decorator: ", time_is) + + # @transaction.atomic + def test_bulk(self): + start = time.time() + user = User.objects.all()[0] + inventory = Inventory(user=user, inventory='inv') + inventory.save() + group_list = [] + # Group.objects.bulk_create([ + # Group(inventory=inventory, group="group_{}".format(group)) for group in range(20000) + # if Group(inventory=inventory, group="group_{}".format(group)).clean_fields(exclude=['id', 'inventory']) is None + # ]) + for i in range(20000): + group = Group(inventory=inventory, group="group_{}".format(i)) + group.clean_fields(exclude=['id', 'inventory']) + # group.save() + # group = Group.objects.get(inventory=inventory, group="group_{}".format(i)) + + group_list.append(group) + Group.objects.bulk_create(group_list) + # for i in range(20000): + # group = Group.objects.get(inventory=inventory, group="group_{}".format(i)) + # group.save() + + time_is = time.time() - start + print("bulk_decorator: ", time_is) + + + +