Merge ~smoser/cloud-init:bug/1635350-tests-read-cfg.d into cloud-init:master

Proposed by Scott Moser
Status: Merged
Merged at revision: 1e55f4127f356b930e2c1ad36dcb6bed24f3beb2
Proposed branch: ~smoser/cloud-init:bug/1635350-tests-read-cfg.d
Merge into: cloud-init:master
Diff against target: 181 lines (+23/-30)
2 files modified
tests/unittests/helpers.py (+8/-0)
tests/unittests/test_data.py (+15/-30)
Reviewer Review Type Date Requested Status
Joshua Powers (community) Approve
cloud-init Commiters Pending
Review via email: mp+309124@code.launchpad.net

Commit message

unittests: do not read system /etc/cloud/cloud.cfg.d

Many of the unit tests in test_data would inadvertantly read the
system's /etc/cloud/cloud.cfg and /etc/cloud/cloud.cfg.d.
This was first noticed on a system deployed by MAAS, where
files in /etc/cloud/cloud.cfg.d/ are root read-only.

This changes those tests to actually make use of
FilesystemMockingTestCase functionality and adds 'reRoot()' to that
class which is easier to use for at least this use case.

LP: #1635350

To post a comment you must log in.
Revision history for this message
Joshua Powers (powersj) wrote :

