1 | # Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc.
|
---|
2 | #
|
---|
3 | # Permission to use, copy, modify, and distribute this software and its
|
---|
4 | # documentation for any purpose with or without fee is hereby granted,
|
---|
5 | # provided that the above copyright notice and this permission notice
|
---|
6 | # appear in all copies.
|
---|
7 | #
|
---|
8 | # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
---|
9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
---|
10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
---|
11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
---|
12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
---|
13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
---|
14 | # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
---|
15 |
|
---|
16 | import cStringIO
|
---|
17 | import filecmp
|
---|
18 | import os
|
---|
19 | import unittest
|
---|
20 |
|
---|
21 | import dns.exception
|
---|
22 | import dns.rdata
|
---|
23 | import dns.rdataclass
|
---|
24 | import dns.rdatatype
|
---|
25 | import dns.rrset
|
---|
26 | import dns.zone
|
---|
27 |
|
---|
28 | example_text = """$TTL 3600
|
---|
29 | $ORIGIN example.
|
---|
30 | @ soa foo bar 1 2 3 4 5
|
---|
31 | @ ns ns1
|
---|
32 | @ ns ns2
|
---|
33 | ns1 a 10.0.0.1
|
---|
34 | ns2 a 10.0.0.2
|
---|
35 | $TTL 300
|
---|
36 | $ORIGIN foo.example.
|
---|
37 | bar mx 0 blaz
|
---|
38 | """
|
---|
39 |
|
---|
40 | example_text_output = """@ 3600 IN SOA foo bar 1 2 3 4 5
|
---|
41 | @ 3600 IN NS ns1
|
---|
42 | @ 3600 IN NS ns2
|
---|
43 | bar.foo 300 IN MX 0 blaz.foo
|
---|
44 | ns1 3600 IN A 10.0.0.1
|
---|
45 | ns2 3600 IN A 10.0.0.2
|
---|
46 | """
|
---|
47 |
|
---|
48 | something_quite_similar = """@ 3600 IN SOA foo bar 1 2 3 4 5
|
---|
49 | @ 3600 IN NS ns1
|
---|
50 | @ 3600 IN NS ns2
|
---|
51 | bar.foo 300 IN MX 0 blaz.foo
|
---|
52 | ns1 3600 IN A 10.0.0.1
|
---|
53 | ns2 3600 IN A 10.0.0.3
|
---|
54 | """
|
---|
55 |
|
---|
56 | something_different = """@ 3600 IN SOA fooa bar 1 2 3 4 5
|
---|
57 | @ 3600 IN NS ns11
|
---|
58 | @ 3600 IN NS ns21
|
---|
59 | bar.fooa 300 IN MX 0 blaz.fooa
|
---|
60 | ns11 3600 IN A 10.0.0.11
|
---|
61 | ns21 3600 IN A 10.0.0.21
|
---|
62 | """
|
---|
63 |
|
---|
64 | ttl_example_text = """$TTL 1h
|
---|
65 | $ORIGIN example.
|
---|
66 | @ soa foo bar 1 2 3 4 5
|
---|
67 | @ ns ns1
|
---|
68 | @ ns ns2
|
---|
69 | ns1 1d1s a 10.0.0.1
|
---|
70 | ns2 1w1D1h1m1S a 10.0.0.2
|
---|
71 | """
|
---|
72 |
|
---|
73 | no_soa_text = """$TTL 1h
|
---|
74 | $ORIGIN example.
|
---|
75 | @ ns ns1
|
---|
76 | @ ns ns2
|
---|
77 | ns1 1d1s a 10.0.0.1
|
---|
78 | ns2 1w1D1h1m1S a 10.0.0.2
|
---|
79 | """
|
---|
80 |
|
---|
81 | no_ns_text = """$TTL 1h
|
---|
82 | $ORIGIN example.
|
---|
83 | @ soa foo bar 1 2 3 4 5
|
---|
84 | """
|
---|
85 |
|
---|
86 | include_text = """$INCLUDE "example"
|
---|
87 | """
|
---|
88 |
|
---|
89 | bad_directive_text = """$FOO bar
|
---|
90 | $ORIGIN example.
|
---|
91 | @ soa foo bar 1 2 3 4 5
|
---|
92 | @ ns ns1
|
---|
93 | @ ns ns2
|
---|
94 | ns1 1d1s a 10.0.0.1
|
---|
95 | ns2 1w1D1h1m1S a 10.0.0.2
|
---|
96 | """
|
---|
97 |
|
---|
98 | _keep_output = False
|
---|
99 |
|
---|
100 | class ZoneTestCase(unittest.TestCase):
|
---|
101 |
|
---|
102 | def testFromFile1(self):
|
---|
103 | z = dns.zone.from_file('example', 'example')
|
---|
104 | ok = False
|
---|
105 | try:
|
---|
106 | z.to_file('example1.out', nl='\x0a')
|
---|
107 | ok = filecmp.cmp('example1.out', 'example1.good')
|
---|
108 | finally:
|
---|
109 | if not _keep_output:
|
---|
110 | os.unlink('example1.out')
|
---|
111 | self.failUnless(ok)
|
---|
112 |
|
---|
113 | def testFromFile2(self):
|
---|
114 | z = dns.zone.from_file('example', 'example', relativize=False)
|
---|
115 | ok = False
|
---|
116 | try:
|
---|
117 | z.to_file('example2.out', relativize=False, nl='\x0a')
|
---|
118 | ok = filecmp.cmp('example2.out', 'example2.good')
|
---|
119 | finally:
|
---|
120 | if not _keep_output:
|
---|
121 | os.unlink('example2.out')
|
---|
122 | self.failUnless(ok)
|
---|
123 |
|
---|
124 | def testFromText(self):
|
---|
125 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
126 | f = cStringIO.StringIO()
|
---|
127 | names = z.nodes.keys()
|
---|
128 | names.sort()
|
---|
129 | for n in names:
|
---|
130 | print >> f, z[n].to_text(n)
|
---|
131 | self.failUnless(f.getvalue() == example_text_output)
|
---|
132 |
|
---|
133 | def testTorture1(self):
|
---|
134 | #
|
---|
135 | # Read a zone containing all our supported RR types, and
|
---|
136 | # for each RR in the zone, convert the rdata into wire format
|
---|
137 | # and then back out, and see if we get equal rdatas.
|
---|
138 | #
|
---|
139 | f = cStringIO.StringIO()
|
---|
140 | o = dns.name.from_text('example.')
|
---|
141 | z = dns.zone.from_file('example', o)
|
---|
142 | for (name, node) in z.iteritems():
|
---|
143 | for rds in node:
|
---|
144 | for rd in rds:
|
---|
145 | f.seek(0)
|
---|
146 | f.truncate()
|
---|
147 | rd.to_wire(f, origin=o)
|
---|
148 | wire = f.getvalue()
|
---|
149 | rd2 = dns.rdata.from_wire(rds.rdclass, rds.rdtype,
|
---|
150 | wire, 0, len(wire),
|
---|
151 | origin = o)
|
---|
152 | self.failUnless(rd == rd2)
|
---|
153 |
|
---|
154 | def testEqual(self):
|
---|
155 | z1 = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
156 | z2 = dns.zone.from_text(example_text_output, 'example.',
|
---|
157 | relativize=True)
|
---|
158 | self.failUnless(z1 == z2)
|
---|
159 |
|
---|
160 | def testNotEqual1(self):
|
---|
161 | z1 = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
162 | z2 = dns.zone.from_text(something_quite_similar, 'example.',
|
---|
163 | relativize=True)
|
---|
164 | self.failUnless(z1 != z2)
|
---|
165 |
|
---|
166 | def testNotEqual2(self):
|
---|
167 | z1 = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
168 | z2 = dns.zone.from_text(something_different, 'example.',
|
---|
169 | relativize=True)
|
---|
170 | self.failUnless(z1 != z2)
|
---|
171 |
|
---|
172 | def testNotEqual3(self):
|
---|
173 | z1 = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
174 | z2 = dns.zone.from_text(something_different, 'example2.',
|
---|
175 | relativize=True)
|
---|
176 | self.failUnless(z1 != z2)
|
---|
177 |
|
---|
178 | def testFindRdataset1(self):
|
---|
179 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
180 | rds = z.find_rdataset('@', 'soa')
|
---|
181 | exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5')
|
---|
182 | self.failUnless(rds == exrds)
|
---|
183 |
|
---|
184 | def testFindRdataset2(self):
|
---|
185 | def bad():
|
---|
186 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
187 | rds = z.find_rdataset('@', 'loc')
|
---|
188 | self.failUnlessRaises(KeyError, bad)
|
---|
189 |
|
---|
190 | def testFindRRset1(self):
|
---|
191 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
192 | rrs = z.find_rrset('@', 'soa')
|
---|
193 | exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5')
|
---|
194 | self.failUnless(rrs == exrrs)
|
---|
195 |
|
---|
196 | def testFindRRset2(self):
|
---|
197 | def bad():
|
---|
198 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
199 | rrs = z.find_rrset('@', 'loc')
|
---|
200 | self.failUnlessRaises(KeyError, bad)
|
---|
201 |
|
---|
202 | def testGetRdataset1(self):
|
---|
203 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
204 | rds = z.get_rdataset('@', 'soa')
|
---|
205 | exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5')
|
---|
206 | self.failUnless(rds == exrds)
|
---|
207 |
|
---|
208 | def testGetRdataset2(self):
|
---|
209 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
210 | rds = z.get_rdataset('@', 'loc')
|
---|
211 | self.failUnless(rds == None)
|
---|
212 |
|
---|
213 | def testGetRRset1(self):
|
---|
214 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
215 | rrs = z.get_rrset('@', 'soa')
|
---|
216 | exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5')
|
---|
217 | self.failUnless(rrs == exrrs)
|
---|
218 |
|
---|
219 | def testGetRRset2(self):
|
---|
220 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
221 | rrs = z.get_rrset('@', 'loc')
|
---|
222 | self.failUnless(rrs == None)
|
---|
223 |
|
---|
224 | def testReplaceRdataset1(self):
|
---|
225 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
226 | rdataset = dns.rdataset.from_text('in', 'ns', 300, 'ns3', 'ns4')
|
---|
227 | z.replace_rdataset('@', rdataset)
|
---|
228 | rds = z.get_rdataset('@', 'ns')
|
---|
229 | self.failUnless(rds is rdataset)
|
---|
230 |
|
---|
231 | def testReplaceRdataset2(self):
|
---|
232 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
233 | rdataset = dns.rdataset.from_text('in', 'txt', 300, '"foo"')
|
---|
234 | z.replace_rdataset('@', rdataset)
|
---|
235 | rds = z.get_rdataset('@', 'txt')
|
---|
236 | self.failUnless(rds is rdataset)
|
---|
237 |
|
---|
238 | def testDeleteRdataset1(self):
|
---|
239 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
240 | z.delete_rdataset('@', 'ns')
|
---|
241 | rds = z.get_rdataset('@', 'ns')
|
---|
242 | self.failUnless(rds is None)
|
---|
243 |
|
---|
244 | def testDeleteRdataset2(self):
|
---|
245 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
246 | z.delete_rdataset('ns1', 'a')
|
---|
247 | node = z.get_node('ns1')
|
---|
248 | self.failUnless(node is None)
|
---|
249 |
|
---|
250 | def testNodeFindRdataset1(self):
|
---|
251 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
252 | node = z['@']
|
---|
253 | rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)
|
---|
254 | exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5')
|
---|
255 | self.failUnless(rds == exrds)
|
---|
256 |
|
---|
257 | def testNodeFindRdataset2(self):
|
---|
258 | def bad():
|
---|
259 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
260 | node = z['@']
|
---|
261 | rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC)
|
---|
262 | self.failUnlessRaises(KeyError, bad)
|
---|
263 |
|
---|
264 | def testNodeGetRdataset1(self):
|
---|
265 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
266 | node = z['@']
|
---|
267 | rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)
|
---|
268 | exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5')
|
---|
269 | self.failUnless(rds == exrds)
|
---|
270 |
|
---|
271 | def testNodeGetRdataset2(self):
|
---|
272 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
273 | node = z['@']
|
---|
274 | rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC)
|
---|
275 | self.failUnless(rds == None)
|
---|
276 |
|
---|
277 | def testNodeDeleteRdataset1(self):
|
---|
278 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
279 | node = z['@']
|
---|
280 | rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)
|
---|
281 | rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)
|
---|
282 | self.failUnless(rds == None)
|
---|
283 |
|
---|
284 | def testNodeDeleteRdataset2(self):
|
---|
285 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
286 | node = z['@']
|
---|
287 | rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC)
|
---|
288 | rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC)
|
---|
289 | self.failUnless(rds == None)
|
---|
290 |
|
---|
291 | def testIterateRdatasets(self):
|
---|
292 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
293 | ns = [n for n, r in z.iterate_rdatasets('A')]
|
---|
294 | ns.sort()
|
---|
295 | self.failUnless(ns == [dns.name.from_text('ns1', None),
|
---|
296 | dns.name.from_text('ns2', None)])
|
---|
297 |
|
---|
298 | def testIterateAllRdatasets(self):
|
---|
299 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
300 | ns = [n for n, r in z.iterate_rdatasets()]
|
---|
301 | ns.sort()
|
---|
302 | self.failUnless(ns == [dns.name.from_text('@', None),
|
---|
303 | dns.name.from_text('@', None),
|
---|
304 | dns.name.from_text('bar.foo', None),
|
---|
305 | dns.name.from_text('ns1', None),
|
---|
306 | dns.name.from_text('ns2', None)])
|
---|
307 |
|
---|
308 | def testIterateRdatas(self):
|
---|
309 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
310 | l = list(z.iterate_rdatas('A'))
|
---|
311 | l.sort()
|
---|
312 | exl = [(dns.name.from_text('ns1', None),
|
---|
313 | 3600,
|
---|
314 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
|
---|
315 | '10.0.0.1')),
|
---|
316 | (dns.name.from_text('ns2', None),
|
---|
317 | 3600,
|
---|
318 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
|
---|
319 | '10.0.0.2'))]
|
---|
320 | self.failUnless(l == exl)
|
---|
321 |
|
---|
322 | def testIterateAllRdatas(self):
|
---|
323 | z = dns.zone.from_text(example_text, 'example.', relativize=True)
|
---|
324 | l = list(z.iterate_rdatas())
|
---|
325 | l.sort()
|
---|
326 | exl = [(dns.name.from_text('@', None),
|
---|
327 | 3600,
|
---|
328 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
|
---|
329 | 'ns1')),
|
---|
330 | (dns.name.from_text('@', None),
|
---|
331 | 3600,
|
---|
332 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
|
---|
333 | 'ns2')),
|
---|
334 | (dns.name.from_text('@', None),
|
---|
335 | 3600,
|
---|
336 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
|
---|
337 | 'foo bar 1 2 3 4 5')),
|
---|
338 | (dns.name.from_text('bar.foo', None),
|
---|
339 | 300,
|
---|
340 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX,
|
---|
341 | '0 blaz.foo')),
|
---|
342 | (dns.name.from_text('ns1', None),
|
---|
343 | 3600,
|
---|
344 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
|
---|
345 | '10.0.0.1')),
|
---|
346 | (dns.name.from_text('ns2', None),
|
---|
347 | 3600,
|
---|
348 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A,
|
---|
349 | '10.0.0.2'))]
|
---|
350 | self.failUnless(l == exl)
|
---|
351 |
|
---|
352 | def testTTLs(self):
|
---|
353 | z = dns.zone.from_text(ttl_example_text, 'example.', relativize=True)
|
---|
354 | n = z['@']
|
---|
355 | rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)
|
---|
356 | self.failUnless(rds.ttl == 3600)
|
---|
357 | n = z['ns1']
|
---|
358 | rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)
|
---|
359 | self.failUnless(rds.ttl == 86401)
|
---|
360 | n = z['ns2']
|
---|
361 | rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)
|
---|
362 | self.failUnless(rds.ttl == 694861)
|
---|
363 |
|
---|
364 | def testNoSOA(self):
|
---|
365 | def bad():
|
---|
366 | z = dns.zone.from_text(no_soa_text, 'example.',
|
---|
367 | relativize=True)
|
---|
368 | self.failUnlessRaises(dns.zone.NoSOA, bad)
|
---|
369 |
|
---|
370 | def testNoNS(self):
|
---|
371 | def bad():
|
---|
372 | z = dns.zone.from_text(no_ns_text, 'example.',
|
---|
373 | relativize=True)
|
---|
374 | self.failUnlessRaises(dns.zone.NoNS, bad)
|
---|
375 |
|
---|
376 | def testInclude(self):
|
---|
377 | z1 = dns.zone.from_text(include_text, 'example.', relativize=True,
|
---|
378 | allow_include=True)
|
---|
379 | z2 = dns.zone.from_file('example', 'example.', relativize=True)
|
---|
380 | self.failUnless(z1 == z2)
|
---|
381 |
|
---|
382 | def testBadDirective(self):
|
---|
383 | def bad():
|
---|
384 | z = dns.zone.from_text(bad_directive_text, 'example.',
|
---|
385 | relativize=True)
|
---|
386 | self.failUnlessRaises(dns.exception.SyntaxError, bad)
|
---|
387 |
|
---|
388 | if __name__ == '__main__':
|
---|
389 | unittest.main()
|
---|