]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Merge update_test.pl into system test scripts
authorMichael Sawyer <source@isc.org>
Mon, 24 Jul 2000 22:53:40 +0000 (22:53 +0000)
committerMichael Sawyer <source@isc.org>
Mon, 24 Jul 2000 22:53:40 +0000 (22:53 +0000)
bin/tests/system/nsupdate/clean.sh
bin/tests/system/nsupdate/ns1/.cvsignore
bin/tests/system/nsupdate/ns1/named.conf
bin/tests/system/nsupdate/ns1/update.orig [new file with mode: 0644]
bin/tests/system/nsupdate/ns2/.cvsignore
bin/tests/system/nsupdate/ns2/named.conf
bin/tests/system/nsupdate/setup.sh
bin/tests/system/nsupdate/tests.sh
bin/tests/system/nsupdate/update_test.pl [new file with mode: 0644]

index 38425626200534aa250114000e98f6ac9d28617f..430e7c8a0138a1d05c32d87150aa03295563deb6 100644 (file)
 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 # SOFTWARE.
 
-# $Id: clean.sh,v 1.1 2000/07/06 00:54:02 mws Exp $
+# $Id: clean.sh,v 1.2 2000/07/24 22:53:33 mws Exp $
 
 #
 # Clean up after zone transfer tests.
 #
 
-rm -f dig.out.ns1 dig.out.ns2 ns1/*.jnl ns2/*.jnl
+rm -f dig.out.ns1 dig.out.ns2 ns1/*.jnl ns2/*.jnl ns1/*.db
+
 
 
 
index cbb42ee873ac270ac8ac56c158c0e7243350db81..105706c29d6a76d09f7d3e4d3c5a48cdb2797ddc 100644 (file)
@@ -1,2 +1,3 @@
 example.db
 named.run
+update.db
index a2e9eb15ce22f0d815a3825b09225a465fc5d0dc..a27abdadcd8849cc450a4a5c7bd49dc63326cd3a 100644 (file)
@@ -15,7 +15,7 @@
  * SOFTWARE.
  */
 
