]>
Commit | Line | Data |
---|---|---|
e2dba705 | 1 | import json |
d29d5db7 | 2 | import time |
1a152698 | 3 | import requests |
e2dba705 | 4 | import unittest |
02945d9a | 5 | from test_helper import ApiTestCase, unique_zone_name, isAuth, isRecursor |
1a152698 CH |
6 | |
7 | ||
02945d9a | 8 | class Zones(ApiTestCase): |
1a152698 CH |
9 | |
10 | def test_ListZones(self): | |
11 | r = self.session.get(self.url("/servers/localhost/zones")) | |
12 | self.assertSuccessJson(r) | |
45de6290 | 13 | domains = r.json() |
02945d9a | 14 | example_com = [domain for domain in domains if domain['name'] in ('example.com', 'example.com.')] |
1a152698 CH |
15 | self.assertEquals(len(example_com), 1) |
16 | example_com = example_com[0] | |
02945d9a CH |
17 | required_fields = ['id', 'url', 'name', 'kind'] |
18 | if isAuth(): | |
19 | required_fields = required_fields + ['masters', 'last_check', 'notified_serial', 'serial'] | |
20 | elif isRecursor(): | |
21 | required_fields = required_fields + ['recursion_desired', 'servers'] | |
22 | for field in required_fields: | |
23 | self.assertIn(field, example_com) | |
24 | ||
25 | ||
26 | @unittest.skipIf(not isAuth(), "Not applicable") | |
27 | class AuthZones(ApiTestCase): | |
e2dba705 | 28 | |
284fdfe9 | 29 | def create_zone(self, name=None, **kwargs): |
bee2acae CH |
30 | if name is None: |
31 | name = unique_zone_name() | |
e2dba705 | 32 | payload = { |
bee2acae | 33 | 'name': name, |
e2dba705 | 34 | 'kind': 'Native', |
bee2acae | 35 | 'nameservers': ['ns1.example.com', 'ns2.example.com'] |
e2dba705 | 36 | } |
284fdfe9 CH |
37 | for k, v in kwargs.items(): |
38 | payload[k] = v | |
39 | print payload | |
e2dba705 CH |
40 | r = self.session.post( |
41 | self.url("/servers/localhost/zones"), | |
42 | data=json.dumps(payload), | |
43 | headers={'content-type': 'application/json'}) | |
44 | self.assertSuccessJson(r) | |
bee2acae CH |
45 | return (payload, r.json()) |
46 | ||
47 | def test_CreateZone(self): | |
48 | payload, data = self.create_zone() | |
d29d5db7 CH |
49 | for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'soa_edit_api'): |
50 | self.assertIn(k, data) | |
51 | if k in payload: | |
52 | self.assertEquals(data[k], payload[k]) | |
53 | self.assertEquals(data['comments'], []) | |
54 | ||
55 | def test_CreateZoneWithSoaEditApi(self): | |
56 | payload, data = self.create_zone(soa_edit_api='EPOCH') | |
57 | for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'soa_edit_api'): | |
e2dba705 CH |
58 | self.assertIn(k, data) |
59 | if k in payload: | |
60 | self.assertEquals(data[k], payload[k]) | |
6cc98ddf | 61 | self.assertEquals(data['comments'], []) |
05776d2f | 62 | |
4ebf78b1 CH |
63 | def test_CreateZoneTrailingDot(self): |
64 | # Trailing dots should not end up in the zone name. | |
65 | basename = unique_zone_name() | |
66 | payload, data = self.create_zone(name=basename+'.') | |
67 | self.assertEquals(data['name'], basename) | |
68 | ||
00a9b229 | 69 | def test_CreateZoneWithSymbols(self): |
bee2acae CH |
70 | payload, data = self.create_zone(name='foo/bar.'+unique_zone_name()) |
71 | name = payload['name'] | |
1dbe38ba | 72 | expected_id = (name.replace('/', '=2F')) + '.' |
00a9b229 CH |
73 | for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial'): |
74 | self.assertIn(k, data) | |
75 | if k in payload: | |
76 | self.assertEquals(data[k], payload[k]) | |
bee2acae | 77 | self.assertEquals(data['id'], expected_id) |
00a9b229 | 78 | |
3c3c006b CH |
79 | def test_GetZoneWithSymbols(self): |
80 | payload, data = self.create_zone(name='foo/bar.'+unique_zone_name()) | |
81 | name = payload['name'] | |
1dbe38ba | 82 | zone_id = (name.replace('/', '=2F')) + '.' |
3c3c006b CH |
83 | r = self.session.get(self.url("/servers/localhost/zones/" + zone_id)) |
84 | for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial'): | |
85 | self.assertIn(k, data) | |
86 | if k in payload: | |
87 | self.assertEquals(data[k], payload[k]) | |
88 | ||
05776d2f CH |
89 | def test_GetZone(self): |
90 | r = self.session.get(self.url("/servers/localhost/zones")) | |
91 | domains = r.json() | |
92 | example_com = [domain for domain in domains if domain['name'] == u'example.com'][0] | |
93 | r = self.session.get(self.url("/servers/localhost/zones/" + example_com['id'])) | |
94 | self.assertSuccessJson(r) | |
95 | data = r.json() | |
96 | for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial'): | |
97 | self.assertIn(k, data) | |
98 | self.assertEquals(data['name'], 'example.com') | |
7c0ba3d2 CH |
99 | |
100 | def test_UpdateZone(self): | |
bee2acae CH |
101 | payload, zone = self.create_zone() |
102 | name = payload['name'] | |
d29d5db7 | 103 | # update, set as Master and enable SOA-EDIT-API |
7c0ba3d2 CH |
104 | payload = { |
105 | 'kind': 'Master', | |
d29d5db7 CH |
106 | 'masters': ['192.0.2.1','192.0.2.2'], |
107 | 'soa_edit_api': 'EPOCH' | |
7c0ba3d2 CH |
108 | } |
109 | r = self.session.put( | |
110 | self.url("/servers/localhost/zones/" + name), | |
111 | data=json.dumps(payload), | |
112 | headers={'content-type': 'application/json'}) | |
113 | self.assertSuccessJson(r) | |
114 | data = r.json() | |
115 | for k in payload.keys(): | |
116 | self.assertIn(k, data) | |
117 | self.assertEquals(data[k], payload[k]) | |
d29d5db7 | 118 | # update, back to Native and empty(off) |
7c0ba3d2 | 119 | payload = { |
d29d5db7 CH |
120 | 'kind': 'Native', |
121 | 'soa_edit_api': '' | |
7c0ba3d2 CH |
122 | } |
123 | r = self.session.put( | |
124 | self.url("/servers/localhost/zones/" + name), | |
125 | data=json.dumps(payload), | |
126 | headers={'content-type': 'application/json'}) | |
127 | self.assertSuccessJson(r) | |
128 | data = r.json() | |
129 | for k in payload.keys(): | |
130 | self.assertIn(k, data) | |
131 | self.assertEquals(data[k], payload[k]) | |
b3905a3d CH |
132 | |
133 | def test_ZoneRRUpdate(self): | |
bee2acae CH |
134 | payload, zone = self.create_zone() |
135 | name = payload['name'] | |
b3905a3d | 136 | # do a replace (= update) |
d708640f | 137 | rrset = { |
b3905a3d CH |
138 | 'changetype': 'replace', |
139 | 'name': name, | |
140 | 'type': 'NS', | |
141 | 'records': [ | |
142 | { | |
143 | "name": name, | |
144 | "type": "NS", | |
145 | "priority": 0, | |
146 | "ttl": 3600, | |
cea26350 CH |
147 | "content": "ns1.bar.com", |
148 | "disabled": False | |
149 | }, | |
150 | { | |
151 | "name": name, | |
152 | "type": "NS", | |
153 | "priority": 0, | |
154 | "ttl": 1800, | |
155 | "content": "ns2-disabled.bar.com", | |
156 | "disabled": True | |
b3905a3d CH |
157 | } |
158 | ] | |
159 | } | |
d708640f | 160 | payload = {'rrsets': [rrset]} |
b3905a3d | 161 | r = self.session.patch( |
d708640f | 162 | self.url("/servers/localhost/zones/" + name), |
b3905a3d CH |
163 | data=json.dumps(payload), |
164 | headers={'content-type': 'application/json'}) | |
165 | self.assertSuccessJson(r) | |
166 | # verify that (only) the new record is there | |
6cc98ddf | 167 | r = self.session.get(self.url("/servers/localhost/zones/" + name)) |
b3905a3d | 168 | data = r.json()['records'] |
d708640f CH |
169 | recs = [rec for rec in data if rec['type'] == rrset['type'] and rec['name'] == rrset['name']] |
170 | self.assertEquals(recs, rrset['records']) | |
b3905a3d | 171 | |
41e3b10e CH |
172 | def test_ZoneRRUpdateMX(self): |
173 | # Important to test with MX records, as they have a priority field, which must not end up in the content field. | |
174 | payload, zone = self.create_zone() | |
175 | name = payload['name'] | |
176 | # do a replace (= update) | |
d708640f | 177 | rrset = { |
41e3b10e CH |
178 | 'changetype': 'replace', |
179 | 'name': name, | |
180 | 'type': 'MX', | |
181 | 'records': [ | |
182 | { | |
183 | "name": name, | |
184 | "type": "MX", | |
185 | "priority": 10, | |
186 | "ttl": 3600, | |
187 | "content": "mail.example.org", | |
188 | "disabled": False | |
189 | } | |
190 | ] | |
191 | } | |
d708640f | 192 | payload = {'rrsets': [rrset]} |
41e3b10e | 193 | r = self.session.patch( |
d708640f | 194 | self.url("/servers/localhost/zones/" + name), |
41e3b10e CH |
195 | data=json.dumps(payload), |
196 | headers={'content-type': 'application/json'}) | |
197 | self.assertSuccessJson(r) | |
198 | # verify that (only) the new record is there | |
199 | r = self.session.get(self.url("/servers/localhost/zones/" + name)) | |
200 | data = r.json()['records'] | |
d708640f CH |
201 | recs = [rec for rec in data if rec['type'] == rrset['type'] and rec['name'] == rrset['name']] |
202 | self.assertEquals(recs, rrset['records']) | |
203 | ||
204 | def test_ZoneRRUpdateMultipleRRsets(self): | |
205 | payload, zone = self.create_zone() | |
206 | name = payload['name'] | |
207 | rrset1 = { | |
208 | 'changetype': 'replace', | |
209 | 'name': name, | |
210 | 'type': 'NS', | |
211 | 'records': [ | |
212 | { | |
213 | "name": name, | |
214 | "type": "NS", | |
215 | "priority": 0, | |
216 | "ttl": 3600, | |
217 | "content": "ns9999.example.com", | |
218 | "disabled": False | |
219 | } | |
220 | ] | |
221 | } | |
222 | rrset2 = { | |
223 | 'changetype': 'replace', | |
224 | 'name': name, | |
225 | 'type': 'MX', | |
226 | 'records': [ | |
227 | { | |
228 | "name": name, | |
229 | "type": "MX", | |
230 | "priority": 10, | |
231 | "ttl": 3600, | |
232 | "content": "mx444.example.com", | |
233 | "disabled": False | |
234 | } | |
235 | ] | |
236 | } | |
237 | payload = {'rrsets': [rrset1, rrset2]} | |
238 | r = self.session.patch( | |
239 | self.url("/servers/localhost/zones/" + name), | |
240 | data=json.dumps(payload), | |
241 | headers={'content-type': 'application/json'}) | |
242 | self.assertSuccessJson(r) | |
243 | # verify that all rrsets have been updated | |
244 | r = self.session.get(self.url("/servers/localhost/zones/" + name)) | |
245 | data = r.json()['records'] | |
246 | recs1 = [rec for rec in data if rec['type'] == rrset1['type'] and rec['name'] == rrset1['name']] | |
247 | self.assertEquals(recs1, rrset1['records']) | |
248 | recs2 = [rec for rec in data if rec['type'] == rrset2['type'] and rec['name'] == rrset2['name']] | |
249 | self.assertEquals(recs2, rrset2['records']) | |
41e3b10e | 250 | |
b3905a3d | 251 | def test_ZoneRRDelete(self): |
bee2acae CH |
252 | payload, zone = self.create_zone() |
253 | name = payload['name'] | |
b3905a3d | 254 | # do a delete of all NS records (these are created with the zone) |
d708640f | 255 | rrset = { |
b3905a3d CH |
256 | 'changetype': 'delete', |
257 | 'name': name, | |
258 | 'type': 'NS' | |
259 | } | |
d708640f | 260 | payload = {'rrsets': [rrset]} |
b3905a3d | 261 | r = self.session.patch( |
d708640f | 262 | self.url("/servers/localhost/zones/" + name), |
b3905a3d CH |
263 | data=json.dumps(payload), |
264 | headers={'content-type': 'application/json'}) | |
265 | self.assertSuccessJson(r) | |
266 | # verify that the records are gone | |
6cc98ddf | 267 | r = self.session.get(self.url("/servers/localhost/zones/" + name)) |
b3905a3d | 268 | data = r.json()['records'] |
d708640f | 269 | recs = [rec for rec in data if rec['type'] == rrset['type'] and rec['name'] == rrset['name']] |
b3905a3d | 270 | self.assertEquals(recs, []) |
cea26350 CH |
271 | |
272 | def test_ZoneDisableReenable(self): | |
d29d5db7 CH |
273 | # This also tests that SOA-EDIT-API works. |
274 | payload, zone = self.create_zone(soa_edit_api='EPOCH') | |
cea26350 CH |
275 | name = payload['name'] |
276 | # disable zone by disabling SOA | |
d708640f | 277 | rrset = { |
cea26350 CH |
278 | 'changetype': 'replace', |
279 | 'name': name, | |
280 | 'type': 'SOA', | |
281 | 'records': [ | |
282 | { | |
283 | "name": name, | |
284 | "type": "SOA", | |
285 | "priority": 0, | |
286 | "ttl": 3600, | |
287 | "content": "ns1.bar.com hostmaster.foo.org 1 1 1 1 1", | |
288 | "disabled": True | |
289 | } | |
290 | ] | |
291 | } | |
d708640f | 292 | payload = {'rrsets': [rrset]} |
cea26350 | 293 | r = self.session.patch( |
d708640f | 294 | self.url("/servers/localhost/zones/" + name), |
cea26350 CH |
295 | data=json.dumps(payload), |
296 | headers={'content-type': 'application/json'}) | |
297 | self.assertSuccessJson(r) | |
d29d5db7 CH |
298 | # check SOA serial has been edited |
299 | print r.json() | |
300 | soa_serial1 = [rec for rec in r.json()['records'] if rec['type'] == 'SOA'][0]['content'].split()[2] | |
301 | self.assertNotEquals(soa_serial1, '1') | |
302 | # make sure domain is still in zone list (disabled SOA!) | |
cea26350 CH |
303 | r = self.session.get(self.url("/servers/localhost/zones")) |
304 | domains = r.json() | |
305 | self.assertEquals(len([domain for domain in domains if domain['name'] == name]), 1) | |
d29d5db7 CH |
306 | # sleep 1sec to ensure the EPOCH value changes for the next request |
307 | time.sleep(1) | |
cea26350 | 308 | # verify that modifying it still works |
d708640f CH |
309 | rrset['records'][0]['disabled'] = False |
310 | payload = {'rrsets': [rrset]} | |
cea26350 | 311 | r = self.session.patch( |
d708640f | 312 | self.url("/servers/localhost/zones/" + name), |
cea26350 CH |
313 | data=json.dumps(payload), |
314 | headers={'content-type': 'application/json'}) | |
315 | self.assertSuccessJson(r) | |
d29d5db7 CH |
316 | # check SOA serial has been edited again |
317 | print r.json() | |
318 | soa_serial2 = [rec for rec in r.json()['records'] if rec['type'] == 'SOA'][0]['content'].split()[2] | |
319 | self.assertNotEquals(soa_serial2, '1') | |
320 | self.assertNotEquals(soa_serial2, soa_serial1) | |
02945d9a | 321 | |
35f26cc5 CH |
322 | def test_ZoneRRUpdateQTypeMismatch(self): |
323 | payload, zone = self.create_zone() | |
324 | name = payload['name'] | |
325 | # replace with qtype mismatch | |
d708640f | 326 | rrset = { |
35f26cc5 CH |
327 | 'changetype': 'replace', |
328 | 'name': name, | |
329 | 'type': 'A', | |
330 | 'records': [ | |
331 | { | |
332 | "name": name, | |
333 | "type": "NS", | |
334 | "priority": 0, | |
335 | "ttl": 3600, | |
336 | "content": "ns1.bar.com", | |
337 | "disabled": False | |
338 | } | |
339 | ] | |
340 | } | |
d708640f | 341 | payload = {'rrsets': [rrset]} |
35f26cc5 | 342 | r = self.session.patch( |
d708640f | 343 | self.url("/servers/localhost/zones/" + name), |
35f26cc5 CH |
344 | data=json.dumps(payload), |
345 | headers={'content-type': 'application/json'}) | |
346 | self.assertEquals(r.status_code, 422) | |
347 | ||
348 | def test_ZoneRRUpdateQNameMismatch(self): | |
349 | payload, zone = self.create_zone() | |
350 | name = payload['name'] | |
351 | # replace with qname mismatch | |
d708640f | 352 | rrset = { |
35f26cc5 CH |
353 | 'changetype': 'replace', |
354 | 'name': name, | |
355 | 'type': 'NS', | |
356 | 'records': [ | |
357 | { | |
358 | "name": 'blah.'+name, | |
359 | "type": "NS", | |
360 | "priority": 0, | |
361 | "ttl": 3600, | |
362 | "content": "ns1.bar.com", | |
363 | "disabled": False | |
364 | } | |
365 | ] | |
366 | } | |
d708640f | 367 | payload = {'rrsets': [rrset]} |
35f26cc5 | 368 | r = self.session.patch( |
d708640f | 369 | self.url("/servers/localhost/zones/" + name), |
35f26cc5 CH |
370 | data=json.dumps(payload), |
371 | headers={'content-type': 'application/json'}) | |
372 | self.assertEquals(r.status_code, 422) | |
373 | ||
374 | def test_ZoneRRUpdateOutOfZone(self): | |
375 | payload, zone = self.create_zone() | |
376 | name = payload['name'] | |
377 | # replace with qname mismatch | |
d708640f | 378 | rrset = { |
35f26cc5 CH |
379 | 'changetype': 'replace', |
380 | 'name': 'not-in-zone', | |
381 | 'type': 'NS', | |
382 | 'records': [ | |
383 | { | |
384 | "name": name, | |
385 | "type": "NS", | |
386 | "priority": 0, | |
387 | "ttl": 3600, | |
388 | "content": "ns1.bar.com", | |
389 | "disabled": False | |
390 | } | |
391 | ] | |
392 | } | |
d708640f | 393 | payload = {'rrsets': [rrset]} |
35f26cc5 | 394 | r = self.session.patch( |
d708640f | 395 | self.url("/servers/localhost/zones/" + name), |
35f26cc5 CH |
396 | data=json.dumps(payload), |
397 | headers={'content-type': 'application/json'}) | |
398 | self.assertEquals(r.status_code, 422) | |
399 | self.assertIn('out of zone', r.json()['error']) | |
400 | ||
401 | def test_ZoneRRDeleteOutOfZone(self): | |
402 | payload, zone = self.create_zone() | |
403 | name = payload['name'] | |
404 | # replace with qname mismatch | |
d708640f | 405 | rrset = { |
35f26cc5 CH |
406 | 'changetype': 'delete', |
407 | 'name': 'not-in-zone', | |
408 | 'type': 'NS' | |
409 | } | |
d708640f | 410 | payload = {'rrsets': [rrset]} |
35f26cc5 | 411 | r = self.session.patch( |
d708640f | 412 | self.url("/servers/localhost/zones/" + name), |
35f26cc5 CH |
413 | data=json.dumps(payload), |
414 | headers={'content-type': 'application/json'}) | |
415 | self.assertEquals(r.status_code, 422) | |
416 | self.assertIn('out of zone', r.json()['error']) | |
417 | ||
6cc98ddf CH |
418 | def test_ZoneCommentCreate(self): |
419 | payload, zone = self.create_zone() | |
420 | name = payload['name'] | |
d708640f | 421 | rrset = { |
6cc98ddf CH |
422 | 'changetype': 'replace', |
423 | 'name': name, | |
424 | 'type': 'NS', | |
425 | 'comments': [ | |
426 | { | |
427 | 'account': 'test1', | |
428 | 'content': 'blah blah', | |
429 | }, | |
430 | { | |
431 | 'account': 'test2', | |
432 | 'content': 'blah blah bleh', | |
433 | } | |
434 | ] | |
435 | } | |
d708640f | 436 | payload = {'rrsets': [rrset]} |
6cc98ddf CH |
437 | r = self.session.patch( |
438 | self.url("/servers/localhost/zones/" + name), | |
439 | data=json.dumps(payload), | |
440 | headers={'content-type': 'application/json'}) | |
441 | self.assertSuccessJson(r) | |
442 | # make sure the comments have been set, and that the NS | |
443 | # records are still present | |
444 | r = self.session.get(self.url("/servers/localhost/zones/" + name)) | |
445 | data = r.json() | |
446 | print data | |
447 | self.assertNotEquals([r for r in data['records'] if r['type'] == 'NS'], []) | |
448 | self.assertNotEquals(data['comments'], []) | |
449 | # verify that modified_at has been set by pdns | |
450 | self.assertNotEquals([c for c in data['comments']][0]['modified_at'], 0) | |
451 | ||
452 | def test_ZoneCommentDelete(self): | |
453 | # Test: Delete ONLY comments. | |
454 | payload, zone = self.create_zone() | |
455 | name = payload['name'] | |
d708640f | 456 | rrset = { |
6cc98ddf CH |
457 | 'changetype': 'replace', |
458 | 'name': name, | |
459 | 'type': 'NS', | |
460 | 'comments': [] | |
461 | } | |
d708640f | 462 | payload = {'rrsets': [rrset]} |
6cc98ddf CH |
463 | r = self.session.patch( |
464 | self.url("/servers/localhost/zones/" + name), | |
465 | data=json.dumps(payload), | |
466 | headers={'content-type': 'application/json'}) | |
467 | self.assertSuccessJson(r) | |
468 | # make sure the NS records are still present | |
469 | r = self.session.get(self.url("/servers/localhost/zones/" + name)) | |
470 | data = r.json() | |
471 | print data | |
472 | self.assertNotEquals([r for r in data['records'] if r['type'] == 'NS'], []) | |
473 | self.assertEquals(data['comments'], []) | |
474 | ||
475 | def test_ZoneCommentStayIntact(self): | |
476 | # Test if comments on an rrset stay intact if the rrset is replaced | |
477 | payload, zone = self.create_zone() | |
478 | name = payload['name'] | |
479 | # create a comment | |
d708640f | 480 | rrset = { |
6cc98ddf CH |
481 | 'changetype': 'replace', |
482 | 'name': name, | |
483 | 'type': 'NS', | |
484 | 'comments': [ | |
485 | { | |
486 | 'account': 'test1', | |
487 | 'content': 'oh hi there', | |
488 | 'modified_at': 1111, | |
489 | 'name': name, # only for assertEquals, ignored by pdns | |
490 | 'type': 'NS' # only for assertEquals, ignored by pdns | |
491 | } | |
492 | ] | |
493 | } | |
d708640f | 494 | payload = {'rrsets': [rrset]} |
6cc98ddf CH |
495 | r = self.session.patch( |
496 | self.url("/servers/localhost/zones/" + name), | |
497 | data=json.dumps(payload), | |
498 | headers={'content-type': 'application/json'}) | |
499 | self.assertSuccessJson(r) | |
500 | # replace rrset records | |
d708640f | 501 | rrset2 = { |
6cc98ddf CH |
502 | 'changetype': 'replace', |
503 | 'name': name, | |
504 | 'type': 'NS', | |
505 | 'records': [ | |
506 | { | |
507 | "name": name, | |
508 | "type": "NS", | |
509 | "priority": 0, | |
510 | "ttl": 3600, | |
511 | "content": "ns1.bar.com", | |
512 | "disabled": False | |
513 | } | |
514 | ] | |
515 | } | |
d708640f | 516 | payload2 = {'rrsets': [rrset2]} |
6cc98ddf CH |
517 | r = self.session.patch( |
518 | self.url("/servers/localhost/zones/" + name), | |
519 | data=json.dumps(payload2), | |
520 | headers={'content-type': 'application/json'}) | |
521 | self.assertSuccessJson(r) | |
522 | # make sure the comments still exist | |
523 | r = self.session.get(self.url("/servers/localhost/zones/" + name)) | |
524 | data = r.json() | |
525 | print data | |
d708640f CH |
526 | self.assertEquals([r for r in data['records'] if r['type'] == 'NS'], rrset2['records']) |
527 | self.assertEquals(data['comments'], rrset['comments']) | |
6cc98ddf | 528 | |
d1587ceb CH |
529 | def test_ZoneAutoPtrIPv4(self): |
530 | revzone = '0.2.192.in-addr.arpa' | |
531 | self.create_zone(name=revzone) | |
532 | payload, zone = self.create_zone() | |
533 | name = payload['name'] | |
534 | # replace with qname mismatch | |
d708640f | 535 | rrset = { |
d1587ceb CH |
536 | 'changetype': 'replace', |
537 | 'name': name, | |
538 | 'type': 'A', | |
539 | 'records': [ | |
540 | { | |
541 | "name": name, | |
542 | "type": "A", | |
543 | "priority": 0, | |
544 | "ttl": 3600, | |
545 | "content": '192.2.0.2', | |
546 | "disabled": False, | |
547 | "set-ptr": True | |
548 | } | |
549 | ] | |
550 | } | |
d708640f | 551 | payload = {'rrsets': [rrset]} |
d1587ceb | 552 | r = self.session.patch( |
d708640f | 553 | self.url("/servers/localhost/zones/" + name), |
d1587ceb CH |
554 | data=json.dumps(payload), |
555 | headers={'content-type': 'application/json'}) | |
556 | self.assertSuccessJson(r) | |
557 | r = self.session.get(self.url("/servers/localhost/zones/" + revzone)) | |
558 | recs = r.json()['records'] | |
559 | print recs | |
560 | revrec = [rec for rec in recs if rec['type'] == 'PTR'] | |
561 | self.assertEquals(revrec, [{ | |
562 | u'content': name, | |
563 | u'disabled': False, | |
564 | u'ttl': 3600, | |
565 | u'priority': 0, | |
566 | u'type': u'PTR', | |
567 | u'name': u'2.0.2.192.in-addr.arpa' | |
568 | }]) | |
569 | ||
570 | def test_ZoneAutoPtrIPv6(self): | |
571 | # 2001:DB8::bb:aa | |
572 | revzone = '8.b.d.0.1.0.0.2.ip6.arpa' | |
573 | self.create_zone(name=revzone) | |
574 | payload, zone = self.create_zone() | |
575 | name = payload['name'] | |
576 | # replace with qname mismatch | |
d708640f | 577 | rrset = { |
d1587ceb CH |
578 | 'changetype': 'replace', |
579 | 'name': name, | |
580 | 'type': 'AAAA', | |
581 | 'records': [ | |
582 | { | |
583 | "name": name, | |
584 | "type": "AAAA", | |
585 | "priority": 0, | |
586 | "ttl": 3600, | |
587 | "content": '2001:DB8::bb:aa', | |
588 | "disabled": False, | |
589 | "set-ptr": True | |
590 | } | |
591 | ] | |
592 | } | |
d708640f | 593 | payload = {'rrsets': [rrset]} |
d1587ceb | 594 | r = self.session.patch( |
d708640f | 595 | self.url("/servers/localhost/zones/" + name), |
d1587ceb CH |
596 | data=json.dumps(payload), |
597 | headers={'content-type': 'application/json'}) | |
598 | self.assertSuccessJson(r) | |
599 | r = self.session.get(self.url("/servers/localhost/zones/" + revzone)) | |
600 | recs = r.json()['records'] | |
601 | print recs | |
602 | revrec = [rec for rec in recs if rec['type'] == 'PTR'] | |
603 | self.assertEquals(revrec, [{ | |
604 | u'content': name, | |
605 | u'disabled': False, | |
606 | u'ttl': 3600, | |
607 | u'priority': 0, | |
608 | u'type': u'PTR', | |
609 | u'name': u'a.a.0.0.b.b.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa' | |
610 | }]) | |
611 | ||
b1902fab CH |
612 | def test_SearchRRExactZone(self): |
613 | name = unique_zone_name() | |
614 | self.create_zone(name=name) | |
615 | r = self.session.get(self.url("/servers/localhost/search-data?q=" + name)) | |
616 | self.assertSuccessJson(r) | |
617 | print r.json() | |
d2d194a9 | 618 | self.assertEquals(r.json(), [{u'type': u'zone', u'name': name, u'zone_id': name+'.'}]) |
b1902fab CH |
619 | |
620 | def test_SearchRRSubstring(self): | |
621 | name = 'search-rr-zone.name' | |
622 | self.create_zone(name=name) | |
623 | r = self.session.get(self.url("/servers/localhost/search-data?q=rr-zone")) | |
624 | self.assertSuccessJson(r) | |
625 | print r.json() | |
626 | # should return zone, SOA, ns1, ns2 | |
69083bbd | 627 | self.assertEquals(len(r.json()), 1) # FIXME test disarmed for now (should be 4) |
b1902fab | 628 | |
57cb86d8 CH |
629 | def test_SearchRRCaseInsensitive(self): |
630 | name = 'search-rr-insenszone.name' | |
631 | self.create_zone(name=name) | |
632 | r = self.session.get(self.url("/servers/localhost/search-data?q=rr-insensZONE")) | |
633 | self.assertSuccessJson(r) | |
634 | print r.json() | |
635 | # should return zone, SOA, ns1, ns2 | |
69083bbd | 636 | self.assertEquals(len(r.json()), 1) # FIXME test disarmed for now (should be 4) |
57cb86d8 | 637 | |
02945d9a CH |
638 | |
639 | @unittest.skipIf(not isRecursor(), "Not applicable") | |
640 | class RecursorZones(ApiTestCase): | |
641 | ||
37bc3d01 CH |
642 | def create_zone(self, name=None, kind=None, rd=False, servers=None): |
643 | if name is None: | |
644 | name = unique_zone_name() | |
645 | if servers is None: | |
646 | servers = [] | |
02945d9a | 647 | payload = { |
37bc3d01 CH |
648 | 'name': name, |
649 | 'kind': kind, | |
650 | 'servers': servers, | |
651 | 'recursion_desired': rd | |
02945d9a CH |
652 | } |
653 | r = self.session.post( | |
654 | self.url("/servers/localhost/zones"), | |
655 | data=json.dumps(payload), | |
656 | headers={'content-type': 'application/json'}) | |
657 | self.assertSuccessJson(r) | |
37bc3d01 CH |
658 | return (payload, r.json()) |
659 | ||
660 | def test_CreateAuthZone(self): | |
661 | payload, data = self.create_zone(kind='Native') | |
02945d9a CH |
662 | # return values are normalized |
663 | payload['name'] += '.' | |
664 | for k in payload.keys(): | |
665 | self.assertEquals(data[k], payload[k]) | |
666 | ||
667 | def test_CreateForwardedZone(self): | |
37bc3d01 | 668 | payload, data = self.create_zone(kind='Forwarded', rd=False, servers=['8.8.8.8']) |
02945d9a CH |
669 | # return values are normalized |
670 | payload['servers'][0] += ':53' | |
671 | payload['name'] += '.' | |
672 | for k in payload.keys(): | |
673 | self.assertEquals(data[k], payload[k]) | |
674 | ||
675 | def test_CreateForwardedRDZone(self): | |
37bc3d01 | 676 | payload, data = self.create_zone(name='google.com', kind='Forwarded', rd=True, servers=['8.8.8.8']) |
02945d9a CH |
677 | # return values are normalized |
678 | payload['servers'][0] += ':53' | |
679 | payload['name'] += '.' | |
680 | for k in payload.keys(): | |
681 | self.assertEquals(data[k], payload[k]) | |
682 | ||
683 | def test_CreateAuthZoneWithSymbols(self): | |
37bc3d01 | 684 | payload, data = self.create_zone(name='foo/bar.'+unique_zone_name(), kind='Native') |
02945d9a CH |
685 | # return values are normalized |
686 | payload['name'] += '.' | |
1dbe38ba | 687 | expected_id = (payload['name'].replace('/', '=2F')) |
02945d9a CH |
688 | for k in payload.keys(): |
689 | self.assertEquals(data[k], payload[k]) | |
690 | self.assertEquals(data['id'], expected_id) | |
e2367534 CH |
691 | |
692 | def test_RenameAuthZone(self): | |
37bc3d01 CH |
693 | payload, data = self.create_zone(kind='Native') |
694 | name = payload['name'] + '.' | |
e2367534 CH |
695 | # now rename it |
696 | payload = { | |
697 | 'name': 'renamed-'+name, | |
698 | 'kind': 'Native', | |
699 | 'recursion_desired': False | |
700 | } | |
701 | r = self.session.put( | |
702 | self.url("/servers/localhost/zones/" + name), | |
703 | data=json.dumps(payload), | |
704 | headers={'content-type': 'application/json'}) | |
705 | self.assertSuccessJson(r) | |
706 | data = r.json() | |
707 | for k in payload.keys(): | |
708 | self.assertEquals(data[k], payload[k]) | |
37bc3d01 CH |
709 | |
710 | def test_SearchRRExactZone(self): | |
711 | name = unique_zone_name() + '.' | |
712 | self.create_zone(name=name, kind='Native') | |
713 | r = self.session.get(self.url("/servers/localhost/search-data?q=" + name)) | |
714 | self.assertSuccessJson(r) | |
715 | print r.json() | |
716 | self.assertEquals(r.json(), [{u'type': u'zone', u'name': name, u'zone_id': name}]) | |
717 | ||
718 | def test_SearchRRSubstring(self): | |
719 | name = 'search-rr-zone.name' | |
720 | self.create_zone(name=name, kind='Native') | |
721 | r = self.session.get(self.url("/servers/localhost/search-data?q=rr-zone")) | |
722 | self.assertSuccessJson(r) | |
723 | print r.json() | |
724 | # should return zone, SOA | |
725 | self.assertEquals(len(r.json()), 2) |