Merge pull request #906 from jangsutsr/refactor_named_url_tests

Refactor named URL unit tests
This commit is contained in:
Aaron Tan
2018-01-04 14:20:27 -05:00
committed by GitHub
2 changed files with 190 additions and 505 deletions

View File

@@ -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++/')

View File

@@ -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"