# # # from unittest import TestCase from helpers import SimpleProvider from octodns.record import Record from octodns.record.exception import ValidationError from octodns.record.rr import RrParseError from octodns.record.urlfwd import UrlfwdRecord, UrlfwdValue from octodns.zone import Zone class TestRecordUrlfwd(TestCase): zone = Zone('unit.tests.', []) def test_urlfwd(self): a_values = [ UrlfwdValue( { 'path': '/', 'target': 'http://foo', 'code': 301, 'masking': 2, 'query': 0, } ), UrlfwdValue( { 'path': '/target', 'target': 'http://target', 'code': 302, 'masking': 2, 'query': 0, } ), ] a_data = {'ttl': 30, 'values': a_values} a = UrlfwdRecord(self.zone, 'a', a_data) self.assertEqual('a', a.name) self.assertEqual('a.unit.tests.', a.fqdn) self.assertEqual(30, a.ttl) self.assertEqual(a_values[0]['path'], a.values[0].path) self.assertEqual(a_values[0]['target'], a.values[0].target) self.assertEqual(a_values[0]['code'], a.values[0].code) self.assertEqual(a_values[0]['masking'], a.values[0].masking) self.assertEqual(a_values[0]['query'], a.values[0].query) self.assertEqual(a_values[1]['path'], a.values[1].path) self.assertEqual(a_values[1]['target'], a.values[1].target) self.assertEqual(a_values[1]['code'], a.values[1].code) self.assertEqual(a_values[1]['masking'], a.values[1].masking) self.assertEqual(a_values[1]['query'], a.values[1].query) self.assertEqual(a_data, a.data) b_value = UrlfwdValue( { 'path': '/', 'target': 'http://location', 'code': 301, 'masking': 2, 'query': 0, } ) b_data = {'ttl': 30, 'value': b_value} b = UrlfwdRecord(self.zone, 'b', b_data) self.assertEqual(b_value['path'], b.values[0].path) self.assertEqual(b_value['target'], b.values[0].target) self.assertEqual(b_value['code'], b.values[0].code) self.assertEqual(b_value['masking'], b.values[0].masking) self.assertEqual(b_value['query'], b.values[0].query) self.assertEqual(b_data, b.data) target = SimpleProvider() # No changes with self self.assertFalse(a.changes(a, target)) # Diff in path causes change other = UrlfwdRecord(self.zone, 'a', {'ttl': 30, 'values': a_values}) other.values[0].path = '/change' change = a.changes(other, target) self.assertEqual(change.existing, a) self.assertEqual(change.new, other) # Diff in target causes change other = UrlfwdRecord(self.zone, 'a', {'ttl': 30, 'values': a_values}) other.values[0].target = 'http://target' change = a.changes(other, target) self.assertEqual(change.existing, a) self.assertEqual(change.new, other) # Diff in code causes change other = UrlfwdRecord(self.zone, 'a', {'ttl': 30, 'values': a_values}) other.values[0].code = 302 change = a.changes(other, target) self.assertEqual(change.existing, a) self.assertEqual(change.new, other) # Diff in masking causes change other = UrlfwdRecord(self.zone, 'a', {'ttl': 30, 'values': a_values}) other.values[0].masking = 0 change = a.changes(other, target) self.assertEqual(change.existing, a) self.assertEqual(change.new, other) # Diff in query causes change other = UrlfwdRecord(self.zone, 'a', {'ttl': 30, 'values': a_values}) other.values[0].query = 1 change = a.changes(other, target) self.assertEqual(change.existing, a) self.assertEqual(change.new, other) # hash v = UrlfwdValue( { 'path': '/', 'target': 'http://place', 'code': 301, 'masking': 2, 'query': 0, } ) o = UrlfwdValue( { 'path': '/location', 'target': 'http://redirect', 'code': 302, 'masking': 2, 'query': 0, } ) values = set() values.add(v) self.assertTrue(v in values) self.assertFalse(o in values) values.add(o) self.assertTrue(o in values) # __repr__ doesn't blow up a.__repr__() def test_validation(self): # doesn't blow up Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'code': 301, 'masking': 2, 'query': 0, }, }, ) Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'values': [ { 'path': '/', 'target': 'http://foo', 'code': 301, 'masking': 2, 'query': 0, }, { 'path': '/target', 'target': 'http://target', 'code': 302, 'masking': 2, 'query': 0, }, ], }, ) # missing path with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'target': 'http://foo', 'code': 301, 'masking': 2, 'query': 0, }, }, ) self.assertEqual(['missing path'], ctx.exception.reasons) # missing target with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'code': 301, 'masking': 2, 'query': 0, }, }, ) self.assertEqual(['missing target'], ctx.exception.reasons) # missing code with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'masking': 2, 'query': 0, }, }, ) self.assertEqual(['missing code'], ctx.exception.reasons) # invalid code with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'code': 'nope', 'masking': 2, 'query': 0, }, }, ) self.assertEqual(['invalid return code "nope"'], ctx.exception.reasons) # unrecognized code with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'code': 3, 'masking': 2, 'query': 0, }, }, ) self.assertEqual( ['unrecognized return code "3"'], ctx.exception.reasons ) # missing masking with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'code': 301, 'query': 0, }, }, ) self.assertEqual(['missing masking'], ctx.exception.reasons) # invalid masking with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'code': 301, 'masking': 'nope', 'query': 0, }, }, ) self.assertEqual( ['invalid masking setting "nope"'], ctx.exception.reasons ) # unrecognized masking with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'code': 301, 'masking': 3, 'query': 0, }, }, ) self.assertEqual( ['unrecognized masking setting "3"'], ctx.exception.reasons ) # missing query with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'code': 301, 'masking': 2, }, }, ) self.assertEqual(['missing query'], ctx.exception.reasons) # invalid query with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'code': 301, 'masking': 2, 'query': 'nope', }, }, ) self.assertEqual( ['invalid query setting "nope"'], ctx.exception.reasons ) # unrecognized query with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'URLFWD', 'ttl': 600, 'value': { 'path': '/', 'target': 'http://foo', 'code': 301, 'masking': 2, 'query': 3, }, }, ) self.assertEqual( ['unrecognized query setting "3"'], ctx.exception.reasons ) def test_urlfwd_value_rdata_text(self): # empty string won't parse with self.assertRaises(RrParseError): UrlfwdValue.parse_rdata_text('') # single word won't parse with self.assertRaises(RrParseError): UrlfwdValue.parse_rdata_text('nope') # 2nd word won't parse with self.assertRaises(RrParseError): UrlfwdValue.parse_rdata_text('1 2') # 3rd word won't parse with self.assertRaises(RrParseError): UrlfwdValue.parse_rdata_text('1 2 3') # 4th word won't parse with self.assertRaises(RrParseError): UrlfwdValue.parse_rdata_text('1 2 3 4') # 6th word won't parse with self.assertRaises(RrParseError): UrlfwdValue.parse_rdata_text('1 2 3 4 5 6') # code, masking, and query not ints self.assertEqual( { 'path': 'one', 'target': 'urlfwd.unit.tests.', 'code': 'one', 'masking': 'two', 'query': 'three', }, UrlfwdValue.parse_rdata_text( 'one urlfwd.unit.tests. one two three' ), ) # valid self.assertEqual( { 'path': 'one', 'target': 'urlfwd.unit.tests.', 'code': 1, 'masking': 2, 'query': 3, }, UrlfwdValue.parse_rdata_text('one urlfwd.unit.tests. 1 2 3'), ) # quoted self.assertEqual( { 'path': 'one', 'target': 'urlfwd.unit.tests.', 'code': 1, 'masking': 2, 'query': 3, }, UrlfwdValue.parse_rdata_text('"one" "urlfwd.unit.tests." 1 2 3'), ) zone = Zone('unit.tests.', []) a = UrlfwdRecord( zone, 'urlfwd', { 'ttl': 32, 'value': { 'path': 'one', 'target': 'urlfwd.unit.tests.', 'code': 1, 'masking': 2, 'query': 3, }, }, ) self.assertEqual('one', a.values[0].path) self.assertEqual('urlfwd.unit.tests.', a.values[0].target) self.assertEqual(1, a.values[0].code) self.assertEqual(2, a.values[0].masking) self.assertEqual(3, a.values[0].query) # both directions should match rdata = '"one" "urlfwd.unit.tests." 1 2 3' record = UrlfwdRecord( zone, 'urlfwd', {'ttl': 32, 'value': UrlfwdValue.parse_rdata_text(rdata)}, ) self.assertEqual(rdata, record.values[0].rdata_text) class TestUrlfwdValue(TestCase): def test_template(self): value = UrlfwdValue( { 'path': '/', 'target': 'http://foo', 'code': 301, 'masking': 2, 'query': 0, } ) got = value.template({'needle': 42}) self.assertIs(value, got) value = UrlfwdValue( { 'path': '/{needle}', 'target': 'http://foo.{needle}', 'code': 301, 'masking': 2, 'query': 0, } ) got = value.template({'needle': 42}) self.assertIsNot(value, got) self.assertEqual('/42', got.path) self.assertEqual('http://foo.42', got.target)