horizon: Move test files to match corresponding module structure
blueprint relocation-test-codes The current test file structure in horizon looks random. This is the first patch of blueprint relocation-test-codes. This commit proposes to change the structure to match the structure of test targets (i.e., main codes). More concretely, a unit test file for {TOP_MODULE}/{MODULE}/{FILENAME}.py will be located at {TOP_MODULE}/test/units/{MODULE}/test_{FILENAME}.py. When a module is test as a whole, a location of a corresponding test file will be {TOP_MODULE}/test/units/{MODULE}/test_{MODULE}.py. This clarifies locations of test files. In addition, this commit changes the base class of utils.test_secret_key from horizon.test.helper.TestCase to unittest.TestCase. This is because calling secret_key.generate_key() somehow interferes django.test.TestCase (which is a parent class of horizon.test.helper.TestCase). Change-Id: I48b9c317645e63a5819c52512b30f25969574817
This commit is contained in:
parent
8bb0d6be83
commit
493a943e6e
|
@ -1,229 +0,0 @@
|
|||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django import shortcuts
|
||||
|
||||
from horizon import forms
|
||||
from horizon.test import helpers as test
|
||||
|
||||
|
||||
class FormMixinTests(test.TestCase):
|
||||
|
||||
def _prepare_view(self, cls, request_headers, *args, **kwargs):
|
||||
req = self.factory.get('/my_url/', **request_headers)
|
||||
req.user = self.user
|
||||
view = cls()
|
||||
view.request = req
|
||||
view.args = args
|
||||
view.kwargs = kwargs
|
||||
view.template_name = 'test_template'
|
||||
# Note(Itxaka): ModalFormView requires a form_class to behave properly
|
||||
view.form_class = TestForm
|
||||
return view
|
||||
|
||||
def test_modal_form_mixin_hide_true_if_ajax(self):
|
||||
view = self._prepare_view(
|
||||
forms.views.ModalFormView,
|
||||
dict(HTTP_X_REQUESTED_WITH='XMLHttpRequest'))
|
||||
context = view.get_context_data()
|
||||
self.assertTrue(context['hide'])
|
||||
|
||||
def test_modal_form_mixin_add_to_field_header_set(self):
|
||||
return self._test_form_mixin_add_to_field_header(add_field=True)
|
||||
|
||||
def test_modal_form_mixin_add_to_field_header_not_set(self):
|
||||
return self._test_form_mixin_add_to_field_header(add_field=False)
|
||||
|
||||
def _test_form_mixin_add_to_field_header(self, add_field=False):
|
||||
options = dict(HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
if add_field:
|
||||
options[forms.views.ADD_TO_FIELD_HEADER] = "keepme"
|
||||
|
||||
view = self._prepare_view(forms.views.ModalFormView, options)
|
||||
context = view.get_context_data()
|
||||
|
||||
if add_field:
|
||||
self.assertEqual("keepme", context['add_to_field'])
|
||||
else:
|
||||
self.assertNotIn('add_to_field', context)
|
||||
|
||||
def test_template_name_change_based_on_ajax_request(self):
|
||||
view = self._prepare_view(
|
||||
forms.views.ModalFormView,
|
||||
dict(HTTP_X_REQUESTED_WITH='XMLHttpRequest'))
|
||||
self.assertEqual('_' + view.template_name,
|
||||
view.get_template_names())
|
||||
|
||||
view = self._prepare_view(forms.views.ModalFormView, {})
|
||||
self.assertEqual(view.template_name, view.get_template_names())
|
||||
|
||||
|
||||
class TestForm(forms.SelfHandlingForm):
|
||||
|
||||
name = forms.CharField(max_length=255)
|
||||
|
||||
def handle(self, request, data):
|
||||
return True
|
||||
|
||||
|
||||
class FormErrorTests(test.TestCase):
|
||||
|
||||
template = 'horizon/common/_form_fields.html'
|
||||
|
||||
def setUp(self):
|
||||
super(FormErrorTests, self).setUp()
|
||||
# Note(Itxaka): We pass data to the form so its bound and has the
|
||||
# proper cleaned_data fields
|
||||
self.form = TestForm(self.request, data={'fake': 'data'})
|
||||
|
||||
def _render_form(self):
|
||||
return shortcuts.render(self.request, self.template,
|
||||
{'form': self.form})
|
||||
|
||||
def test_set_warning(self):
|
||||
warning_text = 'WARNING 29380'
|
||||
self.form.set_warning(warning_text)
|
||||
self.assertEqual([warning_text], self.form.warnings)
|
||||
resp = self._render_form()
|
||||
self.assertIn(warning_text.encode('utf-8'), resp.content)
|
||||
|
||||
def test_api_error(self):
|
||||
error_text = 'ERROR 12938'
|
||||
self.form.full_clean()
|
||||
self.form.api_error(error_text)
|
||||
self.assertEqual([error_text], self.form.non_field_errors())
|
||||
resp = self._render_form()
|
||||
self.assertIn(error_text.encode('utf-8'), resp.content)
|
||||
|
||||
|
||||
class TestChoiceFieldForm(forms.SelfHandlingForm):
|
||||
title_dic = {"label1": {"title": "This is choice 1"},
|
||||
"label2": {"title": "This is choice 2"},
|
||||
"label3": {"title": "This is choice 3"}}
|
||||
name = forms.CharField(max_length=255,
|
||||
label="Test Name",
|
||||
help_text="Please enter a name")
|
||||
test_choices = forms.ChoiceField(
|
||||
label="Test Choices",
|
||||
required=False,
|
||||
help_text="Testing drop down choices",
|
||||
widget=forms.fields.SelectWidget(
|
||||
attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'source'},
|
||||
transform_html_attrs=title_dic.get))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(TestChoiceFieldForm, self).__init__(request, *args,
|
||||
**kwargs)
|
||||
choices = ([('choice1', 'label1'),
|
||||
('choice2', 'label2')])
|
||||
self.fields['test_choices'].choices = choices
|
||||
|
||||
def handle(self, request, data):
|
||||
return True
|
||||
|
||||
|
||||
class ChoiceFieldTests(test.TestCase):
|
||||
|
||||
template = 'horizon/common/_form_fields.html'
|
||||
|
||||
def setUp(self):
|
||||
super(ChoiceFieldTests, self).setUp()
|
||||
self.form = TestChoiceFieldForm(self.request)
|
||||
|
||||
def _render_form(self):
|
||||
return shortcuts.render(self.request, self.template,
|
||||
{'form': self.form})
|
||||
|
||||
def test_legacychoicefield_title(self):
|
||||
resp = self._render_form()
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<option value="choice1" title="This is choice 1">label1</option>',
|
||||
count=1, html=True)
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<option value="choice2" title="This is choice 2">label2</option>',
|
||||
count=1, html=True)
|
||||
|
||||
|
||||
class TestThemableChoiceFieldForm(forms.SelfHandlingForm):
|
||||
# It's POSSIBLE to combine this with the test helper form above, but
|
||||
# I fear we'd run into collisions where one test's desired output is
|
||||
# actually within a separate widget's output.
|
||||
|
||||
title_dic = {"label1": {"title": "This is choice 1"},
|
||||
"label2": {"title": "This is choice 2"},
|
||||
"label3": {"title": "This is choice 3"}}
|
||||
name = forms.CharField(max_length=255,
|
||||
label="Test Name",
|
||||
help_text="Please enter a name")
|
||||
test_choices = forms.ThemableChoiceField(
|
||||
label="Test Choices",
|
||||
required=False,
|
||||
help_text="Testing drop down choices",
|
||||
widget=forms.fields.ThemableSelectWidget(
|
||||
attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'source'},
|
||||
transform_html_attrs=title_dic.get))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(TestThemableChoiceFieldForm, self).__init__(request, *args,
|
||||
**kwargs)
|
||||
choices = ([('choice1', 'label1'),
|
||||
('choice2', 'label2')])
|
||||
self.fields['test_choices'].choices = choices
|
||||
|
||||
def handle(self, request, data):
|
||||
return True
|
||||
|
||||
|
||||
class ThemableChoiceFieldTests(test.TestCase):
|
||||
|
||||
template = 'horizon/common/_form_fields.html'
|
||||
|
||||
def setUp(self):
|
||||
super(ThemableChoiceFieldTests, self).setUp()
|
||||
self.form = TestThemableChoiceFieldForm(self.request)
|
||||
|
||||
def _render_form(self):
|
||||
return shortcuts.render(self.request, self.template,
|
||||
{'form': self.form})
|
||||
|
||||
def test_choicefield_labels_and_title_attr(self):
|
||||
resp = self._render_form()
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<a data-select-value="choice1" title="This is choice 1">'
|
||||
'label1</a>',
|
||||
count=1,
|
||||
html=True)
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<a data-select-value="choice2" title="This is choice 2">'
|
||||
'label2</a>',
|
||||
count=1,
|
||||
html=True)
|
||||
|
||||
def test_choicefield_title_select_compatible(self):
|
||||
resp = self._render_form()
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<option value="choice1" title="This is choice 1">label1</option>',
|
||||
count=1, html=True)
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<option value="choice2" title="This is choice 2">label2</option>',
|
||||
count=1, html=True)
|
|
@ -1,611 +0,0 @@
|
|||
# Copyright 2012 Nebula, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
import os
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
import django.template
|
||||
from django.template import defaultfilters
|
||||
|
||||
from horizon import forms
|
||||
from horizon.test import helpers as test
|
||||
from horizon.utils import filters
|
||||
# we have to import the filter in order to register it
|
||||
from horizon.utils.filters import parse_isotime # noqa: F401
|
||||
from horizon.utils import functions
|
||||
from horizon.utils import memoized
|
||||
from horizon.utils import secret_key
|
||||
from horizon.utils import units
|
||||
from horizon.utils import validators
|
||||
|
||||
|
||||
class ValidatorsTests(test.TestCase):
|
||||
def test_validate_ipv4_cidr(self):
|
||||
GOOD_CIDRS = ("192.168.1.1/16",
|
||||
"192.0.0.1/17",
|
||||
"0.0.0.0/16",
|
||||
"10.144.11.107/4",
|
||||
"255.255.255.255/0",
|
||||
"0.1.2.3/16",
|
||||
"0.0.0.0/32",
|
||||
# short form
|
||||
"128.0/16",
|
||||
"128/4")
|
||||
BAD_CIDRS = ("255.255.255.256\\",
|
||||
"256.255.255.255$",
|
||||
"1.2.3.4.5/41",
|
||||
"0.0.0.0/99",
|
||||
"127.0.0.1/",
|
||||
"127.0.0.1/33",
|
||||
"127.0.0.1/-1",
|
||||
"127.0.0.1/100",
|
||||
# some valid IPv6 addresses
|
||||
"fe80::204:61ff:254.157.241.86/4",
|
||||
"fe80::204:61ff:254.157.241.86/0",
|
||||
"2001:0DB8::CD30:0:0:0:0/60",
|
||||
"2001:0DB8::CD30:0/90")
|
||||
ip = forms.IPField(mask=True, version=forms.IPv4)
|
||||
for cidr in GOOD_CIDRS:
|
||||
self.assertIsNone(ip.validate(cidr))
|
||||
for cidr in BAD_CIDRS:
|
||||
self.assertRaises(ValidationError, ip.validate, cidr)
|
||||
|
||||
def test_validate_ipv6_cidr(self):
|
||||
GOOD_CIDRS = ("::ffff:0:0/56",
|
||||
"2001:0db8::1428:57ab/17",
|
||||
"FEC0::/10",
|
||||
"fe80::204:61ff:254.157.241.86/4",
|
||||
"fe80::204:61ff:254.157.241.86/0",
|
||||
"2001:0DB8::CD30:0:0:0:0/60",
|
||||
"2001:0DB8::CD30:0/90",
|
||||
"::1/128")
|
||||
BAD_CIDRS = ("1111:2222:3333:4444:::/",
|
||||
"::2222:3333:4444:5555:6666:7777:8888:\\",
|
||||
":1111:2222:3333:4444::6666:1.2.3.4/1000",
|
||||
"1111:2222::4444:5555:6666::8888@",
|
||||
"1111:2222::4444:5555:6666:8888/",
|
||||
"::ffff:0:0/129",
|
||||
"1.2.3.4:1111:2222::5555//22",
|
||||
"fe80::204:61ff:254.157.241.86/200",
|
||||
# some valid IPv4 addresses
|
||||
"10.144.11.107/4",
|
||||
"255.255.255.255/0",
|
||||
"0.1.2.3/16")
|
||||
ip = forms.IPField(mask=True, version=forms.IPv6)
|
||||
for cidr in GOOD_CIDRS:
|
||||
self.assertIsNone(ip.validate(cidr))
|
||||
for cidr in BAD_CIDRS:
|
||||
self.assertRaises(ValidationError, ip.validate, cidr)
|
||||
|
||||
def test_validate_mixed_cidr(self):
|
||||
GOOD_CIDRS = ("::ffff:0:0/56",
|
||||
"2001:0db8::1428:57ab/17",
|
||||
"FEC0::/10",
|
||||
"fe80::204:61ff:254.157.241.86/4",
|
||||
"fe80::204:61ff:254.157.241.86/0",
|
||||
"2001:0DB8::CD30:0:0:0:0/60",
|
||||
"0.0.0.0/16",
|
||||
"10.144.11.107/4",
|
||||
"255.255.255.255/0",
|
||||
"0.1.2.3/16",
|
||||
# short form
|
||||
"128.0/16",
|
||||
"10/4")
|
||||
BAD_CIDRS = ("1111:2222:3333:4444::://",
|
||||
"::2222:3333:4444:5555:6666:7777:8888:",
|
||||
":1111:2222:3333:4444::6666:1.2.3.4/1/1",
|
||||
"1111:2222::4444:5555:6666::8888\\2",
|
||||
"1111:2222::4444:5555:6666:8888/",
|
||||
"1111:2222::4444:5555:6666::8888/130",
|
||||
"127.0.0.1/",
|
||||
"127.0.0.1/33",
|
||||
"127.0.0.1/-1")
|
||||
ip = forms.IPField(mask=True, version=forms.IPv4 | forms.IPv6)
|
||||
for cidr in GOOD_CIDRS:
|
||||
self.assertIsNone(ip.validate(cidr))
|
||||
for cidr in BAD_CIDRS:
|
||||
self.assertRaises(ValidationError, ip.validate, cidr)
|
||||
|
||||
def test_validate_IPs(self):
|
||||
GOOD_IPS_V4 = ("0.0.0.0",
|
||||
"10.144.11.107",
|
||||
"169.144.11.107",
|
||||
"172.100.11.107",
|
||||
"255.255.255.255",
|
||||
"0.1.2.3")
|
||||
GOOD_IPS_V6 = ("",
|
||||
"::ffff:0:0",
|
||||
"2001:0db8::1428:57ab",
|
||||
"FEC0::",
|
||||
"fe80::204:61ff:254.157.241.86",
|
||||
"fe80::204:61ff:254.157.241.86",
|
||||
"2001:0DB8::CD30:0:0:0:0")
|
||||
BAD_IPS_V4 = ("1111:2222:3333:4444:::",
|
||||
"::2222:3333:4444:5555:6666:7777:8888:",
|
||||
":1111:2222:3333:4444::6666:1.2.3.4",
|
||||
"1111:2222::4444:5555:6666::8888",
|
||||
"1111:2222::4444:5555:6666:8888/",
|
||||
"1111:2222::4444:5555:6666::8888/130",
|
||||
"127.0.0.1/",
|
||||
"127.0.0.1/33",
|
||||
"127.0.0.1/-1")
|
||||
BAD_IPS_V6 = ("1111:2222:3333:4444:::",
|
||||
"::2222:3333:4444:5555:6666:7777:8888:",
|
||||
":1111:2222:3333:4444::6666:1.2.3.4",
|
||||
"1111:2222::4444:5555:6666::8888",
|
||||
"1111:2222::4444:5555:6666:8888/",
|
||||
"1111:2222::4444:5555:6666::8888/130")
|
||||
ipv4 = forms.IPField(required=True, version=forms.IPv4)
|
||||
ipv6 = forms.IPField(required=False, version=forms.IPv6)
|
||||
ipmixed = forms.IPField(required=False,
|
||||
version=forms.IPv4 | forms.IPv6)
|
||||
|
||||
for ip_addr in GOOD_IPS_V4:
|
||||
self.assertIsNone(ipv4.validate(ip_addr))
|
||||
self.assertIsNone(ipmixed.validate(ip_addr))
|
||||
|
||||
for ip_addr in GOOD_IPS_V6:
|
||||
self.assertIsNone(ipv6.validate(ip_addr))
|
||||
self.assertIsNone(ipmixed.validate(ip_addr))
|
||||
|
||||
for ip_addr in BAD_IPS_V4:
|
||||
self.assertRaises(ValidationError, ipv4.validate, ip_addr)
|
||||
self.assertRaises(ValidationError, ipmixed.validate, ip_addr)
|
||||
|
||||
for ip_addr in BAD_IPS_V6:
|
||||
self.assertRaises(ValidationError, ipv6.validate, ip_addr)
|
||||
self.assertRaises(ValidationError, ipmixed.validate, ip_addr)
|
||||
|
||||
self.assertRaises(ValidationError, ipv4.validate, "") # required=True
|
||||
|
||||
iprange = forms.IPField(required=False,
|
||||
mask=True,
|
||||
mask_range_from=10,
|
||||
version=forms.IPv4 | forms.IPv6)
|
||||
self.assertRaises(ValidationError, iprange.validate,
|
||||
"fe80::204:61ff:254.157.241.86/6")
|
||||
self.assertRaises(ValidationError, iprange.validate,
|
||||
"169.144.11.107/8")
|
||||
self.assertIsNone(iprange.validate("fe80::204:61ff:254.157.241.86/36"))
|
||||
self.assertIsNone(iprange.validate("169.144.11.107/18"))
|
||||
|
||||
def test_validate_multi_ip_field(self):
|
||||
GOOD_CIDRS_INPUT = ("192.168.1.1/16, 192.0.0.1/17",)
|
||||
BAD_CIDRS_INPUT = ("1.2.3.4.5/41,0.0.0.0/99",
|
||||
"1.2.3.4.5/41;0.0.0.0/99",
|
||||
"1.2.3.4.5/41 0.0.0.0/99",
|
||||
"192.168.1.1/16 192.0.0.1/17")
|
||||
|
||||
ip = forms.MultiIPField(mask=True, version=forms.IPv4)
|
||||
for cidr in GOOD_CIDRS_INPUT:
|
||||
self.assertIsNone(ip.validate(cidr))
|
||||
for cidr in BAD_CIDRS_INPUT:
|
||||
self.assertRaises(ValidationError, ip.validate, cidr)
|
||||
|
||||
def test_mac_address_validator(self):
|
||||
GOOD_MAC_ADDRESSES = (
|
||||
"00:11:88:99:Aa:Ff",
|
||||
"00-11-88-99-Aa-Ff",
|
||||
"0011.8899.AaFf",
|
||||
"00118899AaFf",
|
||||
)
|
||||
BAD_MAC_ADDRESSES = (
|
||||
"not a mac",
|
||||
"11:22:33:44:55",
|
||||
"zz:11:22:33:44:55",
|
||||
)
|
||||
|
||||
field = forms.MACAddressField()
|
||||
for input in GOOD_MAC_ADDRESSES:
|
||||
self.assertIsNone(field.validate(input))
|
||||
for input in BAD_MAC_ADDRESSES:
|
||||
self.assertRaises(ValidationError, field.validate, input)
|
||||
|
||||
def test_mac_address_normal_form(self):
|
||||
field = forms.MACAddressField()
|
||||
field.validate("00-11-88-99-Aa-Ff")
|
||||
self.assertEqual(field.mac_address, "00:11:88:99:aa:ff")
|
||||
|
||||
def test_port_validator(self):
|
||||
VALID_PORTS = (1, 65535)
|
||||
INVALID_PORTS = (-1, 65536)
|
||||
|
||||
for port in VALID_PORTS:
|
||||
self.assertIsNone(validators.validate_port_range(port))
|
||||
|
||||
for port in INVALID_PORTS:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_port_range,
|
||||
port)
|
||||
|
||||
def test_icmp_type_validator(self):
|
||||
VALID_ICMP_TYPES = (1, 0, 255, -1)
|
||||
INVALID_ICMP_TYPES = (256, None, -2)
|
||||
|
||||
for icmp_type in VALID_ICMP_TYPES:
|
||||
self.assertIsNone(validators.validate_icmp_type_range(icmp_type))
|
||||
|
||||
for icmp_type in INVALID_ICMP_TYPES:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_icmp_type_range,
|
||||
icmp_type)
|
||||
|
||||
def test_icmp_code_validator(self):
|
||||
VALID_ICMP_CODES = (1, 0, 255, None, -1,)
|
||||
INVALID_ICMP_CODES = (256, -2)
|
||||
|
||||
for icmp_code in VALID_ICMP_CODES:
|
||||
self.assertIsNone(validators.validate_icmp_code_range(icmp_code))
|
||||
|
||||
for icmp_code in INVALID_ICMP_CODES:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_icmp_code_range,
|
||||
icmp_code)
|
||||
|
||||
def test_ip_proto_validator(self):
|
||||
VALID_PROTO = (0, 255, -1)
|
||||
INVALID_PROTO = (-2, 256)
|
||||
|
||||
for proto in VALID_PROTO:
|
||||
self.assertIsNone(validators.validate_ip_protocol(proto))
|
||||
|
||||
for proto in INVALID_PROTO:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_ip_protocol,
|
||||
proto)
|
||||
|
||||
def test_port_range_validator(self):
|
||||
VALID_RANGE = ('1:65535',
|
||||
'1:1')
|
||||
INVALID_RANGE = ('22:22:22:22',
|
||||
'1:-1',
|
||||
'-1:65535')
|
||||
|
||||
test_call = validators.validate_port_or_colon_separated_port_range
|
||||
for prange in VALID_RANGE:
|
||||
self.assertIsNone(test_call(prange))
|
||||
|
||||
for prange in INVALID_RANGE:
|
||||
self.assertRaises(ValidationError, test_call, prange)
|
||||
|
||||
def test_metadata_validator(self):
|
||||
VALID_METADATA = (
|
||||
"key1=val1", "key1=val1,key2=val2",
|
||||
"key1=val1,key2=val2,key3=val3", "key1="
|
||||
)
|
||||
INVALID_METADATA = (
|
||||
"key1==val1", "key1=val1,", "=val1",
|
||||
"=val1", " "
|
||||
)
|
||||
|
||||
for mdata in VALID_METADATA:
|
||||
self.assertIsNone(validators.validate_metadata(mdata))
|
||||
|
||||
for mdata in INVALID_METADATA:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_metadata,
|
||||
mdata)
|
||||
|
||||
|
||||
class SecretKeyTests(test.TestCase):
|
||||
def test_generate_secret_key(self):
|
||||
key = secret_key.generate_key(32)
|
||||
self.assertEqual(32, len(key))
|
||||
self.assertNotEqual(key, secret_key.generate_key(32))
|
||||
|
||||
def test_generate_or_read_key_from_file(self):
|
||||
key_file = ".test_secret_key_store"
|
||||
key = secret_key.generate_or_read_from_file(key_file)
|
||||
|
||||
# Consecutive reads should come from the already existing file:
|
||||
self.assertEqual(secret_key.generate_or_read_from_file(key_file), key)
|
||||
|
||||
# Key file only be read/writable by user:
|
||||
self.assertEqual(0o600, os.stat(key_file).st_mode & 0o777)
|
||||
os.chmod(key_file, 0o644)
|
||||
self.assertRaises(secret_key.FilePermissionError,
|
||||
secret_key.generate_or_read_from_file, key_file)
|
||||
os.remove(key_file)
|
||||
|
||||
|
||||
class FiltersTests(test.TestCase):
|
||||
def test_replace_underscore_filter(self):
|
||||
res = filters.replace_underscores("__under_score__")
|
||||
self.assertEqual(" under score ", res)
|
||||
|
||||
def test_parse_isotime_filter(self):
|
||||
c = django.template.Context({'time': ''})
|
||||
t = django.template.Template('{{ time|parse_isotime }}')
|
||||
output = u""
|
||||
|
||||
self.assertEqual(output, t.render(c))
|
||||
|
||||
c = django.template.Context({'time': 'error'})
|
||||
t = django.template.Template('{{ time|parse_isotime }}')
|
||||
output = u""
|
||||
|
||||
self.assertEqual(output, t.render(c))
|
||||
|
||||
c = django.template.Context({'time': 'error'})
|
||||
t = django.template.Template('{{ time|parse_isotime:"test" }}')
|
||||
output = u"test"
|
||||
|
||||
self.assertEqual(output, t.render(c))
|
||||
|
||||
c = django.template.Context({'time': '2007-03-04T21:08:12'})
|
||||
t = django.template.Template('{{ time|parse_isotime:"test" }}')
|
||||
output = u"March 4, 2007, 3:08 p.m."
|
||||
|
||||
self.assertEqual(output, t.render(c))
|
||||
|
||||
adate = '2007-01-25T12:00:00Z'
|
||||
result = filters.parse_isotime(adate)
|
||||
self.assertIsInstance(result, datetime.datetime)
|
||||
|
||||
|
||||
class TimeSinceNeverFilterTests(test.TestCase):
|
||||
|
||||
default = u"Never"
|
||||
|
||||
def test_timesince_or_never_returns_default_for_empty_string(self):
|
||||
c = django.template.Context({'time': ''})
|
||||
t = django.template.Template('{{ time|timesince_or_never }}')
|
||||
self.assertEqual(self.default, t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_default_for_none(self):
|
||||
c = django.template.Context({'time': None})
|
||||
t = django.template.Template('{{ time|timesince_or_never }}')
|
||||
self.assertEqual(self.default, t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_default_for_gibberish(self):
|
||||
c = django.template.Context({'time': django.template.Context()})
|
||||
t = django.template.Template('{{ time|timesince_or_never }}')
|
||||
self.assertEqual(self.default, t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_with_custom_default(self):
|
||||
custom = "Hello world"
|
||||
c = django.template.Context({'date': ''})
|
||||
t = django.template.Template('{{ date|timesince_or_never:"%s" }}'
|
||||
% custom)
|
||||
self.assertEqual(custom, t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_with_custom_empty_string_default(self):
|
||||
c = django.template.Context({'date': ''})
|
||||
t = django.template.Template('{{ date|timesince_or_never:"" }}')
|
||||
self.assertEqual("", t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_same_output_as_django_date(self):
|
||||
d = datetime.date(year=2014, month=3, day=7)
|
||||
c = django.template.Context({'date': d})
|
||||
t = django.template.Template('{{ date|timesince_or_never }}')
|
||||
self.assertEqual(defaultfilters.timesince(d), t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_same_output_as_django_datetime(self):
|
||||
now = datetime.datetime.now()
|
||||
c = django.template.Context({'date': now})
|
||||
t = django.template.Template('{{ date|timesince_or_never }}')
|
||||
self.assertEqual(defaultfilters.timesince(now), t.render(c))
|
||||
|
||||
|
||||
class MemoizedTests(test.TestCase):
|
||||
def test_memoized_decorator_cache_on_next_call(self):
|
||||
values_list = []
|
||||
|
||||
@memoized.memoized
|
||||
def cache_calls(remove_from):
|
||||
values_list.append(remove_from)
|
||||
return True
|
||||
|
||||
def non_cached_calls(remove_from):
|
||||
values_list.append(remove_from)
|
||||
return True
|
||||
|
||||
for x in range(0, 5):
|
||||
non_cached_calls(1)
|
||||
self.assertEqual(5, len(values_list))
|
||||
|
||||
values_list = []
|
||||
for x in range(0, 5):
|
||||
cache_calls(1)
|
||||
self.assertEqual(1, len(values_list))
|
||||
|
||||
def test_memoized_with_request_call(self):
|
||||
|
||||
chorus = [
|
||||
"I",
|
||||
"Love",
|
||||
"Rock 'n' Roll",
|
||||
"put another coin",
|
||||
"in the Jukebox Baby."
|
||||
]
|
||||
|
||||
leader = 'Joan Jett'
|
||||
group = 'Blackhearts'
|
||||
|
||||
for position, chorus_line in enumerate(chorus):
|
||||
|
||||
changed_args = False
|
||||
|
||||
def some_func(some_param):
|
||||
if not changed_args:
|
||||
self.assertEqual(some_param, chorus_line)
|
||||
else:
|
||||
self.assertNotEqual(some_param, chorus_line)
|
||||
self.assertEqual(some_param, group)
|
||||
return leader
|
||||
|
||||
@memoized.memoized_with_request(some_func, position)
|
||||
def some_other_func(*args):
|
||||
return args
|
||||
|
||||
# check chorus_copy[position] is replaced by some_func's
|
||||
# output
|
||||
output1 = some_other_func(*chorus)
|
||||
self.assertEqual(output1[position], leader)
|
||||
|
||||
# Change args used to call the function
|
||||
chorus_copy = list(chorus)
|
||||
chorus_copy[position] = group
|
||||
changed_args = True
|
||||
# check that some_func is called with a different parameter, and
|
||||
# that check chorus_copy[position] is replaced by some_func's
|
||||
# output and some_other_func still called with the same parameters
|
||||
output2 = some_other_func(*chorus_copy)
|
||||
self.assertEqual(output2[position], leader)
|
||||
# check that some_other_func returned a memoized list.
|
||||
self.assertIs(output1, output2)
|
||||
|
||||
|
||||
class GetConfigValueTests(test.TestCase):
|
||||
key = 'key'
|
||||
value = 'value'
|
||||
requested_url = '/project/instances/'
|
||||
int_default = 30
|
||||
str_default = 'default'
|
||||
|
||||
def test_bad_session_value(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
request.session[self.key] = self.value
|
||||
res = functions.get_config_value(request, self.key, self.int_default)
|
||||
self.assertEqual(res, self.int_default)
|
||||
|
||||
def test_bad_cookie_value(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
if self.key in request.session:
|
||||
del request.session[self.key]
|
||||
request.COOKIES[self.key] = self.value
|
||||
res = functions.get_config_value(request, self.key, self.int_default)
|
||||
self.assertEqual(res, self.int_default)
|
||||
|
||||
def test_float_default_value(self):
|
||||
default = 30.1
|
||||
request = self.factory.get(self.requested_url)
|
||||
request.session[self.key] = self.value
|
||||
res = functions.get_config_value(request, self.key, default)
|
||||
self.assertEqual(res, self.value)
|
||||
|
||||
def test_session_gets_set(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
request.session[self.key] = self.value
|
||||
functions.get_config_value(request, self.key, self.int_default)
|
||||
self.assertEqual(request.session[self.key], self.int_default)
|
||||
|
||||
def test_found_in_session(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
request.session[self.key] = self.value
|
||||
if request.COOKIES.get(self.key):
|
||||
del request.COOKIES[self.key]
|
||||
res = functions.get_config_value(request, self.key, self.str_default)
|
||||
self.assertEqual(res, self.value)
|
||||
|
||||
def test_found_in_cookie(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
if request.session.get(self.key):
|
||||
del request.session[self.key]
|
||||
request.COOKIES[self.key] = self.value
|
||||
res = functions.get_config_value(request, self.key, self.str_default)
|
||||
self.assertEqual(res, self.value)
|
||||
|
||||
def test_found_in_config(self):
|
||||
key = 'TESTSERVER'
|
||||
value = 'http://testserver'
|
||||
request = self.factory.get(self.requested_url)
|
||||
if request.session.get(key):
|
||||
del request.session[key]
|
||||
if request.COOKIES.get(key):
|
||||
del request.COOKIES[key]
|
||||
res = functions.get_config_value(request, key, self.str_default)
|
||||
self.assertEqual(res, value)
|
||||
|
||||
def test_return_default(self):
|
||||
key = 'NOT FOUND ANYWHERE'
|
||||
request = self.factory.get(self.requested_url)
|
||||
if request.session.get(key):
|
||||
del request.session[key]
|
||||
if request.COOKIES.get(key):
|
||||
del request.COOKIES[key]
|
||||
res = functions.get_config_value(request, key, self.str_default)
|
||||
self.assertEqual(res, self.str_default)
|
||||
|
||||
def test_return_default_no_settings(self):
|
||||
key = 'TESTSERVER'
|
||||
request = self.factory.get(self.requested_url)
|
||||
if request.session.get(key):
|
||||
del request.session[key]
|
||||
if request.COOKIES.get(key):
|
||||
del request.COOKIES[key]
|
||||
res = functions.get_config_value(request, key, self.str_default,
|
||||
search_in_settings=False)
|
||||
self.assertEqual(res, self.str_default)
|
||||
|
||||
|
||||
class UnitsTests(test.TestCase):
|
||||
def test_is_supported(self):
|
||||
self.assertTrue(units.is_supported('MB'))
|
||||
self.assertTrue(units.is_supported('min'))
|
||||
self.assertFalse(units.is_supported('KWh'))
|
||||
self.assertFalse(units.is_supported('unknown_unit'))
|
||||
|
||||
def test_is_larger(self):
|
||||
self.assertTrue(units.is_larger('KB', 'B'))
|
||||
self.assertTrue(units.is_larger('MB', 'B'))
|
||||
self.assertTrue(units.is_larger('GB', 'B'))
|
||||
self.assertTrue(units.is_larger('TB', 'B'))
|
||||
self.assertTrue(units.is_larger('GB', 'MB'))
|
||||
self.assertFalse(units.is_larger('B', 'KB'))
|
||||
self.assertFalse(units.is_larger('MB', 'GB'))
|
||||
|
||||
self.assertTrue(units.is_larger('min', 's'))
|
||||
self.assertTrue(units.is_larger('hr', 'min'))
|
||||
self.assertTrue(units.is_larger('hr', 's'))
|
||||
self.assertFalse(units.is_larger('s', 'min'))
|
||||
|
||||
def test_convert(self):
|
||||
self.assertEqual(units.convert(4096, 'MB', 'GB'), (4, 'GB'))
|
||||
self.assertEqual(units.convert(4, 'GB', 'MB'), (4096, 'MB'))
|
||||
|
||||
self.assertEqual(units.convert(1.5, 'hr', 'min'), (90, 'min'))
|
||||
self.assertEqual(units.convert(12, 'hr', 'day'), (0.5, 'day'))
|
||||
|
||||
def test_normalize(self):
|
||||
self.assertEqual(units.normalize(1, 'B'), (1, 'B'))
|
||||
self.assertEqual(units.normalize(1000, 'B'), (1000, 'B'))
|
||||
self.assertEqual(units.normalize(1024, 'B'), (1, 'KB'))
|
||||
self.assertEqual(units.normalize(1024 * 1024, 'B'), (1, 'MB'))
|
||||
self.assertEqual(units.normalize(10 * 1024 ** 3, 'B'), (10, 'GB'))
|
||||
self.assertEqual(units.normalize(1000 * 1024 ** 4, 'B'), (1000, 'TB'))
|
||||
self.assertEqual(units.normalize(1024, 'KB'), (1, 'MB'))
|
||||
self.assertEqual(units.normalize(1024 ** 2, 'KB'), (1, 'GB'))
|
||||
self.assertEqual(units.normalize(10 * 1024, 'MB'), (10, 'GB'))
|
||||
self.assertEqual(units.normalize(0.5, 'KB'), (512, 'B'))
|
||||
self.assertEqual(units.normalize(0.0001, 'MB'), (104.9, 'B'))
|
||||
|
||||
self.assertEqual(units.normalize(1, 's'), (1, 's'))
|
||||
self.assertEqual(units.normalize(120, 's'), (2, 'min'))
|
||||
self.assertEqual(units.normalize(3600, 's'), (60, 'min'))
|
||||
self.assertEqual(units.normalize(3600 * 24, 's'), (24, 'hr'))
|
||||
self.assertEqual(units.normalize(10 * 3600 * 24, 's'), (10, 'day'))
|
||||
self.assertEqual(units.normalize(90, 'min'), (90, 'min'))
|
||||
self.assertEqual(units.normalize(150, 'min'), (2.5, 'hr'))
|
||||
self.assertEqual(units.normalize(60 * 24, 'min'), (24, 'hr'))
|
||||
self.assertEqual(units.normalize(0.5, 'day'), (12, 'hr'))
|
||||
self.assertEqual(units.normalize(10800000000000, 'ns'), (3, 'hr'))
|
||||
self.assertEqual(units.normalize(14, 'day'), (2, 'week'))
|
||||
self.assertEqual(units.normalize(91, 'day'), (3, 'month'))
|
||||
self.assertEqual(units.normalize(18, 'month'), (18, 'month'))
|
||||
self.assertEqual(units.normalize(24, 'month'), (2, 'year'))
|
||||
|
||||
self.assertEqual(units.normalize(1, 'unknown_unit'),
|
||||
(1, 'unknown_unit'))
|
|
@ -0,0 +1,332 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django import shortcuts
|
||||
|
||||
from horizon import forms
|
||||
from horizon.test import helpers as test
|
||||
|
||||
|
||||
class IPFieldTests(test.TestCase):
|
||||
|
||||
def test_validate_ipv4_cidr(self):
|
||||
GOOD_CIDRS = ("192.168.1.1/16",
|
||||
"192.0.0.1/17",
|
||||
"0.0.0.0/16",
|
||||
"10.144.11.107/4",
|
||||
"255.255.255.255/0",
|
||||
"0.1.2.3/16",
|
||||
"0.0.0.0/32",
|
||||
# short form
|
||||
"128.0/16",
|
||||
"128/4")
|
||||
BAD_CIDRS = ("255.255.255.256\\",
|
||||
"256.255.255.255$",
|
||||
"1.2.3.4.5/41",
|
||||
"0.0.0.0/99",
|
||||
"127.0.0.1/",
|
||||
"127.0.0.1/33",
|
||||
"127.0.0.1/-1",
|
||||
"127.0.0.1/100",
|
||||
# some valid IPv6 addresses
|
||||
"fe80::204:61ff:254.157.241.86/4",
|
||||
"fe80::204:61ff:254.157.241.86/0",
|
||||
"2001:0DB8::CD30:0:0:0:0/60",
|
||||
"2001:0DB8::CD30:0/90")
|
||||
ip = forms.IPField(mask=True, version=forms.IPv4)
|
||||
for cidr in GOOD_CIDRS:
|
||||
self.assertIsNone(ip.validate(cidr))
|
||||
for cidr in BAD_CIDRS:
|
||||
self.assertRaises(ValidationError, ip.validate, cidr)
|
||||
|
||||
def test_validate_ipv6_cidr(self):
|
||||
GOOD_CIDRS = ("::ffff:0:0/56",
|
||||
"2001:0db8::1428:57ab/17",
|
||||
"FEC0::/10",
|
||||
"fe80::204:61ff:254.157.241.86/4",
|
||||
"fe80::204:61ff:254.157.241.86/0",
|
||||
"2001:0DB8::CD30:0:0:0:0/60",
|
||||
"2001:0DB8::CD30:0/90",
|
||||
"::1/128")
|
||||
BAD_CIDRS = ("1111:2222:3333:4444:::/",
|
||||
"::2222:3333:4444:5555:6666:7777:8888:\\",
|
||||
":1111:2222:3333:4444::6666:1.2.3.4/1000",
|
||||
"1111:2222::4444:5555:6666::8888@",
|
||||
"1111:2222::4444:5555:6666:8888/",
|
||||
"::ffff:0:0/129",
|
||||
"1.2.3.4:1111:2222::5555//22",
|
||||
"fe80::204:61ff:254.157.241.86/200",
|
||||
# some valid IPv4 addresses
|
||||
"10.144.11.107/4",
|
||||
"255.255.255.255/0",
|
||||
"0.1.2.3/16")
|
||||
ip = forms.IPField(mask=True, version=forms.IPv6)
|
||||
for cidr in GOOD_CIDRS:
|
||||
self.assertIsNone(ip.validate(cidr))
|
||||
for cidr in BAD_CIDRS:
|
||||
self.assertRaises(ValidationError, ip.validate, cidr)
|
||||
|
||||
def test_validate_mixed_cidr(self):
|
||||
GOOD_CIDRS = ("::ffff:0:0/56",
|
||||
"2001:0db8::1428:57ab/17",
|
||||
"FEC0::/10",
|
||||
"fe80::204:61ff:254.157.241.86/4",
|
||||
"fe80::204:61ff:254.157.241.86/0",
|
||||
"2001:0DB8::CD30:0:0:0:0/60",
|
||||
"0.0.0.0/16",
|
||||
"10.144.11.107/4",
|
||||
"255.255.255.255/0",
|
||||
"0.1.2.3/16",
|
||||
# short form
|
||||
"128.0/16",
|
||||
"10/4")
|
||||
BAD_CIDRS = ("1111:2222:3333:4444::://",
|
||||
"::2222:3333:4444:5555:6666:7777:8888:",
|
||||
":1111:2222:3333:4444::6666:1.2.3.4/1/1",
|
||||
"1111:2222::4444:5555:6666::8888\\2",
|
||||
"1111:2222::4444:5555:6666:8888/",
|
||||
"1111:2222::4444:5555:6666::8888/130",
|
||||
"127.0.0.1/",
|
||||
"127.0.0.1/33",
|
||||
"127.0.0.1/-1")
|
||||
ip = forms.IPField(mask=True, version=forms.IPv4 | forms.IPv6)
|
||||
for cidr in GOOD_CIDRS:
|
||||
self.assertIsNone(ip.validate(cidr))
|
||||
for cidr in BAD_CIDRS:
|
||||
self.assertRaises(ValidationError, ip.validate, cidr)
|
||||
|
||||
def test_validate_IPs(self):
|
||||
GOOD_IPS_V4 = ("0.0.0.0",
|
||||
"10.144.11.107",
|
||||
"169.144.11.107",
|
||||
"172.100.11.107",
|
||||
"255.255.255.255",
|
||||
"0.1.2.3")
|
||||
GOOD_IPS_V6 = ("",
|
||||
"::ffff:0:0",
|
||||
"2001:0db8::1428:57ab",
|
||||
"FEC0::",
|
||||
"fe80::204:61ff:254.157.241.86",
|
||||
"fe80::204:61ff:254.157.241.86",
|
||||
"2001:0DB8::CD30:0:0:0:0")
|
||||
BAD_IPS_V4 = ("1111:2222:3333:4444:::",
|
||||
"::2222:3333:4444:5555:6666:7777:8888:",
|
||||
":1111:2222:3333:4444::6666:1.2.3.4",
|
||||
"1111:2222::4444:5555:6666::8888",
|
||||
"1111:2222::4444:5555:6666:8888/",
|
||||
"1111:2222::4444:5555:6666::8888/130",
|
||||
"127.0.0.1/",
|
||||
"127.0.0.1/33",
|
||||
"127.0.0.1/-1")
|
||||
BAD_IPS_V6 = ("1111:2222:3333:4444:::",
|
||||
"::2222:3333:4444:5555:6666:7777:8888:",
|
||||
":1111:2222:3333:4444::6666:1.2.3.4",
|
||||
"1111:2222::4444:5555:6666::8888",
|
||||
"1111:2222::4444:5555:6666:8888/",
|
||||
"1111:2222::4444:5555:6666::8888/130")
|
||||
ipv4 = forms.IPField(required=True, version=forms.IPv4)
|
||||
ipv6 = forms.IPField(required=False, version=forms.IPv6)
|
||||
ipmixed = forms.IPField(required=False,
|
||||
version=forms.IPv4 | forms.IPv6)
|
||||
|
||||
for ip_addr in GOOD_IPS_V4:
|
||||
self.assertIsNone(ipv4.validate(ip_addr))
|
||||
self.assertIsNone(ipmixed.validate(ip_addr))
|
||||
|
||||
for ip_addr in GOOD_IPS_V6:
|
||||
self.assertIsNone(ipv6.validate(ip_addr))
|
||||
self.assertIsNone(ipmixed.validate(ip_addr))
|
||||
|
||||
for ip_addr in BAD_IPS_V4:
|
||||
self.assertRaises(ValidationError, ipv4.validate, ip_addr)
|
||||
self.assertRaises(ValidationError, ipmixed.validate, ip_addr)
|
||||
|
||||
for ip_addr in BAD_IPS_V6:
|
||||
self.assertRaises(ValidationError, ipv6.validate, ip_addr)
|
||||
self.assertRaises(ValidationError, ipmixed.validate, ip_addr)
|
||||
|
||||
self.assertRaises(ValidationError, ipv4.validate, "") # required=True
|
||||
|
||||
iprange = forms.IPField(required=False,
|
||||
mask=True,
|
||||
mask_range_from=10,
|
||||
version=forms.IPv4 | forms.IPv6)
|
||||
self.assertRaises(ValidationError, iprange.validate,
|
||||
"fe80::204:61ff:254.157.241.86/6")
|
||||
self.assertRaises(ValidationError, iprange.validate,
|
||||
"169.144.11.107/8")
|
||||
self.assertIsNone(iprange.validate("fe80::204:61ff:254.157.241.86/36"))
|
||||
self.assertIsNone(iprange.validate("169.144.11.107/18"))
|
||||
|
||||
def test_validate_multi_ip_field(self):
|
||||
GOOD_CIDRS_INPUT = ("192.168.1.1/16, 192.0.0.1/17",)
|
||||
BAD_CIDRS_INPUT = ("1.2.3.4.5/41,0.0.0.0/99",
|
||||
"1.2.3.4.5/41;0.0.0.0/99",
|
||||
"1.2.3.4.5/41 0.0.0.0/99",
|
||||
"192.168.1.1/16 192.0.0.1/17")
|
||||
|
||||
ip = forms.MultiIPField(mask=True, version=forms.IPv4)
|
||||
for cidr in GOOD_CIDRS_INPUT:
|
||||
self.assertIsNone(ip.validate(cidr))
|
||||
for cidr in BAD_CIDRS_INPUT:
|
||||
self.assertRaises(ValidationError, ip.validate, cidr)
|
||||
|
||||
|
||||
class MACAddressFieldTests(test.TestCase):
|
||||
|
||||
def test_mac_address_validator(self):
|
||||
GOOD_MAC_ADDRESSES = (
|
||||
"00:11:88:99:Aa:Ff",
|
||||
"00-11-88-99-Aa-Ff",
|
||||
"0011.8899.AaFf",
|
||||
"00118899AaFf",
|
||||
)
|
||||
BAD_MAC_ADDRESSES = (
|
||||
"not a mac",
|
||||
"11:22:33:44:55",
|
||||
"zz:11:22:33:44:55",
|
||||
)
|
||||
|
||||
field = forms.MACAddressField()
|
||||
for input in GOOD_MAC_ADDRESSES:
|
||||
self.assertIsNone(field.validate(input))
|
||||
for input in BAD_MAC_ADDRESSES:
|
||||
self.assertRaises(ValidationError, field.validate, input)
|
||||
|
||||
def test_mac_address_normal_form(self):
|
||||
field = forms.MACAddressField()
|
||||
field.validate("00-11-88-99-Aa-Ff")
|
||||
self.assertEqual(field.mac_address, "00:11:88:99:aa:ff")
|
||||
|
||||
|
||||
class TestChoiceFieldForm(forms.SelfHandlingForm):
|
||||
title_dic = {"label1": {"title": "This is choice 1"},
|
||||
"label2": {"title": "This is choice 2"},
|
||||
"label3": {"title": "This is choice 3"}}
|
||||
name = forms.CharField(max_length=255,
|
||||
label="Test Name",
|
||||
help_text="Please enter a name")
|
||||
test_choices = forms.ChoiceField(
|
||||
label="Test Choices",
|
||||
required=False,
|
||||
help_text="Testing drop down choices",
|
||||
widget=forms.fields.SelectWidget(
|
||||
attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'source'},
|
||||
transform_html_attrs=title_dic.get))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(TestChoiceFieldForm, self).__init__(request, *args,
|
||||
**kwargs)
|
||||
choices = ([('choice1', 'label1'),
|
||||
('choice2', 'label2')])
|
||||
self.fields['test_choices'].choices = choices
|
||||
|
||||
def handle(self, request, data):
|
||||
return True
|
||||
|
||||
|
||||
class ChoiceFieldTests(test.TestCase):
|
||||
|
||||
template = 'horizon/common/_form_fields.html'
|
||||
|
||||
def setUp(self):
|
||||
super(ChoiceFieldTests, self).setUp()
|
||||
self.form = TestChoiceFieldForm(self.request)
|
||||
|
||||
def _render_form(self):
|
||||
return shortcuts.render(self.request, self.template,
|
||||
{'form': self.form})
|
||||
|
||||
def test_legacychoicefield_title(self):
|
||||
resp = self._render_form()
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<option value="choice1" title="This is choice 1">label1</option>',
|
||||
count=1, html=True)
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<option value="choice2" title="This is choice 2">label2</option>',
|
||||
count=1, html=True)
|
||||
|
||||
|
||||
class TestThemableChoiceFieldForm(forms.SelfHandlingForm):
|
||||
# It's POSSIBLE to combine this with the test helper form above, but
|
||||
# I fear we'd run into collisions where one test's desired output is
|
||||
# actually within a separate widget's output.
|
||||
|
||||
title_dic = {"label1": {"title": "This is choice 1"},
|
||||
"label2": {"title": "This is choice 2"},
|
||||
"label3": {"title": "This is choice 3"}}
|
||||
name = forms.CharField(max_length=255,
|
||||
label="Test Name",
|
||||
help_text="Please enter a name")
|
||||
test_choices = forms.ThemableChoiceField(
|
||||
label="Test Choices",
|
||||
required=False,
|
||||
help_text="Testing drop down choices",
|
||||
widget=forms.fields.ThemableSelectWidget(
|
||||
attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'source'},
|
||||
transform_html_attrs=title_dic.get))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(TestThemableChoiceFieldForm, self).__init__(request, *args,
|
||||
**kwargs)
|
||||
choices = ([('choice1', 'label1'),
|
||||
('choice2', 'label2')])
|
||||
self.fields['test_choices'].choices = choices
|
||||
|
||||
def handle(self, request, data):
|
||||
return True
|
||||
|
||||
|
||||
class ThemableChoiceFieldTests(test.TestCase):
|
||||
|
||||
template = 'horizon/common/_form_fields.html'
|
||||
|
||||
def setUp(self):
|
||||
super(ThemableChoiceFieldTests, self).setUp()
|
||||
self.form = TestThemableChoiceFieldForm(self.request)
|
||||
|
||||
def _render_form(self):
|
||||
return shortcuts.render(self.request, self.template,
|
||||
{'form': self.form})
|
||||
|
||||
def test_choicefield_labels_and_title_attr(self):
|
||||
resp = self._render_form()
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<a data-select-value="choice1" title="This is choice 1">'
|
||||
'label1</a>',
|
||||
count=1,
|
||||
html=True)
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<a data-select-value="choice2" title="This is choice 2">'
|
||||
'label2</a>',
|
||||
count=1,
|
||||
html=True)
|
||||
|
||||
def test_choicefield_title_select_compatible(self):
|
||||
resp = self._render_form()
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<option value="choice1" title="This is choice 1">label1</option>',
|
||||
count=1, html=True)
|
||||
self.assertContains(
|
||||
resp,
|
||||
'<option value="choice2" title="This is choice 2">label2</option>',
|
||||
count=1, html=True)
|
|
@ -0,0 +1,106 @@
|
|||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django import shortcuts
|
||||
|
||||
from horizon import forms
|
||||
from horizon.test import helpers as test
|
||||
|
||||
|
||||
class FormMixinTests(test.TestCase):
|
||||
|
||||
def _prepare_view(self, cls, request_headers, *args, **kwargs):
|
||||
req = self.factory.get('/my_url/', **request_headers)
|
||||
req.user = self.user
|
||||
view = cls()
|
||||
view.request = req
|
||||
view.args = args
|
||||
view.kwargs = kwargs
|
||||
view.template_name = 'test_template'
|
||||
# Note(Itxaka): ModalFormView requires a form_class to behave properly
|
||||
view.form_class = TestForm
|
||||
return view
|
||||
|
||||
def test_modal_form_mixin_hide_true_if_ajax(self):
|
||||
view = self._prepare_view(
|
||||
forms.views.ModalFormView,
|
||||
dict(HTTP_X_REQUESTED_WITH='XMLHttpRequest'))
|
||||
context = view.get_context_data()
|
||||
self.assertTrue(context['hide'])
|
||||
|
||||
def test_modal_form_mixin_add_to_field_header_set(self):
|
||||
return self._test_form_mixin_add_to_field_header(add_field=True)
|
||||
|
||||
def test_modal_form_mixin_add_to_field_header_not_set(self):
|
||||
return self._test_form_mixin_add_to_field_header(add_field=False)
|
||||
|
||||
def _test_form_mixin_add_to_field_header(self, add_field=False):
|
||||
options = dict(HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
if add_field:
|
||||
options[forms.views.ADD_TO_FIELD_HEADER] = "keepme"
|
||||
|
||||
view = self._prepare_view(forms.views.ModalFormView, options)
|
||||
context = view.get_context_data()
|
||||
|
||||
if add_field:
|
||||
self.assertEqual("keepme", context['add_to_field'])
|
||||
else:
|
||||
self.assertNotIn('add_to_field', context)
|
||||
|
||||
def test_template_name_change_based_on_ajax_request(self):
|
||||
view = self._prepare_view(
|
||||
forms.views.ModalFormView,
|
||||
dict(HTTP_X_REQUESTED_WITH='XMLHttpRequest'))
|
||||
self.assertEqual('_' + view.template_name,
|
||||
view.get_template_names())
|
||||
|
||||
view = self._prepare_view(forms.views.ModalFormView, {})
|
||||
self.assertEqual(view.template_name, view.get_template_names())
|
||||
|
||||
|
||||
class TestForm(forms.SelfHandlingForm):
|
||||
|
||||
name = forms.CharField(max_length=255)
|
||||
|
||||
def handle(self, request, data):
|
||||
return True
|
||||
|
||||
|
||||
class FormErrorTests(test.TestCase):
|
||||
|
||||
template = 'horizon/common/_form_fields.html'
|
||||
|
||||
def setUp(self):
|
||||
super(FormErrorTests, self).setUp()
|
||||
# Note(Itxaka): We pass data to the form so its bound and has the
|
||||
# proper cleaned_data fields
|
||||
self.form = TestForm(self.request, data={'fake': 'data'})
|
||||
|
||||
def _render_form(self):
|
||||
return shortcuts.render(self.request, self.template,
|
||||
{'form': self.form})
|
||||
|
||||
def test_set_warning(self):
|
||||
warning_text = 'WARNING 29380'
|
||||
self.form.set_warning(warning_text)
|
||||
self.assertEqual([warning_text], self.form.warnings)
|
||||
resp = self._render_form()
|
||||
self.assertIn(warning_text.encode('utf-8'), resp.content)
|
||||
|
||||
def test_api_error(self):
|
||||
error_text = 'ERROR 12938'
|
||||
self.form.full_clean()
|
||||
self.form.api_error(error_text)
|
||||
self.assertEqual([error_text], self.form.non_field_errors())
|
||||
resp = self._render_form()
|
||||
self.assertIn(error_text.encode('utf-8'), resp.content)
|
|
@ -19,7 +19,6 @@ from django.core.management import CommandError
|
|||
from django.test import TestCase
|
||||
|
||||
from horizon.management.commands import startdash
|
||||
from horizon.management.commands import startpanel
|
||||
|
||||
|
||||
class CommandsTestCase(TestCase):
|
||||
|
@ -36,16 +35,3 @@ class CommandsTestCase(TestCase):
|
|||
files=[], no_color=False, pythonpath=None,
|
||||
settings=None, skip_checks=True, target=None,
|
||||
template=None, traceback=False, verbosity=1)
|
||||
|
||||
def test_startpanel_usage_empty(self):
|
||||
self.assertRaises(CommandError, call_command, 'startpanel')
|
||||
|
||||
@mock.patch.object(startpanel.Command, 'handle', return_value='')
|
||||
def test_startpanel_usage_correct(self, handle):
|
||||
call_command('startpanel', 'test_dash', '--dashboard=foo.bar')
|
||||
|
||||
handle.assert_called_with(panel_name='test_dash', dashboard='foo.bar',
|
||||
extensions=["py", "tmpl", "html"],
|
||||
files=[], no_color=False, pythonpath=None,
|
||||
settings=None, skip_checks=True, target=None,
|
||||
template=None, traceback=False, verbosity=1)
|
|
@ -0,0 +1,36 @@
|
|||
# Copyright 2015, Rackspace, US, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from django.core.management import call_command
|
||||
from django.core.management import CommandError
|
||||
from django.test import TestCase
|
||||
|
||||
from horizon.management.commands import startpanel
|
||||
|
||||
|
||||
class CommandsTestCase(TestCase):
|
||||
def test_startpanel_usage_empty(self):
|
||||
self.assertRaises(CommandError, call_command, 'startpanel')
|
||||
|
||||
@mock.patch.object(startpanel.Command, 'handle', return_value='')
|
||||
def test_startpanel_usage_correct(self, handle):
|
||||
call_command('startpanel', 'test_dash', '--dashboard=foo.bar')
|
||||
|
||||
handle.assert_called_with(panel_name='test_dash', dashboard='foo.bar',
|
||||
extensions=["py", "tmpl", "html"],
|
||||
files=[], no_color=False, pythonpath=None,
|
||||
settings=None, skip_checks=True, target=None,
|
||||
template=None, traceback=False, verbosity=1)
|
|
@ -0,0 +1,80 @@
|
|||
# Copyright 2012 OpenStack Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import django
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils import timezone
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import middleware
|
||||
from horizon.test import helpers as test
|
||||
|
||||
|
||||
class MiddlewareTests(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self._timezone_backup = timezone.get_current_timezone_name()
|
||||
return super(MiddlewareTests, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
timezone.activate(self._timezone_backup)
|
||||
return super(MiddlewareTests, self).tearDown()
|
||||
|
||||
def test_redirect_login_fail_to_login(self):
|
||||
url = settings.LOGIN_URL
|
||||
request = self.factory.post(url)
|
||||
|
||||
mw = middleware.HorizonMiddleware()
|
||||
resp = mw.process_exception(request, exceptions.NotAuthenticated())
|
||||
resp.client = self.client
|
||||
|
||||
if django.VERSION >= (1, 9):
|
||||
self.assertRedirects(resp, settings.TESTSERVER + url)
|
||||
else:
|
||||
self.assertRedirects(resp, url)
|
||||
|
||||
def test_process_response_redirect_on_ajax_request(self):
|
||||
url = settings.LOGIN_URL
|
||||
mw = middleware.HorizonMiddleware()
|
||||
|
||||
request = self.factory.post(url,
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
request.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||
request.horizon = {'async_messages':
|
||||
[('error', 'error_msg', 'extra_tag')]}
|
||||
|
||||
response = HttpResponseRedirect(url)
|
||||
response.client = self.client
|
||||
|
||||
resp = mw.process_response(request, response)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.assertEqual(url, resp['X-Horizon-Location'])
|
||||
|
||||
def test_timezone_awareness(self):
|
||||
url = settings.LOGIN_REDIRECT_URL
|
||||
mw = middleware.HorizonMiddleware()
|
||||
|
||||
request = self.factory.get(url)
|
||||
request.session['django_timezone'] = 'America/Chicago'
|
||||
mw.process_request(request)
|
||||
self.assertEqual(
|
||||
timezone.get_current_timezone_name(), 'America/Chicago')
|
||||
request.session['django_timezone'] = 'Europe/Paris'
|
||||
mw.process_request(request)
|
||||
self.assertEqual(timezone.get_current_timezone_name(), 'Europe/Paris')
|
||||
request.session['django_timezone'] = 'UTC'
|
||||
mw.process_request(request)
|
||||
self.assertEqual(timezone.get_current_timezone_name(), 'UTC')
|
|
@ -14,75 +14,15 @@
|
|||
# under the License.
|
||||
from mock import patch
|
||||
|
||||
import django
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import MiddlewareNotUsed
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.test.utils import override_settings
|
||||
from django.utils import timezone
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import middleware
|
||||
from horizon.test import helpers as test
|
||||
|
||||
|
||||
class MiddlewareTests(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self._timezone_backup = timezone.get_current_timezone_name()
|
||||
return super(MiddlewareTests, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
timezone.activate(self._timezone_backup)
|
||||
return super(MiddlewareTests, self).tearDown()
|
||||
|
||||
def test_redirect_login_fail_to_login(self):
|
||||
url = settings.LOGIN_URL
|
||||
request = self.factory.post(url)
|
||||
|
||||
mw = middleware.HorizonMiddleware()
|
||||
resp = mw.process_exception(request, exceptions.NotAuthenticated())
|
||||
resp.client = self.client
|
||||
|
||||
if django.VERSION >= (1, 9):
|
||||
self.assertRedirects(resp, settings.TESTSERVER + url)
|
||||
else:
|
||||
self.assertRedirects(resp, url)
|
||||
|
||||
def test_process_response_redirect_on_ajax_request(self):
|
||||
url = settings.LOGIN_URL
|
||||
mw = middleware.HorizonMiddleware()
|
||||
|
||||
request = self.factory.post(url,
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
request.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||
request.horizon = {'async_messages':
|
||||
[('error', 'error_msg', 'extra_tag')]}
|
||||
|
||||
response = HttpResponseRedirect(url)
|
||||
response.client = self.client
|
||||
|
||||
resp = mw.process_response(request, response)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.assertEqual(url, resp['X-Horizon-Location'])
|
||||
|
||||
def test_timezone_awareness(self):
|
||||
url = settings.LOGIN_REDIRECT_URL
|
||||
mw = middleware.HorizonMiddleware()
|
||||
|
||||
request = self.factory.get(url)
|
||||
request.session['django_timezone'] = 'America/Chicago'
|
||||
mw.process_request(request)
|
||||
self.assertEqual(
|
||||
timezone.get_current_timezone_name(), 'America/Chicago')
|
||||
request.session['django_timezone'] = 'Europe/Paris'
|
||||
mw.process_request(request)
|
||||
self.assertEqual(timezone.get_current_timezone_name(), 'Europe/Paris')
|
||||
request.session['django_timezone'] = 'UTC'
|
||||
mw.process_request(request)
|
||||
self.assertEqual(timezone.get_current_timezone_name(), 'UTC')
|
||||
|
||||
|
||||
class OperationLogMiddlewareTest(test.TestCase):
|
||||
|
||||
http_host = u'test_host'
|
|
@ -26,8 +26,8 @@ from horizon import middleware
|
|||
from horizon import tabs as horizon_tabs
|
||||
from horizon.test import helpers as test
|
||||
|
||||
from horizon.test.tests.tables import MyTable
|
||||
from horizon.test.tests.tables import TEST_DATA
|
||||
from horizon.test.unit.tables.test_tables import MyTable
|
||||
from horizon.test.unit.tables.test_tables import TEST_DATA
|
||||
|
||||
|
||||
class BaseTestTab(horizon_tabs.Tab):
|
|
@ -17,7 +17,7 @@ import os
|
|||
from django.conf import settings
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon.notifications import JSONMessage
|
||||
from horizon import notifications
|
||||
from horizon.test import helpers as test
|
||||
|
||||
|
||||
|
@ -27,7 +27,7 @@ class NotificationTests(test.TestCase):
|
|||
'messages'))
|
||||
|
||||
def _test_msg(self, path, expected_level, expected_msg=''):
|
||||
msg = JSONMessage(path)
|
||||
msg = notifications.JSONMessage(path)
|
||||
msg.load()
|
||||
|
||||
self.assertEqual(expected_level, msg.level_name)
|
||||
|
@ -47,13 +47,13 @@ class NotificationTests(test.TestCase):
|
|||
path = self.MESSAGES_PATH + '/test_invalid.json'
|
||||
|
||||
with self.assertRaises(exceptions.MessageFailure):
|
||||
msg = JSONMessage(path)
|
||||
msg = notifications.JSONMessage(path)
|
||||
msg.load()
|
||||
|
||||
def test_invalid_msg_file_fail_silently(self):
|
||||
path = self.MESSAGES_PATH + '/test_invalid.json'
|
||||
|
||||
msg = JSONMessage(path, fail_silently=True)
|
||||
msg = notifications.JSONMessage(path, fail_silently=True)
|
||||
msg.load()
|
||||
|
||||
self.assertTrue(msg.failed)
|
|
@ -0,0 +1,100 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
|
||||
import django.template
|
||||
from django.template import defaultfilters
|
||||
|
||||
from horizon.test import helpers as test
|
||||
from horizon.utils import filters
|
||||
# we have to import the filter in order to register it
|
||||
from horizon.utils.filters import parse_isotime # noqa: F401
|
||||
|
||||
|
||||
class FiltersTests(test.TestCase):
|
||||
def test_replace_underscore_filter(self):
|
||||
res = filters.replace_underscores("__under_score__")
|
||||
self.assertEqual(" under score ", res)
|
||||
|
||||
def test_parse_isotime_filter(self):
|
||||
c = django.template.Context({'time': ''})
|
||||
t = django.template.Template('{{ time|parse_isotime }}')
|
||||
output = u""
|
||||
|
||||
self.assertEqual(output, t.render(c))
|
||||
|
||||
c = django.template.Context({'time': 'error'})
|
||||
t = django.template.Template('{{ time|parse_isotime }}')
|
||||
output = u""
|
||||
|
||||
self.assertEqual(output, t.render(c))
|
||||
|
||||
c = django.template.Context({'time': 'error'})
|
||||
t = django.template.Template('{{ time|parse_isotime:"test" }}')
|
||||
output = u"test"
|
||||
|
||||
self.assertEqual(output, t.render(c))
|
||||
|
||||
c = django.template.Context({'time': '2007-03-04T21:08:12'})
|
||||
t = django.template.Template('{{ time|parse_isotime:"test" }}')
|
||||
output = u"March 4, 2007, 3:08 p.m."
|
||||
|
||||
self.assertEqual(output, t.render(c))
|
||||
|
||||
adate = '2007-01-25T12:00:00Z'
|
||||
result = filters.parse_isotime(adate)
|
||||
self.assertIsInstance(result, datetime.datetime)
|
||||
|
||||
|
||||
class TimeSinceNeverFilterTests(test.TestCase):
|
||||
|
||||
default = u"Never"
|
||||
|
||||
def test_timesince_or_never_returns_default_for_empty_string(self):
|
||||
c = django.template.Context({'time': ''})
|
||||
t = django.template.Template('{{ time|timesince_or_never }}')
|
||||
self.assertEqual(self.default, t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_default_for_none(self):
|
||||
c = django.template.Context({'time': None})
|
||||
t = django.template.Template('{{ time|timesince_or_never }}')
|
||||
self.assertEqual(self.default, t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_default_for_gibberish(self):
|
||||
c = django.template.Context({'time': django.template.Context()})
|
||||
t = django.template.Template('{{ time|timesince_or_never }}')
|
||||
self.assertEqual(self.default, t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_with_custom_default(self):
|
||||
custom = "Hello world"
|
||||
c = django.template.Context({'date': ''})
|
||||
t = django.template.Template('{{ date|timesince_or_never:"%s" }}'
|
||||
% custom)
|
||||
self.assertEqual(custom, t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_with_custom_empty_string_default(self):
|
||||
c = django.template.Context({'date': ''})
|
||||
t = django.template.Template('{{ date|timesince_or_never:"" }}')
|
||||
self.assertEqual("", t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_same_output_as_django_date(self):
|
||||
d = datetime.date(year=2014, month=3, day=7)
|
||||
c = django.template.Context({'date': d})
|
||||
t = django.template.Template('{{ date|timesince_or_never }}')
|
||||
self.assertEqual(defaultfilters.timesince(d), t.render(c))
|
||||
|
||||
def test_timesince_or_never_returns_same_output_as_django_datetime(self):
|
||||
now = datetime.datetime.now()
|
||||
c = django.template.Context({'date': now})
|
||||
t = django.template.Template('{{ date|timesince_or_never }}')
|
||||
self.assertEqual(defaultfilters.timesince(now), t.render(c))
|
|
@ -0,0 +1,97 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from horizon.test import helpers as test
|
||||
from horizon.utils import functions
|
||||
|
||||
|
||||
class GetConfigValueTests(test.TestCase):
|
||||
key = 'key'
|
||||
value = 'value'
|
||||
requested_url = '/project/instances/'
|
||||
int_default = 30
|
||||
str_default = 'default'
|
||||
|
||||
def test_bad_session_value(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
request.session[self.key] = self.value
|
||||
res = functions.get_config_value(request, self.key, self.int_default)
|
||||
self.assertEqual(res, self.int_default)
|
||||
|
||||
def test_bad_cookie_value(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
if self.key in request.session:
|
||||
del request.session[self.key]
|
||||
request.COOKIES[self.key] = self.value
|
||||
res = functions.get_config_value(request, self.key, self.int_default)
|
||||
self.assertEqual(res, self.int_default)
|
||||
|
||||
def test_float_default_value(self):
|
||||
default = 30.1
|
||||
request = self.factory.get(self.requested_url)
|
||||
request.session[self.key] = self.value
|
||||
res = functions.get_config_value(request, self.key, default)
|
||||
self.assertEqual(res, self.value)
|
||||
|
||||
def test_session_gets_set(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
request.session[self.key] = self.value
|
||||
functions.get_config_value(request, self.key, self.int_default)
|
||||
self.assertEqual(request.session[self.key], self.int_default)
|
||||
|
||||
def test_found_in_session(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
request.session[self.key] = self.value
|
||||
if request.COOKIES.get(self.key):
|
||||
del request.COOKIES[self.key]
|
||||
res = functions.get_config_value(request, self.key, self.str_default)
|
||||
self.assertEqual(res, self.value)
|
||||
|
||||
def test_found_in_cookie(self):
|
||||
request = self.factory.get(self.requested_url)
|
||||
if request.session.get(self.key):
|
||||
del request.session[self.key]
|
||||
request.COOKIES[self.key] = self.value
|
||||
res = functions.get_config_value(request, self.key, self.str_default)
|
||||
self.assertEqual(res, self.value)
|
||||
|
||||
def test_found_in_config(self):
|
||||
key = 'TESTSERVER'
|
||||
value = 'http://testserver'
|
||||
request = self.factory.get(self.requested_url)
|
||||
if request.session.get(key):
|
||||
del request.session[key]
|
||||
if request.COOKIES.get(key):
|
||||
del request.COOKIES[key]
|
||||
res = functions.get_config_value(request, key, self.str_default)
|
||||
self.assertEqual(res, value)
|
||||
|
||||
def test_return_default(self):
|
||||
key = 'NOT FOUND ANYWHERE'
|
||||
request = self.factory.get(self.requested_url)
|
||||
if request.session.get(key):
|
||||
del request.session[key]
|
||||
if request.COOKIES.get(key):
|
||||
del request.COOKIES[key]
|
||||
res = functions.get_config_value(request, key, self.str_default)
|
||||
self.assertEqual(res, self.str_default)
|
||||
|
||||
def test_return_default_no_settings(self):
|
||||
key = 'TESTSERVER'
|
||||
request = self.factory.get(self.requested_url)
|
||||
if request.session.get(key):
|
||||
del request.session[key]
|
||||
if request.COOKIES.get(key):
|
||||
del request.COOKIES[key]
|
||||
res = functions.get_config_value(request, key, self.str_default,
|
||||
search_in_settings=False)
|
||||
self.assertEqual(res, self.str_default)
|
|
@ -0,0 +1,83 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from horizon.test import helpers as test
|
||||
from horizon.utils import memoized
|
||||
|
||||
|
||||
class MemoizedTests(test.TestCase):
|
||||
def test_memoized_decorator_cache_on_next_call(self):
|
||||
values_list = []
|
||||
|
||||
@memoized.memoized
|
||||
def cache_calls(remove_from):
|
||||
values_list.append(remove_from)
|
||||
return True
|
||||
|
||||
def non_cached_calls(remove_from):
|
||||
values_list.append(remove_from)
|
||||
return True
|
||||
|
||||
for x in range(0, 5):
|
||||
non_cached_calls(1)
|
||||
self.assertEqual(5, len(values_list))
|
||||
|
||||
values_list = []
|
||||
for x in range(0, 5):
|
||||
cache_calls(1)
|
||||
self.assertEqual(1, len(values_list))
|
||||
|
||||
def test_memoized_with_request_call(self):
|
||||
|
||||
chorus = [
|
||||
"I",
|
||||
"Love",
|
||||
"Rock 'n' Roll",
|
||||
"put another coin",
|
||||
"in the Jukebox Baby."
|
||||
]
|
||||
|
||||
leader = 'Joan Jett'
|
||||
group = 'Blackhearts'
|
||||
|
||||
for position, chorus_line in enumerate(chorus):
|
||||
|
||||
changed_args = False
|
||||
|
||||
def some_func(some_param):
|
||||
if not changed_args:
|
||||
self.assertEqual(some_param, chorus_line)
|
||||
else:
|
||||
self.assertNotEqual(some_param, chorus_line)
|
||||
self.assertEqual(some_param, group)
|
||||
return leader
|
||||
|
||||
@memoized.memoized_with_request(some_func, position)
|
||||
def some_other_func(*args):
|
||||
return args
|
||||
|
||||
# check chorus_copy[position] is replaced by some_func's
|
||||
# output
|
||||
output1 = some_other_func(*chorus)
|
||||
self.assertEqual(output1[position], leader)
|
||||
|
||||
# Change args used to call the function
|
||||
chorus_copy = list(chorus)
|
||||
chorus_copy[position] = group
|
||||
changed_args = True
|
||||
# check that some_func is called with a different parameter, and
|
||||
# that check chorus_copy[position] is replaced by some_func's
|
||||
# output and some_other_func still called with the same parameters
|
||||
output2 = some_other_func(*chorus_copy)
|
||||
self.assertEqual(output2[position], leader)
|
||||
# check that some_other_func returned a memoized list.
|
||||
self.assertIs(output1, output2)
|
|
@ -0,0 +1,39 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from horizon.utils import secret_key
|
||||
|
||||
|
||||
class SecretKeyTests(unittest.TestCase):
|
||||
pass
|
||||
|
||||
def test_generate_secret_key(self):
|
||||
key = secret_key.generate_key(32)
|
||||
self.assertEqual(32, len(key))
|
||||
self.assertNotEqual(key, secret_key.generate_key(32))
|
||||
|
||||
def test_generate_or_read_key_from_file(self):
|
||||
key_file = ".test_secret_key_store"
|
||||
key = secret_key.generate_or_read_from_file(key_file)
|
||||
|
||||
# Consecutive reads should come from the already existing file:
|
||||
self.assertEqual(secret_key.generate_or_read_from_file(key_file), key)
|
||||
|
||||
# Key file only be read/writable by user:
|
||||
self.assertEqual(0o600, os.stat(key_file).st_mode & 0o777)
|
||||
os.chmod(key_file, 0o644)
|
||||
self.assertRaises(secret_key.FilePermissionError,
|
||||
secret_key.generate_or_read_from_file, key_file)
|
||||
os.remove(key_file)
|
|
@ -0,0 +1,74 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from horizon.test import helpers as test
|
||||
from horizon.utils import units
|
||||
|
||||
|
||||
class UnitsTests(test.TestCase):
|
||||
def test_is_supported(self):
|
||||
self.assertTrue(units.is_supported('MB'))
|
||||
self.assertTrue(units.is_supported('min'))
|
||||
self.assertFalse(units.is_supported('KWh'))
|
||||
self.assertFalse(units.is_supported('unknown_unit'))
|
||||
|
||||
def test_is_larger(self):
|
||||
self.assertTrue(units.is_larger('KB', 'B'))
|
||||
self.assertTrue(units.is_larger('MB', 'B'))
|
||||
self.assertTrue(units.is_larger('GB', 'B'))
|
||||
self.assertTrue(units.is_larger('TB', 'B'))
|
||||
self.assertTrue(units.is_larger('GB', 'MB'))
|
||||
self.assertFalse(units.is_larger('B', 'KB'))
|
||||
self.assertFalse(units.is_larger('MB', 'GB'))
|
||||
|
||||
self.assertTrue(units.is_larger('min', 's'))
|
||||
self.assertTrue(units.is_larger('hr', 'min'))
|
||||
self.assertTrue(units.is_larger('hr', 's'))
|
||||
self.assertFalse(units.is_larger('s', 'min'))
|
||||
|
||||
def test_convert(self):
|
||||
self.assertEqual(units.convert(4096, 'MB', 'GB'), (4, 'GB'))
|
||||
self.assertEqual(units.convert(4, 'GB', 'MB'), (4096, 'MB'))
|
||||
|
||||
self.assertEqual(units.convert(1.5, 'hr', 'min'), (90, 'min'))
|
||||
self.assertEqual(units.convert(12, 'hr', 'day'), (0.5, 'day'))
|
||||
|
||||
def test_normalize(self):
|
||||
self.assertEqual(units.normalize(1, 'B'), (1, 'B'))
|
||||
self.assertEqual(units.normalize(1000, 'B'), (1000, 'B'))
|
||||
self.assertEqual(units.normalize(1024, 'B'), (1, 'KB'))
|
||||
self.assertEqual(units.normalize(1024 * 1024, 'B'), (1, 'MB'))
|
||||
self.assertEqual(units.normalize(10 * 1024 ** 3, 'B'), (10, 'GB'))
|
||||
self.assertEqual(units.normalize(1000 * 1024 ** 4, 'B'), (1000, 'TB'))
|
||||
self.assertEqual(units.normalize(1024, 'KB'), (1, 'MB'))
|
||||
self.assertEqual(units.normalize(1024 ** 2, 'KB'), (1, 'GB'))
|
||||
self.assertEqual(units.normalize(10 * 1024, 'MB'), (10, 'GB'))
|
||||
self.assertEqual(units.normalize(0.5, 'KB'), (512, 'B'))
|
||||
self.assertEqual(units.normalize(0.0001, 'MB'), (104.9, 'B'))
|
||||
|
||||
self.assertEqual(units.normalize(1, 's'), (1, 's'))
|
||||
self.assertEqual(units.normalize(120, 's'), (2, 'min'))
|
||||
self.assertEqual(units.normalize(3600, 's'), (60, 'min'))
|
||||
self.assertEqual(units.normalize(3600 * 24, 's'), (24, 'hr'))
|
||||
self.assertEqual(units.normalize(10 * 3600 * 24, 's'), (10, 'day'))
|
||||
self.assertEqual(units.normalize(90, 'min'), (90, 'min'))
|
||||
self.assertEqual(units.normalize(150, 'min'), (2.5, 'hr'))
|
||||
self.assertEqual(units.normalize(60 * 24, 'min'), (24, 'hr'))
|
||||
self.assertEqual(units.normalize(0.5, 'day'), (12, 'hr'))
|
||||
self.assertEqual(units.normalize(10800000000000, 'ns'), (3, 'hr'))
|
||||
self.assertEqual(units.normalize(14, 'day'), (2, 'week'))
|
||||
self.assertEqual(units.normalize(91, 'day'), (3, 'month'))
|
||||
self.assertEqual(units.normalize(18, 'month'), (18, 'month'))
|
||||
self.assertEqual(units.normalize(24, 'month'), (2, 'year'))
|
||||
|
||||
self.assertEqual(units.normalize(1, 'unknown_unit'),
|
||||
(1, 'unknown_unit'))
|
|
@ -0,0 +1,99 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from horizon.test import helpers as test
|
||||
from horizon.utils import validators
|
||||
|
||||
|
||||
class ValidatorsTests(test.TestCase):
|
||||
|
||||
def test_port_validator(self):
|
||||
VALID_PORTS = (1, 65535)
|
||||
INVALID_PORTS = (-1, 65536)
|
||||
|
||||
for port in VALID_PORTS:
|
||||
self.assertIsNone(validators.validate_port_range(port))
|
||||
|
||||
for port in INVALID_PORTS:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_port_range,
|
||||
port)
|
||||
|
||||
def test_icmp_type_validator(self):
|
||||
VALID_ICMP_TYPES = (1, 0, 255, -1)
|
||||
INVALID_ICMP_TYPES = (256, None, -2)
|
||||
|
||||
for icmp_type in VALID_ICMP_TYPES:
|
||||
self.assertIsNone(validators.validate_icmp_type_range(icmp_type))
|
||||
|
||||
for icmp_type in INVALID_ICMP_TYPES:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_icmp_type_range,
|
||||
icmp_type)
|
||||
|
||||
def test_icmp_code_validator(self):
|
||||
VALID_ICMP_CODES = (1, 0, 255, None, -1,)
|
||||
INVALID_ICMP_CODES = (256, -2)
|
||||
|
||||
for icmp_code in VALID_ICMP_CODES:
|
||||
self.assertIsNone(validators.validate_icmp_code_range(icmp_code))
|
||||
|
||||
for icmp_code in INVALID_ICMP_CODES:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_icmp_code_range,
|
||||
icmp_code)
|
||||
|
||||
def test_ip_proto_validator(self):
|
||||
VALID_PROTO = (0, 255, -1)
|
||||
INVALID_PROTO = (-2, 256)
|
||||
|
||||
for proto in VALID_PROTO:
|
||||
self.assertIsNone(validators.validate_ip_protocol(proto))
|
||||
|
||||
for proto in INVALID_PROTO:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_ip_protocol,
|
||||
proto)
|
||||
|
||||
def test_port_range_validator(self):
|
||||
VALID_RANGE = ('1:65535',
|
||||
'1:1')
|
||||
INVALID_RANGE = ('22:22:22:22',
|
||||
'1:-1',
|
||||
'-1:65535')
|
||||
|
||||
test_call = validators.validate_port_or_colon_separated_port_range
|
||||
for prange in VALID_RANGE:
|
||||
self.assertIsNone(test_call(prange))
|
||||
|
||||
for prange in INVALID_RANGE:
|
||||
self.assertRaises(ValidationError, test_call, prange)
|
||||
|
||||
def test_metadata_validator(self):
|
||||
VALID_METADATA = (
|
||||
"key1=val1", "key1=val1,key2=val2",
|
||||
"key1=val1,key2=val2,key3=val3", "key1="
|
||||
)
|
||||
INVALID_METADATA = (
|
||||
"key1==val1", "key1=val1,", "=val1",
|
||||
"=val1", " "
|
||||
)
|
||||
|
||||
for mdata in VALID_METADATA:
|
||||
self.assertIsNone(validators.validate_metadata(mdata))
|
||||
|
||||
for mdata in INVALID_METADATA:
|
||||
self.assertRaises(ValidationError,
|
||||
validators.validate_metadata,
|
||||
mdata)
|
|
@ -110,7 +110,8 @@ class TestStepTwo(workflows.Step):
|
|||
contributes = ("instance_id",)
|
||||
connections = {"project_id":
|
||||
(local_callback_func,
|
||||
"horizon.test.tests.workflows.other_callback_func")}
|
||||
"horizon.test.unit.workflows.test_workflows."
|
||||
"other_callback_func")}
|
||||
|
||||
|
||||
class TestExtraStep(workflows.Step):
|
Loading…
Reference in New Issue