diff --git a/awx/main/tests/functional/test_named_url.py b/awx/main/tests/functional/test_named_url.py new file mode 100644 index 0000000000..593822c806 --- /dev/null +++ b/awx/main/tests/functional/test_named_url.py @@ -0,0 +1,190 @@ +import pytest + +from django.core.exceptions import ImproperlyConfigured + +from awx.api.versioning import reverse +from awx.main.middleware import URLModificationMiddleware +from awx.main.models import * # noqa + + +@pytest.fixture(scope='function', autouse=True) +def init_url_modification_middleware(): + # In real-world scenario, named url graph structure is populated by __init__ + # of URLModificationMiddleware. The way Django bootstraps ensures the initialization + # will happen *once and only once*, while the number of initialization is uncontrollable + # in unit test environment. So it is wrapped by try-except block to mute any + # unwanted exceptions. + try: + URLModificationMiddleware() + except ImproperlyConfigured: + pass + + +@pytest.mark.django_db +def test_user(get, admin_user): + test_user = User.objects.create(username='test_user', password='test_user', is_superuser=False) + url = reverse('api:user_detail', kwargs={'pk': test_user.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_user/') + + +@pytest.mark.django_db +def test_team(get, admin_user): + test_org = Organization.objects.create(name='test_org') + test_team = test_org.teams.create(name='test_team') + url = reverse('api:team_detail', kwargs={'pk': test_team.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_team++test_org/') + + +@pytest.mark.django_db +def test_organization(get, admin_user): + test_org = Organization.objects.create(name='test_org') + url = reverse('api:organization_detail', kwargs={'pk': test_org.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_org/') + + +@pytest.mark.django_db +def test_job_template(get, admin_user): + test_jt = JobTemplate.objects.create(name='test_jt') + url = reverse('api:job_template_detail', kwargs={'pk': test_jt.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_jt/') + + +@pytest.mark.django_db +def test_workflow_job_template(get, admin_user): + test_wfjt = WorkflowJobTemplate.objects.create(name='test_wfjt') + url = reverse('api:workflow_job_template_detail', kwargs={'pk': test_wfjt.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_wfjt++/') + test_org = Organization.objects.create(name='test_org') + test_wfjt.organization = test_org + test_wfjt.save() + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_wfjt++test_org/') + + +@pytest.mark.django_db +def test_label(get, admin_user): + test_org = Organization.objects.create(name='test_org') + test_label = test_org.labels.create(name='test_label') + url = reverse('api:label_detail', kwargs={'pk': test_label.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_label++test_org/') + + +@pytest.mark.django_db +def test_project(get, admin_user): + test_proj = Project.objects.create(name='test_proj') + url = reverse('api:project_detail', kwargs={'pk': test_proj.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_proj++/') + test_org = Organization.objects.create(name='test_org') + test_proj.organization = test_org + test_proj.save() + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_proj++test_org/') + + +@pytest.mark.django_db +def test_notification_template(get, admin_user): + test_notification_template = NotificationTemplate.objects.create( + name='test_note', notification_type='slack', + notification_configuration=dict(channels=["Foo", "Bar"], token="token") + ) + url = reverse('api:notification_template_detail', kwargs={'pk': test_notification_template.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_note++/') + test_org = Organization.objects.create(name='test_org') + test_notification_template.organization = test_org + test_notification_template.save() + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_note++test_org/') + + +@pytest.mark.django_db +def test_instance(get, admin_user): + test_instance = Instance.objects.create( + uuid=settings.SYSTEM_UUID, hostname="localhost", capacity=100 + ) + url = reverse('api:instance_detail', kwargs={'pk': test_instance.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/localhost/') + + +@pytest.mark.django_db +def test_instance_group(get, admin_user): + test_instance_group = InstanceGroup.objects.create(name='Tower') + url = reverse('api:instance_group_detail', kwargs={'pk': test_instance_group.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/Tower/') + + +@pytest.mark.django_db +def test_inventory(get, admin_user): + test_inv = Inventory.objects.create(name='test_inv') + url = reverse('api:inventory_detail', kwargs={'pk': test_inv.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_inv++/') + test_org = Organization.objects.create(name='test_org') + test_inv.organization = test_org + test_inv.save() + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_inv++test_org/') + + +@pytest.mark.django_db +def test_host(get, admin_user): + test_org = Organization.objects.create(name='test_org') + test_inv = Inventory.objects.create(name='test_inv', organization=test_org) + test_host = Host.objects.create(name='test_host', inventory=test_inv) + url = reverse('api:host_detail', kwargs={'pk': test_host.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_host++test_inv++test_org/') + + +@pytest.mark.django_db +def test_group(get, admin_user): + test_org = Organization.objects.create(name='test_org') + test_inv = Inventory.objects.create(name='test_inv', organization=test_org) + test_group = Group.objects.create(name='test_group', inventory=test_inv) + url = reverse('api:group_detail', kwargs={'pk': test_group.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_group++test_inv++test_org/') + + +@pytest.mark.django_db +def test_inventory_source(get, admin_user): + test_org = Organization.objects.create(name='test_org') + test_inv = Inventory.objects.create(name='test_inv', organization=test_org) + test_source = InventorySource.objects.create(name='test_source', inventory=test_inv) + url = reverse('api:inventory_source_detail', kwargs={'pk': test_source.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_source++test_inv++test_org/') + test_source.inventory = None + test_source.save() + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_source++/') + + +@pytest.mark.django_db +def test_inventory_script(get, admin_user): + test_script = CustomInventoryScript.objects.create(name='test_script') + url = reverse('api:inventory_script_detail', kwargs={'pk': test_script.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_script++/') + test_org = Organization.objects.create(name='test_org') + test_script.organization = test_org + test_script.save() + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_script++test_org/') + + +@pytest.mark.django_db +def test_credential(get, admin_user, credentialtype_ssh): + test_cred = Credential.objects.create(name='test_cred', credential_type=credentialtype_ssh) + url = reverse('api:credential_detail', kwargs={'pk': test_cred.pk}) + response = get(url, user=admin_user, expect=200) + assert response.data['related']['named_url'].endswith('/test_cred++Machine+ssh++/') diff --git a/awx/main/tests/unit/utils/test_named_url_graph.py b/awx/main/tests/unit/utils/test_named_url_graph.py deleted file mode 100644 index fd9d4c71eb..0000000000 --- a/awx/main/tests/unit/utils/test_named_url_graph.py +++ /dev/null @@ -1,505 +0,0 @@ -# -*- coding: utf-8 -*- -import pytest -import mock -import random - -from django.db import models -from django.contrib.contenttypes.models import ContentType - -from awx.main.utils.named_url_graph import generate_graph -from awx.main.models.base import CommonModel, CommonModelNameNotUnique - - -@pytest.fixture -def common_model_class_mock(): - def class_generator(plural): - class ModelClass(CommonModel): - - class Meta: - verbose_name_plural = plural - pass - return ModelClass - return class_generator - - -@pytest.fixture -def common_model_name_not_unique_class_mock(): - def class_generator(ut, fk_a_obj, fk_b_obj, plural, soft_ut=[]): - class ModelClass(CommonModelNameNotUnique): - - SOFT_UNIQUE_TOGETHER = soft_ut - - class Meta: - unique_together = ut - verbose_name_plural = plural - - fk_a = models.ForeignKey( - fk_a_obj, - null=True, - on_delete=models.CASCADE, - ) - fk_b = models.ForeignKey( - fk_b_obj, - null=True, - on_delete=models.CASCADE, - ) - str_with_choices_a = models.CharField( - choices=("foo", "bar") - ) - str_with_choices_b = models.CharField( - choices=("foo", "bar") - ) - integer = models.IntegerField() - str_without_choices = models.CharField() - return ModelClass - return class_generator - - -@pytest.fixture -def settings_mock(): - class settings_class(object): - pass - return settings_class - - -@pytest.mark.parametrize("unique_together", [ - ("name", "str_without_choices"), - ("name", "str_with_choices_a", 'str_without_choices'), - ("name", "str_with_choices_a", 'integer'), - ("name", "fk_a"), - ("name", "fk_b"), -]) -def test_invalid_generation(common_model_name_not_unique_class_mock, - common_model_class_mock, settings_mock, unique_together): - models = [] - valid_parent_out_of_range = common_model_class_mock('valid_parent_out_of_range') - invalid_parent = common_model_name_not_unique_class_mock( - ('integer', 'name'), - valid_parent_out_of_range, - valid_parent_out_of_range, - 'invalid_parent', - ) - models.append(invalid_parent) - model_1 = common_model_name_not_unique_class_mock( - unique_together, - invalid_parent, - valid_parent_out_of_range, - 'model_1' - ) - models.append(model_1) - - random.shuffle(models) - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph(models) - assert not settings_mock.NAMED_URL_FORMATS - - -def test_soft_unique_together_being_included(common_model_name_not_unique_class_mock, - common_model_class_mock, settings_mock): - models = [] - model_1 = common_model_class_mock('model_1') - models.append(model_1) - model_2 = common_model_name_not_unique_class_mock( - (), - model_1, - model_1, - 'model_2', - soft_ut=[('name', 'fk_a')] - ) - models.append(model_2) - - random.shuffle(models) - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph(models) - assert settings_mock.NAMED_URL_GRAPH[model_1].model == model_1 - assert settings_mock.NAMED_URL_GRAPH[model_1].fields == ('name',) - assert settings_mock.NAMED_URL_GRAPH[model_1].adj_list == [] - - assert settings_mock.NAMED_URL_GRAPH[model_2].model == model_2 - assert settings_mock.NAMED_URL_GRAPH[model_2].fields == ('name',) - assert zip(*settings_mock.NAMED_URL_GRAPH[model_2].adj_list)[0] == ('fk_a',) - assert [x.model for x in zip(*settings_mock.NAMED_URL_GRAPH[model_2].adj_list)[1]] == [model_1] - - -def test_chain_generation(common_model_class_mock, common_model_name_not_unique_class_mock, settings_mock): - """ - Graph topology: - - model_3 - | - | fk_a - | - V - model_2 - | - | fk_a - | - V - model_1 - """ - models = [] - model_1 = common_model_class_mock('model_1') - models.append(model_1) - model_2 = common_model_name_not_unique_class_mock( - ('name', 'fk_a'), - model_1, - model_1, - 'model_2', - ) - models.append(model_2) - model_3 = common_model_name_not_unique_class_mock( - ('name', 'fk_a'), - model_2, - model_1, - 'model_3', - ) - models.append(model_3) - - random.shuffle(models) - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph(models) - - assert settings_mock.NAMED_URL_GRAPH[model_1].model == model_1 - assert settings_mock.NAMED_URL_GRAPH[model_1].fields == ('name',) - assert settings_mock.NAMED_URL_GRAPH[model_1].adj_list == [] - - assert settings_mock.NAMED_URL_GRAPH[model_2].model == model_2 - assert settings_mock.NAMED_URL_GRAPH[model_2].fields == ('name',) - assert zip(*settings_mock.NAMED_URL_GRAPH[model_2].adj_list)[0] == ('fk_a',) - assert [x.model for x in zip(*settings_mock.NAMED_URL_GRAPH[model_2].adj_list)[1]] == [model_1] - - assert settings_mock.NAMED_URL_GRAPH[model_3].model == model_3 - assert settings_mock.NAMED_URL_GRAPH[model_3].fields == ('name',) - assert zip(*settings_mock.NAMED_URL_GRAPH[model_3].adj_list)[0] == ('fk_a',) - assert [x.model for x in zip(*settings_mock.NAMED_URL_GRAPH[model_3].adj_list)[1]] == [model_2] - - -@pytest.mark.xfail(reason="new dynamic model in django 1.11") -def test_graph_generation(common_model_class_mock, common_model_name_not_unique_class_mock, settings_mock): - """ - Graph topology: - - model_1 - /\ - fk_a / \ fk_b - / \ - V V - model_2_1 model_2_2 - /\fk_b /\ - fk_a / \ / \ fk_b - / \ /fk_a\ - V V V - model_3_1 model_3_2 model_3_3 - """ - models = [] - model_3_1 = common_model_class_mock('model_3_1') - models.append(model_3_1) - model_3_2 = common_model_class_mock('model_3_2') - models.append(model_3_2) - model_3_3 = common_model_class_mock('model_3_3') - models.append(model_3_3) - model_2_1 = common_model_name_not_unique_class_mock( - ('name', 'fk_b', 'fk_a'), - model_3_1, - model_3_2, - 'model_2_1', - ) - models.append(model_2_1) - model_2_2 = common_model_name_not_unique_class_mock( - ('name', 'fk_b', 'fk_a'), - model_3_2, - model_3_3, - 'model_2_2', - ) - models.append(model_2_2) - model_1 = common_model_name_not_unique_class_mock( - ('name', 'fk_a', 'fk_b'), - model_2_1, - model_2_2, - 'model_1', - ) - models.append(model_1) - random.shuffle(models) - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph(models) - - assert settings_mock.NAMED_URL_GRAPH[model_1].model == model_1 - assert settings_mock.NAMED_URL_GRAPH[model_1].fields == ('name',) - assert zip(*settings_mock.NAMED_URL_GRAPH[model_1].adj_list)[0] == ('fk_a', 'fk_b') - assert [x.model for x in zip(*settings_mock.NAMED_URL_GRAPH[model_1].adj_list)[1]] == [model_2_1, model_2_2] - - assert settings_mock.NAMED_URL_GRAPH[model_2_1].model == model_2_1 - assert settings_mock.NAMED_URL_GRAPH[model_2_1].fields == ('name',) - assert zip(*settings_mock.NAMED_URL_GRAPH[model_2_1].adj_list)[0] == ('fk_a', 'fk_b') - assert [x.model for x in zip(*settings_mock.NAMED_URL_GRAPH[model_2_1].adj_list)[1]] == [model_3_1, model_3_2] - - assert settings_mock.NAMED_URL_GRAPH[model_2_2].model == model_2_2 - assert settings_mock.NAMED_URL_GRAPH[model_2_2].fields == ('name',) - assert zip(*settings_mock.NAMED_URL_GRAPH[model_2_2].adj_list)[0] == ('fk_a', 'fk_b') - assert [x.model for x in zip(*settings_mock.NAMED_URL_GRAPH[model_2_2].adj_list)[1]] == [model_3_2, model_3_3] - - assert settings_mock.NAMED_URL_GRAPH[model_3_1].model == model_3_1 - assert settings_mock.NAMED_URL_GRAPH[model_3_1].fields == ('name',) - assert settings_mock.NAMED_URL_GRAPH[model_3_1].adj_list == [] - - assert settings_mock.NAMED_URL_GRAPH[model_3_2].model == model_3_2 - assert settings_mock.NAMED_URL_GRAPH[model_3_2].fields == ('name',) - assert settings_mock.NAMED_URL_GRAPH[model_3_2].adj_list == [] - - assert settings_mock.NAMED_URL_GRAPH[model_3_3].model == model_3_3 - assert settings_mock.NAMED_URL_GRAPH[model_3_3].fields == ('name',) - assert settings_mock.NAMED_URL_GRAPH[model_3_3].adj_list == [] - - -@pytest.mark.xfail(reason="new dynamic model in django 1.11") -def test_largest_graph_is_generated(common_model_name_not_unique_class_mock, - common_model_class_mock, settings_mock): - """ - Graph topology: - - model_1 - | - | fk_a - | - V - model_2 - / \ - fk_b / \ fk_a - / \ - V V - valid_model invalid_model - """ - models = [] - valid_model = common_model_class_mock('valid_model') - models.append(valid_model) - invalid_model = common_model_class_mock('invalid_model') - model_2 = common_model_name_not_unique_class_mock( - (('name', 'fk_a'), ('name', 'fk_b')), - invalid_model, - valid_model, - 'model_2', - ) - models.append(model_2) - model_1 = common_model_name_not_unique_class_mock( - ('name', 'fk_a'), - model_2, - model_2, - 'model_1', - ) - models.append(model_1) - - random.shuffle(models) - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph(models) - - assert settings_mock.NAMED_URL_GRAPH[model_1].model == model_1 - assert settings_mock.NAMED_URL_GRAPH[model_1].fields == ('name',) - assert zip(*settings_mock.NAMED_URL_GRAPH[model_1].adj_list)[0] == ('fk_a',) - assert [x.model for x in zip(*settings_mock.NAMED_URL_GRAPH[model_1].adj_list)[1]] == [model_2] - - assert settings_mock.NAMED_URL_GRAPH[model_2].model == model_2 - assert settings_mock.NAMED_URL_GRAPH[model_2].fields == ('name',) - assert zip(*settings_mock.NAMED_URL_GRAPH[model_2].adj_list)[0] == ('fk_b',) - assert [x.model for x in zip(*settings_mock.NAMED_URL_GRAPH[model_2].adj_list)[1]] == [valid_model] - - assert settings_mock.NAMED_URL_GRAPH[valid_model].model == valid_model - assert settings_mock.NAMED_URL_GRAPH[valid_model].fields == ('name',) - assert settings_mock.NAMED_URL_GRAPH[valid_model].adj_list == [] - - assert invalid_model not in settings_mock.NAMED_URL_GRAPH - - -def test_contenttype_being_ignored(common_model_name_not_unique_class_mock, settings_mock): - model = common_model_name_not_unique_class_mock( - ('name', 'fk_a'), - ContentType, - ContentType, - 'model', - ) - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph([model]) - assert settings_mock.NAMED_URL_GRAPH[model].model == model - assert settings_mock.NAMED_URL_GRAPH[model].fields == ('name',) - assert settings_mock.NAMED_URL_GRAPH[model].adj_list == [] - - -@pytest.mark.xfail(reason="new dynamic model in django 1.11") -@pytest.mark.parametrize('input_, output', [ - ('alice++bob+foo++cat++dog', { - 'name': 'alice', - 'fk_a__name': 'bob', - 'fk_a__str_with_choices_a': 'foo', - 'fk_b__name': 'dog', - 'fk_a__fk_a__name': 'cat', - }), - ('alice++++dog', { - 'name': 'alice', - 'fk_b__name': 'dog', - }), - ('alice++bob+foo++cat++', { - 'name': 'alice', - 'fk_a__name': 'bob', - 'fk_a__str_with_choices_a': 'foo', - 'fk_a__fk_a__name': 'cat', - }), - ('alice++bob+foo++++dog', { - 'name': 'alice', - 'fk_a__name': 'bob', - 'fk_a__str_with_choices_a': 'foo', - 'fk_b__name': 'dog', - }), -]) -def test_populate_named_url_query_kwargs(common_model_name_not_unique_class_mock, - common_model_class_mock, settings_mock, - input_, output): - """ - graph topology: - - model_1 - | \ - fk_a | \ fk_b - | \ - v v - model_2_1 model_2_2 - | - | fk_a - | - v - model_3 - """ - models = [] - model_3 = common_model_class_mock('model_3') - models.append(model_3) - model_2_1 = common_model_name_not_unique_class_mock( - ('name', 'fk_a', 'str_with_choices_a'), - model_3, - model_3, - 'model_2_1', - ) - models.append(model_2_1) - model_2_2 = common_model_class_mock('model_2_2') - models.append(model_2_2) - model_1 = common_model_name_not_unique_class_mock( - ('name', 'fk_a', 'fk_b'), - model_2_1, - model_2_2, - 'model_1', - ) - models.append(model_1) - random.shuffle(models) - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph(models) - kwargs = {} - assert settings_mock.NAMED_URL_GRAPH[model_1].populate_named_url_query_kwargs(kwargs, input_) - assert kwargs == output - - -@pytest.mark.parametrize('input_', [ - '4399', - 'alice-foo', - 'alice--bob', - 'alice-foo--bob--cat', - 'alice-foo--bob-', -]) -def test_populate_named_url_invalid_query_kwargs(common_model_name_not_unique_class_mock, - common_model_class_mock, settings_mock, - input_): - models = [] - model_2 = common_model_class_mock('model_2') - models.append(model_2) - model_1 = common_model_name_not_unique_class_mock( - ('name', 'fk_a', 'str_with_choices_a'), - model_2, - model_2, - 'model_1', - ) - models.append(model_1) - random.shuffle(models) - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph(models) - kwargs = {} - assert not settings_mock.NAMED_URL_GRAPH[model_1].populate_named_url_query_kwargs(kwargs, input_) - - -def test_reserved_uri_char_decoding(common_model_class_mock, settings_mock): - model = common_model_class_mock('model') - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph([model]) - kwargs = {} - settings_mock.NAMED_URL_GRAPH[model].populate_named_url_query_kwargs(kwargs, r"%3B%2F%3F%3A%40%3D%26[+]") - assert kwargs == {'name': ';/?:@=&+'} - - -def test_unicode_decoding(common_model_class_mock, settings_mock): - model = common_model_class_mock('model') - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph([model]) - kwargs = {} - settings_mock.NAMED_URL_GRAPH[model].populate_named_url_query_kwargs( - kwargs, r"%E6%88%91%E4%B8%BA%E6%88%91%E8%9B%A4%E7%BB%AD1s" - ) - assert kwargs == {'name': u'我为我蛤续1s'} - - -@pytest.mark.xfail(reason="new dynamic model in django 1.11") -def test_generate_named_url(common_model_name_not_unique_class_mock, - common_model_class_mock, settings_mock): - """ - graph topology: - - model_1 - | \ - fk_a | \ fk_b - | \ - v v - model_2_1 model_2_2 - | - | fk_a - | - v - model_3 - """ - models = [] - model_3 = common_model_class_mock('model_3') - models.append(model_3) - model_2_1 = common_model_name_not_unique_class_mock( - ('name', 'fk_a', 'str_with_choices_a'), - model_3, - model_3, - 'model_2_1', - ) - models.append(model_2_1) - model_2_2 = common_model_class_mock('model_2_2') - models.append(model_2_2) - model_1 = common_model_name_not_unique_class_mock( - ('name', 'fk_a', 'fk_b'), - model_2_1, - model_2_2, - 'model_1', - ) - models.append(model_1) - random.shuffle(models) - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph(models) - obj_3 = model_3(name='cat') - obj_2_2 = model_2_2(name='dog') - obj_2_1 = model_2_1(name='bob', str_with_choices_a='foo', fk_a=obj_3) - obj_1 = model_1(name='alice', fk_a=obj_2_1, fk_b=obj_2_2) - obj_1.fk_b = None - assert settings_mock.NAMED_URL_GRAPH[model_1].generate_named_url(obj_1) == 'alice++bob+foo++cat++' - obj_1.fk_b = obj_2_2 - assert settings_mock.NAMED_URL_GRAPH[model_1].generate_named_url(obj_1) == 'alice++bob+foo++cat++dog' - obj_2_1.fk_a = None - assert settings_mock.NAMED_URL_GRAPH[model_1].generate_named_url(obj_1) == 'alice++bob+foo++++dog' - obj_1.fk_a = None - assert settings_mock.NAMED_URL_GRAPH[model_1].generate_named_url(obj_1) == 'alice++++dog' - obj_1.fk_b = None - assert settings_mock.NAMED_URL_GRAPH[model_1].generate_named_url(obj_1) == 'alice++++' - - -def test_reserved_uri_char_encoding(common_model_class_mock, settings_mock): - model = common_model_class_mock('model') - with mock.patch('awx.main.utils.named_url_graph.settings', settings_mock): - generate_graph([model]) - obj = model(name=u';/?:@=&+我为我蛤续1s') - assert settings_mock.NAMED_URL_GRAPH[model].generate_named_url(obj) == u"%3B%2F%3F%3A%40%3D%26[+]我为我蛤续1s"