Merge lp:~jtv/maas-test/copy-file into lp:maas-test

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: 151
Merged at revision: 146
Proposed branch: lp:~jtv/maas-test/copy-file
Merge into: lp:maas-test
Diff against target: 245 lines (+102/-22)
4 files modified
maastest/kvmfixture.py (+29/-5)
maastest/testing/factory.py (+33/-0)
maastest/tests/test_kvmfixture.py (+32/-1)
maastest/tests/test_maasfixture.py (+8/-16)
To merge this branch: bzr merge lp:~jtv/maas-test/copy-file
Reviewer Review Type Date Requested Status
Julian Edwards (community) Approve
Review via email: mp+214879@code.launchpad.net

Commit message

New KVMFixture method: upload_file, needed for uploading bootresources.yaml. Also, move make_file() test helper into a new factory module.

Description of the change

This is preparation for fixing bug 1302608.

Jeroen

To post a comment you must log in.
Revision history for this message
Julian Edwards (julian-edwards) wrote :

This looks basically OK.

I am a little confused on how Python lets you have two make_file functions in test_maasfixture.py. Why don't you just import the one you need?

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

It was just a way to keep the calls to the pre-existing TestMAASFixture.make_file method unchanged, while still introducing the global make_file function elsewhere. Removed now.

Revision history for this message
MAAS Lander (maas-lander) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'maastest/kvmfixture.py'
2--- maastest/kvmfixture.py 2014-02-26 21:05:58 +0000
3+++ maastest/kvmfixture.py 2014-04-09 06:59:27 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2013 Canonical Ltd. This software is licensed under the
6+# Copyright 2013-2014 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 """Manage a KVM machine."""
10@@ -346,6 +346,19 @@
11 self.running = False
12 logging.info("Done destroying virtual machine %s.", self.name)
13
14+ def _get_base_ssh_options(self):
15+ """Return a list of ssh options for connecting to the VM.
16+
17+ These are minimal options that are needed to connect at all, whether
18+ using `ssh` or `scp`.
19+ """
20+ return [
21+ "-i", self.ssh_private_key_file,
22+ "-o", "LogLevel=quiet",
23+ "-o", "UserKnownHostsFile=/dev/null",
24+ "-o", "StrictHostKeyChecking=no",
25+ ]
26+
27 def _make_ssh_command(self, command_line):
28 """Compose an `ssh` command line to execute `command_line` in the VM.
29
30@@ -358,10 +371,7 @@
31 remote_command_line = ' '.join(map(quote, command_line))
32 return [
33 "ssh",
34- "-i", self.ssh_private_key_file,
35- "-o", "LogLevel=quiet",
36- "-o", "UserKnownHostsFile=/dev/null",
37- "-o", "StrictHostKeyChecking=no",
38+ ] + self._get_base_ssh_options() + [
39 self.identity(),
40 "LC_ALL=%s" % VM_LOCALE,
41 remote_command_line,
42@@ -405,6 +415,20 @@
43 self.addDetail(cmd_prefix + ' stderr', text_content(u_stderr))
44 return retcode, stdout, stderr
45
46+ def upload_file(self, source, dest=None):
47+ """Copy the given file into the virtual machine's filesystem.
48+
49+ :param source: File to copy.
50+ :param dest: Optional destination. May be an absolute path, or one
51+ relative to the `ubuntu` user's home directory. Defaults to the
52+ same base name as `source`, directly in the user's home directory.
53+ """
54+ if dest is None:
55+ dest = os.path.basename(source)
56+ run_command(
57+ ['scp'] + self._get_base_ssh_options() + [source, dest],
58+ check_call=True)
59+
60 def get_ip_from_network_scan(self, mac_address):
61 """Return the IP address associated with a MAC address.
62
63
64=== added directory 'maastest/testing'
65=== added file 'maastest/testing/__init__.py'
66=== added file 'maastest/testing/factory.py'
67--- maastest/testing/factory.py 1970-01-01 00:00:00 +0000
68+++ maastest/testing/factory.py 2014-04-09 06:59:27 +0000
69@@ -0,0 +1,33 @@
70+# Copyright 2014 Canonical Ltd. This software is licensed under the
71+# GNU Affero General Public License version 3 (see the file LICENSE).
72+
73+"""Factory helpers for testing."""
74+
75+from __future__ import (
76+ absolute_import,
77+ print_function,
78+ unicode_literals,
79+ )
80+
81+str = None
82+
83+__metaclass__ = type
84+__all__ = [
85+ 'make_file',
86+ ]
87+
88+from fixtures import TempDir
89+import os.path
90+
91+
92+def make_file(testcase, name=None, content=None):
93+ """Write a file. Attach cleanup to `testcase`."""
94+ if content is None:
95+ content = testcase.getUniqueString()
96+ testcase.assertIsInstance(content, bytes)
97+ if name is None:
98+ name = testcase.getUniqueString()
99+ path = os.path.join(testcase.useFixture(TempDir()).path, name)
100+ with open(path, 'wb') as f:
101+ f.write(content)
102+ return path
103
104=== modified file 'maastest/tests/test_kvmfixture.py'
105--- maastest/tests/test_kvmfixture.py 2014-02-26 21:05:58 +0000
106+++ maastest/tests/test_kvmfixture.py 2014-04-09 06:59:27 +0000
107@@ -1,4 +1,4 @@
108-# Copyright 2013 Canonical Ltd. This software is licensed under the
109+# Copyright 2013-2014 Canonical Ltd. This software is licensed under the
110 # GNU Affero General Public License version 3 (see the file LICENSE).
111
112 """Tests for `maastest.kvmfixture`."""
113@@ -13,13 +13,16 @@
114 __all__ = []
115
116 import itertools
117+import os.path
118 import random
119 from random import randint
120+from tempfile import gettempdir
121 import textwrap
122
123 import fixtures
124 from lxml import etree
125 from maastest import kvmfixture
126+from maastest.testing.factory import make_file
127 from maastest.utils import read_file
128 import mock
129 import netaddr
130@@ -694,6 +697,34 @@
131 'uvt-kvm', 'wait', fixture.name], check_call=True)],
132 kvmfixture.run_command.mock_calls)
133
134+ def test_upload_file_uploads_file(self):
135+ self.patch(kvmfixture, 'run_command', mock.MagicMock())
136+ fixture = self.make_KVMFixture(kvm_timeout=None)
137+ local_file = make_file(self)
138+ remote_file = os.path.join(gettempdir(), self.getUniqueString())
139+ fixture.upload_file(local_file, remote_file)
140+ self.assertEqual(
141+ [
142+ mock.call(
143+ (
144+ ['scp'] +
145+ fixture._get_base_ssh_options() +
146+ [local_file, remote_file]
147+ ),
148+ check_call=True)
149+ ],
150+ kvmfixture.run_command.mock_calls)
151+
152+ def test_upload_file_defaults_to_base_name_in_default_dir(self):
153+ self.patch(kvmfixture, 'run_command', mock.MagicMock())
154+ fixture = self.make_KVMFixture(kvm_timeout=None)
155+ local_file = make_file(self)
156+ fixture.upload_file(local_file)
157+ [command] = kvmfixture.run_command.mock_calls
158+ name, args, kwargs = command
159+ (command_line,) = args
160+ self.assertEqual(os.path.basename(local_file), command_line[-1])
161+
162
163 def xml_normalize(snippet):
164 parser = etree.XMLParser(remove_blank_text=True)
165
166=== modified file 'maastest/tests/test_maasfixture.py'
167--- maastest/tests/test_maasfixture.py 2014-04-03 02:10:29 +0000
168+++ maastest/tests/test_maasfixture.py 2014-04-09 06:59:27 +0000
169@@ -20,19 +20,18 @@
170 repeat,
171 )
172 import json
173-import os.path
174 from random import randint
175 from subprocess import check_call
176 from textwrap import dedent
177
178 from apiclient.maas_client import MAASClient
179-from fixtures import TempDir
180 from maastest import (
181 kvmfixture,
182 maasfixture,
183 utils,
184 )
185 from maastest.maas_enums import NODEGROUPINTERFACE_MANAGEMENT
186+from maastest.testing.factory import make_file
187 import mock
188 import netaddr
189 from six import text_type
190@@ -112,14 +111,7 @@
191 """ % (old_url, new_url)).encode('ascii')
192
193 def make_file(self, name=None, content=None):
194- """Write a file."""
195- self.assertIsInstance(content, bytes)
196- if name is None:
197- name = self.getUniqueString()
198- path = os.path.join(self.useFixture(TempDir()).path, name)
199- with open(path, 'wb') as f:
200- f.write(content)
201- return path
202+ return make_file(self, name=name, content=content)
203
204 def patch_MAASClient(self, client, method, content, code=httplib.OK):
205 """Patch a MAASClient so that it will return a pre-cooked response."""
206@@ -132,8 +124,8 @@
207 def test_compose_rewrite_for_default_maas_url_rewrites_url(self):
208 old_url = 'http://1.1.1.1/'
209 new_url = 'http://2.2.2.2/'
210- config_file = self.make_file(
211- content=self.make_maas_local_settings(old_url))
212+ config_file = make_file(
213+ self, content=self.make_maas_local_settings(old_url))
214
215 command = maasfixture.compose_rewrite_for_default_maas_url(
216 config_file, new_url)
217@@ -149,8 +141,8 @@
218 def test_compose_rewrite_for_default_maas_url_accepts_path(self):
219 old_url = 'http://old-host.com/OLDMAAS'
220 new_url = 'http://new-host.local/NEWMAAS'
221- config_file = self.make_file(
222- content=self.make_maas_local_settings(old_url))
223+ config_file = make_file(
224+ self, content=self.make_maas_local_settings(old_url))
225
226 check_call(
227 maasfixture.compose_rewrite_for_default_maas_url(
228@@ -165,7 +157,7 @@
229 old_url = "http://1.1.1.1/"
230 old_content = b'\n'.join(
231 [top, self.make_maas_local_settings(old_url), bottom])
232- config_file = self.make_file(content=old_content)
233+ config_file = make_file(self, content=old_content)
234 new_url = "http://2.2.2.2/"
235
236 check_call(
237@@ -180,7 +172,7 @@
238 top = b'#DEFAULT_MAAS_URL = "http://9.9.9.9/"\n'
239 old_url = "http://1.1.1.1/"
240 old_content = top + self.make_maas_local_settings(old_url)
241- config_file = self.make_file(content=old_content)
242+ config_file = make_file(self, content=old_content)
243 new_url = "http://2.2.2.2/"
244
245 check_call(

Subscribers

People subscribed via source and target branches