Merge lp:~jtv/maas/test-dhcp-config-with-proper-params into lp:~maas-committers/maas/trunk

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: no longer in the source branch.
Merged at revision: 2788
Proposed branch: lp:~jtv/maas/test-dhcp-config-with-proper-params
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~jtv/maas/dhcp-tests-preparatory-reorg
Diff against target: 349 lines (+155/-94)
5 files modified
src/provisioningserver/dhcp/testing/config.py (+40/-0)
src/provisioningserver/dhcp/tests/test_config.py (+10/-20)
src/provisioningserver/dhcp/tests/test_writer.py (+100/-57)
src/provisioningserver/dhcp/writer.py (+1/-1)
src/provisioningserver/tests/test_tasks.py (+4/-16)
To merge this branch: bzr merge lp:~jtv/maas/test-dhcp-config-with-proper-params
Reviewer Review Type Date Requested Status
Graham Binns (community) Approve
Review via email: mp+231832@code.launchpad.net

Commit message

Make DHCP configuration tests at various levels randomise their DHCP configuration variables.

Description of the change

These changes were salvaged from another branch which I had to abandon because the approach didn't pan out. Some of them will probably smooth the way for IPv6 tests; others are just Better™.

Jeroen

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) wrote :

Looks good. You've got what looks like some code duplication in there, but nothing too heinous.

