diff options
author | Bob Halley <halley@play-bow.org> | 2013-03-31 03:56:55 -0700 |
---|---|---|
committer | Bob Halley <halley@play-bow.org> | 2013-03-31 03:56:55 -0700 |
commit | c5f767e6699c8ce85c4970e3a8d945b2b0b3c60f (patch) | |
tree | e333c1c605c1dac03e829046142692f1d9a943c7 | |
parent | 4cf53b0d70bddaef6b499d2c5d0776f5cb7ef107 (diff) | |
parent | ad792be4a666ee0a487188f3979423588945fa19 (diff) | |
download | dnspython-c5f767e6699c8ce85c4970e3a8d945b2b0b3c60f.tar.gz |
Merge pull request #16 from uberj/generate4
Generate4
-rw-r--r-- | dns/grange.py | 65 | ||||
-rw-r--r-- | dns/zone.py | 167 | ||||
-rw-r--r-- | tests/generate.py | 499 | ||||
-rw-r--r-- | tests/grange.py | 95 |
4 files changed, 824 insertions, 2 deletions
diff --git a/dns/grange.py b/dns/grange.py new file mode 100644 index 0000000..2d4799d --- /dev/null +++ b/dns/grange.py @@ -0,0 +1,65 @@ +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation 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 NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM 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. + +"""DNS GENERATE range conversion.""" + +import dns + +def from_text(text): + """Convert the text form of a range in a GENERATE statement to an + integer. + + @param text: the textual range + @type text: string + @return range: The start, stop and step values. + @type range: tuple + """ + # TODO, figure out the bounds on start, stop and step. + + import pdb + step = 1 + cur = '' + state = 0 + # state 0 1 2 3 4 + # x - y / z + for c in text: + if c == '-' and state == 0: + start = int(cur) + cur = '' + state = 2 + elif c == '/': + stop = int(cur) + cur = '' + state = 4 + elif c.isdigit(): + cur += c + else: + raise dns.exception.SyntaxError("Could not parse %s" % (c)) + + if state in (1, 3): + raise dns.exception.SyntaxError + + if state == 2: + stop = int(cur) + + if state == 4: + step = int(cur) + + assert step >= 1 + assert start >= 0 + assert start <= stop + # TODO, can start == stop? + + return (start, stop, step) diff --git a/dns/zone.py b/dns/zone.py index ac16ad3..9efcf43 100644 --- a/dns/zone.py +++ b/dns/zone.py @@ -18,6 +18,7 @@ from __future__ import generators import sys +import re import dns.exception import dns.name @@ -28,6 +29,8 @@ import dns.rdata import dns.rrset import dns.tokenizer import dns.ttl +import dns.grange + class BadZone(dns.exception.DNSException): """The zone is malformed.""" @@ -641,6 +644,166 @@ class _MasterReader(object): rds = n.find_rdataset(rdclass, rdtype, covers, True) rds.add(rd, ttl) + def _parse_modify(self, side): + # Here we catch everything in '{' '}' in a group so we can replace it + # with ''. + is_generate1 = re.compile("^.*\$({(\+|-?)(\d+),(\d+),(.)}).*$") + is_generate2 = re.compile("^.*\$({(\+|-?)(\d+)}).*$") + is_generate3 = re.compile("^.*\$({(\+|-?)(\d+),(\d+)}).*$") + # Sometimes there are modifiers in the hostname. These come after + # the dollar sign. They are in the form: ${offset[,width[,base]]}. + # Make names + g1 = is_generate1.match(side) + if g1: + mod, sign, offset, width, base = g1.groups() + if sign == '': + sign = '+' + g2 = is_generate2.match(side) + if g2: + mod, sign, offset = g2.groups() + if sign == '': + sign = '+' + width = 0 + base = 'd' + g3 = is_generate3.match(side) + if g3: + mod, sign, offset, width = g1.groups() + if sign == '': + sign = '+' + width = g1.groups()[2] + base = 'd' + + if not (g1 or g2 or g3): + mod = '' + sign = '+' + offset = 0 + width = 0 + base = 'd' + + if base != 'd': + raise NotImplemented + + return mod, sign, offset, width, base + + def _generate_line(self): + # range lhs [ttl] [class] type rhs [ comment ] + """Process one line containing the GENERATE statement from a DNS + master file.""" + if self.current_origin is None: + raise UnknownOrigin + + token = self.tok.get() + # Range (required) + try: + start, stop, step = dns.grange.from_text(token.value) + token = self.tok.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError + except: + raise dns.exception.SyntaxError + + # lhs (required) + try: + lhs = token.value + token = self.tok.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError + except: + raise dns.exception.SyntaxError + + # TTL + try: + ttl = dns.ttl.from_text(token.value) + token = self.tok.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError + except dns.ttl.BadTTL: + ttl = self.ttl + # Class + try: + rdclass = dns.rdataclass.from_text(token.value) + token = self.tok.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError + except dns.exception.SyntaxError: + raise dns.exception.SyntaxError + except: + rdclass = self.zone.rdclass + if rdclass != self.zone.rdclass: + raise dns.exception.SyntaxError("RR class is not zone's class") + # Type + try: + rdtype = dns.rdatatype.from_text(token.value) + token = self.tok.get() + if not token.is_identifier(): + raise dns.exception.SyntaxError + except: + raise dns.exception.SyntaxError("unknown rdatatype '%s'" % + token.value) + + # lhs (required) + try: + rhs = token.value + except: + raise dns.exception.SyntaxError + + + lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs) + rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs) + for i in range(start, stop + 1, step): + # +1 because bind is inclusive and python is exclusive + + if lsign == '+': + lindex = i + int(loffset) + elif lsign == '-': + lindex = i - int(loffset) + + if rsign == '-': + rindex = i - int(roffset) + elif rsign == '+': + rindex = i + int(roffset) + + lzfindex = str(lindex).zfill(int(lwidth)) + rzfindex = str(rindex).zfill(int(rwidth)) + + + name = lhs.replace('$%s' % (lmod), lzfindex) + rdata = rhs.replace('$%s' % (rmod), rzfindex) + + self.last_name = dns.name.from_text(name, self.current_origin) + name = self.last_name + if not name.is_subdomain(self.zone.origin): + self._eat_line() + return + if self.relativize: + name = name.relativize(self.zone.origin) + + n = self.zone.nodes.get(name) + if n is None: + n = self.zone.node_factory() + self.zone.nodes[name] = n + try: + rd = dns.rdata.from_text(rdclass, rdtype, rdata, + self.current_origin, False) + except dns.exception.SyntaxError: + # Catch and reraise. + (ty, va) = sys.exc_info()[:2] + raise va + except: + # All exceptions that occur in the processing of rdata + # are treated as syntax errors. This is not strictly + # correct, but it is correct almost all of the time. + # We convert them to syntax errors so that we can emit + # helpful filename:line info. + (ty, va) = sys.exc_info()[:2] + raise dns.exception.SyntaxError("caught exception %s: %s" % + (str(ty), str(va))) + + rd.choose_relativity(self.zone.origin, self.relativize) + covers = rd.covers() + rds = n.find_rdataset(rdclass, rdtype, covers, True) + rds.add(rd, ttl) + def read(self): """Read a DNS master file and build a zone object. @@ -682,8 +845,6 @@ class _MasterReader(object): self.zone.origin = self.current_origin elif u == '$INCLUDE' and self.allow_include: token = self.tok.get() - if not token.is_quoted_string(): - raise dns.exception.SyntaxError("bad filename in $INCLUDE") filename = token.value token = self.tok.get() if token.is_identifier(): @@ -703,6 +864,8 @@ class _MasterReader(object): self.tok = dns.tokenizer.Tokenizer(self.current_file, filename) self.current_origin = new_origin + elif u == '$GENERATE': + self._generate_line() else: raise dns.exception.SyntaxError("Unknown master file directive '" + u + "'") continue diff --git a/tests/generate.py b/tests/generate.py new file mode 100644 index 0000000..43c5f9a --- /dev/null +++ b/tests/generate.py @@ -0,0 +1,499 @@ +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation 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 NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM 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. + +import sys +sys.path.insert(0, '../') # Force the local project to be *the* dns + +import cStringIO +import filecmp +import os +import unittest + +import dns.exception +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.rrset +import dns.zone + +import pprint + +pp = pprint.PrettyPrinter(indent=2) + +import pdb +example_text = """$TTL 1h +$ORIGIN 0.0.192.IN-ADDR.ARPA. +$GENERATE 1-2 0 CNAME SERVER$.EXAMPLE. +""" + +example_text1 = """$TTL 1h +$ORIGIN 0.0.192.IN-ADDR.ARPA. +$GENERATE 1-10 fooo$ CNAME $.0 +""" + +example_text2 = """$TTL 1h +@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +$GENERATE 3-5 foo$ A 10.0.0.$ +""" + +example_text3 = """$TTL 1h +@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +$GENERATE 4-8/2 foo$ A 10.0.0.$ +""" + +example_text4 = """$TTL 1h +@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +$GENERATE 11-13 wp-db${-10,2,d}.services.mozilla.com 0 CNAME SERVER.FOOBAR. +""" + +example_text5 = """$TTL 1h +@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +$GENERATE 11-13 wp-db${10,2,d}.services.mozilla.com 0 CNAME SERVER.FOOBAR. +""" + +example_text6 = """$TTL 1h +@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +$GENERATE 11-13 wp-db${+10,2,d}.services.mozilla.com 0 CNAME SERVER.FOOBAR. +""" + +example_text7 = """$TTL 1h +@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +$GENERATE 11-13 sync${-10}.db IN A 10.10.16.0 +""" + +example_text8 = """$TTL 1h +@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +$GENERATE 11-12 wp-db${-10,2,d} IN A 10.10.16.0 +""" + +example_text9 = """$TTL 1h +@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +$GENERATE 11-12 wp-db${-10,2,d} IN A 10.10.16.0 +$GENERATE 11-13 sync${-10}.db IN A 10.10.16.0 +""" +example_text10 = """$TTL 1h +@ 3600 IN SOA foo bar 1 2 3 4 5 +@ 3600 IN NS ns1 +@ 3600 IN NS ns2 +bar.foo 300 IN MX 0 blaz.foo +ns1 3600 IN A 10.0.0.1 +ns2 3600 IN A 10.0.0.2 +$GENERATE 27-28 $.2 PTR zlb${-26}.oob +""" + + +class GenerateTestCase(unittest.TestCase): + + def testFromText(self): + def bad(): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + self.failUnlessRaises(dns.zone.NoSOA, bad) + + def testFromText1(self): + def bad(): + z = dns.zone.from_text(example_text1, 'example.', relativize=True) + self.failUnlessRaises(dns.zone.NoSOA, bad) + + def testIterateAllRdatas2(self): + z = dns.zone.from_text(example_text2, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + exl = [(dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2')), + (dns.name.from_text('foo3', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.3')), + (dns.name.from_text('foo4', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.4')), + (dns.name.from_text('foo5', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.5'))] + + exl.sort() + self.failUnless(l == exl) + + def testIterateAllRdatas3(self): + z = dns.zone.from_text(example_text3, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + exl = [(dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2')), + (dns.name.from_text('foo4', None), 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.4')), + (dns.name.from_text('foo6', None), 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.6')), + (dns.name.from_text('foo8', None), 3600, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.8'))] + exl.sort() + self.failUnless(l == exl) + def testGenerate1(self): + z = dns.zone.from_text(example_text4, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + exl = [(dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2')), + + (dns.name.from_text('wp-db01.services.mozilla.com', None), + 0L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, + 'SERVER.FOOBAR.')), + + (dns.name.from_text('wp-db02.services.mozilla.com', None), + 0L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, + 'SERVER.FOOBAR.')), + + (dns.name.from_text('wp-db03.services.mozilla.com', None), + 0L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, + 'SERVER.FOOBAR.'))] + exl.sort() + self.failUnless(l == exl) + + def testGenerate2(self): + z = dns.zone.from_text(example_text5, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + exl = [(dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2')), + + (dns.name.from_text('wp-db21.services.mozilla.com', None), 0L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, + 'SERVER.FOOBAR.')), + + (dns.name.from_text('wp-db22.services.mozilla.com', None), 0L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, + 'SERVER.FOOBAR.')), + + (dns.name.from_text('wp-db23.services.mozilla.com', None), 0L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, + 'SERVER.FOOBAR.'))] + exl.sort() + self.failUnless(l == exl) + + def testGenerate3(self): + z = dns.zone.from_text(example_text6, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + + exl = [(dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2')), + (dns.name.from_text('wp-db21.services.mozilla.com', None), 0L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, + 'SERVER.FOOBAR.')), + + (dns.name.from_text('wp-db22.services.mozilla.com', None), 0L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, + 'SERVER.FOOBAR.')), + + (dns.name.from_text('wp-db23.services.mozilla.com', None), 0L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, + 'SERVER.FOOBAR.'))] + exl.sort() + self.failUnless(l == exl) + + def testGenerate4(self): + z = dns.zone.from_text(example_text7, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + exl = [(dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2')), + + (dns.name.from_text('sync1.db', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.10.16.0')), + + (dns.name.from_text('sync2.db', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.10.16.0')), + + (dns.name.from_text('sync3.db', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.10.16.0'))] + exl.sort() + self.failUnless(l == exl) + + def testGenerate6(self): + z = dns.zone.from_text(example_text9, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + exl = [(dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2')), + + (dns.name.from_text('wp-db01', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.10.16.0')), + (dns.name.from_text('wp-db02', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.10.16.0')), + + (dns.name.from_text('sync1.db', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.10.16.0')), + + (dns.name.from_text('sync2.db', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.10.16.0')), + + (dns.name.from_text('sync3.db', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.10.16.0'))] + exl.sort() + self.failUnless(l == exl) + + def testGenerate7(self): + z = dns.zone.from_text(example_text10, 'example.', relativize=True) + l = list(z.iterate_rdatas()) + l.sort() + exl = [(dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns1')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, + 'ns2')), + (dns.name.from_text('@', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, + 'foo bar 1 2 3 4 5')), + (dns.name.from_text('bar.foo', None), + 300L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, + '0 blaz.foo')), + (dns.name.from_text('ns1', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.1')), + (dns.name.from_text('ns2', None), + 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, + '10.0.0.2')), + + (dns.name.from_text('27.2', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.PTR, + 'zlb1.oob')), + + (dns.name.from_text('28.2', None), 3600L, + dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.PTR, + 'zlb2.oob'))] + + exl.sort() + self.failUnless(l == exl) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/grange.py b/tests/grange.py new file mode 100644 index 0000000..cbfc896 --- /dev/null +++ b/tests/grange.py @@ -0,0 +1,95 @@ +# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation 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 NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM 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. + +import sys +sys.path.insert(0, '../') + +import cStringIO +import filecmp +import os +import unittest + +import dns +import dns.exception +import dns.grange + +import pdb + + + +class GRangeTestCase(unittest.TestCase): + + def testFromText1(self): + start, stop, step = dns.grange.from_text('1-1') + self.assertEqual(start, 1) + self.assertEqual(stop, 1) + self.assertEqual(step, 1) + + def testFromText2(self): + start, stop, step = dns.grange.from_text('1-4') + self.assertEqual(start, 1) + self.assertEqual(stop, 4) + self.assertEqual(step, 1) + + def testFromText3(self): + start, stop, step = dns.grange.from_text('4-255') + self.assertEqual(start, 4) + self.assertEqual(stop, 255) + self.assertEqual(step, 1) + + def testFromText4(self): + start, stop, step = dns.grange.from_text('1-1/1') + self.assertEqual(start, 1) + self.assertEqual(stop, 1) + self.assertEqual(step, 1) + + def testFromText5(self): + start, stop, step = dns.grange.from_text('1-4/2') + self.assertEqual(start, 1) + self.assertEqual(stop, 4) + self.assertEqual(step, 2) + + def testFromText6(self): + start, stop, step = dns.grange.from_text('4-255/77') + self.assertEqual(start, 4) + self.assertEqual(stop, 255) + self.assertEqual(step, 77) + + def testFailFromText1(self): + def bad(): + start = 2 + stop = 1 + step = 1 + dns.grange.from_text('{0}-{1}/{2}'.format(start, stop, step)) + self.assertRaises(AssertionError, bad) + + def testFailFromText2(self): + def bad(): + start = '-1' + stop = 3 + step = 1 + dns.grange.from_text('{0}-{1}/{2}'.format(start, stop, step)) + self.assertRaises(dns.exception.SyntaxError, bad) + + def testFailFromText2(self): + def bad(): + start = 1 + stop = 4 + step = '-2' + dns.grange.from_text('{0}-{1}/{2}'.format(start, stop, step)) + self.assertRaises(dns.exception.SyntaxError, bad) + +if __name__ == '__main__': + unittest.main() |