Merge lp:~bac/lpsetup/lxc-integration into lp:lpsetup
- lxc-integration
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Brad Crittenden |
Approved revision: | 81 |
Merged at revision: | 57 |
Proposed branch: | lp:~bac/lpsetup/lxc-integration |
Merge into: | lp:lpsetup |
Diff against target: |
876 lines (+368/-171) 15 files modified
README.rst (+6/-2) commands.rst (+4/-4) lpsetup/handlers.py (+13/-7) lpsetup/settings.py (+0/-3) lpsetup/subcommands/finish_inithost.py (+18/-11) lpsetup/subcommands/initrepo.py (+24/-12) lpsetup/subcommands/install_lxc.py (+13/-10) lpsetup/subcommands/update.py (+32/-22) lpsetup/tests/integration/common.py (+63/-0) lpsetup/tests/integration/lxc.py (+106/-0) lpsetup/tests/integration/non-lxc.py (+72/-89) lpsetup/tests/subcommands/test_finish_inithost.py (+4/-2) lpsetup/tests/subcommands/test_install_lxc.py (+3/-1) lpsetup/tests/subcommands/test_update.py (+8/-6) pre-commit.sh (+2/-2) |
To merge this branch: | bzr merge lp:~bac/lpsetup/lxc-integration |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Benji York (community) | code | Approve | |
Review via email: mp+115804@code.launchpad.net |
Commit message
Add lxc-based integration test. Fix some idepotent problems.
Description of the change
Add lxc-based integration test.
Discovered a problem with the handling of some command-line options
(working_dir and code_dir) which required some rejiggering. They were
deleted in favor of specifying the repository and checkout-name
separately.
Refactored the test non-lxc.py in order to share code and structure
with lxc.py.
Fun with bzrlib. In retrospect the win over just shelling out to
'bzr' was miniscule.
Brad Crittenden (bac) wrote : | # |
Benji York (benji) wrote : | # |
The branch looks good, there were a couple of small issues that need to
be addressed and then it will be ready to land.
In lpsetup/
that can be single-line instead (on and about line 518 of the diff).
In lpsetup/
not used and there should be two blank lines before the definition of
IntegrationTest
Also, I /think/ the "help" parameter to the first add_argument in
IntegrationTestBase exceeds our prescribed line width.
As we discussed on the call, I'm not happy with the new OOP and
subclassing -- especially since there is more-or-less no state managed
by the object -- the modules themselves would have been sufficient
organization. That being said, it's not the end of the world.
We also need to get the new non-LXC test to use Juju so the test is run
in an isolated and throw-away environment. We decided that landing the
branch as-is and following up with Juju-ification would be fine.
Launchpad QA Bot (lpqabot) wrote : | # |
There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.
Preview Diff
1 | === modified file 'README.rst' | |||
2 | --- README.rst 2012-07-11 16:33:16 +0000 | |||
3 | +++ README.rst 2012-07-19 21:00:25 +0000 | |||
4 | @@ -59,11 +59,15 @@ | |||
5 | 59 | Integration tests can be found in lpsetup/tests/integration. They | 59 | Integration tests can be found in lpsetup/tests/integration. They |
6 | 60 | require the "ubuntu" juju charm which, at the time of this writing, is | 60 | require the "ubuntu" juju charm which, at the time of this writing, is |
7 | 61 | not available in the charm store. Check it out into the local juju | 61 | not available in the charm store. Check it out into the local juju |
9 | 62 | charm repository from lp:~charmers/charms/precise/ubuntu/trunk. | 62 | charm repository from lp:~charmers/charms/precise/ubuntu/trunk. The |
10 | 63 | test expects your Juju repository to be at ~/juju-charms | ||
11 | 63 | 64 | ||
12 | 64 | The integration tests use a juju environment named "lpsetup-testing" so | 65 | The integration tests use a juju environment named "lpsetup-testing" so |
13 | 65 | you must create an appropriately configured juju environment with that | 66 | you must create an appropriately configured juju environment with that |
15 | 66 | name before running the tests. | 67 | name before running the tests in ~/.juju/environments.yaml. |
16 | 68 | |||
17 | 69 | The tests bootstrap the environment for you and fail if it is already | ||
18 | 70 | running. | ||
19 | 67 | 71 | ||
20 | 68 | You may also want to add this to your SSH .config file to suppress the | 72 | You may also want to add this to your SSH .config file to suppress the |
21 | 69 | many yes/no prompts: | 73 | many yes/no prompts: |
22 | 70 | 74 | ||
23 | === modified file 'commands.rst' | |||
24 | --- commands.rst 2012-07-10 19:06:12 +0000 | |||
25 | +++ commands.rst 2012-07-19 21:00:25 +0000 | |||
26 | @@ -51,13 +51,13 @@ | |||
27 | 51 | Completely sets up an LXC environment with Launchpad using the sandbox | 51 | Completely sets up an LXC environment with Launchpad using the sandbox |
28 | 52 | development model: | 52 | development model: |
29 | 53 | 53 | ||
31 | 54 | ~/launchpad | 54 | ~/launchpad/lp-branches |
32 | 55 | bzr repository with --no-trees option. | 55 | bzr repository with --no-trees option. |
34 | 56 | ~/launchpad/devel | 56 | ~/launchpad/lp-branches/devel |
35 | 57 | branch with no trees of trunk. | 57 | branch with no trees of trunk. |
37 | 58 | ~/launchpad/sandbox | 58 | ~/launchpad/lp-branches/sandbox |
38 | 59 | lightweight checkout with a tree of ../devel. | 59 | lightweight checkout with a tree of ../devel. |
40 | 60 | ~/launchpad/bug-xyz | 60 | ~/launchpad/lp-branches/bug-xyz |
41 | 61 | branch with no trees of trunk where bug work is done via switching | 61 | branch with no trees of trunk where bug work is done via switching |
42 | 62 | inside sandbox. | 62 | inside sandbox. |
43 | 63 | 63 | ||
44 | 64 | 64 | ||
45 | === modified file 'lpsetup/handlers.py' | |||
46 | --- lpsetup/handlers.py 2012-07-16 16:43:34 +0000 | |||
47 | +++ lpsetup/handlers.py 2012-07-19 21:00:25 +0000 | |||
48 | @@ -6,6 +6,7 @@ | |||
49 | 6 | 6 | ||
50 | 7 | __metaclass__ = type | 7 | __metaclass__ = type |
51 | 8 | __all__ = [ | 8 | __all__ = [ |
52 | 9 | 'handle_code_dir', | ||
53 | 9 | 'handle_directories', | 10 | 'handle_directories', |
54 | 10 | 'handle_lpuser_as_username', | 11 | 'handle_lpuser_as_username', |
55 | 11 | 'handle_lpuser_from_lplogin', | 12 | 'handle_lpuser_from_lplogin', |
56 | @@ -221,13 +222,13 @@ | |||
57 | 221 | 222 | ||
58 | 222 | 223 | ||
59 | 223 | def handle_directories(namespace): | 224 | def handle_directories(namespace): |
61 | 224 | """Handle repository, code_dir, and dependencies directories. | 225 | """Handle repository and dependencies directories. |
62 | 225 | 226 | ||
63 | 226 | - The ~ construction is automatically expanded. | 227 | - The ~ construction is automatically expanded. |
64 | 227 | - The validation fails for directories not residing inside the home. | 228 | - The validation fails for directories not residing inside the home. |
65 | 228 | - The validation fails if the directory contains spaces. | 229 | - The validation fails if the directory contains spaces. |
66 | 229 | """ | 230 | """ |
68 | 230 | for attr in ('repository', 'code_dir', 'dependencies_dir'): | 231 | for attr in ('repository', 'dependencies_dir'): |
69 | 231 | directory = getattr(namespace, attr, None) | 232 | directory = getattr(namespace, attr, None) |
70 | 232 | if directory is None: | 233 | if directory is None: |
71 | 233 | continue | 234 | continue |
72 | @@ -285,11 +286,6 @@ | |||
73 | 285 | return os.path.abspath(os.path.expanduser(path)) | 286 | return os.path.abspath(os.path.expanduser(path)) |
74 | 286 | 287 | ||
75 | 287 | 288 | ||
76 | 288 | def handle_working_dir(namespace): | ||
77 | 289 | """Handle path to the working directory.""" | ||
78 | 290 | namespace.working_dir = normalize_path(namespace.working_dir) | ||
79 | 291 | |||
80 | 292 | |||
81 | 293 | def handle_branch_and_checkout(namespace): | 289 | def handle_branch_and_checkout(namespace): |
82 | 294 | """Handle branch and checkout names. | 290 | """Handle branch and checkout names. |
83 | 295 | 291 | ||
84 | @@ -303,6 +299,7 @@ | |||
85 | 303 | 299 | ||
86 | 304 | - branch_name | 300 | - branch_name |
87 | 305 | - checkout_name | 301 | - checkout_name |
88 | 302 | - repository | ||
89 | 306 | 303 | ||
90 | 307 | This handler does not modify the namespace. | 304 | This handler does not modify the namespace. |
91 | 308 | """ | 305 | """ |
92 | @@ -318,3 +315,12 @@ | |||
93 | 318 | raise ValidationError( | 315 | raise ValidationError( |
94 | 319 | 'branch and checkout: can not use the same name ({0}).'.format( | 316 | 'branch and checkout: can not use the same name ({0}).'.format( |
95 | 320 | checkout_name)) | 317 | checkout_name)) |
96 | 318 | |||
97 | 319 | |||
98 | 320 | def handle_code_dir(namespace): | ||
99 | 321 | """Handle the computed value for `code_dir`. | ||
100 | 322 | |||
101 | 323 | It must be invoked after handle_directories. | ||
102 | 324 | """ | ||
103 | 325 | namespace.code_dir = os.path.join( | ||
104 | 326 | namespace.repository, namespace.checkout_name) | ||
105 | 321 | 327 | ||
106 | === modified file 'lpsetup/settings.py' | |||
107 | --- lpsetup/settings.py 2012-07-17 17:55:38 +0000 | |||
108 | +++ lpsetup/settings.py 2012-07-19 21:00:25 +0000 | |||
109 | @@ -3,8 +3,6 @@ | |||
110 | 3 | # GNU Affero General Public License version 3 (see the file LICENSE). | 3 | # GNU Affero General Public License version 3 (see the file LICENSE). |
111 | 4 | 4 | ||
112 | 5 | """Global settings and defaults for lpsetup.""" | 5 | """Global settings and defaults for lpsetup.""" |
113 | 6 | import os.path | ||
114 | 7 | |||
115 | 8 | 6 | ||
116 | 9 | APT_REPOSITORIES = ( | 7 | APT_REPOSITORIES = ( |
117 | 10 | 'deb http://archive.ubuntu.com/ubuntu {distro} multiverse', | 8 | 'deb http://archive.ubuntu.com/ubuntu {distro} multiverse', |
118 | @@ -56,7 +54,6 @@ | |||
119 | 56 | LP_BRANCH_NAME = 'devel' | 54 | LP_BRANCH_NAME = 'devel' |
120 | 57 | LP_CHECKOUT_NAME = 'sandbox' | 55 | LP_CHECKOUT_NAME = 'sandbox' |
121 | 58 | LP_REPOSITORY_DIR = '~/launchpad/lp-branches' | 56 | LP_REPOSITORY_DIR = '~/launchpad/lp-branches' |
122 | 59 | LP_CODE_DIR = os.path.join(LP_REPOSITORY_DIR, LP_CHECKOUT_NAME) | ||
123 | 60 | LP_PACKAGES = [ | 57 | LP_PACKAGES = [ |
124 | 61 | # "launchpad-database-dependencies-9.1" can be removed once 8.x is | 58 | # "launchpad-database-dependencies-9.1" can be removed once 8.x is |
125 | 62 | # no longer an option in "launchpad-developer-dependencies. | 59 | # no longer an option in "launchpad-developer-dependencies. |
126 | 63 | 60 | ||
127 | === modified file 'lpsetup/subcommands/finish_inithost.py' | |||
128 | --- lpsetup/subcommands/finish_inithost.py 2012-07-16 08:17:05 +0000 | |||
129 | +++ lpsetup/subcommands/finish_inithost.py 2012-07-19 21:00:25 +0000 | |||
130 | @@ -29,10 +29,15 @@ | |||
131 | 29 | 29 | ||
132 | 30 | from lpsetup import argparser | 30 | from lpsetup import argparser |
133 | 31 | from lpsetup.handlers import ( | 31 | from lpsetup.handlers import ( |
134 | 32 | handle_code_dir, | ||
135 | 32 | handle_directories, | 33 | handle_directories, |
136 | 33 | handle_user, | 34 | handle_user, |
137 | 34 | ) | 35 | ) |
139 | 35 | from lpsetup.settings import LP_CODE_DIR | 36 | from lpsetup.settings import ( |
140 | 37 | LP_CHECKOUT_NAME, | ||
141 | 38 | LP_REPOSITORY_DIR, | ||
142 | 39 | ) | ||
143 | 40 | |||
144 | 36 | from lpsetup.utils import call | 41 | from lpsetup.utils import call |
145 | 37 | 42 | ||
146 | 38 | 43 | ||
147 | @@ -75,22 +80,24 @@ | |||
148 | 75 | handlers = ( | 80 | handlers = ( |
149 | 76 | handle_user, | 81 | handle_user, |
150 | 77 | handle_directories, | 82 | handle_directories, |
151 | 83 | handle_code_dir, | ||
152 | 78 | ) | 84 | ) |
153 | 79 | 85 | ||
154 | 80 | @staticmethod | ||
155 | 81 | def add_common_arguments(parser): | ||
156 | 82 | parser.add_argument( | ||
157 | 83 | '-c', '--code-dir', default=LP_CODE_DIR, | ||
158 | 84 | help='The directory of the Launchpad code checkout. ' | ||
159 | 85 | 'The directory must reside under the home directory of the ' | ||
160 | 86 | 'given user (see -u argument). ' | ||
161 | 87 | '[DEFAULT={0}]'.format(LP_CODE_DIR)) | ||
162 | 88 | |||
163 | 89 | def add_arguments(self, parser): | 86 | def add_arguments(self, parser): |
164 | 90 | super(SubCommand, self).add_arguments(parser) | 87 | super(SubCommand, self).add_arguments(parser) |
165 | 91 | self.add_common_arguments(parser) | ||
166 | 92 | parser.add_argument( | 88 | parser.add_argument( |
167 | 93 | '-u', '--user', | 89 | '-u', '--user', |
168 | 94 | help='The name of the system user. ' | 90 | help='The name of the system user. ' |
169 | 95 | 'The current user is used if this script is not run as ' | 91 | 'The current user is used if this script is not run as ' |
170 | 96 | 'root and this argument is omitted.') | 92 | 'root and this argument is omitted.') |
171 | 93 | parser.add_argument( | ||
172 | 94 | '--checkout-name', default=LP_CHECKOUT_NAME, | ||
173 | 95 | help='Create a checkout with the given name. ' | ||
174 | 96 | 'Ignored if --no-checkout is specified. ' | ||
175 | 97 | 'Defaults to {0}.'.format(LP_CHECKOUT_NAME)) | ||
176 | 98 | parser.add_argument( | ||
177 | 99 | '-r', '--repository', default=LP_REPOSITORY_DIR, | ||
178 | 100 | help='The directory of the Launchpad repository to be created. ' | ||
179 | 101 | 'The directory must reside under the home directory of the ' | ||
180 | 102 | 'given user (see -u argument). ' | ||
181 | 103 | '[DEFAULT={0}]'.format(LP_REPOSITORY_DIR)) | ||
182 | 97 | 104 | ||
183 | === modified file 'lpsetup/subcommands/initrepo.py' | |||
184 | --- lpsetup/subcommands/initrepo.py 2012-07-16 10:09:48 +0000 | |||
185 | +++ lpsetup/subcommands/initrepo.py 2012-07-19 21:00:25 +0000 | |||
186 | @@ -49,27 +49,39 @@ | |||
187 | 49 | is_lightweight = not no_checkout | 49 | is_lightweight = not no_checkout |
188 | 50 | no_trees = '--no-trees' if is_lightweight else None | 50 | no_trees = '--no-trees' if is_lightweight else None |
189 | 51 | # Initialize the repository. | 51 | # Initialize the repository. |
195 | 52 | try: | 52 | |
196 | 53 | call('bzr', 'init-repo', '--quiet', repository, no_trees) | 53 | # Skip creating the repository if it already exists. There is the |
197 | 54 | except subprocess.CalledProcessError as err: | 54 | # risk that it is not made with the same `no_trees` option as |
198 | 55 | msg = 'Error: unable to initialize the repository: ' | 55 | # specified here. |
199 | 56 | raise exceptions.ExecutionError(msg + err.output) | 56 | if not os.path.exists(os.path.join(repository, '.bzr')): |
200 | 57 | try: | ||
201 | 58 | call('bzr', 'init-repo', '--quiet', repository, no_trees) | ||
202 | 59 | except subprocess.CalledProcessError as err: | ||
203 | 60 | msg = 'Error: unable to initialize the repository: ' | ||
204 | 61 | raise exceptions.ExecutionError(msg + err.output) | ||
205 | 57 | # Set up the codebase. | 62 | # Set up the codebase. |
206 | 58 | branch_dir = os.path.join(repository, branch_name) | 63 | branch_dir = os.path.join(repository, branch_name) |
207 | 59 | # Retrieve the branch. | 64 | # Retrieve the branch. |
208 | 65 | if os.path.exists(branch_dir): | ||
209 | 66 | # The branch already exists, so we pull to refresh it rather than | ||
210 | 67 | # creating it. | ||
211 | 68 | cmd = ['bzr', 'pull', '--overwrite', '-d', branch_dir, source] | ||
212 | 69 | else: | ||
213 | 70 | cmd = ['bzr', 'branch', source, branch_dir] | ||
214 | 60 | try: | 71 | try: |
216 | 61 | call('bzr', 'branch', source, branch_dir) | 72 | call(*cmd) |
217 | 62 | except subprocess.CalledProcessError as err: | 73 | except subprocess.CalledProcessError as err: |
218 | 63 | msg = 'Error: unable to branch source: ' | 74 | msg = 'Error: unable to branch source: ' |
219 | 64 | raise exceptions.ExecutionError(msg + err.output) | 75 | raise exceptions.ExecutionError(msg + err.output) |
220 | 65 | if is_lightweight: | 76 | if is_lightweight: |
221 | 66 | checkout_dir = os.path.join(repository, checkout_name) | 77 | checkout_dir = os.path.join(repository, checkout_name) |
228 | 67 | # Create a lightweight checkout. | 78 | # Create a lightweight checkout if it doesn't exist. |
229 | 68 | try: | 79 | if not os.path.exists(checkout_dir): |
230 | 69 | call('bzr', 'co', '--lightweight', branch_dir, checkout_dir) | 80 | try: |
231 | 70 | except subprocess.CalledProcessError as err: | 81 | call('bzr', 'co', '--lightweight', branch_dir, checkout_dir) |
232 | 71 | msg = 'Error: unable to create the lightweight checkout: ' | 82 | except subprocess.CalledProcessError as err: |
233 | 72 | raise exceptions.ExecutionError(msg + err.output) | 83 | msg = 'Error: unable to create the lightweight checkout: ' |
234 | 84 | raise exceptions.ExecutionError(msg + err.output) | ||
235 | 73 | 85 | ||
236 | 74 | 86 | ||
237 | 75 | def setup_bzr_locations( | 87 | def setup_bzr_locations( |
238 | 76 | 88 | ||
239 | === modified file 'lpsetup/subcommands/install_lxc.py' | |||
240 | --- lpsetup/subcommands/install_lxc.py 2012-07-13 14:51:08 +0000 | |||
241 | +++ lpsetup/subcommands/install_lxc.py 2012-07-19 21:00:25 +0000 | |||
242 | @@ -13,6 +13,7 @@ | |||
243 | 13 | import os | 13 | import os |
244 | 14 | 14 | ||
245 | 15 | from lpsetup.handlers import ( | 15 | from lpsetup.handlers import ( |
246 | 16 | handle_code_dir, | ||
247 | 16 | handle_directories, | 17 | handle_directories, |
248 | 17 | handle_source, | 18 | handle_source, |
249 | 18 | ) | 19 | ) |
250 | @@ -21,7 +22,6 @@ | |||
251 | 21 | SCRIPTS, | 22 | SCRIPTS, |
252 | 22 | ) | 23 | ) |
253 | 23 | from lpsetup.subcommands import ( | 24 | from lpsetup.subcommands import ( |
254 | 24 | finish_inithost, | ||
255 | 25 | initlxc, | 25 | initlxc, |
256 | 26 | initrepo, | 26 | initrepo, |
257 | 27 | update, | 27 | update, |
258 | @@ -69,11 +69,9 @@ | |||
259 | 69 | 69 | ||
260 | 70 | 70 | ||
261 | 71 | def cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=None): | 71 | def cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=None): |
262 | 72 | print "args = ", args | ||
263 | 73 | cmd = this_command(home_dir, args) | 72 | cmd = this_command(home_dir, args) |
264 | 74 | if as_user is not None: | 73 | if as_user is not None: |
265 | 75 | cmd = "su {} -c '{}'".format(as_user, cmd) | 74 | cmd = "su {} -c '{}'".format(as_user, cmd) |
266 | 76 | print "CMD = ", cmd | ||
267 | 77 | ssh(lxc_name, cmd, key=ssh_key_path) | 75 | ssh(lxc_name, cmd, key=ssh_key_path) |
268 | 78 | 76 | ||
269 | 79 | 77 | ||
270 | @@ -91,18 +89,20 @@ | |||
271 | 91 | 89 | ||
272 | 92 | def update_in_lxc(lxc_name, ssh_key_path, home_dir, user, external_path, | 90 | def update_in_lxc(lxc_name, ssh_key_path, home_dir, user, external_path, |
273 | 93 | use_http, checkout_name, repository): | 91 | use_http, checkout_name, repository): |
274 | 94 | working_dir = os.path.join(repository, checkout_name) | ||
275 | 95 | args = [ | 92 | args = [ |
277 | 96 | 'update', '--external-path', external_path, '-W', working_dir, | 93 | 'update', '--external-path', external_path, |
278 | 94 | '-r', repository, '--checkout-name', checkout_name, | ||
279 | 97 | ] | 95 | ] |
280 | 98 | if use_http: | 96 | if use_http: |
281 | 99 | args.append('--use-http') | 97 | args.append('--use-http') |
282 | 100 | cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=user) | 98 | cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=user) |
283 | 101 | 99 | ||
284 | 102 | 100 | ||
286 | 103 | def finish_inithost_in_lxc(lxc_name, ssh_key_path, home_dir, user, code_dir): | 101 | def finish_inithost_in_lxc(lxc_name, ssh_key_path, home_dir, user, |
287 | 102 | repository, checkout_name): | ||
288 | 104 | args = [ | 103 | args = [ |
290 | 105 | 'finish-init-host', '--user', user, '--code-dir', code_dir, | 104 | 'finish-init-host', '--user', user, '--repository', repository, |
291 | 105 | '--checkout-name', checkout_name, | ||
292 | 106 | ] | 106 | ] |
293 | 107 | cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args) | 107 | cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args) |
294 | 108 | 108 | ||
295 | @@ -121,14 +121,18 @@ | |||
296 | 121 | (update_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', 'user', | 121 | (update_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', 'user', |
297 | 122 | 'external_path', 'use_http', 'checkout_name', 'repository'), | 122 | 'external_path', 'use_http', 'checkout_name', 'repository'), |
298 | 123 | (finish_inithost_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', | 123 | (finish_inithost_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', |
300 | 124 | 'user', 'code_dir'), | 124 | 'user', 'repository', 'checkout_name'), |
301 | 125 | ) | 125 | ) |
302 | 126 | 126 | ||
303 | 127 | help = __doc__ | 127 | help = __doc__ |
304 | 128 | 128 | ||
305 | 129 | def get_handlers(self, namespace): | 129 | def get_handlers(self, namespace): |
306 | 130 | handlers = super(SubCommand, self).get_handlers(namespace) | 130 | handlers = super(SubCommand, self).get_handlers(namespace) |
308 | 131 | return handlers + (handle_directories, handle_source) | 131 | return handlers + ( |
309 | 132 | handle_directories, | ||
310 | 133 | handle_code_dir, | ||
311 | 134 | handle_source, | ||
312 | 135 | ) | ||
313 | 132 | 136 | ||
314 | 133 | def call_create_scripts(self, namespace, step, args): | 137 | def call_create_scripts(self, namespace, step, args): |
315 | 134 | """Run the `create_scripts` step only if the related flag is set.""" | 138 | """Run the `create_scripts` step only if the related flag is set.""" |
316 | @@ -140,7 +144,6 @@ | |||
317 | 140 | # Inherit arguments from subcommands we depend upon. | 144 | # Inherit arguments from subcommands we depend upon. |
318 | 141 | initrepo.SubCommand.add_common_arguments(parser) | 145 | initrepo.SubCommand.add_common_arguments(parser) |
319 | 142 | update.SubCommand.add_common_arguments(parser) | 146 | update.SubCommand.add_common_arguments(parser) |
320 | 143 | finish_inithost.SubCommand.add_common_arguments(parser) | ||
321 | 144 | # Add parallel testing related arguments. | 147 | # Add parallel testing related arguments. |
322 | 145 | parser.add_argument( | 148 | parser.add_argument( |
323 | 146 | '-C', '--create-scripts', action='store_true', | 149 | '-C', '--create-scripts', action='store_true', |
324 | 147 | 150 | ||
325 | === modified file 'lpsetup/subcommands/update.py' | |||
326 | --- lpsetup/subcommands/update.py 2012-07-13 15:55:40 +0000 | |||
327 | +++ lpsetup/subcommands/update.py 2012-07-19 21:00:25 +0000 | |||
328 | @@ -19,48 +19,49 @@ | |||
329 | 19 | from lpsetup import argparser | 19 | from lpsetup import argparser |
330 | 20 | from lpsetup import handlers | 20 | from lpsetup import handlers |
331 | 21 | from lpsetup.settings import ( | 21 | from lpsetup.settings import ( |
333 | 22 | LP_CODE_DIR, | 22 | LP_CHECKOUT_NAME, |
334 | 23 | LP_REPOSITORY_DIR, | ||
335 | 23 | LP_SOURCE_DEPS, | 24 | LP_SOURCE_DEPS, |
336 | 24 | ) | 25 | ) |
337 | 25 | 26 | ||
338 | 26 | 27 | ||
340 | 27 | def initialize_directories(working_dir, external_path): | 28 | def initialize_directories(code_dir, external_path): |
341 | 28 | """Initialize the eggs, yui, and sourcecode directories. | 29 | """Initialize the eggs, yui, and sourcecode directories. |
342 | 29 | 30 | ||
343 | 30 | Create them if necessary. | 31 | Create them if necessary. |
344 | 31 | """ | 32 | """ |
345 | 32 | for dir_ in ['eggs', 'yui', 'sourcecode']: | 33 | for dir_ in ['eggs', 'yui', 'sourcecode']: |
350 | 33 | mkdirs(os.path.join(working_dir, external_path, dir_)) | 34 | mkdirs(os.path.join(code_dir, external_path, dir_)) |
351 | 34 | 35 | ||
352 | 35 | 36 | ||
353 | 36 | def update_dependencies(working_dir, external_path, use_http): | 37 | def update_dependencies(code_dir, external_path, use_http): |
354 | 37 | """Update the external dependencies.""" | 38 | """Update the external dependencies.""" |
355 | 38 | use_http_param = '--use-http' if use_http else None | 39 | use_http_param = '--use-http' if use_http else None |
357 | 39 | cmd = os.path.join(working_dir, 'utilities', 'update-sourcecode') | 40 | cmd = os.path.join(code_dir, 'utilities', 'update-sourcecode') |
358 | 40 | abs_external_path = os.path.abspath( | 41 | abs_external_path = os.path.abspath( |
360 | 41 | os.path.join(working_dir, external_path)) | 42 | os.path.join(code_dir, external_path)) |
361 | 42 | source_path = os.path.join(abs_external_path, 'sourcecode') | 43 | source_path = os.path.join(abs_external_path, 'sourcecode') |
362 | 43 | run(cmd, use_http_param, source_path) | 44 | run(cmd, use_http_param, source_path) |
363 | 44 | 45 | ||
364 | 45 | # Update the download cache. | 46 | # Update the download cache. |
366 | 46 | download_cache = os.path.join(working_dir, 'download-cache') | 47 | download_cache = os.path.join(code_dir, 'download-cache') |
367 | 47 | if os.path.exists(download_cache): | 48 | if os.path.exists(download_cache): |
368 | 48 | run('bzr', 'up', download_cache) | 49 | run('bzr', 'up', download_cache) |
369 | 49 | else: | 50 | else: |
370 | 50 | run('bzr', 'co', '-v', '--lightweight', LP_SOURCE_DEPS, download_cache) | 51 | run('bzr', 'co', '-v', '--lightweight', LP_SOURCE_DEPS, download_cache) |
371 | 51 | 52 | ||
372 | 52 | # Link to the external sourcecode. | 53 | # Link to the external sourcecode. |
374 | 53 | if abs_external_path != working_dir: | 54 | if abs_external_path != code_dir: |
375 | 54 | cmd = os.path.join( | 55 | cmd = os.path.join( |
377 | 55 | working_dir, 'utilities', 'link-external-sourcecode') | 56 | code_dir, 'utilities', 'link-external-sourcecode') |
378 | 56 | run(cmd, | 57 | run(cmd, |
380 | 57 | '--target', working_dir, | 58 | '--target', code_dir, |
381 | 58 | '--parent', external_path) | 59 | '--parent', external_path) |
382 | 59 | 60 | ||
383 | 60 | 61 | ||
387 | 61 | def update_tree(working_dir): | 62 | def update_tree(code_dir): |
388 | 62 | """Update the tree at working_dir with the latest LP code.""" | 63 | """Update the tree at code_dir with the latest LP code.""" |
389 | 63 | with cd(working_dir): | 64 | with cd(code_dir): |
390 | 64 | run('bzr', 'pull') | 65 | run('bzr', 'pull') |
391 | 65 | 66 | ||
392 | 66 | 67 | ||
393 | @@ -71,14 +72,16 @@ | |||
394 | 71 | """ | 72 | """ |
395 | 72 | 73 | ||
396 | 73 | steps = ( | 74 | steps = ( |
400 | 74 | (initialize_directories, 'working_dir', 'external_path'), | 75 | (initialize_directories, 'code_dir', 'external_path'), |
401 | 75 | (update_dependencies, 'working_dir', 'external_path', 'use_http'), | 76 | (update_dependencies, 'code_dir', 'external_path', 'use_http'), |
402 | 76 | (update_tree, 'working_dir'), | 77 | (update_tree, 'code_dir'), |
403 | 77 | ) | 78 | ) |
404 | 78 | help = __doc__ | 79 | help = __doc__ |
405 | 79 | handlers = ( | 80 | handlers = ( |
406 | 80 | # Normalize paths and default to cwd if none exists. | 81 | # Normalize paths and default to cwd if none exists. |
408 | 81 | handlers.handle_working_dir, | 82 | handlers.handle_user, |
409 | 83 | handlers.handle_directories, | ||
410 | 84 | handlers.handle_code_dir, | ||
411 | 82 | ) | 85 | ) |
412 | 83 | 86 | ||
413 | 84 | @staticmethod | 87 | @staticmethod |
414 | @@ -97,6 +100,13 @@ | |||
415 | 97 | help='Force bzr to use http to get the sourcecode ' | 100 | help='Force bzr to use http to get the sourcecode ' |
416 | 98 | 'branches rather than using bzr+ssh.') | 101 | 'branches rather than using bzr+ssh.') |
417 | 99 | parser.add_argument( | 102 | parser.add_argument( |
421 | 100 | '-W', '--working-dir', default=LP_CODE_DIR, | 103 | '--checkout-name', default=LP_CHECKOUT_NAME, |
422 | 101 | help='Path to branch to update. ' | 104 | help='Create a checkout with the given name. ' |
423 | 102 | '[DEFAULT={0}]'.format(LP_CODE_DIR)) | 105 | 'Ignored if --no-checkout is specified. ' |
424 | 106 | 'Defaults to {0}.'.format(LP_CHECKOUT_NAME)) | ||
425 | 107 | parser.add_argument( | ||
426 | 108 | '-r', '--repository', default=LP_REPOSITORY_DIR, | ||
427 | 109 | help='The directory of the Launchpad repository to be created. ' | ||
428 | 110 | 'The directory must reside under the home directory of the ' | ||
429 | 111 | 'given user (see -u argument). ' | ||
430 | 112 | '[DEFAULT={0}]'.format(LP_REPOSITORY_DIR)) | ||
431 | 103 | 113 | ||
432 | === added file 'lpsetup/tests/integration/common.py' | |||
433 | --- lpsetup/tests/integration/common.py 1970-01-01 00:00:00 +0000 | |||
434 | +++ lpsetup/tests/integration/common.py 2012-07-19 21:00:25 +0000 | |||
435 | @@ -0,0 +1,63 @@ | |||
436 | 1 | #!/usr/bin/env python | ||
437 | 2 | # Copyright 2012 Canonical Ltd. This software is licensed under the | ||
438 | 3 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
439 | 4 | |||
440 | 5 | """Common resources for integration tests.""" | ||
441 | 6 | |||
442 | 7 | __metaclass__ = type | ||
443 | 8 | __all__ = [ | ||
444 | 9 | 'IntegrationTestBase', | ||
445 | 10 | ] | ||
446 | 11 | |||
447 | 12 | import argparse | ||
448 | 13 | from datetime import datetime | ||
449 | 14 | |||
450 | 15 | |||
451 | 16 | class IntegrationTestBase: | ||
452 | 17 | |||
453 | 18 | banner_width = 70 | ||
454 | 19 | test_type = None | ||
455 | 20 | |||
456 | 21 | def __init__(self): | ||
457 | 22 | self.parser = argparse.ArgumentParser() | ||
458 | 23 | self.parser.add_argument( | ||
459 | 24 | '--no-tear-down', action='store_true', default=False, | ||
460 | 25 | help='Do not run the tear down method for debugging.') | ||
461 | 26 | self.args = self.parser.parse_args() | ||
462 | 27 | |||
463 | 28 | def banner(self, msg, width=banner_width): | ||
464 | 29 | print '*' * width | ||
465 | 30 | print '* ' + msg.ljust(width - 4) + ' *' | ||
466 | 31 | print '*' * width | ||
467 | 32 | |||
468 | 33 | def set_up(self): | ||
469 | 34 | self.banner( | ||
470 | 35 | 'Setting up the test environment for {}.'.format(self.test_type)) | ||
471 | 36 | |||
472 | 37 | def tear_down(self): | ||
473 | 38 | self.banner('Cleaning up.') | ||
474 | 39 | |||
475 | 40 | def check_environment(self): | ||
476 | 41 | self.banner('Checking test environment.') | ||
477 | 42 | |||
478 | 43 | def do_test(self): | ||
479 | 44 | self.banner('Running integration tests for {}.'.format(self.test_type)) | ||
480 | 45 | |||
481 | 46 | def run(self): | ||
482 | 47 | start_time = datetime.now() | ||
483 | 48 | self.check_environment() | ||
484 | 49 | try: | ||
485 | 50 | self.set_up() | ||
486 | 51 | try: | ||
487 | 52 | self.do_test() | ||
488 | 53 | except Exception as err: | ||
489 | 54 | self.banner('Test failed. Sorry.') | ||
490 | 55 | print err | ||
491 | 56 | return 1 | ||
492 | 57 | else: | ||
493 | 58 | self.banner('Test succeeded.') | ||
494 | 59 | return 0 | ||
495 | 60 | finally: | ||
496 | 61 | if not self.args.no_tear_down: | ||
497 | 62 | self.tear_down() | ||
498 | 63 | print "Run time: ", datetime.now() - start_time | ||
499 | 0 | 64 | ||
500 | === added file 'lpsetup/tests/integration/lxc.py' | |||
501 | --- lpsetup/tests/integration/lxc.py 1970-01-01 00:00:00 +0000 | |||
502 | +++ lpsetup/tests/integration/lxc.py 2012-07-19 21:00:25 +0000 | |||
503 | @@ -0,0 +1,106 @@ | |||
504 | 1 | #!/usr/bin/env python | ||
505 | 2 | # Copyright 2012 Canonical Ltd. This software is licensed under the | ||
506 | 3 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
507 | 4 | |||
508 | 5 | """A simple, end-to-end integration test.""" | ||
509 | 6 | |||
510 | 7 | from bzrlib.branch import Branch | ||
511 | 8 | from bzrlib.errors import NotBranchError | ||
512 | 9 | from bzrlib.missing import find_unmerged | ||
513 | 10 | from bzrlib.status import show_tree_status | ||
514 | 11 | from bzrlib.workingtree import WorkingTree | ||
515 | 12 | from StringIO import StringIO | ||
516 | 13 | from subprocess import check_call | ||
517 | 14 | import sys | ||
518 | 15 | |||
519 | 16 | from shelltoolbox import run | ||
520 | 17 | |||
521 | 18 | from common import IntegrationTestBase | ||
522 | 19 | |||
523 | 20 | |||
524 | 21 | LXC_NAME = 'lpsetup-testing' | ||
525 | 22 | |||
526 | 23 | |||
527 | 24 | class LXCIntegrationTest(IntegrationTestBase): | ||
528 | 25 | |||
529 | 26 | test_type = 'LXC container' | ||
530 | 27 | repo = '~/launchpad-testing/lp-branches' | ||
531 | 28 | |||
532 | 29 | def get_branch(self, dir='.'): | ||
533 | 30 | branch, _ = Branch.open_containing(dir) | ||
534 | 31 | return branch | ||
535 | 32 | |||
536 | 33 | def get_push_location(self, branch=None): | ||
537 | 34 | if branch is None: | ||
538 | 35 | branch = self.get_branch() | ||
539 | 36 | return branch.get_push_location() | ||
540 | 37 | |||
541 | 38 | def check_environment(self): | ||
542 | 39 | """Be sure the test environment doesn't exist.""" | ||
543 | 40 | # We want to be really sure we do not clobber an existing LXC | ||
544 | 41 | # container, therefore we make sure one doesn't exist before | ||
545 | 42 | # proceeding. | ||
546 | 43 | super(LXCIntegrationTest, self).check_environment() | ||
547 | 44 | cmd = 'sudo lxc-info -n {}'.format(LXC_NAME) | ||
548 | 45 | results = run(*cmd.split()) | ||
549 | 46 | if results.split()[1] == 'RUNNING': | ||
550 | 47 | # The container should not be active. | ||
551 | 48 | raise RuntimeError( | ||
552 | 49 | "An LXC container named '{}' is unexpectedly " | ||
553 | 50 | "running.".format(LXC_NAME)) | ||
554 | 51 | # Ensure the local branch has been pushed. | ||
555 | 52 | # For some reason 'bzr missing' cannot use a 'lp:' URL. http or | ||
556 | 53 | # bzr+ssh URLs work. | ||
557 | 54 | self.branch = self.get_branch() | ||
558 | 55 | self.push_location = self.get_push_location(self.branch) | ||
559 | 56 | if self.push_location.startswith('lp:'): | ||
560 | 57 | raise RuntimeError( | ||
561 | 58 | "Push location must use http or bzr+ssh " | ||
562 | 59 | "protocol: {}".format(self.push_location)) | ||
563 | 60 | # Ensure the branch has been pushed and has no missing revisions. | ||
564 | 61 | try: | ||
565 | 62 | push_branch = self.get_branch(self.push_location) | ||
566 | 63 | except NotBranchError: | ||
567 | 64 | raise RuntimeError( | ||
568 | 65 | 'The branch has never been pushed to Launchpad.') | ||
569 | 66 | tree, _ = WorkingTree.open_containing_paths(None) | ||
570 | 67 | stream = StringIO() | ||
571 | 68 | show_tree_status(tree, to_file=stream) | ||
572 | 69 | if stream.getvalue(): | ||
573 | 70 | raise RuntimeError( | ||
574 | 71 | 'The tree has uncommitted changes. Check them in ' | ||
575 | 72 | 'and push to Launchpad.') | ||
576 | 73 | near, far = find_unmerged(self.branch, push_branch) | ||
577 | 74 | if near or far: | ||
578 | 75 | raise RuntimeError('The local branch and the pushed version ' | ||
579 | 76 | 'have diverged.') | ||
580 | 77 | |||
581 | 78 | def set_up(self): | ||
582 | 79 | """Set up the LXC container environment.""" | ||
583 | 80 | super(LXCIntegrationTest, self).set_up() | ||
584 | 81 | cmd = 'sudo python setup.py install' | ||
585 | 82 | check_call(cmd.split()) | ||
586 | 83 | |||
587 | 84 | def do_test(self): | ||
588 | 85 | """Run an end-to-end integration tests of the non-LXC lpsetup story.""" | ||
589 | 86 | super(LXCIntegrationTest, self).do_test() | ||
590 | 87 | cmd = 'lp-setup install-lxc -B {} -r {} {}'.format( | ||
591 | 88 | self.push_location, self.repo, LXC_NAME) | ||
592 | 89 | check_call(cmd.split()) | ||
593 | 90 | |||
594 | 91 | def tear_down(self): | ||
595 | 92 | super(LXCIntegrationTest, self).tear_down() | ||
596 | 93 | |||
597 | 94 | def lxc_cmd(cmd_name): | ||
598 | 95 | cmd = 'sudo {} -n {}'.format(cmd_name, LXC_NAME) | ||
599 | 96 | check_call(cmd.split()) | ||
600 | 97 | |||
601 | 98 | try: | ||
602 | 99 | lxc_cmd('lxc-stop') | ||
603 | 100 | lxc_cmd('lxc-destroy') | ||
604 | 101 | except: | ||
605 | 102 | pass | ||
606 | 103 | |||
607 | 104 | |||
608 | 105 | if __name__ == '__main__': | ||
609 | 106 | sys.exit(LXCIntegrationTest().run()) | ||
610 | 0 | 107 | ||
611 | === modified file 'lpsetup/tests/integration/non-lxc.py' | |||
612 | --- lpsetup/tests/integration/non-lxc.py 2012-07-10 19:58:56 +0000 | |||
613 | +++ lpsetup/tests/integration/non-lxc.py 2012-07-19 21:00:25 +0000 | |||
614 | @@ -14,96 +14,79 @@ | |||
615 | 14 | PIPE, | 14 | PIPE, |
616 | 15 | ) | 15 | ) |
617 | 16 | 16 | ||
702 | 17 | 17 | from common import IntegrationTestBase | |
703 | 18 | def banner(s): | 18 | |
704 | 19 | width = 70 | 19 | |
705 | 20 | print '*' * width | 20 | class NonLXCIntegrationTest(IntegrationTestBase): |
706 | 21 | print '* ' + s.ljust(width - 4) + ' *' | 21 | |
707 | 22 | print '*' * width | 22 | test_type = 'non-LXC target' |
708 | 23 | 23 | ||
709 | 24 | 24 | def on_remote(self, args): | |
710 | 25 | def on_remote(args): | 25 | if type(args) == str: |
711 | 26 | if type(args) == str: | 26 | args = args.split() |
712 | 27 | args = args.split() | 27 | |
713 | 28 | 28 | check_call('juju ssh 1 -o StrictHostKeyChecking=no' | |
714 | 29 | check_call('juju ssh 1 -o StrictHostKeyChecking=no' | 29 | ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing'.split() |
715 | 30 | ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing'.split() | 30 | + list(args)) |
716 | 31 | + list(args)) | 31 | |
717 | 32 | 32 | def check_environment(self): | |
718 | 33 | 33 | """Be sure the test environment doesn't exist.""" | |
719 | 34 | def check_environment(): | 34 | # We want to be really sure we do not clobber an already-existing juju |
720 | 35 | """Be sure the test environment doesn't exist.""" | 35 | # environment. Therefore we make sure one doesn't exist before |
721 | 36 | banner('Checking test environment.') | 36 | # bootstrapping. |
722 | 37 | # We want to be really sure we do not clobber an already-existing juju | 37 | super(NonLXCIntegrationTest, self).check_environment() |
723 | 38 | # environment. Therefore we make sure one doesn't exist before | 38 | code = os.system('juju status -e lpsetup-testing') |
724 | 39 | # bootstrapping. | 39 | if code == 0: |
725 | 40 | code = os.system('juju status -e lpsetup-testing') | 40 | # The "juju status" should have failed. |
726 | 41 | if code == 0: | 41 | raise RuntimeError('A juju environment unexpectedly exists.') |
727 | 42 | # The "juju status" should have failed. | 42 | |
728 | 43 | raise RuntimeError('A juju environment unexpectedly exists.') | 43 | def set_up(self): |
729 | 44 | 44 | """Set up a juju-managed instance to run the tests on.""" | |
730 | 45 | 45 | super(NonLXCIntegrationTest, self).set_up() | |
731 | 46 | def set_up(): | 46 | check_call('juju bootstrap -e lpsetup-testing'.split()) |
732 | 47 | """Set up a juju-managed instance to run the tests on.""" | 47 | # XXX The "ubuntu" charm is broken, so it has to be loaded from the |
733 | 48 | banner('Setting up the test environment.') | 48 | # local repository. Get it from |
734 | 49 | check_call('juju bootstrap -e lpsetup-testing'.split()) | 49 | # lp:~charmers/charms/precise/ubuntu/trunk. |
735 | 50 | # XXX The "ubuntu" charm is broken, so it has to be loaded from the local | 50 | check_call('juju deploy local:ubuntu --repository ~/juju-charms' |
736 | 51 | # repository. Get it from lp:~charmers/charms/precise/ubuntu/trunk. | 51 | ' -e lpsetup-testing --constraints instance-type=m1.large'.split()) |
737 | 52 | check_call('juju deploy local:ubuntu --repository ~/juju-charms' | 52 | |
738 | 53 | ' -e lpsetup-testing --constraints instance-type=m1.large'.split()) | 53 | start_time = time.time() |
739 | 54 | 54 | while time.time() - start_time < 600: | |
740 | 55 | start_time = time.time() | 55 | process = Popen( |
741 | 56 | while time.time() - start_time < 600: | 56 | 'juju status -e lpsetup-testing'.split(), stdout=PIPE) |
742 | 57 | process = Popen('juju status -e lpsetup-testing'.split(), stdout=PIPE) | 57 | stdout, stderr = process.communicate() |
743 | 58 | stdout, stderr = process.communicate() | 58 | if 'instance-state: running' in stdout: |
744 | 59 | if 'instance-state: running' in stdout: | 59 | break |
661 | 60 | break | ||
662 | 61 | else: | ||
663 | 62 | raise RuntimeError('starting the instance took too long') | ||
664 | 63 | |||
665 | 64 | # Even though the instance-state is "running", it's still not ready, so | ||
666 | 65 | # wait a little while before continuing. | ||
667 | 66 | time.sleep(30) | ||
668 | 67 | |||
669 | 68 | on_remote('sudo apt-add-repository --yes ppa:yellow/ppa') | ||
670 | 69 | on_remote('sudo apt-get update') | ||
671 | 70 | on_remote('sudo apt-get install python-shelltoolbox') | ||
672 | 71 | check_call('juju scp -o StrictHostKeyChecking=no' | ||
673 | 72 | ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing' | ||
674 | 73 | ' -r . 1:lpsetup'.split()) | ||
675 | 74 | |||
676 | 75 | |||
677 | 76 | def do_test(): | ||
678 | 77 | """Run an end-to-end integration tests of the non-LXC lpsetup story.""" | ||
679 | 78 | banner('Running (non-LXC) integration test.') | ||
680 | 79 | # Since the most common scenario is to have bzr whoami setup, we do that | ||
681 | 80 | # instead of providing the arguments directly to lpsetup. | ||
682 | 81 | on_remote(('bzr', 'whoami', '"Not A Real Person <no@example.com>"')) | ||
683 | 82 | on_remote('cd lpsetup; ./lp-setup init-host'.split()) | ||
684 | 83 | |||
685 | 84 | |||
686 | 85 | def tear_down(): | ||
687 | 86 | banner('Cleaning up.') | ||
688 | 87 | code = os.system('echo y | juju destroy-environment -e lpsetup-testing') | ||
689 | 88 | if code != 0: | ||
690 | 89 | raise RuntimeError('Destroying the test juju environment failed.') | ||
691 | 90 | |||
692 | 91 | |||
693 | 92 | def main(): | ||
694 | 93 | check_environment() | ||
695 | 94 | try: | ||
696 | 95 | set_up() | ||
697 | 96 | try: | ||
698 | 97 | do_test() | ||
699 | 98 | except: | ||
700 | 99 | banner('Test failed. Sorry.') | ||
701 | 100 | return 1 | ||
745 | 101 | else: | 60 | else: |
750 | 102 | banner('Test succeeded.') | 61 | raise RuntimeError('starting the instance took too long') |
751 | 103 | return 0 | 62 | |
752 | 104 | finally: | 63 | # Even though the instance-state is "running", it's still not ready, so |
753 | 105 | tear_down() | 64 | # wait a little while before continuing. |
754 | 65 | time.sleep(30) | ||
755 | 66 | |||
756 | 67 | self.on_remote('sudo apt-add-repository --yes ppa:yellow/ppa') | ||
757 | 68 | self.on_remote('sudo apt-get update') | ||
758 | 69 | self.on_remote('sudo apt-get install python-shelltoolbox') | ||
759 | 70 | check_call('juju scp -o StrictHostKeyChecking=no' | ||
760 | 71 | ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing' | ||
761 | 72 | ' -r . 1:lpsetup'.split()) | ||
762 | 73 | |||
763 | 74 | def do_test(self): | ||
764 | 75 | """Run an end-to-end integration tests of the non-LXC lpsetup story.""" | ||
765 | 76 | # Since the most common scenario is to have bzr whoami setup, we do | ||
766 | 77 | # that instead of providing the arguments directly to lpsetup. | ||
767 | 78 | super(NonLXCIntegrationTest, self).do_test() | ||
768 | 79 | self.on_remote( | ||
769 | 80 | ('bzr', 'whoami', '"Not A Real Person <no@example.com>"')) | ||
770 | 81 | self.on_remote('cd lpsetup; ./lp-setup init-host'.split()) | ||
771 | 82 | |||
772 | 83 | def tear_down(self): | ||
773 | 84 | super(NonLXCIntegrationTest, self).tear_down() | ||
774 | 85 | code = os.system( | ||
775 | 86 | 'echo y | juju destroy-environment -e lpsetup-testing') | ||
776 | 87 | if code != 0: | ||
777 | 88 | raise RuntimeError('Destroying the test juju environment failed.') | ||
778 | 106 | 89 | ||
779 | 107 | 90 | ||
780 | 108 | if __name__ == '__main__': | 91 | if __name__ == '__main__': |
782 | 109 | sys.exit(main()) | 92 | sys.exit(NonLXCIntegrationTest().run()) |
783 | 110 | 93 | ||
784 | === modified file 'lpsetup/tests/subcommands/test_finish_inithost.py' | |||
785 | --- lpsetup/tests/subcommands/test_finish_inithost.py 2012-07-12 18:23:37 +0000 | |||
786 | +++ lpsetup/tests/subcommands/test_finish_inithost.py 2012-07-19 21:00:25 +0000 | |||
787 | @@ -19,9 +19,10 @@ | |||
788 | 19 | 19 | ||
789 | 20 | 20 | ||
790 | 21 | def get_arguments(): | 21 | def get_arguments(): |
792 | 22 | code_dir = '~/' + get_random_string() | 22 | repo = '~/' + get_random_string() |
793 | 23 | checkout = get_random_string() | ||
794 | 23 | user = get_random_string() | 24 | user = get_random_string() |
796 | 24 | return ('-c', code_dir, '-u', user) | 25 | return ('-r', repo, '--checkout-name', checkout, '-u', user) |
797 | 25 | 26 | ||
798 | 26 | 27 | ||
799 | 27 | class FinishInitHostTest(StepsBasedSubCommandTestMixin, unittest.TestCase): | 28 | class FinishInitHostTest(StepsBasedSubCommandTestMixin, unittest.TestCase): |
800 | @@ -31,6 +32,7 @@ | |||
801 | 31 | expected_handlers = ( | 32 | expected_handlers = ( |
802 | 32 | handlers.handle_user, | 33 | handlers.handle_user, |
803 | 33 | handlers.handle_directories, | 34 | handlers.handle_directories, |
804 | 35 | handlers.handle_code_dir, | ||
805 | 34 | ) | 36 | ) |
806 | 35 | 37 | ||
807 | 36 | @property | 38 | @property |
808 | 37 | 39 | ||
809 | === modified file 'lpsetup/tests/subcommands/test_install_lxc.py' | |||
810 | --- lpsetup/tests/subcommands/test_install_lxc.py 2012-07-12 22:12:09 +0000 | |||
811 | +++ lpsetup/tests/subcommands/test_install_lxc.py 2012-07-19 21:00:25 +0000 | |||
812 | @@ -34,7 +34,8 @@ | |||
813 | 34 | 34 | ||
814 | 35 | finish_inithost_in_lxc_step = ( | 35 | finish_inithost_in_lxc_step = ( |
815 | 36 | install_lxc.finish_inithost_in_lxc, [ | 36 | install_lxc.finish_inithost_in_lxc, [ |
817 | 37 | 'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'code_dir', | 37 | 'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'repository', |
818 | 38 | 'checkout_name', | ||
819 | 38 | ]) | 39 | ]) |
820 | 39 | 40 | ||
821 | 40 | 41 | ||
822 | @@ -52,6 +53,7 @@ | |||
823 | 52 | expected_arguments = get_arguments() | 53 | expected_arguments = get_arguments() |
824 | 53 | expected_handlers = test_initlxc.InitLxcTest.expected_handlers + ( | 54 | expected_handlers = test_initlxc.InitLxcTest.expected_handlers + ( |
825 | 54 | handlers.handle_directories, | 55 | handlers.handle_directories, |
826 | 56 | handlers.handle_code_dir, | ||
827 | 55 | handlers.handle_source, | 57 | handlers.handle_source, |
828 | 56 | ) | 58 | ) |
829 | 57 | expected_steps = test_initlxc.InitLxcTest.expected_steps + ( | 59 | expected_steps = test_initlxc.InitLxcTest.expected_steps + ( |
830 | 58 | 60 | ||
831 | === modified file 'lpsetup/tests/subcommands/test_update.py' | |||
832 | --- lpsetup/tests/subcommands/test_update.py 2012-07-13 15:55:40 +0000 | |||
833 | +++ lpsetup/tests/subcommands/test_update.py 2012-07-19 21:00:25 +0000 | |||
834 | @@ -18,15 +18,15 @@ | |||
835 | 18 | return ( | 18 | return ( |
836 | 19 | '--external-path', get_random_string(), | 19 | '--external-path', get_random_string(), |
837 | 20 | '--use-http', | 20 | '--use-http', |
840 | 21 | '-e', '../devel', | 21 | '--repository', get_random_string(), |
841 | 22 | '-W', '~/' + get_random_string(), | 22 | '--checkout-name', get_random_string(), |
842 | 23 | ) | 23 | ) |
843 | 24 | 24 | ||
844 | 25 | init_dir_step = ( | 25 | init_dir_step = ( |
846 | 26 | update.initialize_directories, ['working_dir', 'external_path']) | 26 | update.initialize_directories, ['code_dir', 'external_path']) |
847 | 27 | update_dep_step = ( | 27 | update_dep_step = ( |
850 | 28 | update.update_dependencies, ['working_dir', 'external_path', 'use_http']) | 28 | update.update_dependencies, ['code_dir', 'external_path', 'use_http']) |
851 | 29 | update_tree_step = (update.update_tree, ['working_dir']) | 29 | update_tree_step = (update.update_tree, ['code_dir']) |
852 | 30 | 30 | ||
853 | 31 | 31 | ||
854 | 32 | class UpdateTest(StepsBasedSubCommandTestMixin, unittest.TestCase): | 32 | class UpdateTest(StepsBasedSubCommandTestMixin, unittest.TestCase): |
855 | @@ -35,7 +35,9 @@ | |||
856 | 35 | sub_command_class = update.SubCommand | 35 | sub_command_class = update.SubCommand |
857 | 36 | expected_arguments = get_arguments() | 36 | expected_arguments = get_arguments() |
858 | 37 | expected_handlers = ( | 37 | expected_handlers = ( |
860 | 38 | handlers.handle_working_dir, | 38 | handlers.handle_user, |
861 | 39 | handlers.handle_directories, | ||
862 | 40 | handlers.handle_code_dir, | ||
863 | 39 | ) | 41 | ) |
864 | 40 | expected_steps = ( | 42 | expected_steps = ( |
865 | 41 | init_dir_step, | 43 | init_dir_step, |
866 | 42 | 44 | ||
867 | === modified file 'pre-commit.sh' | |||
868 | --- pre-commit.sh 2012-07-11 15:50:01 +0000 | |||
869 | +++ pre-commit.sh 2012-07-19 21:00:25 +0000 | |||
870 | @@ -1,4 +1,4 @@ | |||
871 | 1 | #!/bin/bash | 1 | #!/bin/bash |
872 | 2 | 2 | ||
875 | 3 | pyfiles=`find . -name "*.py" | grep -v distribute_setup.py` | 3 | pyfiles=`find . -name build -prune -o -name "*.py" | grep -v distribute_setup.py` |
876 | 4 | pocketlint $pyfiles && pep8 $pyfiles && nosetests | 4 | pocketlint $pyfiles && pep8 --exclude=build $pyfiles && nosetests |
The LXC-base test can re-use an existing launchpad repository (~/launchpad- testing) if it exists, which speeds things up considerably. With an existing repository the test took 9m13.