Can confirm this merge request fixes the issue that I was seeing. I can now build as a non-root user as expected.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/tests/unittests/helpers.py b/tests/unittests/helpers.py
2index 1cdc05a..a2355a7 100644
3--- a/tests/unittests/helpers.py
4+++ b/tests/unittests/helpers.py
5@@ -205,6 +205,14 @@ class FilesystemMockingTestCase(ResourceUsingTestCase):
6 self.patched_funcs.enter_context(
7 mock.patch.object(sys, 'stderr', stderr))
8
9+ def reRoot(self, root=None):
10+ if root is None:
11+ root = tempfile.mkdtemp()
12+ self.addCleanup(shutil.rmtree, root)
13+ self.patchUtils(root)
14+ self.patchOS(root)
15+ return root
16+
17
18 def import_httpretty():
19 """Import HTTPretty and monkey patch Python 3.4 issue.
20diff --git a/tests/unittests/test_data.py b/tests/unittests/test_data.py
21index 13db8a4..55d9b93 100644
22--- a/tests/unittests/test_data.py
23+++ b/tests/unittests/test_data.py
24@@ -3,8 +3,6 @@
25 import gzip
26 import logging
27 import os
28-import shutil
29-import tempfile
30
31 try:
32 from unittest import mock
33@@ -98,10 +96,7 @@ class TestConsumeUserData(helpers.FilesystemMockingTestCase):
34
35 ci = stages.Init()
36 ci.datasource = FakeDataSource(blob)
37- new_root = tempfile.mkdtemp()
38- self.addCleanup(shutil.rmtree, new_root)
39- self.patchUtils(new_root)
40- self.patchOS(new_root)
41+ self.reRoot()
42 ci.fetch()
43 ci.consume_data()
44 cc_contents = util.load_file(ci.paths.get_ipath("cloud_config"))
45@@ -127,9 +122,7 @@ class TestConsumeUserData(helpers.FilesystemMockingTestCase):
46 { "op": "add", "path": "/foo", "value": "quxC" }
47 ]
48 '''
49- new_root = tempfile.mkdtemp()
50- self.addCleanup(shutil.rmtree, new_root)
51- self._patchIn(new_root)
52+ self.reRoot()
53 initer = stages.Init()
54 initer.datasource = FakeDataSource(user_blob, vendordata=vendor_blob)
55 initer.read_cfg()
56@@ -167,9 +160,7 @@ class TestConsumeUserData(helpers.FilesystemMockingTestCase):
57 { "op": "add", "path": "/foo", "value": "quxC" }
58 ]
59 '''
60- new_root = tempfile.mkdtemp()
61- self.addCleanup(shutil.rmtree, new_root)
62- self._patchIn(new_root)
63+ self.reRoot()
64 initer = stages.Init()
65 initer.datasource = FakeDataSource(user_blob, vendordata=vendor_blob)
66 initer.read_cfg()
67@@ -212,12 +203,9 @@ c: d
68 message.attach(message_cc)
69 message.attach(message_jp)
70
71+ self.reRoot()
72 ci = stages.Init()
73 ci.datasource = FakeDataSource(str(message))
74- new_root = tempfile.mkdtemp()
75- self.addCleanup(shutil.rmtree, new_root)
76- self.patchUtils(new_root)
77- self.patchOS(new_root)
78 ci.fetch()
79 ci.consume_data()
80 cc_contents = util.load_file(ci.paths.get_ipath("cloud_config"))
81@@ -245,9 +233,7 @@ name: user
82 run:
83 - z
84 '''
85- new_root = tempfile.mkdtemp()
86- self.addCleanup(shutil.rmtree, new_root)
87- self._patchIn(new_root)
88+ self.reRoot()
89 initer = stages.Init()
90 initer.datasource = FakeDataSource(user_blob, vendordata=vendor_blob)
91 initer.read_cfg()
92@@ -281,9 +267,7 @@ vendor_data:
93 enabled: True
94 prefix: /bin/true
95 '''
96- new_root = tempfile.mkdtemp()
97- self.addCleanup(shutil.rmtree, new_root)
98- self._patchIn(new_root)
99+ new_root = self.reRoot()
100 initer = stages.Init()
101 initer.datasource = FakeDataSource(user_blob, vendordata=vendor_blob)
102 initer.read_cfg()
103@@ -342,10 +326,7 @@ p: 1
104 paths = c_helpers.Paths({}, ds=FakeDataSource(''))
105 cloud_cfg = handlers.cloud_config.CloudConfigPartHandler(paths)
106
107- new_root = tempfile.mkdtemp()
108- self.addCleanup(shutil.rmtree, new_root)
109- self.patchUtils(new_root)
110- self.patchOS(new_root)
111+ self.reRoot()
112 cloud_cfg.handle_part(None, handlers.CONTENT_START, None, None, None,
113 None)
114 for i, m in enumerate(messages):
115@@ -365,6 +346,7 @@ p: 1
116
117 def test_unhandled_type_warning(self):
118 """Raw text without magic is ignored but shows warning."""
119+ self.reRoot()
120 ci = stages.Init()
121 data = "arbitrary text\n"
122 ci.datasource = FakeDataSource(data)
123@@ -402,10 +384,7 @@ c: 4
124 message.attach(gzip_part(base_content2))
125 ci = stages.Init()
126 ci.datasource = FakeDataSource(str(message))
127- new_root = tempfile.mkdtemp()
128- self.addCleanup(shutil.rmtree, new_root)
129- self.patchUtils(new_root)
130- self.patchOS(new_root)
131+ self.reRoot()
132 ci.fetch()
133 ci.consume_data()
134 contents = util.load_file(ci.paths.get_ipath("cloud_config"))
135@@ -418,6 +397,7 @@ c: 4
136
137 def test_mime_text_plain(self):
138 """Mime message of type text/plain is ignored but shows warning."""
139+ self.reRoot()
140 ci = stages.Init()
141 message = MIMEBase("text", "plain")
142 message.set_payload("Just text")
143@@ -435,6 +415,7 @@ c: 4
144
145 def test_shellscript(self):
146 """Raw text starting #!/bin/sh is treated as script."""
147+ self.reRoot()
148 ci = stages.Init()
149 script = "#!/bin/sh\necho hello\n"
150 ci.datasource = FakeDataSource(script)
151@@ -453,6 +434,7 @@ c: 4
152
153 def test_mime_text_x_shellscript(self):
154 """Mime message of type text/x-shellscript is treated as script."""
155+ self.reRoot()
156 ci = stages.Init()
157 script = "#!/bin/sh\necho hello\n"
158 message = MIMEBase("text", "x-shellscript")
159@@ -473,6 +455,7 @@ c: 4
160
161 def test_mime_text_plain_shell(self):
162 """Mime type text/plain starting #!/bin/sh is treated as script."""
163+ self.reRoot()
164 ci = stages.Init()
165 script = "#!/bin/sh\necho hello\n"
166 message = MIMEBase("text", "plain")
167@@ -493,6 +476,7 @@ c: 4
168
169 def test_mime_application_octet_stream(self):
170 """Mime type application/octet-stream is ignored but shows warning."""
171+ self.reRoot()
172 ci = stages.Init()
173 message = MIMEBase("application", "octet-stream")
174 message.set_payload(b'\xbf\xe6\xb2\xc3\xd3\xba\x13\xa4\xd8\xa1\xcc')
175@@ -516,6 +500,7 @@ c: 4
176 {'content': non_decodable}]
177 message = b'#cloud-config-archive\n' + util.yaml_dumps(data).encode()
178
179+ self.reRoot()
180 ci = stages.Init()
181 ci.datasource = FakeDataSource(message)
182

Subscribers

People subscribed via source and target branches