Merge lp:~harlowja/cloud-init/stage-base-test into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Joshua Harlow
Status: Merged
Merged at revision: 695
Proposed branch: lp:~harlowja/cloud-init/stage-base-test
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 252 lines (+204/-3)
4 files modified
tests/data/roots/simple_ubuntu/etc/networks/interfaces (+3/-0)
tests/unittests/helpers.py (+103/-0)
tests/unittests/test_filters/test_launch_index.py (+11/-3)
tests/unittests/test_runs/test_simple_run.py (+87/-0)
To merge this branch: bzr merge lp:~harlowja/cloud-init/stage-base-test
Reviewer Review Type Date Requested Status
cloud-init Commiters Pending
Review via email: mp+126572@code.launchpad.net

Description of the change

Adds a new awesome test pattern + test.

To post a comment you must log in.
672. By Joshua Harlow

Adjust comment.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'tests/data/roots'
2=== added directory 'tests/data/roots/simple_ubuntu'
3=== added directory 'tests/data/roots/simple_ubuntu/etc'
4=== added directory 'tests/data/roots/simple_ubuntu/etc/networks'
5=== added file 'tests/data/roots/simple_ubuntu/etc/networks/interfaces'
6--- tests/data/roots/simple_ubuntu/etc/networks/interfaces 1970-01-01 00:00:00 +0000
7+++ tests/data/roots/simple_ubuntu/etc/networks/interfaces 2012-09-26 23:45:24 +0000
8@@ -0,0 +1,3 @@
9+auto lo
10+iface lo inet loopback
11+
12
13=== modified file 'tests/unittests/helpers.py'
14--- tests/unittests/helpers.py 2012-09-01 01:28:12 +0000
15+++ tests/unittests/helpers.py 2012-09-26 23:45:24 +0000
16@@ -3,6 +3,37 @@
17 from mocker import MockerTestCase
18
19 from cloudinit import helpers as ch
20+from cloudinit import util
21+
22+import shutil
23+
24+# Makes the old path start
25+# with new base instead of whatever
26+# it previously had
27+def rebase_path(old_path, new_base):
28+ if old_path.startswith(new_base):
29+ # Already handled...
30+ return old_path
31+ # Retarget the base of that path
32+ # to the new base instead of the
33+ # old one...
34+ path = os.path.join(new_base, old_path.lstrip("/"))
35+ path = os.path.abspath(path)
36+ return path
37+
38+
39+# Can work on anything that takes a path as arguments
40+def retarget_many_wrapper(new_base, am, old_func):
41+ def wrapper(*args, **kwds):
42+ n_args = list(args)
43+ nam = am
44+ if am == -1:
45+ nam = len(n_args)
46+ for i in range(0, nam):
47+ path = args[i]
48+ n_args[i] = rebase_path(path, new_base)
49+ return old_func(*n_args, **kwds)
50+ return wrapper
51
52
53 class ResourceUsingTestCase(MockerTestCase):
54@@ -40,3 +71,75 @@
55 'templates_dir': self.resourceLocation(),
56 })
57 return cp
58+
59+
60+class FilesystemMockingTestCase(ResourceUsingTestCase):
61+ def __init__(self, methodName="runTest"):
62+ ResourceUsingTestCase.__init__(self, methodName)
63+ self.patched_funcs = []
64+
65+ def replicateTestRoot(self, example_root, target_root):
66+ real_root = self.resourceLocation()
67+ real_root = os.path.join(real_root, 'roots', example_root)
68+ for (dir_path, _dirnames, filenames) in os.walk(real_root):
69+ real_path = dir_path
70+ make_path = rebase_path(real_path[len(real_root):], target_root)
71+ util.ensure_dir(make_path)
72+ for f in filenames:
73+ real_path = util.abs_join(real_path, f)
74+ make_path = util.abs_join(make_path, f)
75+ shutil.copy(real_path, make_path)
76+
77+ def tearDown(self):
78+ self.restore()
79+ ResourceUsingTestCase.tearDown(self)
80+
81+ def restore(self):
82+ for (mod, f, func) in self.patched_funcs:
83+ setattr(mod, f, func)
84+ self.patched_funcs = []
85+
86+ def patchUtils(self, new_root):
87+ patch_funcs = {
88+ util: [('write_file', 1),
89+ ('load_file', 1),
90+ ('ensure_dir', 1),
91+ ('chmod', 1),
92+ ('delete_dir_contents', 1),
93+ ('del_file', 1),
94+ ('sym_link', -1)],
95+ }
96+ for (mod, funcs) in patch_funcs.items():
97+ for (f, am) in funcs:
98+ func = getattr(mod, f)
99+ trap_func = retarget_many_wrapper(new_root, am, func)
100+ setattr(mod, f, trap_func)
101+ self.patched_funcs.append((mod, f, func))
102+
103+ # Handle subprocess calls
104+ func = getattr(util, 'subp')
105+
106+ def nsubp(*_args, **_kwargs):
107+ return ('', '')
108+
109+ setattr(util, 'subp', nsubp)
110+ self.patched_funcs.append((util, 'subp', func))
111+
112+ def null_func(*_args, **_kwargs):
113+ return None
114+
115+ for f in ['chownbyid', 'chownbyname']:
116+ func = getattr(util, f)
117+ setattr(util, f, null_func)
118+ self.patched_funcs.append((util, f, func))
119+
120+ def patchOS(self, new_root):
121+ patch_funcs = {
122+ os.path: ['isfile', 'exists', 'islink', 'isdir'],
123+ }
124+ for (mod, funcs) in patch_funcs.items():
125+ for f in funcs:
126+ func = getattr(mod, f)
127+ trap_func = retarget_many_wrapper(new_root, 1, func)
128+ setattr(mod, f, trap_func)
129+ self.patched_funcs.append((mod, f, func))
130
131=== modified file 'tests/unittests/test_filters/test_launch_index.py'
132--- tests/unittests/test_filters/test_launch_index.py 2012-09-02 00:00:34 +0000
133+++ tests/unittests/test_filters/test_launch_index.py 2012-09-26 23:45:24 +0000
134@@ -1,6 +1,14 @@
135 import copy
136-
137-import helpers as th
138+import os
139+import sys
140+
141+top_dir = os.path.join(os.path.dirname(__file__), os.pardir, "helpers.py")
142+top_dir = os.path.abspath(top_dir)
143+if os.path.exists(top_dir):
144+ sys.path.insert(0, os.path.dirname(top_dir))
145+
146+
147+import helpers
148
149 import itertools
150
151@@ -18,7 +26,7 @@
152 return am
153
154
155-class TestLaunchFilter(th.ResourceUsingTestCase):
156+class TestLaunchFilter(helpers.ResourceUsingTestCase):
157
158 def assertCounts(self, message, expected_counts):
159 orig_message = copy.deepcopy(message)
160
161=== added directory 'tests/unittests/test_runs'
162=== added file 'tests/unittests/test_runs/test_simple_run.py'
163--- tests/unittests/test_runs/test_simple_run.py 1970-01-01 00:00:00 +0000
164+++ tests/unittests/test_runs/test_simple_run.py 2012-09-26 23:45:24 +0000
165@@ -0,0 +1,87 @@
166+import sys
167+import os
168+
169+# Allow running this test individually
170+top_dir = os.path.join(os.path.dirname(__file__), os.pardir, "helpers.py")
171+top_dir = os.path.abspath(top_dir)
172+if os.path.exists(top_dir):
173+ sys.path.insert(0, os.path.dirname(top_dir))
174+
175+
176+import helpers
177+
178+from cloudinit import util
179+from cloudinit import stages
180+
181+from cloudinit.settings import (PER_INSTANCE)
182+
183+
184+class TestSimpleRun(helpers.FilesystemMockingTestCase):
185+ def _patchIn(self, root):
186+ self.restore()
187+ self.patchOS(root)
188+ self.patchUtils(root)
189+
190+ def _pp_root(self, root, repatch=True):
191+ self.restore()
192+ for (dirpath, dirnames, filenames) in os.walk(root):
193+ print(dirpath)
194+ for f in filenames:
195+ joined = os.path.join(dirpath, f)
196+ if os.path.islink(joined):
197+ print("f %s - (symlink)" % (f))
198+ else:
199+ print("f %s" % (f))
200+ for d in dirnames:
201+ joined = os.path.join(dirpath, d)
202+ if os.path.islink(joined):
203+ print("d %s - (symlink)" % (d))
204+ else:
205+ print("d %s" % (d))
206+ if repatch:
207+ self._patchIn(root)
208+
209+ def test_none_ds(self):
210+ new_root = self.makeDir()
211+ self.replicateTestRoot('simple_ubuntu', new_root)
212+ cfg = {
213+ 'datasource_list': ['None'],
214+ 'write_files': [{
215+ 'path': '/etc/blah.ini',
216+ 'content': 'blah',
217+ 'permissions': 0755,
218+ }],
219+ 'cloud_init_modules': ['write-files'],
220+ }
221+ cloud_cfg = util.yaml_dumps(cfg)
222+ util.ensure_dir(os.path.join(new_root, 'etc', 'cloud'))
223+ util.write_file(os.path.join(new_root, 'etc',
224+ 'cloud', 'cloud.cfg'), cloud_cfg)
225+ self._patchIn(new_root)
226+
227+ # Now start verifying whats created
228+ initer = stages.Init()
229+ initer.read_cfg()
230+ initer.initialize()
231+ self.assertTrue(os.path.exists("/var/lib/cloud"))
232+ for d in ['scripts', 'seed', 'instances', 'handlers', 'sem', 'data']:
233+ self.assertTrue(os.path.isdir(os.path.join("/var/lib/cloud", d)))
234+
235+ initer.fetch()
236+ iid = initer.instancify()
237+ self.assertEquals(iid, 'iid-datasource-none')
238+ initer.update()
239+ self.assertTrue(os.path.islink("var/lib/cloud/instance"))
240+
241+ initer.cloudify().run('consume_userdata',
242+ initer.consume_userdata,
243+ args=[PER_INSTANCE],
244+ freq=PER_INSTANCE)
245+
246+ mods = stages.Modules(initer)
247+ (which_ran, failures) = mods.run_section('cloud_init_modules')
248+ self.assertTrue(len(failures) == 0)
249+ self.assertTrue(os.path.exists('/etc/blah.ini'))
250+ self.assertIn('write-files', which_ran)
251+ contents = util.load_file('/etc/blah.ini')
252+ self.assertEquals(contents, 'blah')