-/* $Id: named.conf,v 1.1 2000/07/06 00:54:03 mws Exp $ */
+/* $Id: named.conf,v 1.2 2000/07/24 22:53:38 mws Exp $ */
 
 options {
        query-source address 10.53.0.1;
@@ -33,3 +33,10 @@ zone "example.nil" {
        allow-update { any; };
        allow-transfer { any; };
 };
+
+zone "update.nil" {
+       type master;
+       file "update.db";
+       allow-update { any; };
+       allow-transfer { any; };
+};
diff --git a/bin/tests/system/nsupdate/ns1/update.orig b/bin/tests/system/nsupdate/ns1/update.orig
new file mode 100644 (file)
index 0000000..9ffd3cf
--- /dev/null
@@ -0,0 +1,28 @@
+; Copyright (C) 2000  Internet Software Consortium.
+; 
+; Permission to use, copy, modify, and distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+; 
+; THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+; ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+; OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+; CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+; DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+; PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+; ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+; SOFTWARE.
+
+; $Id: update.orig,v 1.1 2000/07/24 22:53:39 mws Exp $
+
+$ORIGIN .
+$TTL 300       ; 5 minutes
+update.nil             IN SOA  ns1.example.nil. hostmaster.example.nil. (
+                               1          ; serial
+                               2000       ; refresh (2000 seconds)
+                               2000       ; retry (2000 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+update.nil.            NS      ns1.update.nil.
+ns1.update.nil.                A       10.53.0.2
index 68f882cc9a2147152cfc64db3e0087d41af87945..70d94600a8a1a8483f325a5a525fd03f3e4b68f9 100644 (file)
@@ -1,2 +1,3 @@
 example.bk
 named.run
+update.bk
index 26aa1c647a45cf420eea23c950ba0614481a6930..83523e3ff65b0878ca65576044695cdedc7568ea 100644 (file)
@@ -15,7 +15,7 @@
  * SOFTWARE.
  */
 
-/* $Id: named.conf,v 1.1 2000/07/06 00:54:03 mws Exp $ */
+/* $Id: named.conf,v 1.2 2000/07/24 22:53:40 mws Exp $ */
 
 options {
        query-source address 10.53.0.2;
@@ -35,4 +35,11 @@ zone "example.nil" {
        allow-transfer { any; };
 };
 
+zone "update.nil" {
+       type slave;
+       masters { 10.53.0.1; };
+       file "update.bk";
+       allow-transfer { any; };
+};
+
 
index 1de5ce2fcaa50873042ba071ba48486b751463c3..56db749c60dd29b485fad90c6e56491c6101c089 100644 (file)
@@ -15,7 +15,7 @@
 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 # SOFTWARE.
 
-# $Id: setup.sh,v 1.1 2000/07/06 00:54:02 mws Exp $
+# $Id: setup.sh,v 1.2 2000/07/24 22:53:34 mws Exp $
 
 #
 # jnl and database files MUST be removed before we start
@@ -23,5 +23,6 @@
 
 rm -f ns1/*.jnl ns1/example.db ns2/*.jnl ns2/example.bk
 cp ns1/example.orig ns1/example.db
+cp ns1/update.orig ns1/update.db
 
 
index c971cde2fc6864aa5c112dc6d64cb20e5d55edb2..e9a2b0870bbf9e395df7e0565ea4ec661564faad 100644 (file)
@@ -15,7 +15,7 @@
 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 # SOFTWARE.
 
-# $Id: tests.sh,v 1.4 2000/07/09 16:27:30 tale Exp $
+# $Id: tests.sh,v 1.5 2000/07/24 22:53:35 mws Exp $
 
 #
 # Perform tests
@@ -29,12 +29,10 @@ status=0
 echo "I:fetching first copy of zone before update"
 $DIG +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd example.nil.\
        @10.53.0.1 axfr -p 5300 > dig.out.ns1 || status=1
-grep ";" dig.out.ns1           # XXXDCL Why is this here?
 
 echo "I:fetching second copy of zone before update"
 $DIG +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd example.nil.\
        @10.53.0.1 axfr -p 5300 > dig.out.ns2 || status=1
-grep ";" dig.out.ns2           # XXXDCL Why is this here?
 
 echo "I:comparing pre-update copies to known good data"
 $PERL ../digcomp.pl knowngood.ns1.before dig.out.ns1 || status=1
@@ -49,16 +47,22 @@ sleep 15
 echo "I:fetching first copy of zone after update"
 $DIG +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd example.nil.\
        @10.53.0.1 axfr -p 5300 > dig.out.ns1 || status=1
-grep ";" dig.out.ns1           # XXXDCL Why is this here?
 
 echo "I:fetching second copy of zone after update"
 $DIG +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd example.nil.\
        @10.53.0.1 axfr -p 5300 > dig.out.ns2 || status=1
-grep ";" dig.out.ns2           # XXXDCL Why is this here?
 
 echo "I:comparing post-update copies to known good data"
 $PERL ../digcomp.pl knowngood.ns1.after dig.out.ns1 || status=1
 $PERL ../digcomp.pl knowngood.ns1.after dig.out.ns2 || status=1
 
+if $PERL -e 'use Net::DNS;' 2>/dev/null
+then
+    echo "I:running update.pl test"
+    $PERL update_test.pl -s 10.53.0.1 -p 5300 update.nil. || status=1
+else
+    echo "I:The second part of this test requires the Net::DNS library." >&2
+fi
+
 echo "I:exit status: $status"
 exit $status
diff --git a/bin/tests/system/nsupdate/update_test.pl b/bin/tests/system/nsupdate/update_test.pl
new file mode 100644 (file)
index 0000000..8f25990
--- /dev/null
@@ -0,0 +1,398 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 1999, 2000  Internet Software Consortium.
+# 
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+# ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+# CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+# SOFTWARE.
+
+#
+# Dynamic update test suite.
+#
+# Usage:
+#
+#   perl update_test.pl [-s server] [-p port] zone
+#
+# The server defaults to 127.0.0.1.
+# The port defaults to 53.
+#
+# The "Special NS rules" tests will only work correctly if the 
+# has no NS records to begin with, or alternatively has a 
+# single NS record pointing at the name "ns1" (relative to
+# the zone name).
+#
+# Installation notes:
+#
+# This program uses the Net::DNS::Resolver module.
+# You can install it by saying
+#
+#    perl -MCPAN -e "install Net::DNS"
+#
+# $Id: update_test.pl,v 1.1 2000/07/24 22:53:36 mws Exp $
+#
+
+use Getopt::Std;
+use Net::DNS;
+use Net::DNS::Update;
+use Net::DNS::Resolver;
+
+$opt_s = "127.0.0.1";
+$opt_p = 53;
+
+getopt('s:p:');
+
+$res = new Net::DNS::Resolver;
+$res->nameservers($opt_s);
+$res->port($opt_p);
+$res->defnames(0); # Do not append default domain.
+
+@ARGV == 1 or die
+    "usage: perl update_test.pl [-s server] [-p port] zone\n";
+
+$zone = shift @ARGV;
+
+my $failures = 0;
+
+sub assert {
+    my ($cond, $explanation) = @_;
+    if (!$cond) {
+       print "I:Test Failed: $explanation ***\n";
+       $failures++
+    }
+}
+
+sub test {
+    my ($expected, @records) = @_;
+
+    my $update = new Net::DNS::Update("$zone");
+    
+    foreach $rec (@records) {
+       $update->push(@$rec);
+    }
+    
+    $reply = $res->send($update);
+
+    # Did it work?
+    if (defined $reply) {
+       my $rcode = $reply->header->rcode;
+        assert($rcode eq $expected, "expected $expected, got $rcode");
+    } else {
+       print "I:Update failed: ", $res->errorstring, "\n";
+    }
+}
+
+sub section {
+    my ($msg) = @_;
+    print "I:$msg\n";
+}
+
+section("Delete any leftovers from previous tests");
+test("NOERROR", ["update", rr_del("a.$zone")]);
+test("NOERROR", ["update", rr_del("b.$zone")]);
+test("NOERROR", ["update", rr_del("c.$zone")]);
+test("NOERROR", ["update", rr_del("d.$zone")]);
+test("NOERROR", ["update", rr_del("e.$zone")]);
+test("NOERROR", ["update", rr_del("f.$zone")]);
+test("NOERROR", ["update", rr_del("ns.s.$zone")]);
+test("NOERROR", ["update", rr_del("s.$zone")]);
+test("NOERROR", ["update", rr_del("t.$zone")]);
+test("NOERROR", ["update", rr_del("*.$zone")]);
+test("NOERROR", ["update", rr_del("u.$zone")]);
+test("NOERROR", ["update", rr_del("a.u.$zone")]);
+test("NOERROR", ["update", rr_del("b.u.$zone")]);
+
+section("Simple prerequisites in the absence of data");
+# Name is in Use
+test("NXDOMAIN", ["pre", yxdomain("a.$zone")]);
+# RRset exists (value independent)
+test("NXRRSET", ["pre", yxrrset("a.$zone A")]);
+# Name is not in use
+test("NOERROR", ["pre", nxdomain("a.$zone")]);
+# RRset does not exist
+test("NOERROR", ["pre", nxrrset("a.$zone A")]);
+# RRset exists (value dependent)
+test("NXRRSET", ["pre", yxrrset("a.$zone 300 A 73.80.65.49")]);
+
+
+section ("Simple creation of data");
+test("NOERROR", ["update", rr_add("a.$zone 300 A 73.80.65.49")]);
+
+section ("Simple prerequisites in the presence of data");
+# Name is in use
+test("NOERROR", ["pre", yxdomain("a.$zone")]);
+# RRset exists (value independent)
+test("NOERROR", ["pre", yxrrset("a.$zone A")]);
+# Name is not in use
+test("YXDOMAIN", ["pre", nxdomain("a.$zone")]);
+# RRset does not exist
+test("YXRRSET", ["pre", nxrrset("a.$zone A")]);
+# RRset exists (value dependent)
+test("NOERROR", ["pre", yxrrset("a.$zone 300 A 73.80.65.49")]);
+
+#
+# Merging of RRsets
+#
+test("NOERROR", ["update", rr_add("a.$zone 300 A 73.80.65.50")]);
+
+section("Detailed tests of \"RRset exists (value dependent)\" prerequisites");
+test("NOERROR", ["pre",
+                yxrrset("a.$zone 300 A 73.80.65.49"),
+                yxrrset("a.$zone 300 A 73.80.65.50")]);
+test("NOERROR", ["pre",
+                yxrrset("a.$zone 300 A 73.80.65.50"),
+                yxrrset("a.$zone 300 A 73.80.65.49")]);
+test("NXRRSET", ["pre", yxrrset("a.$zone 300 A 73.80.65.49")]);
+test("NXRRSET", ["pre", yxrrset("a.$zone 300 A 73.80.65.50")]);
+test("NXRRSET", ["pre",
+                yxrrset("a.$zone 300 A 73.80.65.49"),
+                yxrrset("a.$zone 300 A 73.80.65.50"),
+                yxrrset("a.$zone 300 A 73.80.65.51")]);
+
+
+section("Torture test of \"RRset exists (value dependent)\" prerequisites.");
+
+test("NOERROR", ["update",
+                rr_add("e.$zone 300 A 73.80.65.49"),
+                rr_add("e.$zone 300 TXT 'one'"),
+                rr_add("e.$zone 300 A 73.80.65.50")]);
+test("NOERROR", ["update",
+                rr_add("e.$zone 300 A 73.80.65.52"),
+                rr_add("f.$zone 300 A 73.80.65.52"),            
+                rr_add("e.$zone 300 A 73.80.65.51")]);
+test("NOERROR", ["update",
+                rr_add("e.$zone 300 TXT 'three'"),
+                rr_add("e.$zone 300 TXT 'two'")]);
+test("NOERROR", ["update",
+                rr_add("e.$zone 300 MX 10 mail.$zone")]);
+
+test("NOERROR", ["pre",
+                yxrrset("e.$zone 300 A 73.80.65.52"),
+                yxrrset("e.$zone 300 TXT 'two'"),
+                yxrrset("e.$zone 300 A 73.80.65.51"),
+                yxrrset("e.$zone 300 TXT 'three'"),
+                yxrrset("e.$zone 300 A 73.80.65.50"),
+                yxrrset("f.$zone 300 A 73.80.65.52"),
+                yxrrset("e.$zone 300 A 73.80.65.49"),
+                yxrrset("e.$zone 300 TXT 'one'")]);
+
+
+section("Subtraction of RRsets");
+test("NOERROR", ["update", rr_del("a.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["pre",
+                yxrrset("a.$zone 300 A 73.80.65.50")]);
+
+test("NOERROR", ["update", rr_del("a.$zone 300 A 73.80.65.50")]);
+test("NOERROR", ["pre", nxrrset("a.$zone 300 A")]);
+test("NOERROR", ["pre", nxdomain("a.$zone")]);
+
+section("Other forms of deletion");
+test("NOERROR", ["update", rr_add("a.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["update", rr_add("a.$zone 300 A 73.80.65.50")]);
+test("NOERROR", ["update", rr_add("a.$zone 300 MX 10 mail.$zone")]);
+test("NOERROR", ["update", rr_del("a.$zone 300 A")]);
+test("NOERROR", ["pre", nxrrset("a.$zone 300 A")]);
+test("NOERROR", ["update", rr_add("a.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["update", rr_add("a.$zone 300 A 73.80.65.50")]);
+test("NOERROR", ["update", rr_del("a.$zone")]);
+test("NOERROR", ["pre", nxdomain("a.$zone")]);
+
+section("Case insensitivity");
+test("NOERROR", ["update", rr_add("a.$zone 300 PTR foo.net.")]);
+test("NOERROR", ["pre", yxrrset("A.$zone 300 PTR fOo.NeT.")]);
+
+section("Special CNAME rules");
+test("NOERROR", ["update", rr_add("b.$zone 300 CNAME foo.net.")]);
+test("NOERROR", ["update", rr_add("b.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["pre", yxrrset("b.$zone 300 CNAME foo.net.")]);
+test("NOERROR", ["pre", nxrrset("b.$zone A")]);
+
+test("NOERROR", ["update", rr_add("c.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["update", rr_add("c.$zone 300 CNAME foo.net.")]);
+test("NOERROR", ["pre", yxrrset("c.$zone A")]);
+test("NOERROR", ["pre", nxrrset("c.$zone CNAME")]);
+
+# XXX should test with SIG, KEY, NXT, too.
+
+#
+# Currently commented out because Net::DNS does not properly
+# support WKS records.
+#
+#section("Special WKS rules");
+#test("NOERROR", ["update", rr_add("c.$zone 300 WKS 73.80.65.49 TCP telnet ftp")]);
+#test("NOERROR", ["update", rr_add("c.$zone 300 WKS 73.80.65.49 UDP telnet ftp")]);
+#test("NOERROR", ["update", rr_add("c.$zone 300 WKS 73.80.65.50 TCP telnet ftp")]);
+#test("NOERROR", ["update", rr_add("c.$zone 300 WKS 73.80.65.49 TCP smtp")]);
+#test("NOERROR", ["pre",
+#               yxrrset("c.$zone 300 WKS 73.80.65.49 TCP smtp"),
+#               yxrrset("c.$zone 300 WKS 73.80.65.49 UDP telnet ftp"),
+#               yxrrset("c.$zone 300 WKS 73.80.65.50 TCP telnet ftp")]);
+
+
+section("Special NS rules");
+
+# Deleting the last NS record using "Delete an RR from an RRset"
+# should fail at the zone apex and work elsewhere.  The pseudocode
+# in RFC2136 says it should fail everywhere, but this is in conflict
+# with the actual text.
+
+# Apex
+test("NOERROR", ["update",
+                rr_add("$zone 300 NS ns1.$zone"),
+                rr_add("$zone 300 NS ns2.$zone")]);
+test("NOERROR", ["update", rr_del("$zone 300 NS ns1.$zone")]);
+test("NOERROR", ["update", rr_del("$zone 300 NS ns2.$zone")]);
+test("NOERROR", ["pre",
+                yxrrset("$zone 300 NS ns2.$zone")]);
+
+# Non-apex
+test("NOERROR", ["update", rr_add("n.$zone 300 NS ns1.$zone")]);
+test("NOERROR", ["update", rr_del("n.$zone 300 NS ns1.$zone")]);
+test("NOERROR", ["pre", nxrrset("n.$zone 300 NS")]);
+
+# Other ways of deleting NS records should also fail at the apex
+# and work elsewhere.
+
+# Non-apex
+test("NOERROR", ["update", rr_add("n.$zone 300 NS ns1.$zone")]);
+test("NOERROR", ["update", rr_del("n.$zone 300 NS")]);
+test("NOERROR", ["pre", nxrrset("n.$zone 300 NS")]);
+
+test("NOERROR", ["update", rr_add("n.$zone 300 NS ns1.$zone")]);
+test("NOERROR", ["pre", yxrrset("n.$zone 300 NS")]);
+test("NOERROR", ["update", rr_del("n.$zone")]);
+test("NOERROR", ["pre", nxrrset("n.$zone 300 NS")]);
+
+# Apex
+test("NOERROR", ["update", rr_del("$zone NS")]);
+test("NOERROR", ["pre",
+                yxrrset("$zone 300 NS ns2.$zone")]);
+
+test("NOERROR", ["update", rr_del("$zone")]);
+test("NOERROR", ["pre",
+                yxrrset("$zone 300 NS ns2.$zone")]);
+
+# They should not touch the SOA, either.
+
+test("NOERROR", ["update", rr_del("$zone SOA")]);
+test("NOERROR", ["pre", yxrrset("$zone SOA")]);
+
+
+section("Idempotency");
+
+test("NOERROR", ["update", rr_add("d.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["pre", yxrrset("d.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["update",
+                rr_add("d.$zone 300 A 73.80.65.49"),
+                rr_del("d.$zone A")]);
+test("NOERROR", ["pre", nxrrset("d.$zone 300 A 73.80.65.49")]);
+
+test("NOERROR", ["update", rr_del("d.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["pre", nxrrset("d.$zone 300 A")]);
+test("NOERROR", ["update",
+                  rr_del("d.$zone 300 A"),
+                  rr_add("d.$zone 300 A 73.80.65.49")]);
+
+test("NOERROR", ["pre", yxrrset("d.$zone 300 A")]);
+
+section("Out-of-zone prerequisites and updates");
+test("NOTZONE", ["pre", yxrrset("a.somewhere.else. 300 A 73.80.65.49")]);
+test("NOTZONE", ["update", rr_add("a.somewhere.else. 300 A 73.80.65.49")]);
+
+
+section("Glue");
+test("NOERROR", ["update", rr_add("s.$zone 300 NS ns.s.$zone")]);
+test("NOERROR", ["update", rr_add("ns.s.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["pre", yxrrset("ns.s.$zone 300 A 73.80.65.49")]);
+
+section("Wildcards");
+test("NOERROR", ["update", rr_add("*.$zone 300 MX 10 mail.$zone")]);
+test("NOERROR", ["pre", yxrrset("*.$zone 300 MX 10 mail.$zone")]);
+test("NXRRSET", ["pre", yxrrset("w.$zone 300 MX 10 mail.$zone")]);
+test("NOERROR", ["pre", nxrrset("w.$zone MX")]);
+test("NOERROR", ["pre", nxdomain("w.$zone")]);
+
+
+section("SOA serial handling");
+
+my $soatimers = "20 20 1814400 3600";
+
+# Get the current SOA serial number.
+my $query = $res->query($zone, "SOA");
+my ($old_soa) = $query->answer;
+
+my $old_serial = $old_soa->serial;
+
+# Increment it by 10.
+my $new_serial = $old_serial + 10;
+if ($new_serial > 0xFFFFFFFF) {
+    $new_serial -= 0x80000000;
+    $new_serial -= 0x80000000;
+}
+
+# Replace the SOA with a new one.
+test("NOERROR", ["update", rr_add("$zone 300 SOA mname1. . $new_serial $soatimers")]);
+
+# Check that the SOA really got replaced.
+($db_soa) = $res->query($zone, "SOA")->answer;
+assert($db_soa->mname eq "mname1");
+
+# Check that attempts to decrement the serial number are ignored.
+$new_serial = $old_serial - 10;
+if ($new_serial < 0) {
+    $new_serial += 0x80000000;
+    $new_serial += 0x80000000;
+}
+test("NOERROR", ["update", rr_add("$zone 300 SOA mname2. . $new_serial $soatimers")]);
+assert($db_soa->mname eq "mname1");
+
+# Check that attempts to leave the serial number unchanged are ignored.
+($old_soa) = $res->query($zone, "SOA")->answer;
+$old_serial = $old_soa->serial;
+test("NOERROR", ["update", rr_add("$zone 300 SOA mname3. . $old_serial " .
+                                 $soatimers)]);
+($db_soa) = $res->query($zone, "SOA")->answer;
+assert($db_soa->mname eq "mname1");
+
+#
+# Currently commented out because Net::DNS does not properly
+# support multiple strings in TXT records.
+#
+#section("Big data");
+#test("NOERROR", ["update", rr_add("a.$zone 300 TXT aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc")]);
+#test("NOERROR", ["update", rr_del("a.$zone 300 TXT aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc")]);
+test("NOERROR", ["update", rr_add("a.$zone 300 TXT " . ("foo " x 3))]);
+
+section("Updating TTLs only");
+
+test("NOERROR", ["update", rr_add("t.$zone 300 A 73.80.65.49")]);
+($a) = $res->query("t.$zone", "A")->answer;
+assert($a->ttl == 300);
+test("NOERROR", ["update",
+                rr_del("t.$zone 300 A 73.80.65.49"),
+                rr_add("t.$zone 301 A 73.80.65.49")]);
+($a) = $res->query("t.$zone", "A")->answer;
+assert($a->ttl == 301);
+
+section("Obscuring existing data by zone cut");
+test("NOERROR", ["update", rr_add("a.u.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["update", rr_add("b.u.$zone 300 A 73.80.65.49")]);
+test("NOERROR", ["update", rr_add("u.$zone 300 TXT txt-not-in-nxt")]);
+test("NOERROR", ["update", rr_add("u.$zone 300 NS ns.u.$zone")]);
+
+test("NOERROR", ["update", rr_del("u.$zone 300 NS ns.u.$zone")]);
+
+if ($failures) {
+    print "$failures tests failed.\n";
+} else {
+    print "All tests successful.\n";
+}
+exit $failures;