From 5d6ea242c063e99e5300f0cca39d1966950a48d3 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Wed, 27 Jan 2016 11:38:56 -0500 Subject: [PATCH 1/7] reorganzing tests folder make tests a module refacotring to local imports for tests fixing test import of tasks fixing test import of tasks more testing fixups --- Makefile | 3 + awx/fact/tests/utils/dbtransform.py | 9 +- awx/main/models/credential.py | 4 - awx/main/tests/__init__.py | 22 ---- awx/main/tests/functional/__init__.py | 24 ++++ .../tests/{ => functional}/activity_stream.py | 2 +- awx/main/tests/{ => functional}/ad_hoc.py | 4 +- awx/main/tests/{ => functional}/base.py | 0 .../{ => functional}/commands/__init__.py | 0 .../{ => functional}/commands/age_deleted.py | 4 +- .../tests/{ => functional}/commands/base.py | 2 +- .../commands/cleanup_facts.py | 6 +- .../commands/commands_monolithic.py | 12 +- .../commands/remove_instance.py | 4 +- .../commands/run_fact_cache_receiver.py | 4 +- .../commands/run_socketio_service.py | 0 .../commands/update_password.py | 10 +- .../data/large_ec2_inventory.py | 0 .../tests/{ => functional}/data/largeinv.py | 0 .../{ => functional}/data/splunk_inventory.py | 0 .../tests/{ => functional}/fact/__init__.py | 0 .../tests/{ => functional}/fact/fact_api.py | 4 +- awx/main/tests/{ => functional}/ha.py | 0 awx/main/tests/{ => functional}/inventory.py | 2 +- .../tests/{ => functional}/jobs/__init__.py | 0 awx/main/tests/{ => functional}/jobs/base.py | 10 +- .../tests/{ => functional}/jobs/job_launch.py | 0 .../{ => functional}/jobs/job_relaunch.py | 4 +- .../{ => functional}/jobs/jobs_monolithic.py | 0 .../{ => functional}/jobs/start_cancel.py | 4 +- .../{ => functional}/jobs/survey_password.py | 6 +- awx/main/tests/{ => functional}/licenses.py | 2 +- .../tests/{ => functional}/organizations.py | 2 +- awx/main/tests/{ => functional}/projects.py | 4 +- awx/main/tests/{ => functional}/redact.py | 2 +- awx/main/tests/{ => functional}/schedules.py | 2 +- awx/main/tests/{ => functional}/scripts.py | 2 +- awx/main/tests/{ => functional}/settings.py | 2 +- awx/main/tests/{ => functional}/tasks.py | 2 +- .../tests/{ => functional}/unified_jobs.py | 0 awx/main/tests/{ => functional}/users.py | 2 +- awx/main/tests/{ => functional}/views.py | 4 +- awx/main/tests/unit/utils/__init__.py | 0 awx/main/utils.py | 122 ++++++++++++++++++ 44 files changed, 205 insertions(+), 81 deletions(-) create mode 100644 awx/main/tests/functional/__init__.py rename awx/main/tests/{ => functional}/activity_stream.py (98%) rename awx/main/tests/{ => functional}/ad_hoc.py (99%) rename awx/main/tests/{ => functional}/base.py (100%) rename awx/main/tests/{ => functional}/commands/__init__.py (100%) rename awx/main/tests/{ => functional}/commands/age_deleted.py (92%) rename awx/main/tests/{ => functional}/commands/base.py (98%) rename awx/main/tests/{ => functional}/commands/cleanup_facts.py (98%) rename awx/main/tests/{ => functional}/commands/commands_monolithic.py (99%) rename awx/main/tests/{ => functional}/commands/remove_instance.py (93%) rename awx/main/tests/{ => functional}/commands/run_fact_cache_receiver.py (99%) rename awx/main/tests/{ => functional}/commands/run_socketio_service.py (100%) rename awx/main/tests/{ => functional}/commands/update_password.py (92%) rename awx/main/tests/{ => functional}/data/large_ec2_inventory.py (100%) rename awx/main/tests/{ => functional}/data/largeinv.py (100%) rename awx/main/tests/{ => functional}/data/splunk_inventory.py (100%) rename awx/main/tests/{ => functional}/fact/__init__.py (100%) rename awx/main/tests/{ => functional}/fact/fact_api.py (98%) rename awx/main/tests/{ => functional}/ha.py (100%) rename awx/main/tests/{ => functional}/inventory.py (99%) rename awx/main/tests/{ => functional}/jobs/__init__.py (100%) rename awx/main/tests/{ => functional}/jobs/base.py (99%) rename awx/main/tests/{ => functional}/jobs/job_launch.py (100%) rename awx/main/tests/{ => functional}/jobs/job_relaunch.py (97%) rename awx/main/tests/{ => functional}/jobs/jobs_monolithic.py (100%) rename awx/main/tests/{ => functional}/jobs/start_cancel.py (98%) rename awx/main/tests/{ => functional}/jobs/survey_password.py (98%) rename awx/main/tests/{ => functional}/licenses.py (99%) rename awx/main/tests/{ => functional}/organizations.py (99%) rename awx/main/tests/{ => functional}/projects.py (99%) rename awx/main/tests/{ => functional}/redact.py (99%) rename awx/main/tests/{ => functional}/schedules.py (99%) rename awx/main/tests/{ => functional}/scripts.py (99%) rename awx/main/tests/{ => functional}/settings.py (99%) rename awx/main/tests/{ => functional}/tasks.py (99%) rename awx/main/tests/{ => functional}/unified_jobs.py (100%) rename awx/main/tests/{ => functional}/users.py (99%) rename awx/main/tests/{ => functional}/views.py (97%) create mode 100644 awx/main/tests/unit/utils/__init__.py diff --git a/Makefile b/Makefile index a9f0cc557d..abb16932c6 100644 --- a/Makefile +++ b/Makefile @@ -362,6 +362,9 @@ check: flake8 pep8 # pyflakes pylint test: $(PYTHON) manage.py test -v2 awx.main.tests +test_unit: + $(PYTHON) -m py.test awx/main/tests/unit + # Run all API unit tests with coverage enabled. test_coverage: coverage run manage.py test -v2 awx.main.tests diff --git a/awx/fact/tests/utils/dbtransform.py b/awx/fact/tests/utils/dbtransform.py index 97bfad9c65..5f0eb1ad24 100644 --- a/awx/fact/tests/utils/dbtransform.py +++ b/awx/fact/tests/utils/dbtransform.py @@ -1,15 +1,16 @@ # Copyright (c) 2015 Ansible, Inc. # All Rights Reserved +from django.test import TestCase + # AWX -from awx.main.tests.base import BaseTest from awx.fact.models.fact import * # noqa from awx.fact.utils.dbtransform import KeyTransform #__all__ = ['DBTransformTest', 'KeyTransformUnitTest'] __all__ = ['KeyTransformUnitTest'] -class KeyTransformUnitTest(BaseTest): +class KeyTransformUnitTest(TestCase): def setUp(self): super(KeyTransformUnitTest, self).setUp() self.key_transform = KeyTransform([('.', '\uff0E'), ('$', '\uff04')]) @@ -82,7 +83,7 @@ class KeyTransformUnitTest(BaseTest): data = self.key_transform.transform_incoming(value, None) self.assertEqual(data, value_transformed) - + data = self.key_transform.transform_outgoing(value_transformed, None) self.assertEqual(data, value) @@ -103,7 +104,7 @@ class KeyTransformUnitTest(BaseTest): } data = self.key_transform.transform_incoming(value, None) self.assertEqual(data, value_transformed) - + data = self.key_transform.transform_outgoing(value_transformed, None) self.assertEqual(data, value) diff --git a/awx/main/models/credential.py b/awx/main/models/credential.py index a1deb7053f..e0d75dc182 100644 --- a/awx/main/models/credential.py +++ b/awx/main/models/credential.py @@ -1,10 +1,6 @@ # Copyright (c) 2015 Ansible, Inc. # All Rights Reserved. -# Python -import base64 -import re - # Django from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/awx/main/tests/__init__.py b/awx/main/tests/__init__.py index 4f1e89274e..e69de29bb2 100644 --- a/awx/main/tests/__init__.py +++ b/awx/main/tests/__init__.py @@ -1,22 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -from awx.main.tests.organizations import * # noqa -from awx.main.tests.users import * # noqa -from awx.main.tests.inventory import * # noqa -from awx.main.tests.projects import ProjectsTest, ProjectUpdatesTest # noqa -from awx.main.tests.commands import * # noqa -from awx.main.tests.scripts import * # noqa -from awx.main.tests.tasks import RunJobTest # noqa -from awx.main.tests.ad_hoc import * # noqa -from awx.main.tests.licenses import LicenseTests # noqa -from awx.main.tests.jobs import * # noqa -from awx.main.tests.activity_stream import * # noqa -from awx.main.tests.schedules import * # noqa -from awx.main.tests.redact import * # noqa -from awx.main.tests.views import * # noqa -from awx.main.tests.commands import * # noqa -from awx.main.tests.fact import * # noqa -from awx.main.tests.unified_jobs import * # noqa -from awx.main.tests.ha import * # noqa -from awx.main.tests.settings import * # noqa diff --git a/awx/main/tests/functional/__init__.py b/awx/main/tests/functional/__init__.py new file mode 100644 index 0000000000..37a6f1e643 --- /dev/null +++ b/awx/main/tests/functional/__init__.py @@ -0,0 +1,24 @@ +# Copyright (c) 2015 Ansible, Inc. +# All Rights Reserved. +import logging +logging.disable(logging.CRITICAL) + +from .organizations import * # noqa +from .users import * # noqa +from .inventory import * # noqa +from .projects import ProjectsTest, ProjectUpdatesTest # noqa +from .commands import * # noqa +from .scripts import * # noqa +from .tasks import RunJobTest # noqa +from .ad_hoc import * # noqa +from .licenses import LicenseTests # noqa +from .jobs import * # noqa +from .activity_stream import * # noqa +from .schedules import * # noqa +from .redact import * # noqa +from .views import * # noqa +from .commands import * # noqa +from .fact import * # noqa +from .unified_jobs import * # noqa +from .ha import * # noqa +from .settings import * # noqa diff --git a/awx/main/tests/activity_stream.py b/awx/main/tests/functional/activity_stream.py similarity index 98% rename from awx/main/tests/activity_stream.py rename to awx/main/tests/functional/activity_stream.py index 9798695954..81ebb7dc66 100644 --- a/awx/main/tests/activity_stream.py +++ b/awx/main/tests/functional/activity_stream.py @@ -6,7 +6,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTest +from .base import BaseTest class ActivityStreamTest(BaseTest): diff --git a/awx/main/tests/ad_hoc.py b/awx/main/tests/functional/ad_hoc.py similarity index 99% rename from awx/main/tests/ad_hoc.py rename to awx/main/tests/functional/ad_hoc.py index 957cd7c084..154a8d69ec 100644 --- a/awx/main/tests/ad_hoc.py +++ b/awx/main/tests/functional/ad_hoc.py @@ -18,8 +18,8 @@ from crum import impersonate # AWX from awx.main.utils import * # noqa from awx.main.models import * # noqa -from awx.main.tests.base import BaseJobExecutionTest -from awx.main.tests.tasks import TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK +from .base import BaseJobExecutionTest +from .tasks import TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK __all__ = ['RunAdHocCommandTest', 'AdHocCommandApiTest'] diff --git a/awx/main/tests/base.py b/awx/main/tests/functional/base.py similarity index 100% rename from awx/main/tests/base.py rename to awx/main/tests/functional/base.py diff --git a/awx/main/tests/commands/__init__.py b/awx/main/tests/functional/commands/__init__.py similarity index 100% rename from awx/main/tests/commands/__init__.py rename to awx/main/tests/functional/commands/__init__.py diff --git a/awx/main/tests/commands/age_deleted.py b/awx/main/tests/functional/commands/age_deleted.py similarity index 92% rename from awx/main/tests/commands/age_deleted.py rename to awx/main/tests/functional/commands/age_deleted.py index 02738c2c1f..eec90814d1 100644 --- a/awx/main/tests/commands/age_deleted.py +++ b/awx/main/tests/functional/commands/age_deleted.py @@ -2,8 +2,8 @@ # All Rights Reserved # AWX -from awx.main.tests.base import BaseTest -from awx.main.tests.commands.base import BaseCommandMixin +from ..base import BaseTest +from .base import BaseCommandMixin __all__ = ['AgeDeletedCommandFunctionalTest'] diff --git a/awx/main/tests/commands/base.py b/awx/main/tests/functional/commands/base.py similarity index 98% rename from awx/main/tests/commands/base.py rename to awx/main/tests/functional/commands/base.py index 2f1d795d27..10d2096c41 100644 --- a/awx/main/tests/commands/base.py +++ b/awx/main/tests/functional/commands/base.py @@ -11,7 +11,7 @@ from django.core.management import call_command # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTestMixin +from ..base import BaseTestMixin class BaseCommandMixin(BaseTestMixin): def create_test_inventories(self): diff --git a/awx/main/tests/commands/cleanup_facts.py b/awx/main/tests/functional/commands/cleanup_facts.py similarity index 98% rename from awx/main/tests/commands/cleanup_facts.py rename to awx/main/tests/functional/commands/cleanup_facts.py index d6f0bd0b97..a637340bd0 100644 --- a/awx/main/tests/commands/cleanup_facts.py +++ b/awx/main/tests/functional/commands/cleanup_facts.py @@ -10,9 +10,9 @@ import mock from django.core.management.base import CommandError # AWX -from awx.main.tests.base import BaseTest +from ..base import BaseTest from awx.fact.tests.base import MongoDBRequired, FactScanBuilder, TEST_FACT_PACKAGES, TEST_FACT_ANSIBLE, TEST_FACT_SERVICES -from awx.main.tests.commands.base import BaseCommandMixin +from .base import BaseCommandMixin from awx.main.management.commands.cleanup_facts import Command, CleanupFacts from awx.fact.models.fact import * # noqa @@ -45,7 +45,7 @@ class CleanupFactsCommandFunctionalTest(BaseCommandMixin, BaseTest, MongoDBRequi def test_invoke_params_required(self): result, stdout, stderr = self.run_command('cleanup_facts') self.assertIsInstance(result, CommandError) - self.assertEqual(str(result), 'Both --granularity and --older_than are required.') + self.assertEqual(str(result), 'Both --granularity and --older_than are required.') def test_module(self): self.builder.add_fact('packages', TEST_FACT_PACKAGES) diff --git a/awx/main/tests/commands/commands_monolithic.py b/awx/main/tests/functional/commands/commands_monolithic.py similarity index 99% rename from awx/main/tests/commands/commands_monolithic.py rename to awx/main/tests/functional/commands/commands_monolithic.py index d13bbe05f2..fa69a13742 100644 --- a/awx/main/tests/commands/commands_monolithic.py +++ b/awx/main/tests/functional/commands/commands_monolithic.py @@ -24,7 +24,7 @@ from django.test.utils import override_settings # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTest, BaseLiveServerTest +from ..base import BaseTest, BaseLiveServerTest __all__ = ['CreateDefaultOrgTest', 'DumpDataTest', 'CleanupDeletedTest', 'CleanupJobsTest', 'CleanupActivityStreamTest', @@ -471,7 +471,7 @@ class CleanupJobsTest(BaseCommandMixin, BaseLiveServerTest): self.assertTrue(ad_hoc_command.signal_start()) ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk) self.assertEqual(ad_hoc_command.status, 'successful') - + # With days=1, no jobs will be deleted. jobs_before = Job.objects.all().count() self.assertTrue(jobs_before) @@ -690,7 +690,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): self.assertTrue('required' in str(result)) # Inventory ID, with invalid source. invalid_source = ''.join([os.path.splitext(self.ini_path)[0] + '-invalid', - os.path.splitext(self.ini_path)[1]]) + os.path.splitext(self.ini_path)[1]]) result, stdout, stderr = self.run_command('inventory_import', inventory_id=inventory_id, source=invalid_source) @@ -766,7 +766,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): self.assertEqual(group.children.count(), 0) hosts = set(group.hosts.values_list('name', flat=True)) host_names = set(['db1.example.com','db2.example.com']) - self.assertEqual(hosts, host_names) + self.assertEqual(hosts, host_names) elif group.name == 'webservers': self.assertEqual(group.variables_dict, {'webvar': 'blah'}) self.assertEqual(group.children.count(), 0) @@ -860,7 +860,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): self.assertEqual(group.children.filter(active=True).count(), 0) hosts = set(group.hosts.filter(active=True).values_list('name', flat=True)) host_names = set(['db1.example.com','db2.example.com']) - self.assertEqual(hosts, host_names) + self.assertEqual(hosts, host_names) elif group.name == 'webservers': self.assertEqual(group.variables_dict, {'webvar': 'blah'}) self.assertEqual(group.children.filter(active=True).count(), 0) @@ -1013,7 +1013,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): rest_api_url = urlparse.urlunsplit([parts.scheme, netloc, parts.path, parts.query, parts.fragment]) os.environ.setdefault('REST_API_URL', rest_api_url) - os.environ['INVENTORY_ID'] = str(old_inv.pk) + os.environ['INVENTORY_ID'] = str(old_inv.pk) source = os.path.join(os.path.dirname(__file__), '..', '..', '..', 'plugins', 'inventory', 'awxrest.py') result, stdout, stderr = self.run_command('inventory_import', diff --git a/awx/main/tests/commands/remove_instance.py b/awx/main/tests/functional/commands/remove_instance.py similarity index 93% rename from awx/main/tests/commands/remove_instance.py rename to awx/main/tests/functional/commands/remove_instance.py index d93285ea7e..f9713457bd 100644 --- a/awx/main/tests/commands/remove_instance.py +++ b/awx/main/tests/functional/commands/remove_instance.py @@ -5,8 +5,8 @@ import uuid # AWX -from awx.main.tests.base import BaseTest -from awx.main.tests.commands.base import BaseCommandMixin +from ..base import BaseTest +from .base import BaseCommandMixin from awx.main.models import * # noqa __all__ = ['RemoveInstanceCommandFunctionalTest'] diff --git a/awx/main/tests/commands/run_fact_cache_receiver.py b/awx/main/tests/functional/commands/run_fact_cache_receiver.py similarity index 99% rename from awx/main/tests/commands/run_fact_cache_receiver.py rename to awx/main/tests/functional/commands/run_fact_cache_receiver.py index 0dac618758..f5d5e5da09 100644 --- a/awx/main/tests/commands/run_fact_cache_receiver.py +++ b/awx/main/tests/functional/commands/run_fact_cache_receiver.py @@ -10,9 +10,9 @@ from copy import deepcopy from mock import MagicMock # AWX -from awx.main.tests.base import BaseTest +from ..base import BaseTest from awx.fact.tests.base import MongoDBRequired -from awx.main.tests.commands.base import BaseCommandMixin +from .base import BaseCommandMixin from awx.main.management.commands.run_fact_cache_receiver import FactCacheReceiver from awx.fact.models.fact import * # noqa diff --git a/awx/main/tests/commands/run_socketio_service.py b/awx/main/tests/functional/commands/run_socketio_service.py similarity index 100% rename from awx/main/tests/commands/run_socketio_service.py rename to awx/main/tests/functional/commands/run_socketio_service.py diff --git a/awx/main/tests/commands/update_password.py b/awx/main/tests/functional/commands/update_password.py similarity index 92% rename from awx/main/tests/commands/update_password.py rename to awx/main/tests/functional/commands/update_password.py index 60eb04de88..ec89892c1d 100644 --- a/awx/main/tests/commands/update_password.py +++ b/awx/main/tests/functional/commands/update_password.py @@ -2,8 +2,8 @@ # All Rights Reserved # AWX -from awx.main.tests.base import BaseTest -from awx.main.tests.commands.base import BaseCommandMixin +from ..base import BaseTest +from .base import BaseCommandMixin # Django from django.core.management.base import CommandError @@ -20,16 +20,16 @@ class UpdatePasswordCommandFunctionalTest(BaseCommandMixin, BaseTest): def test_updated_ok(self): result, stdout, stderr = self.run_command('update_password', username='admin', password='dingleberry') self.assertEqual(stdout, 'Password updated\n') - + def test_same_password(self): result, stdout, stderr = self.run_command('update_password', username='admin', password='admin') self.assertEqual(stdout, 'Password not updated\n') - + def test_error_username_required(self): result, stdout, stderr = self.run_command('update_password', password='foo') self.assertIsInstance(result, CommandError) self.assertEqual(str(result), 'username required') - + def test_error_password_required(self): result, stdout, stderr = self.run_command('update_password', username='admin') self.assertIsInstance(result, CommandError) diff --git a/awx/main/tests/data/large_ec2_inventory.py b/awx/main/tests/functional/data/large_ec2_inventory.py similarity index 100% rename from awx/main/tests/data/large_ec2_inventory.py rename to awx/main/tests/functional/data/large_ec2_inventory.py diff --git a/awx/main/tests/data/largeinv.py b/awx/main/tests/functional/data/largeinv.py similarity index 100% rename from awx/main/tests/data/largeinv.py rename to awx/main/tests/functional/data/largeinv.py diff --git a/awx/main/tests/data/splunk_inventory.py b/awx/main/tests/functional/data/splunk_inventory.py similarity index 100% rename from awx/main/tests/data/splunk_inventory.py rename to awx/main/tests/functional/data/splunk_inventory.py diff --git a/awx/main/tests/fact/__init__.py b/awx/main/tests/functional/fact/__init__.py similarity index 100% rename from awx/main/tests/fact/__init__.py rename to awx/main/tests/functional/fact/__init__.py diff --git a/awx/main/tests/fact/fact_api.py b/awx/main/tests/functional/fact/fact_api.py similarity index 98% rename from awx/main/tests/fact/fact_api.py rename to awx/main/tests/functional/fact/fact_api.py index 157cec3757..36038b987f 100644 --- a/awx/main/tests/fact/fact_api.py +++ b/awx/main/tests/functional/fact/fact_api.py @@ -10,7 +10,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.utils import timestamp_apiformat from awx.main.models import * # noqa -from awx.main.tests.base import BaseLiveServerTest +from ..base import BaseLiveServerTest from awx.fact.models import * # noqa from awx.fact.tests.base import BaseFactTestMixin, FactScanBuilder, TEST_FACT_ANSIBLE, TEST_FACT_PACKAGES, TEST_FACT_SERVICES from awx.main.utils import build_url @@ -181,7 +181,7 @@ class FactViewApiTest(FactApiBaseTest): def test_view_time_filter(self): self.setup_facts(6) ts = self.builder.get_timestamp(3) - self.get_fact(Fact.objects.filter(host=self.fact_host, module='ansible', timestamp__lte=ts).order_by('-timestamp')[0], + self.get_fact(Fact.objects.filter(host=self.fact_host, module='ansible', timestamp__lte=ts).order_by('-timestamp')[0], dict(datetime=ts)) diff --git a/awx/main/tests/ha.py b/awx/main/tests/functional/ha.py similarity index 100% rename from awx/main/tests/ha.py rename to awx/main/tests/functional/ha.py diff --git a/awx/main/tests/inventory.py b/awx/main/tests/functional/inventory.py similarity index 99% rename from awx/main/tests/inventory.py rename to awx/main/tests/functional/inventory.py index de7149df3e..08c2378bc9 100644 --- a/awx/main/tests/inventory.py +++ b/awx/main/tests/functional/inventory.py @@ -18,7 +18,7 @@ from django.utils.timezone import now # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTest, BaseTransactionTest +from .base import BaseTest, BaseTransactionTest __all__ = ['InventoryTest', 'InventoryUpdatesTest', 'InventoryCredentialTest'] diff --git a/awx/main/tests/jobs/__init__.py b/awx/main/tests/functional/jobs/__init__.py similarity index 100% rename from awx/main/tests/jobs/__init__.py rename to awx/main/tests/functional/jobs/__init__.py diff --git a/awx/main/tests/jobs/base.py b/awx/main/tests/functional/jobs/base.py similarity index 99% rename from awx/main/tests/jobs/base.py rename to awx/main/tests/functional/jobs/base.py index dcb056abb7..1c45e94e4d 100644 --- a/awx/main/tests/jobs/base.py +++ b/awx/main/tests/functional/jobs/base.py @@ -3,7 +3,7 @@ import uuid # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTestMixin +from ..base import BaseTestMixin TEST_PLAYBOOK = '''- hosts: all gather_facts: false @@ -128,7 +128,7 @@ class BaseJobTestMixin(BaseTestMixin): # He works with Randall self.user_billybob = self.make_user('billybob') self.org_ops.users.add(self.user_billybob) - + # Jim is the newest intern. He can login, but can't do anything quite yet # except make everyone else fresh coffee. self.user_jim = self.make_user('jim') @@ -256,7 +256,7 @@ class BaseJobTestMixin(BaseTestMixin): self.team_ops_testers.users.add(self.user_billybob) # Each user has his/her own set of credentials. - from awx.main.tests.tasks import (TEST_SSH_KEY_DATA, + from ..tasks import (TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK) self.cred_sue = self.user_sue.credentials.create( @@ -429,7 +429,7 @@ class BaseJobTestMixin(BaseTestMixin): #self.permission1 = Permission.objects.create( # inventory = self.inventory, # project = self.project, - # team = self.team, + # team = self.team, # permission_type = PERM_INVENTORY_DEPLOY, # created_by = self.normal_django_user #) @@ -441,7 +441,7 @@ class BaseJobTestMixin(BaseTestMixin): # permission_type = PERM_INVENTORY_CHECK, # created_by = self.normal_django_user #) - + # Engineering has job templates to check/run the dev project onto # their own inventory. self.jt_eng_check = JobTemplate.objects.create( diff --git a/awx/main/tests/jobs/job_launch.py b/awx/main/tests/functional/jobs/job_launch.py similarity index 100% rename from awx/main/tests/jobs/job_launch.py rename to awx/main/tests/functional/jobs/job_launch.py diff --git a/awx/main/tests/jobs/job_relaunch.py b/awx/main/tests/functional/jobs/job_relaunch.py similarity index 97% rename from awx/main/tests/jobs/job_relaunch.py rename to awx/main/tests/functional/jobs/job_relaunch.py index 04ae95ba75..6fcc1b8b82 100644 --- a/awx/main/tests/jobs/job_relaunch.py +++ b/awx/main/tests/functional/jobs/job_relaunch.py @@ -10,7 +10,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseLiveServerTest +from ..base import BaseLiveServerTest from .base import BaseJobTestMixin __all__ = ['JobRelaunchTest',] @@ -63,7 +63,7 @@ class JobRelaunchTest(BaseJobTestMixin, BaseLiveServerTest): self.jt_ops_east_run.extra_vars = jt_extra_vars self.jt_ops_east_run.save() - + response = self.post(url, {}, expect=201) j = Job.objects.get(pk=response['job']) self.assertTrue(j.status == 'successful') diff --git a/awx/main/tests/jobs/jobs_monolithic.py b/awx/main/tests/functional/jobs/jobs_monolithic.py similarity index 100% rename from awx/main/tests/jobs/jobs_monolithic.py rename to awx/main/tests/functional/jobs/jobs_monolithic.py diff --git a/awx/main/tests/jobs/start_cancel.py b/awx/main/tests/functional/jobs/start_cancel.py similarity index 98% rename from awx/main/tests/jobs/start_cancel.py rename to awx/main/tests/functional/jobs/start_cancel.py index 54ff2255d9..676ad13f3b 100644 --- a/awx/main/tests/jobs/start_cancel.py +++ b/awx/main/tests/functional/jobs/start_cancel.py @@ -10,7 +10,7 @@ from django.conf import settings # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseLiveServerTest +from ..base import BaseLiveServerTest from .base import BaseJobTestMixin __all__ = ['JobStartCancelTest',] @@ -92,7 +92,7 @@ class JobStartCancelTest(BaseJobTestMixin, BaseLiveServerTest): # self.assertEqual(job.status, 'failed') # Test with a job that prompts for SSH unlock key, given the right key. - from awx.main.tests.tasks import TEST_SSH_KEY_DATA_UNLOCK + from ..tasks import TEST_SSH_KEY_DATA_UNLOCK # job = self.jt_ops_west_run.create_job( # credential=self.cred_greg, # created_by=self.user_sue, diff --git a/awx/main/tests/jobs/survey_password.py b/awx/main/tests/functional/jobs/survey_password.py similarity index 98% rename from awx/main/tests/jobs/survey_password.py rename to awx/main/tests/functional/jobs/survey_password.py index c5243712b5..fc46fcfc48 100644 --- a/awx/main/tests/jobs/survey_password.py +++ b/awx/main/tests/functional/jobs/survey_password.py @@ -6,7 +6,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTest, QueueStartStopTestMixin +from ..base import BaseTest, QueueStartStopTestMixin __all__ = ['SurveyPasswordRedactedTest'] @@ -87,7 +87,7 @@ TEST_COMPLEX_SURVEY = ''' TEST_SINGLE_PASSWORDS = [ - { + { 'description': 'Single instance with a . after', 'text' : 'See spot. See spot run. See spot run %s. That is a fast run.' % PASSWORD, 'passwords': [PASSWORD], @@ -233,5 +233,5 @@ class SurveyPasswordRedactedTest(SurveyPasswordBaseTest): # should redact values in extra_vars def test_redact_job_extra_vars(self): for test in self.tests['simple']: - response = self._get_url_job_details(test['job']) + response = self._get_url_job_details(test['job']) self.check_extra_vars_redacted(test, response) diff --git a/awx/main/tests/licenses.py b/awx/main/tests/functional/licenses.py similarity index 99% rename from awx/main/tests/licenses.py rename to awx/main/tests/functional/licenses.py index 6703db54cd..0c0c43fcfa 100644 --- a/awx/main/tests/licenses.py +++ b/awx/main/tests/functional/licenses.py @@ -6,7 +6,7 @@ import os import tempfile from awx.main.models import Host, Inventory, Organization -from awx.main.tests.base import BaseTest +from .base import BaseTest import awx.main.task_engine from awx.main.task_engine import * # noqa diff --git a/awx/main/tests/organizations.py b/awx/main/tests/functional/organizations.py similarity index 99% rename from awx/main/tests/organizations.py rename to awx/main/tests/functional/organizations.py index 8378ab12cb..e10d6dd92a 100644 --- a/awx/main/tests/organizations.py +++ b/awx/main/tests/functional/organizations.py @@ -12,7 +12,7 @@ from django.utils.timezone import now as tz_now # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTest +from .base import BaseTest __all__ = ['AuthTokenLimitUnitTest', 'OrganizationsTest'] diff --git a/awx/main/tests/projects.py b/awx/main/tests/functional/projects.py similarity index 99% rename from awx/main/tests/projects.py rename to awx/main/tests/functional/projects.py index d12fd89e7b..eb1579fdea 100644 --- a/awx/main/tests/projects.py +++ b/awx/main/tests/functional/projects.py @@ -20,8 +20,8 @@ from django.utils.timezone import now # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTransactionTest -from awx.main.tests.tasks import TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK, TEST_OPENSSH_KEY_DATA, TEST_OPENSSH_KEY_DATA_LOCKED +from .base import BaseTransactionTest +from .tasks import TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK, TEST_OPENSSH_KEY_DATA, TEST_OPENSSH_KEY_DATA_LOCKED from awx.main.utils import decrypt_field, update_scm_url TEST_PLAYBOOK = '''- hosts: mygroup diff --git a/awx/main/tests/redact.py b/awx/main/tests/functional/redact.py similarity index 99% rename from awx/main/tests/redact.py rename to awx/main/tests/functional/redact.py index ea61aebd77..40e8869398 100644 --- a/awx/main/tests/redact.py +++ b/awx/main/tests/functional/redact.py @@ -3,7 +3,7 @@ import textwrap # AWX from awx.main.redact import UriCleaner -from awx.main.tests.base import BaseTest, URI +from .base import BaseTest, URI __all__ = ['UriCleanTests'] diff --git a/awx/main/tests/schedules.py b/awx/main/tests/functional/schedules.py similarity index 99% rename from awx/main/tests/schedules.py rename to awx/main/tests/functional/schedules.py index 4a4a0bcee3..1beeff6286 100644 --- a/awx/main/tests/schedules.py +++ b/awx/main/tests/functional/schedules.py @@ -10,7 +10,7 @@ from django.utils.timezone import now # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTest +from .base import BaseTest __all__ = ['ScheduleTest'] diff --git a/awx/main/tests/scripts.py b/awx/main/tests/functional/scripts.py similarity index 99% rename from awx/main/tests/scripts.py rename to awx/main/tests/functional/scripts.py index 459070a868..50dd336ac2 100644 --- a/awx/main/tests/scripts.py +++ b/awx/main/tests/functional/scripts.py @@ -10,7 +10,7 @@ import urlparse # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseLiveServerTest +from .base import BaseLiveServerTest __all__ = ['InventoryScriptTest'] diff --git a/awx/main/tests/settings.py b/awx/main/tests/functional/settings.py similarity index 99% rename from awx/main/tests/settings.py rename to awx/main/tests/functional/settings.py index a727213454..14e4285d09 100644 --- a/awx/main/tests/settings.py +++ b/awx/main/tests/functional/settings.py @@ -1,7 +1,7 @@ # Copyright (c) 2016 Ansible, Inc. # All Rights Reserved. -from awx.main.tests.base import BaseTest +from .base import BaseTest from awx.main.models import * # noqa from django.core.urlresolvers import reverse diff --git a/awx/main/tests/tasks.py b/awx/main/tests/functional/tasks.py similarity index 99% rename from awx/main/tests/tasks.py rename to awx/main/tests/functional/tasks.py index acdff99e29..7bf0648957 100644 --- a/awx/main/tests/tasks.py +++ b/awx/main/tests/functional/tasks.py @@ -21,7 +21,7 @@ from crum import impersonate # AWX from awx.main.utils import * # noqa from awx.main.models import * # noqa -from awx.main.tests.base import BaseJobExecutionTest +from .base import BaseJobExecutionTest TEST_PLAYBOOK = u''' - name: test success diff --git a/awx/main/tests/unified_jobs.py b/awx/main/tests/functional/unified_jobs.py similarity index 100% rename from awx/main/tests/unified_jobs.py rename to awx/main/tests/functional/unified_jobs.py diff --git a/awx/main/tests/users.py b/awx/main/tests/functional/users.py similarity index 99% rename from awx/main/tests/users.py rename to awx/main/tests/functional/users.py index 78aca9da4b..11f27a6fd4 100644 --- a/awx/main/tests/users.py +++ b/awx/main/tests/functional/users.py @@ -15,7 +15,7 @@ from django.test.utils import override_settings # AWX from awx.main.models import * # noqa -from awx.main.tests.base import BaseTest +from .base import BaseTest from awx.main.conf import tower_settings __all__ = ['AuthTokenTimeoutTest', 'AuthTokenLimitTest', 'AuthTokenProxyTest', 'UsersTest', 'LdapTest'] diff --git a/awx/main/tests/views.py b/awx/main/tests/functional/views.py similarity index 97% rename from awx/main/tests/views.py rename to awx/main/tests/functional/views.py index 6903b1ebf8..e53fdce500 100644 --- a/awx/main/tests/views.py +++ b/awx/main/tests/functional/views.py @@ -2,8 +2,8 @@ from django.core.urlresolvers import reverse # Reuse Test code -from awx.main.tests.base import BaseLiveServerTest, QueueStartStopTestMixin -from awx.main.tests.base import URI +from .base import BaseLiveServerTest, QueueStartStopTestMixin +from .base import URI from awx.main.models.projects import * # noqa __all__ = ['UnifiedJobStdoutRedactedTests'] diff --git a/awx/main/tests/unit/utils/__init__.py b/awx/main/tests/unit/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/awx/main/utils.py b/awx/main/utils.py index 63b4a9441c..96df62b379 100644 --- a/awx/main/utils.py +++ b/awx/main/utils.py @@ -20,6 +20,7 @@ import tempfile from rest_framework.exceptions import ParseError, PermissionDenied from django.utils.encoding import smart_str from django.core.urlresolvers import reverse +from django.core.exceptions import ValidationError # PyCrypto from Crypto.Cipher import AES @@ -522,4 +523,125 @@ def timedelta_total_seconds(timedelta): timedelta.microseconds + 0.0 + (timedelta.seconds + timedelta.days * 24 * 3600) * 10 ** 6) / 10 ** 6 +def validate_ssh_private_key(data): + """Validate that the given SSH private key or certificate is, + in fact, valid. + """ + # Map the X in BEGIN X PRIVATE KEY to the key type (ssh-keygen -t). + # Tower jobs using OPENSSH format private keys may still fail if the + # system SSH implementation lacks support for this format. + key_types = { + 'RSA': 'rsa', + 'DSA': 'dsa', + 'EC': 'ecdsa', + 'OPENSSH': 'ed25519', + '': 'rsa1', + } + # Key properties to return if valid. + key_data = { + 'key_type': None, # Key type (from above mapping). + 'key_seg': '', # Key segment (all text including begin/end). + 'key_b64': '', # Key data as base64. + 'key_bin': '', # Key data as binary. + 'key_enc': None, # Boolean, whether key is encrypted. + 'cert_seg': '', # Cert segment (all text including begin/end). + 'cert_b64': '', # Cert data as base64. + 'cert_bin': '', # Cert data as binary. + } + data = data.strip() + validation_error = ValidationError('Invalid private key') + + # Sanity check: We may potentially receive a full PEM certificate, + # and we want to accept these. + cert_begin_re = r'(-{4,})\s*BEGIN\s+CERTIFICATE\s*(-{4,})' + cert_end_re = r'(-{4,})\s*END\s+CERTIFICATE\s*(-{4,})' + cert_begin_match = re.search(cert_begin_re, data) + cert_end_match = re.search(cert_end_re, data) + if cert_begin_match and not cert_end_match: + raise validation_error + elif not cert_begin_match and cert_end_match: + raise validation_error + elif cert_begin_match and cert_end_match: + cert_dashes = set([cert_begin_match.groups()[0], cert_begin_match.groups()[1], + cert_end_match.groups()[0], cert_end_match.groups()[1]]) + if len(cert_dashes) != 1: + raise validation_error + key_data['cert_seg'] = data[cert_begin_match.start():cert_end_match.end()] + + # Find the private key, and also ensure that it internally matches + # itself. + # Set up the valid private key header and footer. + begin_re = r'(-{4,})\s*BEGIN\s+([A-Z0-9]+)?\s*PRIVATE\sKEY\s*(-{4,})' + end_re = r'(-{4,})\s*END\s+([A-Z0-9]+)?\s*PRIVATE\sKEY\s*(-{4,})' + begin_match = re.search(begin_re, data) + end_match = re.search(end_re, data) + if not begin_match or not end_match: + raise validation_error + + # Ensure that everything, such as dash counts and key type, lines up, + # and raise an error if it does not. + dashes = set([begin_match.groups()[0], begin_match.groups()[2], + end_match.groups()[0], end_match.groups()[2]]) + if len(dashes) != 1: + raise validation_error + if begin_match.groups()[1] != end_match.groups()[1]: + raise validation_error + key_type = begin_match.groups()[1] or '' + try: + key_data['key_type'] = key_types[key_type] + except KeyError: + raise ValidationError('Invalid private key: unsupported type %s' % key_type) + + # The private key data begins and ends with the private key. + key_data['key_seg'] = data[begin_match.start():end_match.end()] + + # Establish that we are able to base64 decode the private key; + # if we can't, then it's not a valid key. + # + # If we got a certificate, validate that also, in the same way. + header_re = re.compile(r'^(.+?):\s*?(.+?)(\\??)$') + for segment_name in ('cert', 'key'): + segment_to_validate = key_data['%s_seg' % segment_name] + # If we have nothing; skip this one. + # We've already validated that we have a private key above, + # so we don't need to do it again. + if not segment_to_validate: + continue + + # Ensure that this segment is valid base64 data. + base64_data = '' + line_continues = False + lines = segment_to_validate.splitlines() + for line in lines[1:-1]: + line = line.strip() + if not line: + continue + if line_continues: + line_continues = line.endswith('\\') + continue + line_match = header_re.match(line) + if line_match: + line_continues = line.endswith('\\') + continue + base64_data += line + try: + decoded_data = base64.b64decode(base64_data) + if not decoded_data: + raise validation_error + key_data['%s_b64' % segment_name] = base64_data + key_data['%s_bin' % segment_name] = decoded_data + except TypeError: + raise validation_error + + # Determine if key is encrypted. + if key_data['key_type'] == 'ed25519': + # See https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L3218 + # Decoded key data starts with magic string (null-terminated), four byte + # length field, followed by the ciphername -- if ciphername is anything + # other than 'none' the key is encrypted. + key_data['key_enc'] = not bool(key_data['key_bin'].startswith('openssh-key-v1\x00\x00\x00\x00\x04none')) + else: + key_data['key_enc'] = bool('ENCRYPTED' in key_data['key_seg']) + + return key_data From 3d4580611eedec18fa9928732dea44f77e1d6d57 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Wed, 27 Jan 2016 13:42:58 -0500 Subject: [PATCH 2/7] added pytest to requirements_dev reworking test strucutre reworked pytest.ini, removed functional imports, updated req_dev remove unneeded __init__ files add testing checker to local_settings examples adding testing packages to system Python for docker --- Makefile | 6 +- awx/main/models/credential.py | 3 + awx/main/tests/__init__.py | 0 awx/main/tests/functional/__init__.py | 24 ---- .../tests/functional/commands/__init__.py | 13 -- awx/main/tests/functional/fact/__init__.py | 6 - awx/main/tests/functional/jobs/__init__.py | 11 -- awx/main/tests/unit/utils/__init__.py | 0 awx/main/utils.py | 122 ------------------ awx/settings/local_settings.py.docker_compose | 9 +- awx/settings/local_settings.py.example | 9 +- pytest.ini | 5 + requirements/requirements_dev.txt | 4 + tools/docker-compose/Dockerfile | 4 + 14 files changed, 35 insertions(+), 181 deletions(-) delete mode 100644 awx/main/tests/__init__.py delete mode 100644 awx/main/tests/functional/__init__.py delete mode 100644 awx/main/tests/functional/commands/__init__.py delete mode 100644 awx/main/tests/functional/fact/__init__.py delete mode 100644 awx/main/tests/functional/jobs/__init__.py delete mode 100644 awx/main/tests/unit/utils/__init__.py create mode 100644 pytest.ini diff --git a/Makefile b/Makefile index abb16932c6..3d406b106b 100644 --- a/Makefile +++ b/Makefile @@ -357,17 +357,17 @@ pylint: reports @(set -o pipefail && $@ | reports/$@.report) check: flake8 pep8 # pyflakes pylint - + # Run all API unit tests. test: - $(PYTHON) manage.py test -v2 awx.main.tests + $(PYTHON) -m py.test awx/main/tests test_unit: $(PYTHON) -m py.test awx/main/tests/unit # Run all API unit tests with coverage enabled. test_coverage: - coverage run manage.py test -v2 awx.main.tests + $(PYTHON) -m py.test --cov=awx awx/main/tests # Output test coverage as HTML (into htmlcov directory). coverage_html: diff --git a/awx/main/models/credential.py b/awx/main/models/credential.py index e0d75dc182..c72c67b715 100644 --- a/awx/main/models/credential.py +++ b/awx/main/models/credential.py @@ -1,6 +1,9 @@ # Copyright (c) 2015 Ansible, Inc. # All Rights Reserved. +import base64 +import re + # Django from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/awx/main/tests/__init__.py b/awx/main/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/awx/main/tests/functional/__init__.py b/awx/main/tests/functional/__init__.py deleted file mode 100644 index 37a6f1e643..0000000000 --- a/awx/main/tests/functional/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. -import logging -logging.disable(logging.CRITICAL) - -from .organizations import * # noqa -from .users import * # noqa -from .inventory import * # noqa -from .projects import ProjectsTest, ProjectUpdatesTest # noqa -from .commands import * # noqa -from .scripts import * # noqa -from .tasks import RunJobTest # noqa -from .ad_hoc import * # noqa -from .licenses import LicenseTests # noqa -from .jobs import * # noqa -from .activity_stream import * # noqa -from .schedules import * # noqa -from .redact import * # noqa -from .views import * # noqa -from .commands import * # noqa -from .fact import * # noqa -from .unified_jobs import * # noqa -from .ha import * # noqa -from .settings import * # noqa diff --git a/awx/main/tests/functional/commands/__init__.py b/awx/main/tests/functional/commands/__init__.py deleted file mode 100644 index 84212dd2fb..0000000000 --- a/awx/main/tests/functional/commands/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved - -from __future__ import absolute_import - -from .run_fact_cache_receiver import * # noqa -from .commands_monolithic import * # noqa -from .cleanup_facts import * # noqa -from .age_deleted import * # noqa -from .remove_instance import * # noqa -from .run_socketio_service import * # noqa -from .update_password import * # noqa - diff --git a/awx/main/tests/functional/fact/__init__.py b/awx/main/tests/functional/fact/__init__.py deleted file mode 100644 index 234499d6e9..0000000000 --- a/awx/main/tests/functional/fact/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved - -from __future__ import absolute_import - -from .fact_api import * # noqa diff --git a/awx/main/tests/functional/jobs/__init__.py b/awx/main/tests/functional/jobs/__init__.py deleted file mode 100644 index 092826ccf0..0000000000 --- a/awx/main/tests/functional/jobs/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved - -from __future__ import absolute_import - -from .jobs_monolithic import * # noqa -from .job_launch import * # noqa -from .job_relaunch import * # noqa -from .survey_password import * # noqa -from .start_cancel import * # noqa -from .base import * # noqa diff --git a/awx/main/tests/unit/utils/__init__.py b/awx/main/tests/unit/utils/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/awx/main/utils.py b/awx/main/utils.py index 96df62b379..5b9b7a1f46 100644 --- a/awx/main/utils.py +++ b/awx/main/utils.py @@ -523,125 +523,3 @@ def timedelta_total_seconds(timedelta): timedelta.microseconds + 0.0 + (timedelta.seconds + timedelta.days * 24 * 3600) * 10 ** 6) / 10 ** 6 -def validate_ssh_private_key(data): - """Validate that the given SSH private key or certificate is, - in fact, valid. - """ - # Map the X in BEGIN X PRIVATE KEY to the key type (ssh-keygen -t). - # Tower jobs using OPENSSH format private keys may still fail if the - # system SSH implementation lacks support for this format. - key_types = { - 'RSA': 'rsa', - 'DSA': 'dsa', - 'EC': 'ecdsa', - 'OPENSSH': 'ed25519', - '': 'rsa1', - } - # Key properties to return if valid. - key_data = { - 'key_type': None, # Key type (from above mapping). - 'key_seg': '', # Key segment (all text including begin/end). - 'key_b64': '', # Key data as base64. - 'key_bin': '', # Key data as binary. - 'key_enc': None, # Boolean, whether key is encrypted. - 'cert_seg': '', # Cert segment (all text including begin/end). - 'cert_b64': '', # Cert data as base64. - 'cert_bin': '', # Cert data as binary. - } - data = data.strip() - validation_error = ValidationError('Invalid private key') - - # Sanity check: We may potentially receive a full PEM certificate, - # and we want to accept these. - cert_begin_re = r'(-{4,})\s*BEGIN\s+CERTIFICATE\s*(-{4,})' - cert_end_re = r'(-{4,})\s*END\s+CERTIFICATE\s*(-{4,})' - cert_begin_match = re.search(cert_begin_re, data) - cert_end_match = re.search(cert_end_re, data) - if cert_begin_match and not cert_end_match: - raise validation_error - elif not cert_begin_match and cert_end_match: - raise validation_error - elif cert_begin_match and cert_end_match: - cert_dashes = set([cert_begin_match.groups()[0], cert_begin_match.groups()[1], - cert_end_match.groups()[0], cert_end_match.groups()[1]]) - if len(cert_dashes) != 1: - raise validation_error - key_data['cert_seg'] = data[cert_begin_match.start():cert_end_match.end()] - - # Find the private key, and also ensure that it internally matches - # itself. - # Set up the valid private key header and footer. - begin_re = r'(-{4,})\s*BEGIN\s+([A-Z0-9]+)?\s*PRIVATE\sKEY\s*(-{4,})' - end_re = r'(-{4,})\s*END\s+([A-Z0-9]+)?\s*PRIVATE\sKEY\s*(-{4,})' - begin_match = re.search(begin_re, data) - end_match = re.search(end_re, data) - if not begin_match or not end_match: - raise validation_error - - # Ensure that everything, such as dash counts and key type, lines up, - # and raise an error if it does not. - dashes = set([begin_match.groups()[0], begin_match.groups()[2], - end_match.groups()[0], end_match.groups()[2]]) - if len(dashes) != 1: - raise validation_error - if begin_match.groups()[1] != end_match.groups()[1]: - raise validation_error - key_type = begin_match.groups()[1] or '' - try: - key_data['key_type'] = key_types[key_type] - except KeyError: - raise ValidationError('Invalid private key: unsupported type %s' % key_type) - - # The private key data begins and ends with the private key. - key_data['key_seg'] = data[begin_match.start():end_match.end()] - - # Establish that we are able to base64 decode the private key; - # if we can't, then it's not a valid key. - # - # If we got a certificate, validate that also, in the same way. - header_re = re.compile(r'^(.+?):\s*?(.+?)(\\??)$') - for segment_name in ('cert', 'key'): - segment_to_validate = key_data['%s_seg' % segment_name] - # If we have nothing; skip this one. - # We've already validated that we have a private key above, - # so we don't need to do it again. - if not segment_to_validate: - continue - - # Ensure that this segment is valid base64 data. - base64_data = '' - line_continues = False - lines = segment_to_validate.splitlines() - for line in lines[1:-1]: - line = line.strip() - if not line: - continue - if line_continues: - line_continues = line.endswith('\\') - continue - line_match = header_re.match(line) - if line_match: - line_continues = line.endswith('\\') - continue - base64_data += line - try: - decoded_data = base64.b64decode(base64_data) - if not decoded_data: - raise validation_error - key_data['%s_b64' % segment_name] = base64_data - key_data['%s_bin' % segment_name] = decoded_data - except TypeError: - raise validation_error - - # Determine if key is encrypted. - if key_data['key_type'] == 'ed25519': - # See https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L3218 - # Decoded key data starts with magic string (null-terminated), four byte - # length field, followed by the ciphername -- if ciphername is anything - # other than 'none' the key is encrypted. - key_data['key_enc'] = not bool(key_data['key_bin'].startswith('openssh-key-v1\x00\x00\x00\x00\x04none')) - else: - key_data['key_enc'] = bool('ENCRYPTED' in key_data['key_seg']) - - return key_data - diff --git a/awx/settings/local_settings.py.docker_compose b/awx/settings/local_settings.py.docker_compose index 905e26857f..794d3ce073 100644 --- a/awx/settings/local_settings.py.docker_compose +++ b/awx/settings/local_settings.py.docker_compose @@ -30,10 +30,17 @@ DATABASES = { } } +def is_testing(argv): + if "py.test" in argv[0] or "py/test.py" in argv[0]: + return True + elif argv[1] == "test": + return True + return False + # Use SQLite for unit tests instead of PostgreSQL. If the lines below are # commented out, Django will create the test_awx-dev database in PostgreSQL to # run unit tests. -if len(sys.argv) >= 2 and sys.argv[1] == 'test': +if len(sys.argv) >= 2 and is_testing(sys.argv): DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', diff --git a/awx/settings/local_settings.py.example b/awx/settings/local_settings.py.example index 2fb0c745fc..52648798fe 100644 --- a/awx/settings/local_settings.py.example +++ b/awx/settings/local_settings.py.example @@ -30,10 +30,17 @@ DATABASES = { } } +def is_testing(argv): + if "py.test" in argv[0] or "py/test.py" in argv[0]: + return True + elif argv[1] == "test": + return True + return False + # Use SQLite for unit tests instead of PostgreSQL. If the lines below are # commented out, Django will create the test_awx-dev database in PostgreSQL to # run unit tests. -if len(sys.argv) >= 2 and sys.argv[1] == 'test': +if len(sys.argv) >= 2 and is_testing(sys.argv): DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000..751ebbb85f --- /dev/null +++ b/pytest.ini @@ -0,0 +1,5 @@ +[pytest] +DJANGO_SETTINGS_MODULE = awx.settings.development +python_paths = awx/lib/site-packages +python_files = *.py +addopts = --create-db diff --git a/requirements/requirements_dev.txt b/requirements/requirements_dev.txt index a2ff6cf11a..bd7d5f54c8 100644 --- a/requirements/requirements_dev.txt +++ b/requirements/requirements_dev.txt @@ -4,3 +4,7 @@ django-debug-toolbar==1.3.2 unittest2 pep8 flake8 +pytest +pytest-cov +pytest-django +pytest-pythonpath diff --git a/tools/docker-compose/Dockerfile b/tools/docker-compose/Dockerfile index 32be28ca01..e2e57fd4a1 100644 --- a/tools/docker-compose/Dockerfile +++ b/tools/docker-compose/Dockerfile @@ -12,6 +12,10 @@ RUN echo "deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-or RUN apt-get update RUN apt-get install -y openssh-server ansible mg vim tmux git mercurial subversion python-dev python-psycopg2 make postgresql-client libpq-dev nodejs python-psutil libxml2-dev libxslt-dev lib32z1-dev libsasl2-dev libldap2-dev libffi-dev libzmq-dev proot python-pip libxmlsec1-dev swig redis-server && rm -rf /var/lib/apt/lists/* RUN pip install flake8 +RUN pip install pytest +RUN pip install pytest-pythonpath +RUN pip install pytest-django +RUN pip install pytest-cov RUN /usr/bin/ssh-keygen -q -t rsa -N "" -f /root/.ssh/id_rsa RUN mkdir -p /etc/tower RUN mkdir -p /data/db From 6eae492d28a06d518113367d56821614bc0e51fe Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Thu, 28 Jan 2016 10:58:44 -0500 Subject: [PATCH 3/7] updating commands tests updating test imports, again relocate base and make tests a module added pytest config for awx/lib/site-packages restrucuting more test imports more test refactoring refactoring commands tests --- awx/main/tests/__init__.py | 0 awx/main/tests/{functional => }/base.py | 0 awx/main/tests/data/__init__.py | 0 .../data/large_ec2_inventory.py | 0 .../tests/{functional => }/data/largeinv.py | 0 .../{functional => }/data/splunk_inventory.py | 0 awx/main/tests/data/ssh.py | 169 ++++++++++++++++ awx/main/tests/functional/activity_stream.py | 2 +- awx/main/tests/functional/ad_hoc.py | 8 +- .../tests/functional/commands/age_deleted.py | 4 +- .../functional/commands/cleanup_facts.py | 4 +- .../commands/{base.py => command_base.py} | 2 +- .../commands/commands_monolithic.py | 2 +- .../functional/commands/remove_instance.py | 4 +- .../commands/run_fact_cache_receiver.py | 4 +- .../functional/commands/update_password.py | 4 +- awx/main/tests/functional/fact/fact_api.py | 2 +- awx/main/tests/functional/inventory.py | 52 ++--- .../functional/jobs/{base.py => job_base.py} | 4 +- awx/main/tests/functional/jobs/job_launch.py | 2 +- .../tests/functional/jobs/job_relaunch.py | 4 +- .../tests/functional/jobs/jobs_monolithic.py | 30 +-- .../tests/functional/jobs/start_cancel.py | 6 +- .../tests/functional/jobs/survey_password.py | 2 +- awx/main/tests/functional/licenses.py | 6 +- awx/main/tests/functional/organizations.py | 32 +-- awx/main/tests/functional/projects.py | 32 +-- awx/main/tests/functional/redact.py | 18 +- awx/main/tests/functional/schedules.py | 2 +- awx/main/tests/functional/scripts.py | 4 +- awx/main/tests/functional/settings.py | 2 +- awx/main/tests/functional/tasks.py | 183 +----------------- awx/main/tests/functional/users.py | 28 +-- awx/main/tests/functional/views.py | 9 +- pytest.ini | 1 + 35 files changed, 319 insertions(+), 303 deletions(-) create mode 100644 awx/main/tests/__init__.py rename awx/main/tests/{functional => }/base.py (100%) create mode 100644 awx/main/tests/data/__init__.py rename awx/main/tests/{functional => }/data/large_ec2_inventory.py (100%) rename awx/main/tests/{functional => }/data/largeinv.py (100%) rename awx/main/tests/{functional => }/data/splunk_inventory.py (100%) create mode 100644 awx/main/tests/data/ssh.py rename awx/main/tests/functional/commands/{base.py => command_base.py} (98%) rename awx/main/tests/functional/jobs/{base.py => job_base.py} (99%) diff --git a/awx/main/tests/__init__.py b/awx/main/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/awx/main/tests/functional/base.py b/awx/main/tests/base.py similarity index 100% rename from awx/main/tests/functional/base.py rename to awx/main/tests/base.py diff --git a/awx/main/tests/data/__init__.py b/awx/main/tests/data/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/awx/main/tests/functional/data/large_ec2_inventory.py b/awx/main/tests/data/large_ec2_inventory.py similarity index 100% rename from awx/main/tests/functional/data/large_ec2_inventory.py rename to awx/main/tests/data/large_ec2_inventory.py diff --git a/awx/main/tests/functional/data/largeinv.py b/awx/main/tests/data/largeinv.py similarity index 100% rename from awx/main/tests/functional/data/largeinv.py rename to awx/main/tests/data/largeinv.py diff --git a/awx/main/tests/functional/data/splunk_inventory.py b/awx/main/tests/data/splunk_inventory.py similarity index 100% rename from awx/main/tests/functional/data/splunk_inventory.py rename to awx/main/tests/data/splunk_inventory.py diff --git a/awx/main/tests/data/ssh.py b/awx/main/tests/data/ssh.py new file mode 100644 index 0000000000..ff5592358e --- /dev/null +++ b/awx/main/tests/data/ssh.py @@ -0,0 +1,169 @@ +TEST_SSH_KEY_DATA = '''-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAyQ8F5bbgjHvk4SZJsKI9OmJKMFxZqRhvx4LaqjLTKbBwRBsY +1/C00NPiZn70dKbeyV7RNVZxuzM6yd3D3lwTdbDu/eJ0x72t3ch+TdLt/aenyy10 +IvZyhSlxCLDkDaVVPFYJOQzVS8TkdOi6ZHc+R0c0A+4ZE8OQ8C0zIKtUTHqRk4/v +gYK5guhNS0DdgWkBj6K+r/9D4bqdPTJPt4S7H75vb1tBgseiqftEkLYOhTK2gsCi +5uJgpG4zPQY4Kk/97dbW7pwcvPkr1rKkAwEJ27Bfo+DBv3oEx3SinpXQtOrH1aEO +RHSXldBaymdBtVLUhjxDlnnQ7Ps+fNX04R7N4QIDAQABAoIBAQClEDxbNyRqsVxa +q8BbzxZNVFxsD6Vceb9rIDa8/DT4SO4iO8zNm8QWnZ2FYDz5d/X3hGxlSa7dbVWa +XQJtD1K6kKPks4IEaejP58Ypxj20vWu4Fnz+Jy4lvLwb0n2n5lBv1IKF389NATw9 +7sL3sB3lDsPZZiQYYbogNDuBWqc+kP0zD84bONsM/B2HMRm9BRv2UsZf+zKU4pTA +UqHffyjmw7LqHmbtVjwVcUsC+xcE4kCuWLvabFnTWOSnWECyIw2+trxKdwCXbfzG +s5rn4Dj+aEKimzFaRpTSVx6w4yw9xw/EjsSaZ88jKSpTP8ocCut6zv+P/JwlukEX +4A4FxqyxAoGBAOp3G9EIAAWijcIgO5OdiZNEqVyqd3yyPzT6d/q7bf4dpVCZiLNA +bRmge83aMc4g2Dpkn/++It3bDmnXXGg+BZSX5KT9JLklXchaw9phv9J0diZEUvYS +mSQafbUGIqYnYzns3TU0cbgITs1iVIEstHYjGr3J88nDG+HFCHboxa93AoGBANuG +cDFgyvm79+haK2fHhUCZgaFFYBpkpuz+zjDjzIytOzymWa2gD9jIa7mvdvoH2ge3 +AVG0vy+n9cJaqJMuLkhdI01wVlqY9wvDHFyZCXyIvKVPMljKeTvCNGCupsG4R171 +gSKT5ryOx58MGbE7knAZC+QWpwxFpdpbfej6g7NnAoGBAMz6ipAJbXN/tG0FnvAj +pxXfzizcPw/+CTI40tGaMMQbiN5ZC+CiL39bBUFnQ2mQ31jVheegg3zvuL8hb4EW +z+wjitoPEZ7nowC5EUaHdJr6BBzaWKkWg1nD6yhqj7ow7xfCE3YjPlQEt1fpYjV4 +LuClOgi4WPCIKYUMq6TBRaprAoGAVrEjs0xPPApQH5EkXQp9BALbH23/Qs0G4sbJ +dKMxT0jGAPCMr7VrLKgRarXxXVImdy99NOAVNGO2+PbGZcEyA9/MJjO71nFb9mgp +1iOVjHmPThUVg90JvWC3QIsYTZ5RiR2Yzqfr0gDsslGb/9LPxLcPbBbKB12l3rKM +6amswvcCgYEAvgcSlTfAkI3ac8rB70HuDmSdqKblIiQjtPtT/ixXaFkZOmHRr4AE +KepMRDnaO/ldPDPEWCGqPzEM0t/0jS8/hCu3zLHHpZ+0LnHq+EXkOI0/GB4P+z5l +Vz3kouC0BTav0rCEnDop/cWMTiAp/XhKXfrTTTOra/F8l2xD8n/mnzY= +-----END RSA PRIVATE KEY-----''' + +TEST_SSH_KEY_DATA_LOCKED = '''-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,6B4E92AF4C29DE26FD8535D81825BDE6 + +pg8YplxPpfzgEGUiko34DGaYklyGyYKXjOrGFGyLoquNAVNFyewT34dDrZi0IAaE +79wMVcdlHbrJfZz8ML8I/ft6zM6BdlwZExH4y9DRAaktY3yIXxSvowBQ6ljh3wUy +M6m0afOfVjT22V8hLFgX0yTQ6P9zTG1cmj6+JQWTsMJ5EP3rnFK5CyrJXP48B3GI +GgE66rkXDvcKlVeIrbrpcTyfmEpafPgVRJYCDFXxeO/BfKgUFVxFq1PgFbvGQMmD +wA6EsyRrN+aoub1sqzj8tM8e4nwEi0EifdRShkFeqH4GUOKypanTXfCqwFBgYi5a +i3YwSnniZZPwCniGR5cl8oetrc5dubq/IR0txsGi2lO6zJEWdSer/EadS0QAll4S +yXrSc/lFaez1VmVe/8aoBKDOHhe7jV3YXAuqCeB4o/SThB/9Gad44MTbqFH3d7cD +k+F0Cjup7LZqZpXeB7ZHRG/Yt9MtBzwDVmEWaxA1WIN5a8xyZEVzRswSi4lZX69z +Va7eTKcrCbHOQmIbLZGRiZbAbfgriwwxQCJWELv80h+A754Bhi23n3WzcT094fRi +cqK//HcHHXxYGmrfUbHYcj+GCQ07Uk2ZR3qglmPISUCgfZwM9k0LpXudWE8vmF2S +pAnbgxgrfUMtpu5EAO+d8Sn5wQLVD7YzPBUhM4PYfYUbJnRoZQryuR4lqCzcg0te +BM8x1LzSXyBEbQaonuMzSz1hCQ9hZpUwUEqDWAT3cPNmgyWkXQ1P8ehJhTmryGJw +/GHxNzMZDGj+bBKo7ic3r1g3ZmmlSU1EVxMLvRBKhdc1XicBVqepDma6/LEpj+5X +oplR+3Q0QSQ8CchcSxYtOpI3UBCatpyu09GtfzS+7bI5I7FVYUccR83+oQlKpPHC +5O2irB8JeXqAY679fx2N4i0E6l5Xr5AjUtOBCNil0Y70eOf9ER6i7kGakR7bUtk5 +fQn8Em9pLsYYalnekn4sxyHpGq59KgNPjQiJRByYidSJ/oyNbmtPlxfXLwpuicd2 +8HLm1e0UeGidfF/bSlySwDzy1ZlSr/Apdcn9ou5hfhaGuQvjr9SvJwxQFNRMPdHj +ukBSDGuxyyU+qBrWJhFsymiZAWDofY/4GzgMu4hh0PwN5arzoTxnLHmc/VFttyMx +nP7bTaa9Sr54TlMr7NuKTzz5biXKjqJ9AZKIUF2+ERebjV0hMpJ5NPsLwPUnA9kx +R3tl1JL2Ia82ovS81Ghff/cBZsx/+LQYa+ac4eDTyXxyg4ei5tPwOlzz7pDKJAr9 +XEh2X6rywCNghEMZPaOQLiEDLJ2is6P4OarSa/yoU4OMetpFfwZ0oJSCmGlEa+CF +zeJ80yXhU1Ru2eqiUjCAUg25BFPwoiMJDc6jWWow7OrXCQsw7Ddo2ncy1p9QeWjM +2R4ojPHWuXKYxvwVSc8NZHASlycBCaxHLDAEyH4avOSDPWOB1H5t+RrNmo0qgush +0aRo6F7BjzB2rA4E+xu2u11TBfF8iB3PC919/vxnkXF97NqezsaCz6VbRlsU0A+B +wwoi+P4JlJF6ZuhuDv6mhmBCSdXdc1bvimvdpOljhThr+cG5mM08iqWGKdA665cw +-----END RSA PRIVATE KEY----- +''' + +TEST_OPENSSH_KEY_DATA = '''-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEA1AZAwUJUiLmOXjbO5q2ZE5DF+gMpPKe8NEr12FpvOaJr1Nz/DNpf +FE/VbssOJ4CRD/6MItlPSG2pC1Cv3AYSL7NBc0YCMlBR/P/nLI8pLAzU3p3KRYvR+R6cMW +3nMcxyB1UUgzXY9dTVFIyejOsm7stGuNfdDTTLBE2vTDz6CyzxxSALEOdYut5cfeTUuG7d +nP01K3JiaHjHaXDmwraRR/JlitylaZUnSZ+/b9WCMX5FyeJ6CnGdvcCuvMK0iNjZ8R+PxP +xJBM5AlJC5J6qa8YmeaQ6lA/2S+/wGuhJmocmiXiLFy9IzIPnQiR+h8DqStp4xp245UQxe +TIGSMmq8DQAAA9A4FMRSOBTEUgAAAAdzc2gtcnNhAAABAQDUBkDBQlSIuY5eNs7mrZkTkM +X6Ayk8p7w0SvXYWm85omvU3P8M2l8UT9Vuyw4ngJEP/owi2U9IbakLUK/cBhIvs0FzRgIy +UFH8/+csjyksDNTencpFi9H5HpwxbecxzHIHVRSDNdj11NUUjJ6M6ybuy0a4190NNMsETa +9MPPoLLPHFIAsQ51i63lx95NS4bt2c/TUrcmJoeMdpcObCtpFH8mWK3KVplSdJn79v1YIx +fkXJ4noKcZ29wK68wrSI2NnxH4/E/EkEzkCUkLknqprxiZ5pDqUD/ZL7/Aa6EmahyaJeIs +XL0jMg+dCJH6HwOpK2njGnbjlRDF5MgZIyarwNAAAAAwEAAQAAAQAp8orBMYRUAJIgJavN +i67rZgslKZbw/yaHGgWFpm628mFvHcIAIvwIorrRTq8gNZl9lpjXFDNRWxDEwlPorfLPKS +Hb0pAAsE9oRKDR+gjlRCyhVop8M+t45At25A2HlrFArh5+zxp7mH4HsMJ1ktiDCgiV7W84 +e6dm1I/H/5BgwUlTNoVOGPrU183gqRsHIICjfmnjl2ObJoly+MTrAy7E9rSmsO+pHKl8z0 +XODWh3mo+EkCoYrK6kP96Jy3BepSmbZMROEsctS7Mkzu6QdnfTY3QqIzENYtTGJuAGktGj +su4MHP8hbj+TznNkFeZdmIC0uTnIKu1uquwuFF1HPZiBAAAAgACX9xPKS2J04WXpQag+JS +06n2zSuBHW7Kq4q/LMydoTRd8Quf6u6eivSBrl7H779LCtGCIZqJAslvWOyPyz2CohcCBU +emubiHcUA+aN7R9E0tyitwWraJjMIwpQ7+AbgdsLsuxozNeccSrr0tva2c5y9x7YGBcIdC +UJDt4xnBi7AAAAgQDz771v8Mb18kq5W+inDcYPFUNXGtNfeYZEOhYFpxunFnYwTEAG0Xnh +YpQXOAFZ2q5mkFQHMl4cOKwoAlaP0dM4v0JKPjFDLvGisEu95fnivj4YAMP/UHgKKxBbqW +HPUhg3adAmIJ9z9u/VmTErbVklcKWlyZuTUkxeQ/BJmSIRUQAAAIEA3oKAzdDURjy8zxLX +gBLCPdi8AxCiqQJBCsGxXCgKtZewset1XJHIN9ryfb4QSZFkSOlm/LgdeGtS8Or0GNPRYd +hgnUCF0LkEsDQ7HzPZYujLrAwjumvGQH6ORp5vRh0tQb93o4e1/A2vpdSKeH7gCe/jfUSY +h7dFGNoAI4cF7/0AAAAUcm9vdEBwaWxsb3cuaXhtbS5uZXQBAgMEBQYH +-----END OPENSSH PRIVATE KEY----- +''' + +TEST_OPENSSH_KEY_DATA_LOCKED = '''-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABALaWMfjc +hSvC7aXxQs1ZDiAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQDEDWKwZD8+ +h+2gZZKna8dy2QL4jJxM1eLGDcQDnuip1ixhaf5MT5T6BMploXXHs1pfuwx8yTQ6Ts/VJp +WX6cuHQg8sPGM3P7HNGUqs9q/EQfrrRxz555uL08CRaS6FjM/6x9iolNhHU910Wlg+R+ZS +xiMrrY/s03EiEChsAWTbwBGqTopGC2xMFgIxINoQtTFXv7MtCbDfl8aWKQRDmzkLvwT07N +ycj2kqADqoukD/2bQvPrW6FIZPJPpAdeAe2SZbf/y92NgVz/glOdtjaJp3oqn1QHrOA9/k +XgXOjgVQUbzX7qyLWenxM138VsRKUJZeROaHt1MWApLrLtKQ36SrAAAD0A+PODJjfeKm3U +JknlSYD7fFh6bVZGwG6LnLMtobs0elOfj2+sdg+hOVqyrA0rPOHES5yGKslTc/wRkRQ95m +dBleAyTDIOQ90IqDxT3lsNQwpscsFKPYKGmaUvZLLk4aNY1GeANtByXwTsjetVqn8Uo59A +zu6phX8Aagn2h0qxQwBnDjlzsXf6g5H7UPZd/t1dYr1NfVP6KWJrg0jivAI8tzO2HcM9W2 +cyOaodBw/6TsJNKvDV714Z+apvrNDEufBUsovKjAna2BDVZIhTCg5mYm0Dks8JStQrG2S1 +Yk8EM3+fpo8uMoHVz1jbYC8UX12pwIU67MhUn24KBxqulCYaTMsrLFkNWk6vKgwib+sIa4 +i1Bij1Zd0rdJWypQqTc2Oj3bBSYM47AksMXcKVpuNnFLh4+eokpQzbtIYpRqhOTh1Fky7z +xkhTgWVvf/F19M9t1bz3Rm1/t5I75Ag9qfKWs06j+VVfXnDt5v5hYAEhoJjMzSjgKaqc5g +YndeWeUwO6Vijt4XpkB8+0R7Kptsh9L0UUsNIcRoGcqrM8IUVb3D8vPWppPlj9d6LB+FCo +Cy1JlscnpBb8AQy9QMvrJTHKOyjRcenVxILPiN8PypIC008jvqpDzKimAxM4IMuA7AWE6w +j5+CzfUhDAJGdl2qH/nVc7GFUtz8bVA/v9Zkawg2MLcafgGollbLcTbKwDFcenQuyHT+Hj +uDm2f0oV/EDKFqLijlV8vcLBNUZoxY/L62Vora1jlqnapq2Z/AM9NicoELYNe21ReJ5dxM +7Pk/QdSrZjQzxoHf8uBDpb7x/KyfnSdf8GmdGCxoJ5mcepwD4tROMFC104tN0STJpdGVSm +Q5ZG1JDN7F9iJCCAwyulWH/XxTzFYnQ84199cQeV/M9rXXgbXa8ApAung6X9j8y1fcw9Lw +wV1aP06bCNgM0U50PiZ54HXwzVt+Ghs06TEF4/ZQiIgNJxdw0HFxAJj8qHqUCHuSmvBgnN +qRW/uruItwpXLaL00EHu7rAFlBi1BnnetI+D12ls04mlyTUFFM5v520B5zPV+5If2hx91w +C6Oxl1Wsp3gPkK2yiuy8qcrvoEoJ25TeEhUGEAPWx2OuQJO/Lpq9aF/JJoqGwnBaXdCsi+ +5ig+ZMq5GKQtyydzyXImjlNEUH1w2prRDiGVEufANA5LSLCtqOLgDzXS62WUBjJBrQJVAM +YpWz1tiZQoyv1RT3Y0O0Vwe2Z5AK3fVM0I5jWdiLrIErtcR4ULa6T56QtA52DufhKzINTR +Vg9TtUBqfKIpRQikPSjm7vpY/Xnbc= +-----END OPENSSH PRIVATE KEY----- +''' + +TEST_SSH_CERT_KEY = """-----BEGIN CERTIFICATE----- +MIIDNTCCAh2gAwIBAgIBATALBgkqhkiG9w0BAQswSTEWMBQGA1UEAwwNV2luZG93 +cyBBenVyZTELMAkGA1UEBhMCVVMxIjAgBgkqhkiG9w0BCQEWE2x1a2VAc25lZXJp +bmdlci5jb20wHhcNMTQwNzI4MTQzMjExWhcNMTUwNzI4MTQzMjExWjBJMRYwFAYD +VQQDDA1XaW5kb3dzIEF6dXJlMQswCQYDVQQGEwJVUzEiMCAGCSqGSIb3DQEJARYT +bHVrZUBzbmVlcmluZ2VyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL9UHMhmAkbEJtg7jxAYjRbyTILDkNG5X/5UDpReIBD3VZfIrrXKX/groKbE +uiH9vdHkhdbOV1WkINuz+12Hdfk7irRXPRNC6SQVNeCy/DuCIEX+pQCAn60pc3eT +ctQG4oCiwQrlFMjoV9S5kbKoUavtuEt7Huo4YIVJK1/McEYq8mIM1W6MGOwXQI0b +rKsp1zRviiQWU5zijQYxepSpBNJcGS1lNhD1m5ycy7+0Zm7FqBa6nlf/2kLadREF +4o3bHljfrLTa+czV9lI9HjwpeLCfccx0T7etpv+u/JzSlt1MlAnlCNtz2wo1oNdi +scyRdRlb00AWQMneQfSYgwGHyQ8CAwEAAaMqMCgwDgYDVR0PAQH/BAQDAgeAMBYG +A1UdJQEB/wQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCc064W0uk3 +hVVYtHuOBPSag9TvyqJrnvHsPgWiwFTh7t4CGF2TiH6myxkboAN0BGZqIj0zorT+ +VORmZ4PrDqV29q8M77n4aTmDmqXXcCAMOtyC87xlK+YvsVtrvu2zYXnZV+BJ+UtT +FpDqgMLrE0ecnkDClAK4vPx3TqSzU3v//lgUG1o3VibJbzMptggMVA4Hl9AXGLnU +FNpK5B4mm/PQHQC1Ma/nweMoDcVlQUne8XgnwEf0ixGkViFLm6FmI7DfKUpq3zXb +vWKu8qiBmz4tju6LT2n+q66MNEMmS1qhuJJYZrORJgQkCVbo1RRwW6UNZSIjD8D6 +8QJhq7hCxteN +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAv1QcyGYCRsQm2DuPEBiNFvJMgsOQ0blf/lQOlF4gEPdVl8iu +tcpf+CugpsS6If290eSF1s5XVaQg27P7XYd1+TuKtFc9E0LpJBU14LL8O4IgRf6l +AICfrSlzd5Ny1AbigKLBCuUUyOhX1LmRsqhRq+24S3se6jhghUkrX8xwRiryYgzV +bowY7BdAjRusqynXNG+KJBZTnOKNBjF6lKkE0lwZLWU2EPWbnJzLv7RmbsWoFrqe +V//aQtp1EQXijdseWN+stNr5zNX2Uj0ePCl4sJ9xzHRPt62m/678nNKW3UyUCeUI +23PbCjWg12KxzJF1GVvTQBZAyd5B9JiDAYfJDwIDAQABAoIBACNozL7l6ivwp4PD +WhHPiWUiyLg2u3mlBjgKlHwvA15AeC3ULUllv+ctI9lZdV1PGa9bzM1ZeN5XtuES +aUYBCPtsYppHvvzumDleV49TcM0OoyxxGVaDd4nTrxQFTO4irA7EkFeU2Ajqvz6W +bXmUHzFjmIUXrzwH3Q0t4oIjUvAZNhNY63G3XZ264pNckvtuRArgn0r7e+trplII +qDYPwOLPhorwG6a0HIsSWbECA+NbzC5wBIr4CMfDRiHDQ5g4cGstpbBAUkAs2LSU +2QcGp3AIqOnzMDxLTMqKcKQ9YXOMqTpVoyll+jkgdHLCqHjo+O51/E5AsjBcabmi +4LpeVsECgYEA+7g2y8J54GWhNOpJ+RQ6IvoUuA9YmEe3byIglat5b+AWuy7Miq4u +VSiIjEqDf8Ci1LxHrkRCe4S/9VZSNJdfbv5I1LW3Wx4JRZ1JFR5Z9B0XI5SdkokM +O9DXIJHgxSzC9kCKgBpH5KxqMpEdMMv70C7gbMpnONEL1zIOZJxAwq8CgYEAwpUB +Dp5l8Wpma5SnUAJiTU9XdgtPr1M8WFde9jP3e2VK2O4DmnZkLN5aLbMfnftUNAl1 +mP4CTxtkkEwNtkol+rZAy6wwzQA/TP2yC0Wfw+xeDTKJ+JDDoWM+4FAhjBpns/gx +Ehfqj76jRjBW9DtARaHgrIHHFUn2p6wMZq4Sd6ECgYEA4jlNrdQrGnvb5KWHM750 +/UhJ5J2OHtWdStid9kU0j1ISu8k0dJJT+57BEWxKQD9NV+madkjMgxvsNL6OhMti +LmuD4v8pOU+GP7U6oCs15slaKVUARFi80OlA3fmcyzgOQ6f/kV+NKzu0+ZsnY9p/ +hjsK4VsKZ6qgfJd1DgDLxusCgYArXCDcLRfycA9ascmG3sEhESkgOO0M2LN9zBpx +KqtfZ/cB2CgdZ3xzMylNPbkx7yuYXPNDoHbLQgNq1EfJ80P7VlmiCUDmrcNtWKsw +L9emRSnALx7nsPqnIAKG4dRX8Bpj1E67BXFTjtu7bFI0Im/0FFqIlnLSn6TDQGeT +Cf87gQKBgCgW/kFaQAhP5Pdb7oOQcaF4/dq50QNDyQMFOPKWHY/5IrsIrDVI5V/D +o1npLPB+YE3baQqo58JX1UuO83F4zlwzS3Q4lS3dxg+gdvgzFHvQd/SV5IDhmLWL +L5Hj+B02+FAiz8zVGumbVykvPtzgTb0E+0rJKNO0/EgGqWsk/oC0 +-----END RSA PRIVATE KEY----- +""" + +TEST_SSH_KEY_DATA_UNLOCK = 'unlockme' diff --git a/awx/main/tests/functional/activity_stream.py b/awx/main/tests/functional/activity_stream.py index 81ebb7dc66..9798695954 100644 --- a/awx/main/tests/functional/activity_stream.py +++ b/awx/main/tests/functional/activity_stream.py @@ -6,7 +6,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.models import * # noqa -from .base import BaseTest +from awx.main.tests.base import BaseTest class ActivityStreamTest(BaseTest): diff --git a/awx/main/tests/functional/ad_hoc.py b/awx/main/tests/functional/ad_hoc.py index 154a8d69ec..d0e75d2f19 100644 --- a/awx/main/tests/functional/ad_hoc.py +++ b/awx/main/tests/functional/ad_hoc.py @@ -18,8 +18,8 @@ from crum import impersonate # AWX from awx.main.utils import * # noqa from awx.main.models import * # noqa -from .base import BaseJobExecutionTest -from .tasks import TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK +from awx.main.tests.base import BaseJobExecutionTest +from tasks import TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK __all__ = ['RunAdHocCommandTest', 'AdHocCommandApiTest'] @@ -568,7 +568,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest): with self.current_user('admin'): response = self.run_test_ad_hoc_command(become_enabled=True) self.assertEqual(response['become_enabled'], True) - + # Try to run with expired license. self.create_expired_license_file() with self.current_user('admin'): @@ -1199,7 +1199,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest): with self.current_user('admin'): response = self.run_test_ad_hoc_command() - # Test the ad hoc command events list for a host. Should return the + # Test the ad hoc command events list for a host. Should return the # events only for that particular host. url = reverse('api:host_ad_hoc_command_events_list', args=(self.host.pk,)) with self.current_user('admin'): diff --git a/awx/main/tests/functional/commands/age_deleted.py b/awx/main/tests/functional/commands/age_deleted.py index eec90814d1..ec5591d28e 100644 --- a/awx/main/tests/functional/commands/age_deleted.py +++ b/awx/main/tests/functional/commands/age_deleted.py @@ -2,8 +2,8 @@ # All Rights Reserved # AWX -from ..base import BaseTest -from .base import BaseCommandMixin +from awx.main.tests.base import BaseTest +from command_base import BaseCommandMixin __all__ = ['AgeDeletedCommandFunctionalTest'] diff --git a/awx/main/tests/functional/commands/cleanup_facts.py b/awx/main/tests/functional/commands/cleanup_facts.py index a637340bd0..fc0f049aad 100644 --- a/awx/main/tests/functional/commands/cleanup_facts.py +++ b/awx/main/tests/functional/commands/cleanup_facts.py @@ -10,9 +10,9 @@ import mock from django.core.management.base import CommandError # AWX -from ..base import BaseTest +from awx.main.tests.base import BaseTest from awx.fact.tests.base import MongoDBRequired, FactScanBuilder, TEST_FACT_PACKAGES, TEST_FACT_ANSIBLE, TEST_FACT_SERVICES -from .base import BaseCommandMixin +from command_base import BaseCommandMixin from awx.main.management.commands.cleanup_facts import Command, CleanupFacts from awx.fact.models.fact import * # noqa diff --git a/awx/main/tests/functional/commands/base.py b/awx/main/tests/functional/commands/command_base.py similarity index 98% rename from awx/main/tests/functional/commands/base.py rename to awx/main/tests/functional/commands/command_base.py index 10d2096c41..2f1d795d27 100644 --- a/awx/main/tests/functional/commands/base.py +++ b/awx/main/tests/functional/commands/command_base.py @@ -11,7 +11,7 @@ from django.core.management import call_command # AWX from awx.main.models import * # noqa -from ..base import BaseTestMixin +from awx.main.tests.base import BaseTestMixin class BaseCommandMixin(BaseTestMixin): def create_test_inventories(self): diff --git a/awx/main/tests/functional/commands/commands_monolithic.py b/awx/main/tests/functional/commands/commands_monolithic.py index fa69a13742..13dae57177 100644 --- a/awx/main/tests/functional/commands/commands_monolithic.py +++ b/awx/main/tests/functional/commands/commands_monolithic.py @@ -24,7 +24,7 @@ from django.test.utils import override_settings # AWX from awx.main.models import * # noqa -from ..base import BaseTest, BaseLiveServerTest +from awx.main.tests.base import BaseTest, BaseLiveServerTest __all__ = ['CreateDefaultOrgTest', 'DumpDataTest', 'CleanupDeletedTest', 'CleanupJobsTest', 'CleanupActivityStreamTest', diff --git a/awx/main/tests/functional/commands/remove_instance.py b/awx/main/tests/functional/commands/remove_instance.py index f9713457bd..6fa8d65d4b 100644 --- a/awx/main/tests/functional/commands/remove_instance.py +++ b/awx/main/tests/functional/commands/remove_instance.py @@ -5,8 +5,8 @@ import uuid # AWX -from ..base import BaseTest -from .base import BaseCommandMixin +from awx.main.tests.base import BaseTest +from command_base import BaseCommandMixin from awx.main.models import * # noqa __all__ = ['RemoveInstanceCommandFunctionalTest'] diff --git a/awx/main/tests/functional/commands/run_fact_cache_receiver.py b/awx/main/tests/functional/commands/run_fact_cache_receiver.py index f5d5e5da09..7dedf7657a 100644 --- a/awx/main/tests/functional/commands/run_fact_cache_receiver.py +++ b/awx/main/tests/functional/commands/run_fact_cache_receiver.py @@ -10,9 +10,9 @@ from copy import deepcopy from mock import MagicMock # AWX -from ..base import BaseTest +from awx.main.tests.base import BaseTest from awx.fact.tests.base import MongoDBRequired -from .base import BaseCommandMixin +from command_base import BaseCommandMixin from awx.main.management.commands.run_fact_cache_receiver import FactCacheReceiver from awx.fact.models.fact import * # noqa diff --git a/awx/main/tests/functional/commands/update_password.py b/awx/main/tests/functional/commands/update_password.py index ec89892c1d..cecbb1667d 100644 --- a/awx/main/tests/functional/commands/update_password.py +++ b/awx/main/tests/functional/commands/update_password.py @@ -2,8 +2,8 @@ # All Rights Reserved # AWX -from ..base import BaseTest -from .base import BaseCommandMixin +from awx.main.tests.base import BaseTest +from command_base import BaseCommandMixin # Django from django.core.management.base import CommandError diff --git a/awx/main/tests/functional/fact/fact_api.py b/awx/main/tests/functional/fact/fact_api.py index 36038b987f..d13b17f060 100644 --- a/awx/main/tests/functional/fact/fact_api.py +++ b/awx/main/tests/functional/fact/fact_api.py @@ -10,7 +10,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.utils import timestamp_apiformat from awx.main.models import * # noqa -from ..base import BaseLiveServerTest +from awx.main.tests.base import BaseLiveServerTest from awx.fact.models import * # noqa from awx.fact.tests.base import BaseFactTestMixin, FactScanBuilder, TEST_FACT_ANSIBLE, TEST_FACT_PACKAGES, TEST_FACT_SERVICES from awx.main.utils import build_url diff --git a/awx/main/tests/functional/inventory.py b/awx/main/tests/functional/inventory.py index 08c2378bc9..9503b4232c 100644 --- a/awx/main/tests/functional/inventory.py +++ b/awx/main/tests/functional/inventory.py @@ -18,7 +18,7 @@ from django.utils.timezone import now # AWX from awx.main.models import * # noqa -from .base import BaseTest, BaseTransactionTest +from awx.main.tests.base import BaseTest, BaseTransactionTest __all__ = ['InventoryTest', 'InventoryUpdatesTest', 'InventoryCredentialTest'] @@ -151,11 +151,11 @@ class InventoryTest(BaseTest): def test_put_inventory_detail(self): url_a = reverse('api:inventory_detail', args=(self.inventory_a.pk,)) url_b = reverse('api:inventory_detail', args=(self.inventory_b.pk,)) - + # Check put to detail view with invalid authentication. self.check_invalid_auth(url_a, methods=('put',)) self.check_invalid_auth(url_b, methods=('put',)) - + # a super user can update inventory records with self.current_user(self.super_django_user): data = self.get(url_a, expect=200) @@ -200,7 +200,7 @@ class InventoryTest(BaseTest): self.put(url_a, data, expect=403) # Via AC-376: - # Create an inventory. Leave the description empty. + # Create an inventory. Leave the description empty. # Edit the new inventory, change the Name, click Save. list_url = reverse('api:inventory_list') new_data = dict(name='inventory-c', description='', @@ -220,13 +220,13 @@ class InventoryTest(BaseTest): def test_delete_inventory_detail(self): url_a = reverse('api:inventory_detail', args=(self.inventory_a.pk,)) url_b = reverse('api:inventory_detail', args=(self.inventory_b.pk,)) - + # Create test hosts and groups within each inventory. self.inventory_a.hosts.create(name='host-a') self.inventory_a.groups.create(name='group-a') self.inventory_b.hosts.create(name='host-b') self.inventory_b.groups.create(name='group-b') - + # Check put to detail view with invalid authentication. self.check_invalid_auth(url_a, methods=('delete',)) self.check_invalid_auth(url_b, methods=('delete',)) @@ -487,7 +487,7 @@ class InventoryTest(BaseTest): self.post(url5, data=new_group_d, expect=400, auth=self.get_other_credentials()) got = self.get(url5, expect=200, auth=self.get_other_credentials()) self.assertEquals(got['count'], 5) - + # side check: see if root groups URL is operational. These are groups without parents. root_groups = self.get(root_groups, expect=200, auth=self.get_super_credentials()) self.assertEquals(root_groups['count'], 2) @@ -497,7 +497,7 @@ class InventoryTest(BaseTest): self.post(url5, data=remove_me, expect=204, auth=self.get_other_credentials()) got = self.get(url5, expect=200, auth=self.get_other_credentials()) self.assertEquals(got['count'], 4) - + ################################################### # VARIABLES @@ -507,31 +507,31 @@ class InventoryTest(BaseTest): # attempting to get a variable object creates it, even though it does not already exist vdata_url = reverse('api:host_variable_data', args=(added_by_collection_a['id'],)) - + got = self.get(vdata_url, expect=200, auth=self.get_super_credentials()) self.assertEquals(got, {}) # super user can create variable objects # an org admin can create variable objects (defers to inventory permissions) got = self.put(vdata_url, data=vars_a, expect=200, auth=self.get_super_credentials()) - self.assertEquals(got, vars_a) + self.assertEquals(got, vars_a) - # verify that we can update things and get them back + # verify that we can update things and get them back got = self.put(vdata_url, data=vars_c, expect=200, auth=self.get_super_credentials()) - self.assertEquals(got, vars_c) + self.assertEquals(got, vars_c) got = self.get(vdata_url, expect=200, auth=self.get_super_credentials()) - self.assertEquals(got, vars_c) + self.assertEquals(got, vars_c) # a normal user cannot edit variable objects self.put(vdata_url, data=vars_a, expect=403, auth=self.get_nobody_credentials()) # a normal user with inventory write permissions can edit variable objects... got = self.put(vdata_url, data=vars_b, expect=200, auth=self.get_normal_credentials()) - self.assertEquals(got, vars_b) + self.assertEquals(got, vars_b) ################################################### # VARIABLES -> GROUPS - + vars_a = dict(asdf=7777, dog='droopy', cat='battlecat', unstructured=dict(a=[1,1,1],b=dict(x=1,y=2))) vars_b = dict(asdf=8888, dog='snoopy', cat='cheshire', unstructured=dict(a=[2,2,2],b=dict(x=3,y=4))) vars_c = dict(asdf=9999, dog='pluto', cat='five', unstructured=dict(a=[3,3,3],b=dict(z=5))) @@ -547,7 +547,7 @@ class InventoryTest(BaseTest): # an org admin can associate variable objects with groups put = self.put(vdata1_url, data=vars_b, expect=200, auth=self.get_normal_credentials()) - + # a normal user cannot associate variable objects with groups put = self.put(vdata1_url, data=vars_b, expect=403, auth=self.get_nobody_credentials()) @@ -557,11 +557,11 @@ class InventoryTest(BaseTest): ################################################### # VARIABLES -> INVENTORY - + vars_a = dict(asdf=9873, dog='lassie', cat='heathcliff', unstructured=dict(a=[1,1,1],b=dict(x=1,y=2))) vars_b = dict(asdf=2736, dog='benji', cat='garfield', unstructured=dict(a=[2,2,2],b=dict(x=3,y=4))) vars_c = dict(asdf=7692, dog='buck', cat='sylvester', unstructured=dict(a=[3,3,3],b=dict(z=5))) - + vdata_url = reverse('api:inventory_variable_data', args=(self.inventory_a.pk,)) # a super user can associate variable objects with inventory @@ -700,7 +700,7 @@ class InventoryTest(BaseTest): new_data = dict(inventory=inv.pk, name='completely new', description='blarg?') kids = self.get(subgroups_url2, expect=200, auth=self.get_normal_credentials()) self.assertEqual(kids['count'], 1) - posted2 = self.post(subgroups_url2, data=new_data, expect=201, auth=self.get_normal_credentials()) + posted2 = self.post(subgroups_url2, data=new_data, expect=201, auth=self.get_normal_credentials()) # a group can't be it's own grandparent subsub = posted2['related']['children'] @@ -715,16 +715,16 @@ class InventoryTest(BaseTest): # double post causes conflict error (actually, should it? -- just got a 204, already associated) # self.post(subgroups_url2, data=got, expect=409, auth=self.get_normal_credentials()) - checked = self.get(subgroups_url2, expect=200, auth=self.get_normal_credentials()) + checked = self.get(subgroups_url2, expect=200, auth=self.get_normal_credentials()) # a normal user cannot set subgroups self.post(subgroups_url3, data=got, expect=403, auth=self.get_nobody_credentials()) # a normal user with inventory edit permissions can associate subgroups (but not when they belong to different inventories!) #self.post(subgroups_url3, data=got, expect=204, auth=self.get_other_credentials()) - #checked = self.get(subgroups_url3, expect=200, auth=self.get_normal_credentials()) + #checked = self.get(subgroups_url3, expect=200, auth=self.get_normal_credentials()) #self.assertEqual(checked['count'], 1) - + # slight detour # can see all hosts under a group, even if it has subgroups # this URL is NOT postable @@ -739,7 +739,7 @@ class InventoryTest(BaseTest): result = checked['results'][0] result['disassociate'] = 1 self.post(subgroups_url3, data=result, expect=204, auth=self.get_other_credentials()) - checked = self.get(subgroups_url3, expect=200, auth=self.get_normal_credentials()) + checked = self.get(subgroups_url3, expect=200, auth=self.get_normal_credentials()) self.assertEqual(checked['count'], 0) # try to double disassociate to see what happens (should no-op) self.post(subgroups_url3, data=result, expect=204, auth=self.get_other_credentials()) @@ -803,7 +803,7 @@ class InventoryTest(BaseTest): # FIXME: RELATED FIELDS # on an inventory resource, I can see related resources for hosts and groups and permissions - # and these work + # and these work # on a host resource, I can see related resources variables and inventories # and these work # on a group resource, I can see related resources for variables, inventories, and children @@ -884,11 +884,11 @@ class InventoryTest(BaseTest): g_d = self.inventory_a.groups.create(name='D') g_d.inventory_source g_d.parents.add(g_c) - + url = reverse('api:inventory_tree_view', args=(self.inventory_a.pk,)) with self.current_user(self.super_django_user): response = self.get(url, expect=200) - + self.assertTrue(isinstance(response, list)) self.assertEqual(len(response), 1) self.assertEqual(response[0]['id'], g_a.pk) diff --git a/awx/main/tests/functional/jobs/base.py b/awx/main/tests/functional/jobs/job_base.py similarity index 99% rename from awx/main/tests/functional/jobs/base.py rename to awx/main/tests/functional/jobs/job_base.py index 1c45e94e4d..769ba406a5 100644 --- a/awx/main/tests/functional/jobs/base.py +++ b/awx/main/tests/functional/jobs/job_base.py @@ -3,7 +3,7 @@ import uuid # AWX from awx.main.models import * # noqa -from ..base import BaseTestMixin +from awx.main.tests.base import BaseTestMixin TEST_PLAYBOOK = '''- hosts: all gather_facts: false @@ -256,7 +256,7 @@ class BaseJobTestMixin(BaseTestMixin): self.team_ops_testers.users.add(self.user_billybob) # Each user has his/her own set of credentials. - from ..tasks import (TEST_SSH_KEY_DATA, + from awx.main.tests.data.ssh import (TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK) self.cred_sue = self.user_sue.credentials.create( diff --git a/awx/main/tests/functional/jobs/job_launch.py b/awx/main/tests/functional/jobs/job_launch.py index 66a0ca5a72..00bfbb8b2b 100644 --- a/awx/main/tests/functional/jobs/job_launch.py +++ b/awx/main/tests/functional/jobs/job_launch.py @@ -10,7 +10,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.models import * # noqa -from .base import BaseJobTestMixin +from job_base import BaseJobTestMixin import yaml __all__ = ['JobTemplateLaunchTest', 'JobTemplateLaunchPasswordsTest'] diff --git a/awx/main/tests/functional/jobs/job_relaunch.py b/awx/main/tests/functional/jobs/job_relaunch.py index 6fcc1b8b82..0c9eff99bd 100644 --- a/awx/main/tests/functional/jobs/job_relaunch.py +++ b/awx/main/tests/functional/jobs/job_relaunch.py @@ -10,8 +10,8 @@ from django.core.urlresolvers import reverse # AWX from awx.main.models import * # noqa -from ..base import BaseLiveServerTest -from .base import BaseJobTestMixin +from awx.main.tests.base import BaseLiveServerTest +from job_base import BaseJobTestMixin __all__ = ['JobRelaunchTest',] diff --git a/awx/main/tests/functional/jobs/jobs_monolithic.py b/awx/main/tests/functional/jobs/jobs_monolithic.py index 7f3e337503..0ea0661cd7 100644 --- a/awx/main/tests/functional/jobs/jobs_monolithic.py +++ b/awx/main/tests/functional/jobs/jobs_monolithic.py @@ -22,7 +22,7 @@ import requests # AWX from awx.main.models import * # noqa -from base import BaseJobTestMixin +from job_base import BaseJobTestMixin __all__ = ['JobTemplateTest', 'JobTest', 'JobTemplateCallbackTest', 'JobTransactionTest', 'JobTemplateSurveyTest'] @@ -218,7 +218,7 @@ class JobTemplateTest(BaseJobTestMixin, django.test.TestCase): resp = self.get(url, expect=200) print [x['name'] for x in resp['results']] self.assertEquals(resp['count'], 3) - + # Chuck has permission to see all Eng Job Templates as Lead Engineer # Note: Since chuck is an org admin he can also see the support scan template with self.current_user(self.user_chuck): @@ -270,7 +270,7 @@ class JobTemplateTest(BaseJobTestMixin, django.test.TestCase): resp = self.get(url, expect=200) print [x['name'] for x in resp['results']] self.assertEquals(resp['count'], 6) - + def test_credentials_list(self): url = reverse('api:credential_list') @@ -331,7 +331,7 @@ class JobTemplateTest(BaseJobTestMixin, django.test.TestCase): d['job_type'] = 'world domination' response = self.post(url, d, expect=400) self.assertTrue('job_type' in response) - + # Test playbook not in list of project playbooks. with self.current_user(self.user_sue): d = dict(data.items()) @@ -603,11 +603,11 @@ class JobTest(BaseJobTestMixin, django.test.TestCase): data = self.get('/api/v1/job_templates/', expect=401) data = self.get('/api/v1/job_templates/', expect=200, auth=self.get_normal_credentials()) self.assertTrue(data['count'], 2) - + rec = dict( - name = 'job-foo', - credential = self.credential.pk, - inventory = self.inventory.pk, + name = 'job-foo', + credential = self.credential.pk, + inventory = self.inventory.pk, project = self.project.pk, job_type = PERM_INVENTORY_DEPLOY ) @@ -617,7 +617,7 @@ class JobTest(BaseJobTestMixin, django.test.TestCase): self.assertEquals(posted['url'], '/api/v1/job_templates/3/') # other_django_user is on a team that can deploy, so can create both deploy and check type jobs - rec['name'] = 'job-foo2' + rec['name'] = 'job-foo2' posted = self.post('/api/v1/job_templates/', rec, expect=201, auth=self.get_other_credentials()) rec['name'] = 'job-foo3' rec['job_type'] = PERM_INVENTORY_CHECK @@ -732,7 +732,7 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase): raise socket.herror('unknown test host') raddr = '.'.join(list(reversed(ip.split('.'))) + ['in-addr', 'arpa']) return (host, [raddr], [ip]) - + def getaddrinfo(self, host, port, family=0, socktype=0, proto=0, flags=0): if family or socktype or proto or flags: return self._original_getaddrinfo(host, port, family, socktype, @@ -765,7 +765,7 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase): host_vars['ansible_ssh_host'] = ip host.variables = json.dumps(host_vars) host.save() - + # Find a valid job template to use to test the callback. job_template = None qs = JobTemplate.objects.filter(job_type='run', @@ -1095,7 +1095,7 @@ class JobTemplateSurveyTest(BaseJobTestMixin, django.test.TestCase): jt_url = reverse('api:job_template_detail', args=(response['id'],)) with self.current_user(self.user_sue): self.patch(jt_url, dict(survey_enabled=True), expect=402) - + def test_post_job_template_survey(self): url = reverse('api:job_template_list') data = dict( @@ -1220,11 +1220,11 @@ class JobTemplateSurveyTest(BaseJobTestMixin, django.test.TestCase): self.get(url, expect=200) with self.current_user(self.user_chuck): - self.get(url, expect=200) + self.get(url, expect=200) # Doug and Juan can't with self.current_user(self.user_doug): self.get(url, expect=403) - + with self.current_user(self.user_juan): - self.get(url, expect=403) + self.get(url, expect=403) diff --git a/awx/main/tests/functional/jobs/start_cancel.py b/awx/main/tests/functional/jobs/start_cancel.py index 676ad13f3b..afacb4f863 100644 --- a/awx/main/tests/functional/jobs/start_cancel.py +++ b/awx/main/tests/functional/jobs/start_cancel.py @@ -10,8 +10,8 @@ from django.conf import settings # AWX from awx.main.models import * # noqa -from ..base import BaseLiveServerTest -from .base import BaseJobTestMixin +from awx.main.tests.base import BaseLiveServerTest +from job_base import BaseJobTestMixin __all__ = ['JobStartCancelTest',] @@ -92,7 +92,7 @@ class JobStartCancelTest(BaseJobTestMixin, BaseLiveServerTest): # self.assertEqual(job.status, 'failed') # Test with a job that prompts for SSH unlock key, given the right key. - from ..tasks import TEST_SSH_KEY_DATA_UNLOCK + from awx.main.tests.data.ssh import TEST_SSH_KEY_DATA_UNLOCK # job = self.jt_ops_west_run.create_job( # credential=self.cred_greg, # created_by=self.user_sue, diff --git a/awx/main/tests/functional/jobs/survey_password.py b/awx/main/tests/functional/jobs/survey_password.py index fc46fcfc48..f7588301d8 100644 --- a/awx/main/tests/functional/jobs/survey_password.py +++ b/awx/main/tests/functional/jobs/survey_password.py @@ -6,7 +6,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.models import * # noqa -from ..base import BaseTest, QueueStartStopTestMixin +from awx.main.tests.base import BaseTest, QueueStartStopTestMixin __all__ = ['SurveyPasswordRedactedTest'] diff --git a/awx/main/tests/functional/licenses.py b/awx/main/tests/functional/licenses.py index 0c0c43fcfa..d6cde2a0a4 100644 --- a/awx/main/tests/functional/licenses.py +++ b/awx/main/tests/functional/licenses.py @@ -6,7 +6,7 @@ import os import tempfile from awx.main.models import Host, Inventory, Organization -from .base import BaseTest +from awx.main.tests.base import BaseTest import awx.main.task_engine from awx.main.task_engine import * # noqa @@ -46,7 +46,7 @@ class LicenseTests(BaseTest): def test_license_writer(self): - writer = TaskEngager( + writer = TaskEngager( company_name='acmecorp', contact_name='Michael DeHaan', contact_email='michael@ansibleworks.com', @@ -58,7 +58,7 @@ class LicenseTests(BaseTest): assert data['instance_count'] == 500 assert data['contact_name'] == 'Michael DeHaan' assert data['contact_email'] == 'michael@ansibleworks.com' - assert data['license_date'] == 25000 + assert data['license_date'] == 25000 assert data['license_key'] == "11bae31f31c6a6cdcb483a278cdbe98bd8ac5761acd7163a50090b0f098b3a13" strdata = writer.get_string() diff --git a/awx/main/tests/functional/organizations.py b/awx/main/tests/functional/organizations.py index e10d6dd92a..cf3c64ab87 100644 --- a/awx/main/tests/functional/organizations.py +++ b/awx/main/tests/functional/organizations.py @@ -12,7 +12,7 @@ from django.utils.timezone import now as tz_now # AWX from awx.main.models import * # noqa -from .base import BaseTest +from awx.main.tests.base import BaseTest __all__ = ['AuthTokenLimitUnitTest', 'OrganizationsTest'] @@ -62,7 +62,7 @@ class OrganizationsTest(BaseTest): # TODO: Test non-enterprise license self.create_test_license_file() self.setup_users() - + self.organizations = self.make_organizations(self.super_django_user, 10) self.projects = self.make_projects(self.normal_django_user, 10) @@ -71,7 +71,7 @@ class OrganizationsTest(BaseTest): 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]: + 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]) @@ -91,7 +91,7 @@ class OrganizationsTest(BaseTest): x.admins.add(self.super_django_user) x.users.add(self.super_django_user) x.users.add(self.other_django_user) - + self.organizations[0].users.add(self.normal_django_user) self.organizations[1].admins.add(self.normal_django_user) @@ -251,11 +251,11 @@ class OrganizationsTest(BaseTest): 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()) @@ -267,22 +267,22 @@ class OrganizationsTest(BaseTest): # look at what we got back from the post, make sure we added an org last_org = Organization.objects.order_by('-pk')[0] self.assertTrue(data1['url'].endswith("/%d/" % last_org.pk)) - + # Test that not even super users can create an organization with a basic license self.create_basic_license_file() cant_org = dict(name='silly user org', description='4815162342') self.post(self.collection(), cant_org, expect=402, auth=self.get_super_credentials()) 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'] projects1_url = orgs['results'][1]['related']['projects'] projects2_url = orgs['results'][2]['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] @@ -303,7 +303,7 @@ class OrganizationsTest(BaseTest): self.post(projects1_url, a_project, expect=204, auth=self.get_super_credentials()) projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials()) self.assertEquals(projects1['count'], 5) - + a_project = projects1['results'][-1] a_project['disassociate'] = 1 projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials()) @@ -324,7 +324,7 @@ class OrganizationsTest(BaseTest): # and can't do post a project he can read to an organization he cannot self.post(projects2_url, dict(id=new_project_a.pk), expect=403, auth=self.get_normal_credentials()) - + def test_post_item_subobjects_users(self): @@ -411,8 +411,8 @@ class OrganizationsTest(BaseTest): # 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. - + # 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()) @@ -425,14 +425,14 @@ class OrganizationsTest(BaseTest): # 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()) diff --git a/awx/main/tests/functional/projects.py b/awx/main/tests/functional/projects.py index eb1579fdea..b7378d14ef 100644 --- a/awx/main/tests/functional/projects.py +++ b/awx/main/tests/functional/projects.py @@ -20,8 +20,14 @@ from django.utils.timezone import now # AWX from awx.main.models import * # noqa -from .base import BaseTransactionTest -from .tasks import TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK, TEST_OPENSSH_KEY_DATA, TEST_OPENSSH_KEY_DATA_LOCKED +from awx.main.tests.base import BaseTransactionTest +from awx.main.tests.data.ssh import ( + TEST_SSH_KEY_DATA, + TEST_SSH_KEY_DATA_LOCKED, + TEST_SSH_KEY_DATA_UNLOCK, + TEST_OPENSSH_KEY_DATA, + TEST_OPENSSH_KEY_DATA_LOCKED, +) from awx.main.utils import decrypt_field, update_scm_url TEST_PLAYBOOK = '''- hosts: mygroup @@ -238,7 +244,7 @@ class ProjectsTest(BaseTransactionTest): auth=self.get_super_credentials()) response = self.put(project_detail, project_data, expect=200, auth=self.get_super_credentials()) - + # cannot update using local_path from another project. project_data['local_path'] = self.projects[2].local_path response = self.put(project_detail, project_data, expect=400, @@ -391,14 +397,14 @@ class ProjectsTest(BaseTransactionTest): # ===================================================================== # TEAM PROJECTS - + team = Team.objects.filter(active=True, organization__pk=self.organizations[1].pk)[0] team_projects = reverse('api:team_projects_list', args=(team.pk,)) - + p1 = self.projects[0] team.projects.add(p1) team.save() - + got = self.get(team_projects, expect=200, auth=self.get_super_credentials()) # FIXME: project postablility tests somewhat incomplete. @@ -430,7 +436,7 @@ class ProjectsTest(BaseTransactionTest): self.post(team_users, data=dict(x, is_superuser=False), expect=204, auth=self.get_normal_credentials()) # The normal admin user can't create a super user vicariously through the team/project - self.post(team_users, data=dict(username='attempted_superuser_create', password='thepassword', + self.post(team_users, data=dict(username='attempted_superuser_create', password='thepassword', is_superuser=True), expect=403, auth=self.get_normal_credentials()) # ... but a superuser can self.post(team_users, data=dict(username='attempted_superuser_create', password='thepassword', @@ -682,7 +688,7 @@ class ProjectsTest(BaseTransactionTest): team = Team.objects.order_by('pk')[0] organization = Organization.objects.order_by('pk')[0] inventory = Inventory.objects.create( - name = 'test inventory', + name = 'test inventory', organization = organization, created_by = self.super_django_user ) @@ -691,10 +697,10 @@ class ProjectsTest(BaseTransactionTest): # can add permissions to a user user_permission = dict( - name='user can deploy a certain project to a certain inventory', + name='user can deploy a certain project to a certain inventory', # user=user.pk, # no need to specify, this will be automatically filled in - inventory=inventory.pk, - project=project.pk, + inventory=inventory.pk, + project=project.pk, permission_type=PERM_INVENTORY_DEPLOY ) team_permission = dict( @@ -993,7 +999,7 @@ class ProjectUpdatesTest(BaseTransactionTest): new_url = new_url or url new_url_u = new_url_u or url new_url_up = new_url_up or url - + # Check existing URL as-is. if is_exception(new_url): self.assertRaises(new_url, update_scm_url, scm_type, url) @@ -1130,7 +1136,7 @@ class ProjectUpdatesTest(BaseTransactionTest): after = file(path, 'rb').read() return path, before, after self.fail('no file found to change!') - + def check_project_scm(self, project): project = Project.objects.get(pk=project.pk) project_path = project.get_project_path(check_if_exists=False) diff --git a/awx/main/tests/functional/redact.py b/awx/main/tests/functional/redact.py index 40e8869398..3ce38bc7ad 100644 --- a/awx/main/tests/functional/redact.py +++ b/awx/main/tests/functional/redact.py @@ -3,7 +3,7 @@ import textwrap # AWX from awx.main.redact import UriCleaner -from .base import BaseTest, URI +from awx.main.tests.base import BaseTest, URI __all__ = ['UriCleanTests'] @@ -38,15 +38,15 @@ uri = URI(scheme="https", username="myusername", password="mypasswordwith%40", h TEST_CLEARTEXT.append({ 'uri' : uri, 'text' : textwrap.dedent("""\ - PLAY [all] ******************************************************************** + PLAY [all] ******************************************************************** - TASK: [delete project directory before update] ******************************** + TASK: [delete project directory before update] ******************************** skipping: [localhost] - TASK: [update project using git and accept hostkey] *************************** + TASK: [update project using git and accept hostkey] *************************** skipping: [localhost] - TASK: [update project using git] ********************************************** + TASK: [update project using git] ********************************************** failed: [localhost] => {"cmd": "/usr/bin/git ls-remote https://%s:%s -h refs/heads/HEAD", "failed": true, "rc": 128} stderr: fatal: unable to access '%s': Could not resolve host: nonexistant.ansible.com @@ -54,10 +54,10 @@ TEST_CLEARTEXT.append({ FATAL: all hosts have already failed -- aborting - PLAY RECAP ******************************************************************** + PLAY RECAP ******************************************************************** to retry, use: --limit @/root/project_update.retry - localhost : ok=0 changed=0 unreachable=0 failed=1 + localhost : ok=0 changed=0 unreachable=0 failed=1 """ % (uri.username, uri.password, str(uri), str(uri))), 'host_occurrences' : 2 @@ -69,11 +69,11 @@ TEST_CLEARTEXT.append({ 'text' : textwrap.dedent("""\ TASK: [update project using git] ** failed: [localhost] => {"cmd": "/usr/bin/git ls-remote https://REDACTED:********", "failed": true, "rc": 128} - stderr: error: Couldn't resolve host '@%s' while accessing %s + stderr: error: Couldn't resolve host '@%s' while accessing %s fatal: HTTP request failed - msg: error: Couldn't resolve host '@%s' while accessing %s + msg: error: Couldn't resolve host '@%s' while accessing %s fatal: HTTP request failed """ % (uri.host, str(uri), uri.host, str(uri))), diff --git a/awx/main/tests/functional/schedules.py b/awx/main/tests/functional/schedules.py index 1beeff6286..4a4a0bcee3 100644 --- a/awx/main/tests/functional/schedules.py +++ b/awx/main/tests/functional/schedules.py @@ -10,7 +10,7 @@ from django.utils.timezone import now # AWX from awx.main.models import * # noqa -from .base import BaseTest +from awx.main.tests.base import BaseTest __all__ = ['ScheduleTest'] diff --git a/awx/main/tests/functional/scripts.py b/awx/main/tests/functional/scripts.py index 50dd336ac2..bdd81a7f7e 100644 --- a/awx/main/tests/functional/scripts.py +++ b/awx/main/tests/functional/scripts.py @@ -10,7 +10,7 @@ import urlparse # AWX from awx.main.models import * # noqa -from .base import BaseLiveServerTest +from awx.main.tests.base import BaseLiveServerTest __all__ = ['InventoryScriptTest'] @@ -93,7 +93,7 @@ class InventoryScriptTest(BaseScriptTest): # add localhost just to make sure it's thrown into all (Ansible github bug) local = inventory.hosts.create(name='localhost', inventory=inventory, variables={}) - hosts.append(local) + hosts.append(local) self.hosts.extend(hosts) groups = [] diff --git a/awx/main/tests/functional/settings.py b/awx/main/tests/functional/settings.py index 14e4285d09..a727213454 100644 --- a/awx/main/tests/functional/settings.py +++ b/awx/main/tests/functional/settings.py @@ -1,7 +1,7 @@ # Copyright (c) 2016 Ansible, Inc. # All Rights Reserved. -from .base import BaseTest +from awx.main.tests.base import BaseTest from awx.main.models import * # noqa from django.core.urlresolvers import reverse diff --git a/awx/main/tests/functional/tasks.py b/awx/main/tests/functional/tasks.py index 7bf0648957..a57202a958 100644 --- a/awx/main/tests/functional/tasks.py +++ b/awx/main/tests/functional/tasks.py @@ -21,7 +21,14 @@ from crum import impersonate # AWX from awx.main.utils import * # noqa from awx.main.models import * # noqa -from .base import BaseJobExecutionTest +from awx.main.tests.base import BaseJobExecutionTest +from awx.main.tests.data.ssh import ( + TEST_SSH_KEY_DATA, + TEST_SSH_KEY_DATA_LOCKED, + TEST_OPENSSH_KEY_DATA, + TEST_SSH_CERT_KEY, + TEST_SSH_KEY_DATA_UNLOCK, +) TEST_PLAYBOOK = u''' - name: test success @@ -230,176 +237,6 @@ TEST_VAULT_PLAYBOOK = '''$ANSIBLE_VAULT;1.1;AES256 TEST_VAULT_PASSWORD = '1234' -TEST_SSH_KEY_DATA = '''-----BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEAyQ8F5bbgjHvk4SZJsKI9OmJKMFxZqRhvx4LaqjLTKbBwRBsY -1/C00NPiZn70dKbeyV7RNVZxuzM6yd3D3lwTdbDu/eJ0x72t3ch+TdLt/aenyy10 -IvZyhSlxCLDkDaVVPFYJOQzVS8TkdOi6ZHc+R0c0A+4ZE8OQ8C0zIKtUTHqRk4/v -gYK5guhNS0DdgWkBj6K+r/9D4bqdPTJPt4S7H75vb1tBgseiqftEkLYOhTK2gsCi -5uJgpG4zPQY4Kk/97dbW7pwcvPkr1rKkAwEJ27Bfo+DBv3oEx3SinpXQtOrH1aEO -RHSXldBaymdBtVLUhjxDlnnQ7Ps+fNX04R7N4QIDAQABAoIBAQClEDxbNyRqsVxa -q8BbzxZNVFxsD6Vceb9rIDa8/DT4SO4iO8zNm8QWnZ2FYDz5d/X3hGxlSa7dbVWa -XQJtD1K6kKPks4IEaejP58Ypxj20vWu4Fnz+Jy4lvLwb0n2n5lBv1IKF389NATw9 -7sL3sB3lDsPZZiQYYbogNDuBWqc+kP0zD84bONsM/B2HMRm9BRv2UsZf+zKU4pTA -UqHffyjmw7LqHmbtVjwVcUsC+xcE4kCuWLvabFnTWOSnWECyIw2+trxKdwCXbfzG -s5rn4Dj+aEKimzFaRpTSVx6w4yw9xw/EjsSaZ88jKSpTP8ocCut6zv+P/JwlukEX -4A4FxqyxAoGBAOp3G9EIAAWijcIgO5OdiZNEqVyqd3yyPzT6d/q7bf4dpVCZiLNA -bRmge83aMc4g2Dpkn/++It3bDmnXXGg+BZSX5KT9JLklXchaw9phv9J0diZEUvYS -mSQafbUGIqYnYzns3TU0cbgITs1iVIEstHYjGr3J88nDG+HFCHboxa93AoGBANuG -cDFgyvm79+haK2fHhUCZgaFFYBpkpuz+zjDjzIytOzymWa2gD9jIa7mvdvoH2ge3 -AVG0vy+n9cJaqJMuLkhdI01wVlqY9wvDHFyZCXyIvKVPMljKeTvCNGCupsG4R171 -gSKT5ryOx58MGbE7knAZC+QWpwxFpdpbfej6g7NnAoGBAMz6ipAJbXN/tG0FnvAj -pxXfzizcPw/+CTI40tGaMMQbiN5ZC+CiL39bBUFnQ2mQ31jVheegg3zvuL8hb4EW -z+wjitoPEZ7nowC5EUaHdJr6BBzaWKkWg1nD6yhqj7ow7xfCE3YjPlQEt1fpYjV4 -LuClOgi4WPCIKYUMq6TBRaprAoGAVrEjs0xPPApQH5EkXQp9BALbH23/Qs0G4sbJ -dKMxT0jGAPCMr7VrLKgRarXxXVImdy99NOAVNGO2+PbGZcEyA9/MJjO71nFb9mgp -1iOVjHmPThUVg90JvWC3QIsYTZ5RiR2Yzqfr0gDsslGb/9LPxLcPbBbKB12l3rKM -6amswvcCgYEAvgcSlTfAkI3ac8rB70HuDmSdqKblIiQjtPtT/ixXaFkZOmHRr4AE -KepMRDnaO/ldPDPEWCGqPzEM0t/0jS8/hCu3zLHHpZ+0LnHq+EXkOI0/GB4P+z5l -Vz3kouC0BTav0rCEnDop/cWMTiAp/XhKXfrTTTOra/F8l2xD8n/mnzY= ------END RSA PRIVATE KEY-----''' - -TEST_SSH_KEY_DATA_LOCKED = '''-----BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: AES-128-CBC,6B4E92AF4C29DE26FD8535D81825BDE6 - -pg8YplxPpfzgEGUiko34DGaYklyGyYKXjOrGFGyLoquNAVNFyewT34dDrZi0IAaE -79wMVcdlHbrJfZz8ML8I/ft6zM6BdlwZExH4y9DRAaktY3yIXxSvowBQ6ljh3wUy -M6m0afOfVjT22V8hLFgX0yTQ6P9zTG1cmj6+JQWTsMJ5EP3rnFK5CyrJXP48B3GI -GgE66rkXDvcKlVeIrbrpcTyfmEpafPgVRJYCDFXxeO/BfKgUFVxFq1PgFbvGQMmD -wA6EsyRrN+aoub1sqzj8tM8e4nwEi0EifdRShkFeqH4GUOKypanTXfCqwFBgYi5a -i3YwSnniZZPwCniGR5cl8oetrc5dubq/IR0txsGi2lO6zJEWdSer/EadS0QAll4S -yXrSc/lFaez1VmVe/8aoBKDOHhe7jV3YXAuqCeB4o/SThB/9Gad44MTbqFH3d7cD -k+F0Cjup7LZqZpXeB7ZHRG/Yt9MtBzwDVmEWaxA1WIN5a8xyZEVzRswSi4lZX69z -Va7eTKcrCbHOQmIbLZGRiZbAbfgriwwxQCJWELv80h+A754Bhi23n3WzcT094fRi -cqK//HcHHXxYGmrfUbHYcj+GCQ07Uk2ZR3qglmPISUCgfZwM9k0LpXudWE8vmF2S -pAnbgxgrfUMtpu5EAO+d8Sn5wQLVD7YzPBUhM4PYfYUbJnRoZQryuR4lqCzcg0te -BM8x1LzSXyBEbQaonuMzSz1hCQ9hZpUwUEqDWAT3cPNmgyWkXQ1P8ehJhTmryGJw -/GHxNzMZDGj+bBKo7ic3r1g3ZmmlSU1EVxMLvRBKhdc1XicBVqepDma6/LEpj+5X -oplR+3Q0QSQ8CchcSxYtOpI3UBCatpyu09GtfzS+7bI5I7FVYUccR83+oQlKpPHC -5O2irB8JeXqAY679fx2N4i0E6l5Xr5AjUtOBCNil0Y70eOf9ER6i7kGakR7bUtk5 -fQn8Em9pLsYYalnekn4sxyHpGq59KgNPjQiJRByYidSJ/oyNbmtPlxfXLwpuicd2 -8HLm1e0UeGidfF/bSlySwDzy1ZlSr/Apdcn9ou5hfhaGuQvjr9SvJwxQFNRMPdHj -ukBSDGuxyyU+qBrWJhFsymiZAWDofY/4GzgMu4hh0PwN5arzoTxnLHmc/VFttyMx -nP7bTaa9Sr54TlMr7NuKTzz5biXKjqJ9AZKIUF2+ERebjV0hMpJ5NPsLwPUnA9kx -R3tl1JL2Ia82ovS81Ghff/cBZsx/+LQYa+ac4eDTyXxyg4ei5tPwOlzz7pDKJAr9 -XEh2X6rywCNghEMZPaOQLiEDLJ2is6P4OarSa/yoU4OMetpFfwZ0oJSCmGlEa+CF -zeJ80yXhU1Ru2eqiUjCAUg25BFPwoiMJDc6jWWow7OrXCQsw7Ddo2ncy1p9QeWjM -2R4ojPHWuXKYxvwVSc8NZHASlycBCaxHLDAEyH4avOSDPWOB1H5t+RrNmo0qgush -0aRo6F7BjzB2rA4E+xu2u11TBfF8iB3PC919/vxnkXF97NqezsaCz6VbRlsU0A+B -wwoi+P4JlJF6ZuhuDv6mhmBCSdXdc1bvimvdpOljhThr+cG5mM08iqWGKdA665cw ------END RSA PRIVATE KEY----- -''' - -TEST_OPENSSH_KEY_DATA = '''-----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn -NhAAAAAwEAAQAAAQEA1AZAwUJUiLmOXjbO5q2ZE5DF+gMpPKe8NEr12FpvOaJr1Nz/DNpf -FE/VbssOJ4CRD/6MItlPSG2pC1Cv3AYSL7NBc0YCMlBR/P/nLI8pLAzU3p3KRYvR+R6cMW -3nMcxyB1UUgzXY9dTVFIyejOsm7stGuNfdDTTLBE2vTDz6CyzxxSALEOdYut5cfeTUuG7d -nP01K3JiaHjHaXDmwraRR/JlitylaZUnSZ+/b9WCMX5FyeJ6CnGdvcCuvMK0iNjZ8R+PxP -xJBM5AlJC5J6qa8YmeaQ6lA/2S+/wGuhJmocmiXiLFy9IzIPnQiR+h8DqStp4xp245UQxe -TIGSMmq8DQAAA9A4FMRSOBTEUgAAAAdzc2gtcnNhAAABAQDUBkDBQlSIuY5eNs7mrZkTkM -X6Ayk8p7w0SvXYWm85omvU3P8M2l8UT9Vuyw4ngJEP/owi2U9IbakLUK/cBhIvs0FzRgIy -UFH8/+csjyksDNTencpFi9H5HpwxbecxzHIHVRSDNdj11NUUjJ6M6ybuy0a4190NNMsETa -9MPPoLLPHFIAsQ51i63lx95NS4bt2c/TUrcmJoeMdpcObCtpFH8mWK3KVplSdJn79v1YIx -fkXJ4noKcZ29wK68wrSI2NnxH4/E/EkEzkCUkLknqprxiZ5pDqUD/ZL7/Aa6EmahyaJeIs -XL0jMg+dCJH6HwOpK2njGnbjlRDF5MgZIyarwNAAAAAwEAAQAAAQAp8orBMYRUAJIgJavN -i67rZgslKZbw/yaHGgWFpm628mFvHcIAIvwIorrRTq8gNZl9lpjXFDNRWxDEwlPorfLPKS -Hb0pAAsE9oRKDR+gjlRCyhVop8M+t45At25A2HlrFArh5+zxp7mH4HsMJ1ktiDCgiV7W84 -e6dm1I/H/5BgwUlTNoVOGPrU183gqRsHIICjfmnjl2ObJoly+MTrAy7E9rSmsO+pHKl8z0 -XODWh3mo+EkCoYrK6kP96Jy3BepSmbZMROEsctS7Mkzu6QdnfTY3QqIzENYtTGJuAGktGj -su4MHP8hbj+TznNkFeZdmIC0uTnIKu1uquwuFF1HPZiBAAAAgACX9xPKS2J04WXpQag+JS -06n2zSuBHW7Kq4q/LMydoTRd8Quf6u6eivSBrl7H779LCtGCIZqJAslvWOyPyz2CohcCBU -emubiHcUA+aN7R9E0tyitwWraJjMIwpQ7+AbgdsLsuxozNeccSrr0tva2c5y9x7YGBcIdC -UJDt4xnBi7AAAAgQDz771v8Mb18kq5W+inDcYPFUNXGtNfeYZEOhYFpxunFnYwTEAG0Xnh -YpQXOAFZ2q5mkFQHMl4cOKwoAlaP0dM4v0JKPjFDLvGisEu95fnivj4YAMP/UHgKKxBbqW -HPUhg3adAmIJ9z9u/VmTErbVklcKWlyZuTUkxeQ/BJmSIRUQAAAIEA3oKAzdDURjy8zxLX -gBLCPdi8AxCiqQJBCsGxXCgKtZewset1XJHIN9ryfb4QSZFkSOlm/LgdeGtS8Or0GNPRYd -hgnUCF0LkEsDQ7HzPZYujLrAwjumvGQH6ORp5vRh0tQb93o4e1/A2vpdSKeH7gCe/jfUSY -h7dFGNoAI4cF7/0AAAAUcm9vdEBwaWxsb3cuaXhtbS5uZXQBAgMEBQYH ------END OPENSSH PRIVATE KEY----- -''' - -TEST_OPENSSH_KEY_DATA_LOCKED = '''-----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABALaWMfjc -hSvC7aXxQs1ZDiAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQDEDWKwZD8+ -h+2gZZKna8dy2QL4jJxM1eLGDcQDnuip1ixhaf5MT5T6BMploXXHs1pfuwx8yTQ6Ts/VJp -WX6cuHQg8sPGM3P7HNGUqs9q/EQfrrRxz555uL08CRaS6FjM/6x9iolNhHU910Wlg+R+ZS -xiMrrY/s03EiEChsAWTbwBGqTopGC2xMFgIxINoQtTFXv7MtCbDfl8aWKQRDmzkLvwT07N -ycj2kqADqoukD/2bQvPrW6FIZPJPpAdeAe2SZbf/y92NgVz/glOdtjaJp3oqn1QHrOA9/k -XgXOjgVQUbzX7qyLWenxM138VsRKUJZeROaHt1MWApLrLtKQ36SrAAAD0A+PODJjfeKm3U -JknlSYD7fFh6bVZGwG6LnLMtobs0elOfj2+sdg+hOVqyrA0rPOHES5yGKslTc/wRkRQ95m -dBleAyTDIOQ90IqDxT3lsNQwpscsFKPYKGmaUvZLLk4aNY1GeANtByXwTsjetVqn8Uo59A -zu6phX8Aagn2h0qxQwBnDjlzsXf6g5H7UPZd/t1dYr1NfVP6KWJrg0jivAI8tzO2HcM9W2 -cyOaodBw/6TsJNKvDV714Z+apvrNDEufBUsovKjAna2BDVZIhTCg5mYm0Dks8JStQrG2S1 -Yk8EM3+fpo8uMoHVz1jbYC8UX12pwIU67MhUn24KBxqulCYaTMsrLFkNWk6vKgwib+sIa4 -i1Bij1Zd0rdJWypQqTc2Oj3bBSYM47AksMXcKVpuNnFLh4+eokpQzbtIYpRqhOTh1Fky7z -xkhTgWVvf/F19M9t1bz3Rm1/t5I75Ag9qfKWs06j+VVfXnDt5v5hYAEhoJjMzSjgKaqc5g -YndeWeUwO6Vijt4XpkB8+0R7Kptsh9L0UUsNIcRoGcqrM8IUVb3D8vPWppPlj9d6LB+FCo -Cy1JlscnpBb8AQy9QMvrJTHKOyjRcenVxILPiN8PypIC008jvqpDzKimAxM4IMuA7AWE6w -j5+CzfUhDAJGdl2qH/nVc7GFUtz8bVA/v9Zkawg2MLcafgGollbLcTbKwDFcenQuyHT+Hj -uDm2f0oV/EDKFqLijlV8vcLBNUZoxY/L62Vora1jlqnapq2Z/AM9NicoELYNe21ReJ5dxM -7Pk/QdSrZjQzxoHf8uBDpb7x/KyfnSdf8GmdGCxoJ5mcepwD4tROMFC104tN0STJpdGVSm -Q5ZG1JDN7F9iJCCAwyulWH/XxTzFYnQ84199cQeV/M9rXXgbXa8ApAung6X9j8y1fcw9Lw -wV1aP06bCNgM0U50PiZ54HXwzVt+Ghs06TEF4/ZQiIgNJxdw0HFxAJj8qHqUCHuSmvBgnN -qRW/uruItwpXLaL00EHu7rAFlBi1BnnetI+D12ls04mlyTUFFM5v520B5zPV+5If2hx91w -C6Oxl1Wsp3gPkK2yiuy8qcrvoEoJ25TeEhUGEAPWx2OuQJO/Lpq9aF/JJoqGwnBaXdCsi+ -5ig+ZMq5GKQtyydzyXImjlNEUH1w2prRDiGVEufANA5LSLCtqOLgDzXS62WUBjJBrQJVAM -YpWz1tiZQoyv1RT3Y0O0Vwe2Z5AK3fVM0I5jWdiLrIErtcR4ULa6T56QtA52DufhKzINTR -Vg9TtUBqfKIpRQikPSjm7vpY/Xnbc= ------END OPENSSH PRIVATE KEY----- -''' - -TEST_SSH_CERT_KEY = """-----BEGIN CERTIFICATE----- -MIIDNTCCAh2gAwIBAgIBATALBgkqhkiG9w0BAQswSTEWMBQGA1UEAwwNV2luZG93 -cyBBenVyZTELMAkGA1UEBhMCVVMxIjAgBgkqhkiG9w0BCQEWE2x1a2VAc25lZXJp -bmdlci5jb20wHhcNMTQwNzI4MTQzMjExWhcNMTUwNzI4MTQzMjExWjBJMRYwFAYD -VQQDDA1XaW5kb3dzIEF6dXJlMQswCQYDVQQGEwJVUzEiMCAGCSqGSIb3DQEJARYT -bHVrZUBzbmVlcmluZ2VyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL9UHMhmAkbEJtg7jxAYjRbyTILDkNG5X/5UDpReIBD3VZfIrrXKX/groKbE -uiH9vdHkhdbOV1WkINuz+12Hdfk7irRXPRNC6SQVNeCy/DuCIEX+pQCAn60pc3eT -ctQG4oCiwQrlFMjoV9S5kbKoUavtuEt7Huo4YIVJK1/McEYq8mIM1W6MGOwXQI0b -rKsp1zRviiQWU5zijQYxepSpBNJcGS1lNhD1m5ycy7+0Zm7FqBa6nlf/2kLadREF -4o3bHljfrLTa+czV9lI9HjwpeLCfccx0T7etpv+u/JzSlt1MlAnlCNtz2wo1oNdi -scyRdRlb00AWQMneQfSYgwGHyQ8CAwEAAaMqMCgwDgYDVR0PAQH/BAQDAgeAMBYG -A1UdJQEB/wQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCc064W0uk3 -hVVYtHuOBPSag9TvyqJrnvHsPgWiwFTh7t4CGF2TiH6myxkboAN0BGZqIj0zorT+ -VORmZ4PrDqV29q8M77n4aTmDmqXXcCAMOtyC87xlK+YvsVtrvu2zYXnZV+BJ+UtT -FpDqgMLrE0ecnkDClAK4vPx3TqSzU3v//lgUG1o3VibJbzMptggMVA4Hl9AXGLnU -FNpK5B4mm/PQHQC1Ma/nweMoDcVlQUne8XgnwEf0ixGkViFLm6FmI7DfKUpq3zXb -vWKu8qiBmz4tju6LT2n+q66MNEMmS1qhuJJYZrORJgQkCVbo1RRwW6UNZSIjD8D6 -8QJhq7hCxteN ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAv1QcyGYCRsQm2DuPEBiNFvJMgsOQ0blf/lQOlF4gEPdVl8iu -tcpf+CugpsS6If290eSF1s5XVaQg27P7XYd1+TuKtFc9E0LpJBU14LL8O4IgRf6l -AICfrSlzd5Ny1AbigKLBCuUUyOhX1LmRsqhRq+24S3se6jhghUkrX8xwRiryYgzV -bowY7BdAjRusqynXNG+KJBZTnOKNBjF6lKkE0lwZLWU2EPWbnJzLv7RmbsWoFrqe -V//aQtp1EQXijdseWN+stNr5zNX2Uj0ePCl4sJ9xzHRPt62m/678nNKW3UyUCeUI -23PbCjWg12KxzJF1GVvTQBZAyd5B9JiDAYfJDwIDAQABAoIBACNozL7l6ivwp4PD -WhHPiWUiyLg2u3mlBjgKlHwvA15AeC3ULUllv+ctI9lZdV1PGa9bzM1ZeN5XtuES -aUYBCPtsYppHvvzumDleV49TcM0OoyxxGVaDd4nTrxQFTO4irA7EkFeU2Ajqvz6W -bXmUHzFjmIUXrzwH3Q0t4oIjUvAZNhNY63G3XZ264pNckvtuRArgn0r7e+trplII -qDYPwOLPhorwG6a0HIsSWbECA+NbzC5wBIr4CMfDRiHDQ5g4cGstpbBAUkAs2LSU -2QcGp3AIqOnzMDxLTMqKcKQ9YXOMqTpVoyll+jkgdHLCqHjo+O51/E5AsjBcabmi -4LpeVsECgYEA+7g2y8J54GWhNOpJ+RQ6IvoUuA9YmEe3byIglat5b+AWuy7Miq4u -VSiIjEqDf8Ci1LxHrkRCe4S/9VZSNJdfbv5I1LW3Wx4JRZ1JFR5Z9B0XI5SdkokM -O9DXIJHgxSzC9kCKgBpH5KxqMpEdMMv70C7gbMpnONEL1zIOZJxAwq8CgYEAwpUB -Dp5l8Wpma5SnUAJiTU9XdgtPr1M8WFde9jP3e2VK2O4DmnZkLN5aLbMfnftUNAl1 -mP4CTxtkkEwNtkol+rZAy6wwzQA/TP2yC0Wfw+xeDTKJ+JDDoWM+4FAhjBpns/gx -Ehfqj76jRjBW9DtARaHgrIHHFUn2p6wMZq4Sd6ECgYEA4jlNrdQrGnvb5KWHM750 -/UhJ5J2OHtWdStid9kU0j1ISu8k0dJJT+57BEWxKQD9NV+madkjMgxvsNL6OhMti -LmuD4v8pOU+GP7U6oCs15slaKVUARFi80OlA3fmcyzgOQ6f/kV+NKzu0+ZsnY9p/ -hjsK4VsKZ6qgfJd1DgDLxusCgYArXCDcLRfycA9ascmG3sEhESkgOO0M2LN9zBpx -KqtfZ/cB2CgdZ3xzMylNPbkx7yuYXPNDoHbLQgNq1EfJ80P7VlmiCUDmrcNtWKsw -L9emRSnALx7nsPqnIAKG4dRX8Bpj1E67BXFTjtu7bFI0Im/0FFqIlnLSn6TDQGeT -Cf87gQKBgCgW/kFaQAhP5Pdb7oOQcaF4/dq50QNDyQMFOPKWHY/5IrsIrDVI5V/D -o1npLPB+YE3baQqo58JX1UuO83F4zlwzS3Q4lS3dxg+gdvgzFHvQd/SV5IDhmLWL -L5Hj+B02+FAiz8zVGumbVykvPtzgTb0E+0rJKNO0/EgGqWsk/oC0 ------END RSA PRIVATE KEY----- -""" - -TEST_SSH_KEY_DATA_UNLOCK = 'unlockme' - class RunJobTest(BaseJobExecutionTest): ''' Test cases for RunJob celery task. @@ -1077,7 +914,7 @@ class RunJobTest(BaseJobExecutionTest): self.assertTrue('"--become-method"' in job.job_args) self.assertTrue('"--ask-become-pass"' in job.job_args) self.assertTrue('"--become"' in job.job_args) - + def test_unlocked_ssh_key(self): self.create_test_credential(ssh_key_data=TEST_SSH_KEY_DATA) self.create_test_project(TEST_PLAYBOOK) @@ -1395,7 +1232,7 @@ class RunJobTest(BaseJobExecutionTest): # Hide local settings path. settings.AWX_PROOT_HIDE_PATHS = [os.path.join(settings.BASE_DIR, 'settings')] # Create another project alongside the one we're using to verify it - # is hidden. + # is hidden. self.create_test_credential() self.create_test_project(TEST_PLAYBOOK) other_project_path = self.project.local_path diff --git a/awx/main/tests/functional/users.py b/awx/main/tests/functional/users.py index 11f27a6fd4..91720212ff 100644 --- a/awx/main/tests/functional/users.py +++ b/awx/main/tests/functional/users.py @@ -15,7 +15,7 @@ from django.test.utils import override_settings # AWX from awx.main.models import * # noqa -from .base import BaseTest +from awx.main.tests.base import BaseTest from awx.main.conf import tower_settings __all__ = ['AuthTokenTimeoutTest', 'AuthTokenLimitTest', 'AuthTokenProxyTest', 'UsersTest', 'LdapTest'] @@ -61,7 +61,7 @@ class AuthTokenLimitTest(BaseTest): 'token': response['token'] } self.get(user_me_url, expect=200, auth=auth_token1) - + mock_get_request_hash.return_value = "session_2" response = self.post(auth_token_url, data, expect=200, auth=None) auth_token2 = { @@ -133,7 +133,7 @@ class AuthTokenProxyTest(BaseTest): remote_addr = '192.168.75.1' auth_token = self._request_auth_token(remote_addr) - + # Verify we can access our own user information, from the remote address specified via HTTP_X_FORWARDED_FOR client_kwargs = {'HTTP_X_FORWARDED_FOR': remote_addr} response = self._get_me(expect=200, auth=auth_token, remote_addr=remote_addr, client_kwargs=client_kwargs) @@ -183,7 +183,7 @@ class UsersTest(BaseTest): url = reverse('api:user_list') new_user = dict(username='blippy') self.post(url, expect=400, data=new_user, auth=self.get_super_credentials()) - + def test_only_super_user_or_org_admin_can_add_users(self): url = reverse('api:user_list') new_user = dict(username='blippy', password='hippy') @@ -269,7 +269,7 @@ class UsersTest(BaseTest): # auth method was used in the request. response_header = response.response.get('WWW-Authenticate', '') self.assertEqual(response_header.split()[0], 'Token') - + # Request a new auth token from the new remote address. data = dict(zip(('username', 'password'), self.get_normal_credentials())) response = self.post(auth_token_url, data, expect=200, auth=None, @@ -298,7 +298,7 @@ class UsersTest(BaseTest): response = self.get(user_me_url, expect=401) response_header = response.response.get('WWW-Authenticate', '') self.assertEqual(response_header.split()[0], 'Basic') - + # A request that attempts Basic auth should request Basic auth again. response = self.get(user_me_url, expect=401, auth=('invalid', 'password')) @@ -431,7 +431,7 @@ class UsersTest(BaseTest): self.get(url, expect=404, auth=self.get_super_credentials()) obj = User.objects.get(pk=user_pk) self.assertEquals(obj.is_active, False) - + def test_non_org_admin_user_cannot_delete_any_user_including_himself(self): url1 = reverse('api:user_detail', args=(self.super_django_user.pk,)) url2 = reverse('api:user_detail', args=(self.normal_django_user.pk,)) @@ -471,11 +471,11 @@ class UsersTest(BaseTest): url = reverse('api:user_organizations_list', args=(self.normal_django_user.pk,)) data = self.get(url, expect=200, auth=self.get_normal_credentials()) - self.assertEquals(data['count'], 1) + self.assertEquals(data['count'], 1) # also accessible via superuser data = self.get(url, expect=200, auth=self.get_super_credentials()) - self.assertEquals(data['count'], 1) - # and also by other user... + self.assertEquals(data['count'], 1) + # and also by other user... data = self.get(url, expect=200, auth=self.get_other_credentials()) # but not by nobody user data = self.get(url, expect=403, auth=self.get_nobody_credentials()) @@ -492,7 +492,7 @@ class UsersTest(BaseTest): data = self.get(url, expect=200, auth=self.get_other_credentials()) # but not by nobody user data = self.get(url, expect=403, auth=self.get_nobody_credentials()) - + # teams the user is on, should be 0 url = reverse('api:user_teams_list', args=(self.normal_django_user.pk,)) data = self.get(url, expect=200, auth=self.get_normal_credentials()) @@ -566,7 +566,7 @@ class UsersTest(BaseTest): qs = base_qs.filter(username__exact='normal') self.assertTrue(qs.count()) self.check_get_list(url, self.super_django_user, qs) - + # Filter by username with __iexact suffix. url = '%s?username__iexact=NORMAL' % base_url qs = base_qs.filter(username__iexact='NORMAL') @@ -707,7 +707,7 @@ class UsersTest(BaseTest): self.assertTrue(qs.count()) self.check_get_list(url, self.super_django_user, qs) - # Filter by is_staff (field not exposed via API). FIXME: Should + # Filter by is_staff (field not exposed via API). FIXME: Should # eventually not be allowed! url = '%s?is_staff=true' % base_url qs = base_qs.filter(is_staff=True) @@ -792,7 +792,7 @@ class UsersTest(BaseTest): qs = base_qs.filter(organizations__admins__username__startswith='norm') self.assertTrue(qs.count()) self.check_get_list(url, self.super_django_user, qs) - + # Filter by username with __in list. url = '%s?username__in=normal,admin' % base_url qs = base_qs.filter(username__in=('normal', 'admin')) diff --git a/awx/main/tests/functional/views.py b/awx/main/tests/functional/views.py index e53fdce500..4ccd6f64ec 100644 --- a/awx/main/tests/functional/views.py +++ b/awx/main/tests/functional/views.py @@ -2,8 +2,11 @@ from django.core.urlresolvers import reverse # Reuse Test code -from .base import BaseLiveServerTest, QueueStartStopTestMixin -from .base import URI +from awx.main.tests.base import ( + BaseLiveServerTest, + QueueStartStopTestMixin, + URI, +) from awx.main.models.projects import * # noqa __all__ = ['UnifiedJobStdoutRedactedTests'] @@ -31,7 +34,7 @@ class UnifiedJobStdoutRedactedTests(BaseLiveServerTest, QueueStartStopTestMixin) def setUp(self): super(UnifiedJobStdoutRedactedTests, self).setUp() self.setup_instances() - self.setup_users() + self.setup_users() self.test_cases = [] self.negative_test_cases = [] diff --git a/pytest.ini b/pytest.ini index 751ebbb85f..a679c1bdc4 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,5 +1,6 @@ [pytest] DJANGO_SETTINGS_MODULE = awx.settings.development python_paths = awx/lib/site-packages +site_dirs = awx/lib/site-packages python_files = *.py addopts = --create-db From 71a1547c3a404fd31704b541274f773c43359357 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Thu, 28 Jan 2016 12:01:12 -0500 Subject: [PATCH 4/7] fixing ad_hoc imports flake8 fixes Fix and add awx/api/tests added fact tests added proper xml reports for jenkins added jenkins requirements and adjusted Makefile target --- .coveragerc | 2 ++ Makefile | 12 ++++++------ awx/api/tests/job_tasks.py | 2 +- awx/main/models/credential.py | 1 + awx/main/tests/functional/ad_hoc.py | 6 +++++- awx/main/tests/functional/jobs/job_launch.py | 2 +- awx/main/tests/functional/jobs/job_relaunch.py | 2 +- awx/main/tests/functional/jobs/jobs_monolithic.py | 2 +- awx/main/tests/functional/jobs/start_cancel.py | 2 +- awx/main/tests/{functional/jobs => }/job_base.py | 4 ++-- awx/main/utils.py | 1 - requirements/requirements_jenkins.txt | 4 ++++ tools/docker-compose/Dockerfile | 5 +---- 13 files changed, 26 insertions(+), 19 deletions(-) rename awx/main/tests/{functional/jobs => }/job_base.py (99%) diff --git a/.coveragerc b/.coveragerc index d7a734c1d6..f9ef3447bf 100644 --- a/.coveragerc +++ b/.coveragerc @@ -25,3 +25,5 @@ exclude_lines = ignore_errors = True +[xml] +output = ./reports/coverage.xml diff --git a/Makefile b/Makefile index 3d406b106b..435b059388 100644 --- a/Makefile +++ b/Makefile @@ -155,7 +155,7 @@ endif .PHONY: clean rebase push requirements requirements_dev requirements_jenkins \ real-requirements real-requirements_dev real-requirements_jenkins \ develop refresh adduser syncdb migrate dbchange dbshell runserver celeryd \ - receiver test test_coverage coverage_html test_jenkins dev_build \ + receiver test test_unit test_coverage coverage_html test_jenkins dev_build \ release_build release_clean sdist rpmtar mock-rpm mock-srpm rpm-sign \ build-ui sync-ui test-ui build-ui-for-coverage test-ui-for-coverage \ build-ui-for-browser-tests test-ui-debug jshint ngdocs \ @@ -360,14 +360,14 @@ check: flake8 pep8 # pyflakes pylint # Run all API unit tests. test: - $(PYTHON) -m py.test awx/main/tests + py.test awx/main/tests awx/api/tests awx/fact/tests test_unit: - $(PYTHON) -m py.test awx/main/tests/unit + py.test awx/main/tests/unit # Run all API unit tests with coverage enabled. test_coverage: - $(PYTHON) -m py.test --cov=awx awx/main/tests + py.test --cov=awx --cov-report=xml --junitxml=./reports/junit.xml awx/main/tests awx/api/tests awx/fact/tests # Output test coverage as HTML (into htmlcov directory). coverage_html: @@ -378,8 +378,8 @@ test_tox: tox -v # Run unit tests to produce output for Jenkins. -test_jenkins: - $(PYTHON) manage.py jenkins -v2 --enable-coverage --project-apps-tests +# Alias existing make target so old versions run against Jekins the same way +test_jenkins : test_coverage # UI TASKS # -------------------------------------- diff --git a/awx/api/tests/job_tasks.py b/awx/api/tests/job_tasks.py index 36c7eb6fb0..93861f8d56 100644 --- a/awx/api/tests/job_tasks.py +++ b/awx/api/tests/job_tasks.py @@ -5,7 +5,7 @@ from django.conf import settings from django.test import LiveServerTestCase from django.test.utils import override_settings -from awx.main.tests.jobs import BaseJobTestMixin +from awx.main.tests.job_base import BaseJobTestMixin @override_settings(CELERY_ALWAYS_EAGER=True, diff --git a/awx/main/models/credential.py b/awx/main/models/credential.py index c72c67b715..8f0d32d87a 100644 --- a/awx/main/models/credential.py +++ b/awx/main/models/credential.py @@ -470,3 +470,4 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique): if 'cloud' not in update_fields: update_fields.append('cloud') super(Credential, self).save(*args, **kwargs) + diff --git a/awx/main/tests/functional/ad_hoc.py b/awx/main/tests/functional/ad_hoc.py index d0e75d2f19..41993f885b 100644 --- a/awx/main/tests/functional/ad_hoc.py +++ b/awx/main/tests/functional/ad_hoc.py @@ -19,7 +19,11 @@ from crum import impersonate from awx.main.utils import * # noqa from awx.main.models import * # noqa from awx.main.tests.base import BaseJobExecutionTest -from tasks import TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK +from awx.main.tests.data.ssh import ( + TEST_SSH_KEY_DATA, + TEST_SSH_KEY_DATA_LOCKED, + TEST_SSH_KEY_DATA_UNLOCK, +) __all__ = ['RunAdHocCommandTest', 'AdHocCommandApiTest'] diff --git a/awx/main/tests/functional/jobs/job_launch.py b/awx/main/tests/functional/jobs/job_launch.py index 00bfbb8b2b..4d1899de09 100644 --- a/awx/main/tests/functional/jobs/job_launch.py +++ b/awx/main/tests/functional/jobs/job_launch.py @@ -10,7 +10,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.models import * # noqa -from job_base import BaseJobTestMixin +from awx.main.tests.job_base import BaseJobTestMixin import yaml __all__ = ['JobTemplateLaunchTest', 'JobTemplateLaunchPasswordsTest'] diff --git a/awx/main/tests/functional/jobs/job_relaunch.py b/awx/main/tests/functional/jobs/job_relaunch.py index 0c9eff99bd..437c6ed099 100644 --- a/awx/main/tests/functional/jobs/job_relaunch.py +++ b/awx/main/tests/functional/jobs/job_relaunch.py @@ -11,7 +11,7 @@ from django.core.urlresolvers import reverse # AWX from awx.main.models import * # noqa from awx.main.tests.base import BaseLiveServerTest -from job_base import BaseJobTestMixin +from awx.main.tests.job_base import BaseJobTestMixin __all__ = ['JobRelaunchTest',] diff --git a/awx/main/tests/functional/jobs/jobs_monolithic.py b/awx/main/tests/functional/jobs/jobs_monolithic.py index 0ea0661cd7..72283f29f9 100644 --- a/awx/main/tests/functional/jobs/jobs_monolithic.py +++ b/awx/main/tests/functional/jobs/jobs_monolithic.py @@ -22,7 +22,7 @@ import requests # AWX from awx.main.models import * # noqa -from job_base import BaseJobTestMixin +from awx.main.tests.job_base import BaseJobTestMixin __all__ = ['JobTemplateTest', 'JobTest', 'JobTemplateCallbackTest', 'JobTransactionTest', 'JobTemplateSurveyTest'] diff --git a/awx/main/tests/functional/jobs/start_cancel.py b/awx/main/tests/functional/jobs/start_cancel.py index afacb4f863..e57c70ef15 100644 --- a/awx/main/tests/functional/jobs/start_cancel.py +++ b/awx/main/tests/functional/jobs/start_cancel.py @@ -11,7 +11,7 @@ from django.conf import settings # AWX from awx.main.models import * # noqa from awx.main.tests.base import BaseLiveServerTest -from job_base import BaseJobTestMixin +from awx.main.tests.job_base import BaseJobTestMixin __all__ = ['JobStartCancelTest',] diff --git a/awx/main/tests/functional/jobs/job_base.py b/awx/main/tests/job_base.py similarity index 99% rename from awx/main/tests/functional/jobs/job_base.py rename to awx/main/tests/job_base.py index 769ba406a5..5b7408d19d 100644 --- a/awx/main/tests/functional/jobs/job_base.py +++ b/awx/main/tests/job_base.py @@ -257,8 +257,8 @@ class BaseJobTestMixin(BaseTestMixin): # Each user has his/her own set of credentials. from awx.main.tests.data.ssh import (TEST_SSH_KEY_DATA, - TEST_SSH_KEY_DATA_LOCKED, - TEST_SSH_KEY_DATA_UNLOCK) + TEST_SSH_KEY_DATA_LOCKED, + TEST_SSH_KEY_DATA_UNLOCK) self.cred_sue = self.user_sue.credentials.create( username='sue', password=TEST_SSH_KEY_DATA, diff --git a/awx/main/utils.py b/awx/main/utils.py index 5b9b7a1f46..110df9a5fd 100644 --- a/awx/main/utils.py +++ b/awx/main/utils.py @@ -20,7 +20,6 @@ import tempfile from rest_framework.exceptions import ParseError, PermissionDenied from django.utils.encoding import smart_str from django.core.urlresolvers import reverse -from django.core.exceptions import ValidationError # PyCrypto from Crypto.Cipher import AES diff --git a/requirements/requirements_jenkins.txt b/requirements/requirements_jenkins.txt index 8ccdb6c3a1..7ea9c8642f 100644 --- a/requirements/requirements_jenkins.txt +++ b/requirements/requirements_jenkins.txt @@ -9,3 +9,7 @@ pylint flake8 distribute==0.7.3 unittest2 +pytest +pytest-cov +pytest-django +pytest-pythonpath diff --git a/tools/docker-compose/Dockerfile b/tools/docker-compose/Dockerfile index e2e57fd4a1..b4a25a78cc 100644 --- a/tools/docker-compose/Dockerfile +++ b/tools/docker-compose/Dockerfile @@ -12,10 +12,7 @@ RUN echo "deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-or RUN apt-get update RUN apt-get install -y openssh-server ansible mg vim tmux git mercurial subversion python-dev python-psycopg2 make postgresql-client libpq-dev nodejs python-psutil libxml2-dev libxslt-dev lib32z1-dev libsasl2-dev libldap2-dev libffi-dev libzmq-dev proot python-pip libxmlsec1-dev swig redis-server && rm -rf /var/lib/apt/lists/* RUN pip install flake8 -RUN pip install pytest -RUN pip install pytest-pythonpath -RUN pip install pytest-django -RUN pip install pytest-cov +RUN pip install pytest pytest-pythonpath pytest-django pytest-cov RUN /usr/bin/ssh-keygen -q -t rsa -N "" -f /root/.ssh/id_rsa RUN mkdir -p /etc/tower RUN mkdir -p /data/db From 320a5b77762c8b527e7ff98b7670c07c0ecee434 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Fri, 29 Jan 2016 10:19:37 -0500 Subject: [PATCH 5/7] fixing tests that use inventory data --- awx/main/tests/functional/commands/commands_monolithic.py | 8 ++++---- awx/main/tests/functional/scripts.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/awx/main/tests/functional/commands/commands_monolithic.py b/awx/main/tests/functional/commands/commands_monolithic.py index 13dae57177..af4916e42d 100644 --- a/awx/main/tests/functional/commands/commands_monolithic.py +++ b/awx/main/tests/functional/commands/commands_monolithic.py @@ -1014,7 +1014,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): parts.query, parts.fragment]) os.environ.setdefault('REST_API_URL', rest_api_url) os.environ['INVENTORY_ID'] = str(old_inv.pk) - source = os.path.join(os.path.dirname(__file__), '..', '..', '..', 'plugins', + source = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', 'plugins', 'inventory', 'awxrest.py') result, stdout, stderr = self.run_command('inventory_import', inventory_id=new_inv.pk, @@ -1051,7 +1051,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): new_inv = self.organizations[0].inventories.create(name='newec2') self.assertEqual(new_inv.hosts.count(), 0) self.assertEqual(new_inv.groups.count(), 0) - os.chdir(os.path.join(os.path.dirname(__file__), '..', 'data')) + os.chdir(os.path.join(os.path.dirname(__file__), '..', '..', 'data')) inv_file = 'large_ec2_inventory.py' result, stdout, stderr = self.run_command('inventory_import', inventory_id=new_inv.pk, @@ -1072,7 +1072,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): new_inv = self.organizations[0].inventories.create(name='splunk') self.assertEqual(new_inv.hosts.count(), 0) self.assertEqual(new_inv.groups.count(), 0) - inv_file = os.path.join(os.path.dirname(__file__), '..', 'data', + inv_file = os.path.join(os.path.dirname(__file__), '..', '..', 'data', 'splunk_inventory.py') result, stdout, stderr = self.run_command('inventory_import', inventory_id=new_inv.pk, @@ -1095,7 +1095,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): def _check_largeinv_import(self, new_inv, nhosts, nhosts_inactive=0): self._start_time = time.time() - inv_file = os.path.join(os.path.dirname(__file__), '..', 'data', 'largeinv.py') + inv_file = os.path.join(os.path.dirname(__file__), '..', '..', 'data', 'largeinv.py') ngroups = self._get_ngroups_for_nhosts(nhosts) os.environ['NHOSTS'] = str(nhosts) result, stdout, stderr = self.run_command('inventory_import', diff --git a/awx/main/tests/functional/scripts.py b/awx/main/tests/functional/scripts.py index bdd81a7f7e..cdf6758921 100644 --- a/awx/main/tests/functional/scripts.py +++ b/awx/main/tests/functional/scripts.py @@ -130,7 +130,7 @@ class InventoryScriptTest(BaseScriptTest): os.environ.setdefault('REST_API_URL', rest_api_url) #os.environ.setdefault('REST_API_TOKEN', # self.super_django_user.auth_token.key) - name = os.path.join(os.path.dirname(__file__), '..', '..', 'plugins', + name = os.path.join(os.path.dirname(__file__), '..', '..', '..', 'plugins', 'inventory', 'awxrest.py') return self.run_script(name, *args, **options) From a44318f0cdfa706a04b3372db52f2cfb4106d0bf Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Mon, 1 Feb 2016 18:17:23 -0500 Subject: [PATCH 6/7] fixed check_license to work with py.test --- awx/main/access.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/awx/main/access.py b/awx/main/access.py index de2f69a914..ad87506ab2 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -149,7 +149,7 @@ class BaseAccess(object): def check_license(self, add_host=False, feature=None, check_expiration=True): reader = TaskSerializer() validation_info = reader.from_database() - if ('test' in sys.argv or 'jenkins' in sys.argv) and not os.environ.get('SKIP_LICENSE_FIXUP_FOR_TEST', ''): + if ('test' in sys.argv or 'py.test' in sys.argv[0] or 'jenkins' in sys.argv) and not os.environ.get('SKIP_LICENSE_FIXUP_FOR_TEST', ''): validation_info['free_instances'] = 99999999 validation_info['time_remaining'] = 99999999 validation_info['grace_period_remaining'] = 99999999 @@ -912,8 +912,8 @@ class JobTemplateAccess(BaseAccess): ) return base_qs.filter( - Q(id__in=org_admin_ids) | - Q(id__in=perm_deploy_ids) | + Q(id__in=org_admin_ids) | + Q(id__in=perm_deploy_ids) | Q(id__in=perm_check_ids) ) @@ -926,7 +926,7 @@ class JobTemplateAccess(BaseAccess): a user can create a job template if they are a superuser, an org admin of any org that the project is a member, or if they have user or team based permissions tying the project to the inventory source for the - given action as well as the 'create' deploy permission. + given action as well as the 'create' deploy permission. Users who are able to create deploy jobs can also run normal and check (dry run) jobs. ''' if not data or '_method' in data: # So the browseable API will work? @@ -1126,8 +1126,8 @@ class JobAccess(BaseAccess): ) return base_qs.filter( - Q(id__in=org_admin_ids) | - Q(id__in=perm_deploy_ids) | + Q(id__in=org_admin_ids) | + Q(id__in=perm_deploy_ids) | Q(id__in=perm_check_ids) ) @@ -1367,9 +1367,9 @@ class UnifiedJobTemplateAccess(BaseAccess): projects without SCM configured or inventory sources without a cloud source. ''' - + model = UnifiedJobTemplate - + def get_queryset(self): qs = self.model.objects.filter(active=True).distinct() project_qs = self.user.get_queryset(Project).filter(scm_type__in=[s[0] for s in Project.SCM_TYPE_CHOICES]) From f12ab22591b3c21cfbb5e2db6c4f8ea79ff7baf0 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Tue, 2 Feb 2016 09:13:16 -0500 Subject: [PATCH 7/7] functional -> old --- awx/main/tests/old/README.md | 7 +++++++ awx/main/tests/{functional => old}/activity_stream.py | 0 awx/main/tests/{functional => old}/ad_hoc.py | 0 awx/main/tests/{functional => old}/commands/age_deleted.py | 0 .../tests/{functional => old}/commands/cleanup_facts.py | 0 .../tests/{functional => old}/commands/command_base.py | 0 .../{functional => old}/commands/commands_monolithic.py | 0 .../tests/{functional => old}/commands/remove_instance.py | 0 .../commands/run_fact_cache_receiver.py | 0 .../{functional => old}/commands/run_socketio_service.py | 0 .../tests/{functional => old}/commands/update_password.py | 0 awx/main/tests/{functional => old}/fact/fact_api.py | 0 awx/main/tests/{functional => old}/ha.py | 0 awx/main/tests/{functional => old}/inventory.py | 0 awx/main/tests/{functional => old}/jobs/job_launch.py | 0 awx/main/tests/{functional => old}/jobs/job_relaunch.py | 0 awx/main/tests/{functional => old}/jobs/jobs_monolithic.py | 0 awx/main/tests/{functional => old}/jobs/start_cancel.py | 0 awx/main/tests/{functional => old}/jobs/survey_password.py | 0 awx/main/tests/{functional => old}/licenses.py | 0 awx/main/tests/{functional => old}/organizations.py | 0 awx/main/tests/{functional => old}/projects.py | 0 awx/main/tests/{functional => old}/redact.py | 0 awx/main/tests/{functional => old}/schedules.py | 0 awx/main/tests/{functional => old}/scripts.py | 0 awx/main/tests/{functional => old}/settings.py | 0 awx/main/tests/{functional => old}/tasks.py | 0 awx/main/tests/{functional => old}/unified_jobs.py | 0 awx/main/tests/{functional => old}/users.py | 0 awx/main/tests/{functional => old}/views.py | 0 30 files changed, 7 insertions(+) create mode 100644 awx/main/tests/old/README.md rename awx/main/tests/{functional => old}/activity_stream.py (100%) rename awx/main/tests/{functional => old}/ad_hoc.py (100%) rename awx/main/tests/{functional => old}/commands/age_deleted.py (100%) rename awx/main/tests/{functional => old}/commands/cleanup_facts.py (100%) rename awx/main/tests/{functional => old}/commands/command_base.py (100%) rename awx/main/tests/{functional => old}/commands/commands_monolithic.py (100%) rename awx/main/tests/{functional => old}/commands/remove_instance.py (100%) rename awx/main/tests/{functional => old}/commands/run_fact_cache_receiver.py (100%) rename awx/main/tests/{functional => old}/commands/run_socketio_service.py (100%) rename awx/main/tests/{functional => old}/commands/update_password.py (100%) rename awx/main/tests/{functional => old}/fact/fact_api.py (100%) rename awx/main/tests/{functional => old}/ha.py (100%) rename awx/main/tests/{functional => old}/inventory.py (100%) rename awx/main/tests/{functional => old}/jobs/job_launch.py (100%) rename awx/main/tests/{functional => old}/jobs/job_relaunch.py (100%) rename awx/main/tests/{functional => old}/jobs/jobs_monolithic.py (100%) rename awx/main/tests/{functional => old}/jobs/start_cancel.py (100%) rename awx/main/tests/{functional => old}/jobs/survey_password.py (100%) rename awx/main/tests/{functional => old}/licenses.py (100%) rename awx/main/tests/{functional => old}/organizations.py (100%) rename awx/main/tests/{functional => old}/projects.py (100%) rename awx/main/tests/{functional => old}/redact.py (100%) rename awx/main/tests/{functional => old}/schedules.py (100%) rename awx/main/tests/{functional => old}/scripts.py (100%) rename awx/main/tests/{functional => old}/settings.py (100%) rename awx/main/tests/{functional => old}/tasks.py (100%) rename awx/main/tests/{functional => old}/unified_jobs.py (100%) rename awx/main/tests/{functional => old}/users.py (100%) rename awx/main/tests/{functional => old}/views.py (100%) diff --git a/awx/main/tests/old/README.md b/awx/main/tests/old/README.md new file mode 100644 index 0000000000..92582d890d --- /dev/null +++ b/awx/main/tests/old/README.md @@ -0,0 +1,7 @@ +Old Tests +========= +This are the old django.TestCase / unittest.TestCase tests for Tower. + +No new tests should be added to this folder. Overtime, we will be refactoring +tests out of this folder as py.test tests and into their respective functional +and unit folders. diff --git a/awx/main/tests/functional/activity_stream.py b/awx/main/tests/old/activity_stream.py similarity index 100% rename from awx/main/tests/functional/activity_stream.py rename to awx/main/tests/old/activity_stream.py diff --git a/awx/main/tests/functional/ad_hoc.py b/awx/main/tests/old/ad_hoc.py similarity index 100% rename from awx/main/tests/functional/ad_hoc.py rename to awx/main/tests/old/ad_hoc.py diff --git a/awx/main/tests/functional/commands/age_deleted.py b/awx/main/tests/old/commands/age_deleted.py similarity index 100% rename from awx/main/tests/functional/commands/age_deleted.py rename to awx/main/tests/old/commands/age_deleted.py diff --git a/awx/main/tests/functional/commands/cleanup_facts.py b/awx/main/tests/old/commands/cleanup_facts.py similarity index 100% rename from awx/main/tests/functional/commands/cleanup_facts.py rename to awx/main/tests/old/commands/cleanup_facts.py diff --git a/awx/main/tests/functional/commands/command_base.py b/awx/main/tests/old/commands/command_base.py similarity index 100% rename from awx/main/tests/functional/commands/command_base.py rename to awx/main/tests/old/commands/command_base.py diff --git a/awx/main/tests/functional/commands/commands_monolithic.py b/awx/main/tests/old/commands/commands_monolithic.py similarity index 100% rename from awx/main/tests/functional/commands/commands_monolithic.py rename to awx/main/tests/old/commands/commands_monolithic.py diff --git a/awx/main/tests/functional/commands/remove_instance.py b/awx/main/tests/old/commands/remove_instance.py similarity index 100% rename from awx/main/tests/functional/commands/remove_instance.py rename to awx/main/tests/old/commands/remove_instance.py diff --git a/awx/main/tests/functional/commands/run_fact_cache_receiver.py b/awx/main/tests/old/commands/run_fact_cache_receiver.py similarity index 100% rename from awx/main/tests/functional/commands/run_fact_cache_receiver.py rename to awx/main/tests/old/commands/run_fact_cache_receiver.py diff --git a/awx/main/tests/functional/commands/run_socketio_service.py b/awx/main/tests/old/commands/run_socketio_service.py similarity index 100% rename from awx/main/tests/functional/commands/run_socketio_service.py rename to awx/main/tests/old/commands/run_socketio_service.py diff --git a/awx/main/tests/functional/commands/update_password.py b/awx/main/tests/old/commands/update_password.py similarity index 100% rename from awx/main/tests/functional/commands/update_password.py rename to awx/main/tests/old/commands/update_password.py diff --git a/awx/main/tests/functional/fact/fact_api.py b/awx/main/tests/old/fact/fact_api.py similarity index 100% rename from awx/main/tests/functional/fact/fact_api.py rename to awx/main/tests/old/fact/fact_api.py diff --git a/awx/main/tests/functional/ha.py b/awx/main/tests/old/ha.py similarity index 100% rename from awx/main/tests/functional/ha.py rename to awx/main/tests/old/ha.py diff --git a/awx/main/tests/functional/inventory.py b/awx/main/tests/old/inventory.py similarity index 100% rename from awx/main/tests/functional/inventory.py rename to awx/main/tests/old/inventory.py diff --git a/awx/main/tests/functional/jobs/job_launch.py b/awx/main/tests/old/jobs/job_launch.py similarity index 100% rename from awx/main/tests/functional/jobs/job_launch.py rename to awx/main/tests/old/jobs/job_launch.py diff --git a/awx/main/tests/functional/jobs/job_relaunch.py b/awx/main/tests/old/jobs/job_relaunch.py similarity index 100% rename from awx/main/tests/functional/jobs/job_relaunch.py rename to awx/main/tests/old/jobs/job_relaunch.py diff --git a/awx/main/tests/functional/jobs/jobs_monolithic.py b/awx/main/tests/old/jobs/jobs_monolithic.py similarity index 100% rename from awx/main/tests/functional/jobs/jobs_monolithic.py rename to awx/main/tests/old/jobs/jobs_monolithic.py diff --git a/awx/main/tests/functional/jobs/start_cancel.py b/awx/main/tests/old/jobs/start_cancel.py similarity index 100% rename from awx/main/tests/functional/jobs/start_cancel.py rename to awx/main/tests/old/jobs/start_cancel.py diff --git a/awx/main/tests/functional/jobs/survey_password.py b/awx/main/tests/old/jobs/survey_password.py similarity index 100% rename from awx/main/tests/functional/jobs/survey_password.py rename to awx/main/tests/old/jobs/survey_password.py diff --git a/awx/main/tests/functional/licenses.py b/awx/main/tests/old/licenses.py similarity index 100% rename from awx/main/tests/functional/licenses.py rename to awx/main/tests/old/licenses.py diff --git a/awx/main/tests/functional/organizations.py b/awx/main/tests/old/organizations.py similarity index 100% rename from awx/main/tests/functional/organizations.py rename to awx/main/tests/old/organizations.py diff --git a/awx/main/tests/functional/projects.py b/awx/main/tests/old/projects.py similarity index 100% rename from awx/main/tests/functional/projects.py rename to awx/main/tests/old/projects.py diff --git a/awx/main/tests/functional/redact.py b/awx/main/tests/old/redact.py similarity index 100% rename from awx/main/tests/functional/redact.py rename to awx/main/tests/old/redact.py diff --git a/awx/main/tests/functional/schedules.py b/awx/main/tests/old/schedules.py similarity index 100% rename from awx/main/tests/functional/schedules.py rename to awx/main/tests/old/schedules.py diff --git a/awx/main/tests/functional/scripts.py b/awx/main/tests/old/scripts.py similarity index 100% rename from awx/main/tests/functional/scripts.py rename to awx/main/tests/old/scripts.py diff --git a/awx/main/tests/functional/settings.py b/awx/main/tests/old/settings.py similarity index 100% rename from awx/main/tests/functional/settings.py rename to awx/main/tests/old/settings.py diff --git a/awx/main/tests/functional/tasks.py b/awx/main/tests/old/tasks.py similarity index 100% rename from awx/main/tests/functional/tasks.py rename to awx/main/tests/old/tasks.py diff --git a/awx/main/tests/functional/unified_jobs.py b/awx/main/tests/old/unified_jobs.py similarity index 100% rename from awx/main/tests/functional/unified_jobs.py rename to awx/main/tests/old/unified_jobs.py diff --git a/awx/main/tests/functional/users.py b/awx/main/tests/old/users.py similarity index 100% rename from awx/main/tests/functional/users.py rename to awx/main/tests/old/users.py diff --git a/awx/main/tests/functional/views.py b/awx/main/tests/old/views.py similarity index 100% rename from awx/main/tests/functional/views.py rename to awx/main/tests/old/views.py