# # # from unittest import TestCase from octodns.record import Record from octodns.record.tlsa import TlsaRecord, TlsaValue from octodns.record.exception import ValidationError from octodns.record.rr import RrParseError from octodns.zone import Zone from helpers import SimpleProvider class TestRecordTlsa(TestCase): zone = Zone('unit.tests.', []) def test_tlsa(self): a_values = [ TlsaValue( { 'certificate_usage': 1, 'selector': 1, 'matching_type': 1, 'certificate_association_data': 'ABABABABABABABABAB', } ), TlsaValue( { 'certificate_usage': 2, 'selector': 0, 'matching_type': 2, 'certificate_association_data': 'ABABABABABABABABAC', } ), ] a_data = {'ttl': 30, 'values': a_values} a = TlsaRecord(self.zone, 'a', a_data) self.assertEqual('a.unit.tests.', a.fqdn) self.assertEqual('a', a.name) self.assertEqual(30, a.ttl) self.assertEqual( a_values[0]['certificate_usage'], a.values[0].certificate_usage ) self.assertEqual(a_values[0]['selector'], a.values[0].selector) self.assertEqual( a_values[0]['matching_type'], a.values[0].matching_type ) self.assertEqual( a_values[0]['certificate_association_data'], a.values[0].certificate_association_data, ) self.assertEqual( a_values[1]['certificate_usage'], a.values[1].certificate_usage ) self.assertEqual(a_values[1]['selector'], a.values[1].selector) self.assertEqual( a_values[1]['matching_type'], a.values[1].matching_type ) self.assertEqual( a_values[1]['certificate_association_data'], a.values[1].certificate_association_data, ) self.assertEqual(a_data, a.data) b_value = TlsaValue( { 'certificate_usage': 0, 'selector': 0, 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAAAA', } ) b_data = {'ttl': 30, 'value': b_value} b = TlsaRecord(self.zone, 'b', b_data) self.assertEqual( b_value['certificate_usage'], b.values[0].certificate_usage ) self.assertEqual(b_value['selector'], b.values[0].selector) self.assertEqual(b_value['matching_type'], b.values[0].matching_type) self.assertEqual( b_value['certificate_association_data'], b.values[0].certificate_association_data, ) self.assertEqual(b_data, b.data) target = SimpleProvider() # No changes with self self.assertFalse(a.changes(a, target)) # Diff in certificate_usage causes change other = TlsaRecord(self.zone, 'a', {'ttl': 30, 'values': a_values}) other.values[0].certificate_usage = 0 change = a.changes(other, target) self.assertEqual(change.existing, a) self.assertEqual(change.new, other) # Diff in selector causes change other = TlsaRecord(self.zone, 'a', {'ttl': 30, 'values': a_values}) other.values[0].selector = 0 change = a.changes(other, target) self.assertEqual(change.existing, a) self.assertEqual(change.new, other) # Diff in matching_type causes change other = TlsaRecord(self.zone, 'a', {'ttl': 30, 'values': a_values}) other.values[0].matching_type = 0 change = a.changes(other, target) self.assertEqual(change.existing, a) self.assertEqual(change.new, other) # Diff in certificate_association_data causes change other = TlsaRecord(self.zone, 'a', {'ttl': 30, 'values': a_values}) other.values[0].certificate_association_data = 'AAAAAAAAAAAAA' change = a.changes(other, target) self.assertEqual(change.existing, a) self.assertEqual(change.new, other) # __repr__ doesn't blow up a.__repr__() def test_tsla_value_rdata_text(self): # empty string won't parse with self.assertRaises(RrParseError): TlsaValue.parse_rdata_text('') # single word won't parse with self.assertRaises(RrParseError): TlsaValue.parse_rdata_text('nope') # 2nd word won't parse with self.assertRaises(RrParseError): TlsaValue.parse_rdata_text('1 2') # 3rd word won't parse with self.assertRaises(RrParseError): TlsaValue.parse_rdata_text('1 2 3') # 5th word won't parse with self.assertRaises(RrParseError): TlsaValue.parse_rdata_text('1 2 3 abcd another') # non-ints self.assertEqual( { 'certificate_usage': 'one', 'selector': 'two', 'matching_type': 'three', 'certificate_association_data': 'abcd', }, TlsaValue.parse_rdata_text('one two three abcd'), ) # valid self.assertEqual( { 'certificate_usage': 1, 'selector': 2, 'matching_type': 3, 'certificate_association_data': 'abcd', }, TlsaValue.parse_rdata_text('1 2 3 abcd'), ) zone = Zone('unit.tests.', []) a = TlsaRecord( zone, 'tlsa', { 'ttl': 32, 'value': { 'certificate_usage': 2, 'selector': 1, 'matching_type': 0, 'certificate_association_data': 'abcd', }, }, ) self.assertEqual(2, a.values[0].certificate_usage) self.assertEqual(1, a.values[0].selector) self.assertEqual(0, a.values[0].matching_type) self.assertEqual('abcd', a.values[0].certificate_association_data) self.assertEqual('2 1 0 abcd', a.values[0].rdata_text) def test_validation(self): # doesn't blow up Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 0, 'selector': 0, 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) # Multi value, second missing certificate usage with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'values': [ { 'certificate_usage': 0, 'selector': 0, 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, { 'selector': 0, 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, ], }, ) self.assertEqual( ['missing certificate_usage'], ctx.exception.reasons ) # missing certificate_association_data with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 0, 'selector': 0, 'matching_type': 0, }, }, ) self.assertEqual( ['missing certificate_association_data'], ctx.exception.reasons ) # missing certificate_usage with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'selector': 0, 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) self.assertEqual( ['missing certificate_usage'], ctx.exception.reasons ) # False certificate_usage with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 4, 'selector': 0, 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) self.assertEqual( 'invalid certificate_usage "{value["certificate_usage"]}"', ctx.exception.reasons, ) # Invalid certificate_usage with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 'XYZ', 'selector': 0, 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) self.assertEqual( 'invalid certificate_usage "{value["certificate_usage"]}"', ctx.exception.reasons, ) # missing selector with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 0, 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) self.assertEqual(['missing selector'], ctx.exception.reasons) # False selector with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 0, 'selector': 4, 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) self.assertEqual( 'invalid selector "{value["selector"]}"', ctx.exception.reasons ) # Invalid selector with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 0, 'selector': 'XYZ', 'matching_type': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) self.assertEqual( 'invalid selector "{value["selector"]}"', ctx.exception.reasons ) # missing matching_type with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 0, 'selector': 0, 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) self.assertEqual(['missing matching_type'], ctx.exception.reasons) # False matching_type with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 0, 'selector': 1, 'matching_type': 3, 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) self.assertEqual( 'invalid matching_type "{value["matching_type"]}"', ctx.exception.reasons, ) # Invalid matching_type with self.assertRaises(ValidationError) as ctx: Record.new( self.zone, '', { 'type': 'TLSA', 'ttl': 600, 'value': { 'certificate_usage': 0, 'selector': 1, 'matching_type': 'XYZ', 'certificate_association_data': 'AAAAAAAAAAAAA', }, }, ) self.assertEqual( 'invalid matching_type "{value["matching_type"]}"', ctx.exception.reasons, )