From: Bob Halley Date: Sun, 28 Nov 2021 22:26:21 +0000 (-0800) Subject: Fix replacement txn bugs in non-versioned zones [#732]. X-Git-Tag: v2.2.0rc1~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c706e26e990856311e35f46cb58eaf333e80ed2f;p=thirdparty%2Fdnspython.git Fix replacement txn bugs in non-versioned zones [#732]. --- diff --git a/dns/zone.py b/dns/zone.py index d1549287..2f99b1b7 100644 --- a/dns/zone.py +++ b/dns/zone.py @@ -805,7 +805,7 @@ class Transaction(dns.transaction.Transaction): rdataset = self.rdatasets.get((name, rdtype, covers)) if rdataset is self._deleted_rdataset: return None - elif rdataset is None: + elif rdataset is None and not self.replacement: rdataset = self.zone.get_rdataset(name, rdtype, covers) return rdataset @@ -863,6 +863,8 @@ class Transaction(dns.transaction.Transaction): def _end_transaction(self, commit): if commit and self._changed(): + if self.replacement: + self.zone.nodes = {} for (name, rdtype, covers), rdataset in \ self.rdatasets.items(): if rdataset is self._deleted_rdataset: @@ -877,10 +879,13 @@ class Transaction(dns.transaction.Transaction): def _iterate_rdatasets(self): # Expensive but simple! Use a versioned zone for efficient txn # iteration. - rdatasets = {} - for (name, rdataset) in self.zone.iterate_rdatasets(): - rdatasets[(name, rdataset.rdtype, rdataset.covers)] = rdataset - rdatasets.update(self.rdatasets) + if self.replacement: + rdatasets = self.rdatasets + else: + rdatasets = {} + for (name, rdataset) in self.zone.iterate_rdatasets(): + rdatasets[(name, rdataset.rdtype, rdataset.covers)] = rdataset + rdatasets.update(self.rdatasets) for (name, _, _), rdataset in rdatasets.items(): yield (name, rdataset) diff --git a/tests/test_transaction.py b/tests/test_transaction.py index 85aa9868..ce533c51 100644 --- a/tests/test_transaction.py +++ b/tests/test_transaction.py @@ -497,6 +497,35 @@ def test_zone_iteration(zone): actual[(name, rdataset.rdtype, rdataset.covers)] = rdataset assert actual == expected +def test_iteration_in_replacement_txn(zone): + rds = dns.rdataset.from_text('in', 'a', 300, '1.2.3.4', '5.6.7.8') + expected = {} + expected[(dns.name.empty, rds.rdtype, rds.covers)] = rds + with zone.writer(True) as txn: + txn.replace(dns.name.empty, rds) + actual = {} + for (name, rdataset) in txn: + actual[(name, rdataset.rdtype, rdataset.covers)] = rdataset + assert actual == expected + +def test_replacement_commit(zone): + rds = dns.rdataset.from_text('in', 'a', 300, '1.2.3.4', '5.6.7.8') + expected = {} + expected[(dns.name.empty, rds.rdtype, rds.covers)] = rds + with zone.writer(True) as txn: + txn.replace(dns.name.empty, rds) + with zone.reader() as txn: + actual = {} + for (name, rdataset) in txn: + actual[(name, rdataset.rdtype, rdataset.covers)] = rdataset + assert actual == expected + +def test_replacement_get(zone): + with zone.writer(True) as txn: + rds = txn.get(dns.name.empty, 'soa') + assert rds is None + + @pytest.fixture def vzone(): return dns.zone.from_text(example_text, zone_factory=dns.versioned.Zone)