diff --git a/CHANGELOG.md b/CHANGELOG.md index b0a738c..fa7fb68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,9 @@ * Record.lenient property added similar to other common/standard _octodns data * Processor.process_source_and_target_zones added to support modifying both the desired and/or existing zones just prior to computing changes. +* Fix bug with Record.copy when values is an empty list [] * Fix an issue in MetaProcessor/Manager.include_meta where include_provider wasn't correctly taking effect -* Fix bug with Record.copy when values is an empty list [] ## v1.3.0 - 2023-11-14 - New and improved processors diff --git a/README.md b/README.md index 4c5cac0..f69f17c 100644 --- a/README.md +++ b/README.md @@ -313,8 +313,8 @@ Similar to providers, but can only serve to populate records into a zone, cannot | Source | Record Support | Dynamic | Notes | |--|--|--|--| | [EnvVarSource](/octodns/source/envvar.py) | TXT | No | read-only environment variable injection | -| [AxfrSource](/octodns/source/axfr.py) | A, AAAA, CAA, CNAME, LOC, MX, NS, PTR, SPF, SRV, TXT | No | read-only | -| [ZoneFileSource](/octodns/source/axfr.py) | A, AAAA, CAA, CNAME, MX, NS, PTR, SPF, SRV, TXT | No | read-only | +| [AxfrSource](https://github.com/octodns/octodns-bind/) | A, AAAA, CAA, CNAME, LOC, MX, NS, PTR, SPF, SRV, TXT | No | read-only | +| [ZoneFileSource](https://github.com/octodns/octodns-bind/) | A, AAAA, CAA, CNAME, MX, NS, PTR, SPF, SRV, TXT | No | read-only | | [TinyDnsFileSource](/octodns/source/tinydns.py) | A, CNAME, MX, NS, PTR | No | read-only | ### Notes diff --git a/octodns/record/base.py b/octodns/record/base.py index d203cea..443e7ba 100644 --- a/octodns/record/base.py +++ b/octodns/record/base.py @@ -309,16 +309,16 @@ class ValuesMixin(object): def _data(self): ret = super()._data() - if len(self.values) > 1: - values = [getattr(v, 'data', v) for v in self.values if v] - if len(values) > 1: - ret['values'] = values - elif len(values) == 1: - ret['value'] = values[0] - elif len(self.values) == 1: + if len(self.values) == 1: v = self.values[0] if v: ret['value'] = getattr(v, 'data', v) + else: + values = [getattr(v, 'data', v) for v in self.values if v] + if len(values) == 1: + ret['value'] = values[0] + else: + ret['values'] = values return ret @@ -374,8 +374,7 @@ class ValueMixin(object): def _data(self): ret = super()._data() - if self.value: - ret['value'] = getattr(self.value, 'data', self.value) + ret['value'] = getattr(self.value, 'data', self.value) return ret @property diff --git a/pyproject.toml b/pyproject.toml index 74c48d7..f54dbb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,4 +13,4 @@ filterwarnings = [ 'error', 'ignore:.*DEPRECATED.*2.0', ] -pythonpath = "." \ No newline at end of file +pythonpath = "." diff --git a/tests/test_octodns_record.py b/tests/test_octodns_record.py index 0fe3d57..c85341f 100644 --- a/tests/test_octodns_record.py +++ b/tests/test_octodns_record.py @@ -197,19 +197,19 @@ class TestRecord(TestCase): ) def test_values_mixin_data(self): - # no values, no value or values in data + # empty values -> empty values in data a = ARecord(self.zone, '', {'type': 'A', 'ttl': 600, 'values': []}) - self.assertNotIn('values', a.data) + self.assertEqual([], a.data['values']) # empty value, no value or values in data b = ARecord(self.zone, '', {'type': 'A', 'ttl': 600, 'values': ['']}) self.assertNotIn('value', b.data) - # empty/None values, no value or values in data + # empty/None values -> empty values in data c = ARecord( self.zone, '', {'type': 'A', 'ttl': 600, 'values': ['', None]} ) - self.assertNotIn('values', c.data) + self.assertEqual([], a.data['values']) # empty/None values and valid, value in data c = ARecord( @@ -225,13 +225,13 @@ class TestRecord(TestCase): a = AliasRecord( self.zone, '', {'type': 'ALIAS', 'ttl': 600, 'value': None} ) - self.assertNotIn('value', a.data) + self.assertIsNone(a.data['value']) # unspecified value, no value in data a = AliasRecord( self.zone, '', {'type': 'ALIAS', 'ttl': 600, 'value': ''} ) - self.assertNotIn('value', a.data) + self.assertIsNone(a.data['value']) def test_record_new(self): txt = Record.new( @@ -251,6 +251,20 @@ class TestRecord(TestCase): Record.new(self.zone, 'unknown', {'type': 'XXX'}) self.assertTrue('Unknown record type' in str(ctx.exception)) + def test_record_new_with_values_and_value(self): + a = Record.new( + self.zone, + 'a', + { + 'ttl': 44, + 'type': 'A', + 'value': '1.2.3.4', + 'values': ['2.3.4.5', '3.4.5.6'], + }, + ) + # values is preferred over value when both exist + self.assertEqual(['2.3.4.5', '3.4.5.6'], a.values) + def test_record_copy(self): a = Record.new( self.zone, 'a', {'ttl': 44, 'type': 'A', 'value': '1.2.3.4'} @@ -349,6 +363,16 @@ class TestRecord(TestCase): dup = txt.copy() self.assertEqual(txt.values, dup.values) + cname = Record.new( + self.zone, + 'cname', + {'ttl': 45, 'type': 'CNAME', 'value': ''}, + lenient=True, + ) + + dup = cname.copy() + self.assertEqual(cname.value, dup.value) + def test_change(self): existing = Record.new( self.zone, 'txt', {'ttl': 44, 'type': 'TXT', 'value': 'some text'}