s4-python: Move dnspython to lib/, like the other Python modules
[samba.git] / lib / dnspython / tests / zone.py
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()