review: Approve
Revision history for this message
Jeroen T. Vermeulen (jtv) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'src/provisioningserver/dhcp/testing'
2=== added file 'src/provisioningserver/dhcp/testing/__init__.py'
3=== added file 'src/provisioningserver/dhcp/testing/config.py'
4--- src/provisioningserver/dhcp/testing/config.py 1970-01-01 00:00:00 +0000
5+++ src/provisioningserver/dhcp/testing/config.py 2014-08-22 10:23:17 +0000
6@@ -0,0 +1,40 @@
7+# Copyright 2014 Canonical Ltd. This software is licensed under the
8+# GNU Affero General Public License version 3 (see the file LICENSE).
9+
10+"""Test helpers related to DHCP configuration."""
11+
12+from __future__ import (
13+ absolute_import,
14+ print_function,
15+ unicode_literals,
16+ )
17+
18+str = None
19+
20+__metaclass__ = type
21+__all__ = [
22+ 'make_subnet_config',
23+ ]
24+
25+from maastesting.factory import factory
26+from netaddr import IPAddress
27+
28+
29+def make_subnet_config(network=None):
30+ """Return complete DHCP configuration dict for a subnet."""
31+ if network is None:
32+ network = factory.getRandomNetwork()
33+ ip_low, ip_high = factory.make_ip_range(network)
34+ return {
35+ 'interface': factory.make_name('eth', sep=''),
36+ 'subnet': unicode(IPAddress(network.first)),
37+ 'subnet_mask': unicode(network.netmask),
38+ 'subnet_cidr': unicode(network.cidr),
39+ 'broadcast_ip': unicode(network.broadcast),
40+ 'dns_servers': unicode(factory.pick_ip_in_network(network)),
41+ 'ntp_server': unicode(factory.pick_ip_in_network(network)),
42+ 'domain_name': '%s.example.com' % factory.make_name('domain'),
43+ 'router_ip': unicode(factory.pick_ip_in_network(network)),
44+ 'ip_range_low': unicode(ip_low),
45+ 'ip_range_high': unicode(ip_high),
46+ }
47
48=== modified file 'src/provisioningserver/dhcp/tests/test_config.py'
49--- src/provisioningserver/dhcp/tests/test_config.py 2014-08-22 02:42:35 +0000
50+++ src/provisioningserver/dhcp/tests/test_config.py 2014-08-22 10:23:17 +0000
51@@ -24,6 +24,7 @@
52 from maastesting.factory import factory
53 from provisioningserver.boot import BootMethodRegistry
54 from provisioningserver.dhcp import config
55+from provisioningserver.dhcp.testing.config import make_subnet_config
56 from provisioningserver.testing.testcase import PservTestCase
57 import tempita
58 from testtools.matchers import (
59@@ -50,26 +51,15 @@
60
61
62 def make_sample_params():
63- """Produce a dict of sample parameters.
64-
65- The sample provides all parameters used by the DHCP template.
66- """
67- return dict(
68- omapi_key="random",
69- dhcp_subnets=[dict(
70- subnet="10.0.0.0",
71- interface="eth0",
72- subnet_mask="255.0.0.0",
73- subnet_cidr="10.0.0.0/8",
74- broadcast_ip="10.255.255.255",
75- dns_servers="10.1.0.1 10.1.0.2",
76- ntp_server="8.8.8.8",
77- domain_name="example.com",
78- router_ip="10.0.0.2",
79- ip_range_low="10.0.0.3",
80- ip_range_high="10.0.0.254",
81- )]
82- )
83+ """Return a dict of arbitrary DHCP configuration parameters."""
84+ if factory.pick_bool():
85+ network = factory.getRandomNetwork()
86+ else:
87+ network = factory.make_ipv6_network()
88+ return {
89+ 'omapi_key': factory.make_name('key'),
90+ 'dhcp_subnets': [make_subnet_config(network)],
91+ }
92
93
94 class TestGetConfig(PservTestCase):
95
96=== modified file 'src/provisioningserver/dhcp/tests/test_writer.py'
97--- src/provisioningserver/dhcp/tests/test_writer.py 2014-03-28 04:36:31 +0000
98+++ src/provisioningserver/dhcp/tests/test_writer.py 2014-08-22 10:23:17 +0000
99@@ -1,4 +1,4 @@
100-# Copyright 2012, 2013 Canonical Ltd. This software is licensed under the
101+# Copyright 2012-2014 Canonical Ltd. This software is licensed under the
102 # GNU Affero General Public License version 3 (see the file LICENSE).
103
104 """Tests for `provisioningserver.dhcp.writer`."""
105@@ -24,8 +24,12 @@
106 import sys
107
108 from maastesting import root
109+from maastesting.factory import factory
110 from maastesting.testcase import MAASTestCase
111+from mock import Mock
112 from provisioningserver.dhcp import writer
113+from provisioningserver.dhcp.testing.config import make_subnet_config
114+from provisioningserver.utils.fs import read_text_file
115 from testtools.matchers import (
116 ContainsAll,
117 MatchesStructure,
118@@ -35,37 +39,78 @@
119 class TestScript(MAASTestCase):
120 """Test the DHCP configuration writer."""
121
122- test_args = (
123- '--subnet', 'subnet',
124- '--interface', 'eth0',
125- '--subnet-mask', 'subnet-mask',
126- '--broadcast-ip', 'broadcast-ip',
127- '--dns-servers', 'dns-servers',
128- '--ntp-server', 'ntp-server',
129- '--domain-name', 'domain-name',
130- '--router-ip', 'router-ip',
131- '--ip-range-low', 'ip-range-low',
132- '--ip-range-high', 'ip-range-high',
133- '--omapi-key', 'omapi-key',
134- )
135+ def make_args(self, network=None):
136+ """Create a fake parameter for `run`, based on `network`."""
137+ settings = make_subnet_config(network)
138+ args = Mock()
139+ args.outfile = None
140+ args.omapi_key = factory.make_name('key')
141+ args.subnet = settings['subnet']
142+ args.interface = settings['interface']
143+ args.subnet_mask = settings['subnet_mask']
144+ args.broadcast_ip = settings['broadcast_ip']
145+ args.dns_servers = settings['dns_servers']
146+ args.ntp_server = settings['ntp_server']
147+ args.domain_name = settings['domain_name']
148+ args.router_ip = settings['router_ip']
149+ args.ip_range_low = settings['ip_range_low']
150+ args.ip_range_high = settings['ip_range_high']
151+ return args
152
153 def test_script_executable(self):
154- script = ["%s/bin/maas-provision" % root, "generate-dhcp-config"]
155- script.extend(self.test_args)
156+ args = self.make_args()
157+ script = [
158+ "%s/bin/maas-provision" % root,
159+ "generate-dhcp-config",
160+ '--subnet', args.subnet,
161+ '--interface', args.interface,
162+ '--subnet-mask', args.subnet_mask,
163+ '--broadcast-ip', args.broadcast_ip,
164+ '--dns-servers', args.dns_servers,
165+ '--ntp-server', args.ntp_server,
166+ '--domain-name', args.domain_name,
167+ '--router-ip', args.router_ip,
168+ '--ip-range-low', args.ip_range_low,
169+ '--ip-range-high', args.ip_range_high,
170+ '--omapi-key', args.omapi_key,
171+ ]
172+
173 cmd = Popen(
174 script, stdout=PIPE, env=dict(PYTHONPATH=":".join(sys.path)))
175 output, err = cmd.communicate()
176+
177 self.assertEqual(0, cmd.returncode, err)
178- contains_all_params = ContainsAll(
179- ['subnet', 'subnet-mask', 'broadcast-ip',
180- 'omapi-key', 'dns-servers', 'ntp-server', 'domain-name',
181- 'router-ip', 'ip-range-low', 'ip-range-high'])
182- self.assertThat(output, contains_all_params)
183+
184+ self.assertThat(output, ContainsAll([
185+ args.subnet,
186+ args.subnet_mask,
187+ args.broadcast_ip,
188+ args.omapi_key,
189+ args.dns_servers,
190+ args.ntp_server,
191+ args.domain_name,
192+ args.router_ip,
193+ args.ip_range_low,
194+ args.ip_range_high,
195+ ]))
196
197 def test_arg_setup(self):
198+ test_args = (
199+ '--subnet', 'subnet',
200+ '--interface', 'eth0',
201+ '--subnet-mask', 'subnet-mask',
202+ '--broadcast-ip', 'broadcast-ip',
203+ '--dns-servers', 'dns-servers',
204+ '--ntp-server', 'ntp-server',
205+ '--domain-name', 'domain-name',
206+ '--router-ip', 'router-ip',
207+ '--ip-range-low', 'ip-range-low',
208+ '--ip-range-high', 'ip-range-high',
209+ '--omapi-key', 'omapi-key',
210+ )
211 parser = ArgumentParser()
212 writer.add_arguments(parser)
213- args = parser.parse_args(self.test_args)
214+ args = parser.parse_args(test_args)
215 self.assertThat(
216 args, MatchesStructure.byEquality(
217 subnet='subnet',
218@@ -82,46 +127,44 @@
219
220 def test_run(self):
221 self.patch(sys, "stdout", BytesIO())
222- parser = ArgumentParser()
223- writer.add_arguments(parser)
224- args = parser.parse_args(self.test_args)
225+ args = self.make_args(factory.getRandomNetwork())
226+
227 writer.run(args)
228+
229 output = sys.stdout.getvalue()
230 contains_all_params = ContainsAll([
231- 'subnet',
232- 'interface',
233- 'subnet-mask',
234- 'broadcast-ip',
235- 'omapi-key',
236- 'dns-servers',
237- 'ntp-server',
238- 'domain-name',
239- 'router-ip',
240- 'ip-range-low',
241- 'ip-range-high',
242+ args.subnet,
243+ args.interface,
244+ args.subnet_mask,
245+ args.broadcast_ip,
246+ args.omapi_key,
247+ args.dns_servers,
248+ args.ntp_server,
249+ args.domain_name,
250+ args.router_ip,
251+ args.ip_range_low,
252+ args.ip_range_high,
253 ])
254 self.assertThat(output, contains_all_params)
255
256 def test_run_save_to_file(self):
257- parser = ArgumentParser()
258- writer.add_arguments(parser)
259- outfile = os.path.join(self.make_dir(), "outfile.txt")
260- args = parser.parse_args(
261- self.test_args + ("--outfile", outfile))
262+ args = self.make_args()
263+ args.outfile = os.path.join(self.make_dir(), "outfile.txt")
264+
265 writer.run(args)
266- with open(outfile, "rb") as stream:
267- output = stream.read()
268- contains_all_params = ContainsAll([
269- 'subnet',
270- 'interface',
271- 'subnet-mask',
272- 'broadcast-ip',
273- 'omapi-key',
274- 'dns-servers',
275- 'ntp-server',
276- 'domain-name',
277- 'router-ip',
278- 'ip-range-low',
279- 'ip-range-high',
280- ])
281- self.assertThat(output, contains_all_params)
282+
283+ self.assertThat(
284+ read_text_file(args.outfile),
285+ ContainsAll([
286+ args.subnet,
287+ args.interface,
288+ args.subnet_mask,
289+ args.broadcast_ip,
290+ args.omapi_key,
291+ args.dns_servers,
292+ args.ntp_server,
293+ args.domain_name,
294+ args.router_ip,
295+ args.ip_range_low,
296+ args.ip_range_high,
297+ ]))
298
299=== modified file 'src/provisioningserver/dhcp/writer.py'
300--- src/provisioningserver/dhcp/writer.py 2014-08-21 13:27:59 +0000
301+++ src/provisioningserver/dhcp/writer.py 2014-08-22 10:23:17 +0000
302@@ -74,7 +74,7 @@
303
304 def run(args):
305 """Generate a DHCP server configuration, and write it to stdout."""
306- params = vars(args)
307+ params = vars(args).copy()
308 omapi_key = params.pop('omapi_key')
309 outfile = params.pop('outfile')
310 kwargs = {
311
312=== modified file 'src/provisioningserver/tests/test_tasks.py'
313--- src/provisioningserver/tests/test_tasks.py 2014-08-21 13:27:59 +0000
314+++ src/provisioningserver/tests/test_tasks.py 2014-08-22 10:23:17 +0000
315@@ -54,6 +54,7 @@
316 config,
317 leases,
318 )
319+from provisioningserver.dhcp.testing.config import make_subnet_config
320 from provisioningserver.dns.config import (
321 celery_conf,
322 MAAS_NAMED_CONF_NAME,
323@@ -189,23 +190,10 @@
324
325 def make_dhcp_config_params(self):
326 """Fake up a dict of dhcp configuration parameters."""
327- param_names = [
328- 'interface',
329- 'subnet',
330- 'subnet_mask',
331- 'broadcast_ip',
332- 'dns_servers',
333- 'domain_name',
334- 'router_ip',
335- 'ip_range_low',
336- 'ip_range_high',
337- ]
338 return {
339- 'dhcp_subnets': [
340- {param: factory.make_string() for param in param_names}
341- ],
342- 'omapi_key': factory.make_string(),
343- }
344+ 'omapi_key': factory.make_name('key'),
345+ 'dhcp_subnets': [make_subnet_config()],
346+ }
347
348 def test_upload_dhcp_leases(self):
349 self.patch(