~abentley/juju-ci-tools/client-from-config-4

« back to all changes in this revision

Viewing changes to tests/test_industrial_test.py

  • Committer: Martin Packman
  • Date: 2015-11-17 14:19:06 UTC
  • mto: This revision was merged to the branch mainline in revision 1155.
  • Revision ID: martin.packman@canonical.com-20151117141906-a4zmuqre72s7fyf1
Sample script for generating image streams for rackspace

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# coding=utf-8
2
2
from argparse import Namespace
3
3
from collections import OrderedDict
4
 
from contextlib import (
5
 
    closing,
6
 
    contextmanager,
7
 
    )
8
 
import json
 
4
from contextlib import contextmanager
9
5
import os
10
6
from tempfile import (
11
7
    mkdtemp,
22
18
import yaml
23
19
 
24
20
from industrial_test import (
25
 
    AttemptSuite,
26
 
    AttemptSuiteFactory,
27
21
    BACKUP,
28
22
    BackupRestoreAttempt,
29
23
    BootstrapAttempt,
39
33
    maybe_write_json,
40
34
    MultiIndustrialTest,
41
35
    parse_args,
42
 
    PrepareUpgradeJujuAttempt,
43
36
    QUICK,
44
37
    StageInfo,
45
38
    SteppedStageAttempt,
49
42
from jujuconfig import get_euca_env
50
43
from jujupy import (
51
44
    EnvJujuClient,
52
 
    EnvJujuClient1X,
53
45
    get_timeout_prefix,
54
 
    JujuData,
55
 
    KVM_MACHINE,
56
 
    LXC_MACHINE,
57
 
    LXD_MACHINE,
58
46
    SimpleEnvironment,
59
47
    Status,
60
48
    _temp_env,
62
50
from substrate import AWSAccount
63
51
from tests import (
64
52
    FakeHomeTestCase,
65
 
    parse_error,
66
53
    TestCase,
67
 
    use_context,
68
54
)
69
 
from tests.test_deploy_stack import FakeBootstrapManager
70
 
from test_jujupy import (
71
 
    assert_juju_call,
72
 
    fake_juju_client,
73
 
    FakePopen,
74
 
    observable_temp_file,
75
 
    )
 
55
from test_jujupy import assert_juju_call
76
56
from test_substrate import (
77
57
    get_aws_env,
78
58
    get_os_config,
79
59
    make_os_security_group_instance,
80
60
    make_os_security_groups,
81
61
    )
82
 
from utility import (
83
 
    LoggedException,
84
 
    temp_dir,
85
 
    )
 
62
from tests import parse_error
86
63
 
87
64
 
88
65
__metaclass__ = type
89
66
 
90
67
 
91
 
def get_aws_juju_data():
92
 
    aws_env = get_aws_env()
93
 
    return JujuData(aws_env.environment, aws_env.config)
94
 
 
95
 
 
96
68
class JujuPyTestCase(FakeHomeTestCase):
97
69
 
98
70
    def setUp(self):
147
119
    """
148
120
    kwargs = {}
149
121
    if len(statuses) > 1:
150
 
        kwargs['side_effect'] = (Status.from_text(json.dumps(s))
 
122
        kwargs['side_effect'] = (Status.from_text(yaml.safe_dump(s))
151
123
                                 for s in statuses).next
152
124
    else:
153
 
        kwargs['return_value'] = Status.from_text(json.dumps(statuses[0]))
 
125
        kwargs['return_value'] = Status.from_text(yaml.safe_dump(statuses[0]))
154
126
    if client is not None:
155
127
        return patch.object(client, 'get_status', autospec=True, **kwargs)
156
128
    return patch('jujupy.EnvJujuClient.get_status', autospec=True, **kwargs)
171
143
            args = parse_args(['rai', 'new-juju'])
172
144
        self.assertRegexpMatches(
173
145
            stderr.getvalue(), '.*error: too few arguments.*')
174
 
        with parse_error(self) as stderr:
175
 
            args = parse_args(['rai', 'new-juju', QUICK])
176
 
        self.assertRegexpMatches(
177
 
            stderr.getvalue(), '.*error: too few arguments.*')
178
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir'])
 
146
        args = parse_args(['rai', 'new-juju', QUICK])
179
147
        self.assertEqual(args.env, 'rai')
180
148
        self.assertEqual(args.new_juju_path, 'new-juju')
181
 
        self.assertEqual(args.log_dir, 'log-dir')
182
149
        self.assertEqual(args.suite, [QUICK])
183
 
        self.assertIs(args.agent_stream, None)
184
150
 
185
151
    def test_parse_args_attempts(self):
186
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir'])
 
152
        args = parse_args(['rai', 'new-juju', QUICK])
187
153
        self.assertEqual(args.attempts, 2)
188
 
        args = parse_args(['rai', 'new-juju', '--attempts', '3', QUICK,
189
 
                           'log-dir'])
 
154
        args = parse_args(['rai', 'new-juju', '--attempts', '3', QUICK])
190
155
        self.assertEqual(args.attempts, 3)
191
156
 
192
157
    def test_parse_args_json_file(self):
193
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir'])
 
158
        args = parse_args(['rai', 'new-juju', QUICK])
194
159
        self.assertIs(args.json_file, None)
195
 
        args = parse_args(['rai', 'new-juju', '--json-file', 'foobar', QUICK,
196
 
                           'log-dir'])
 
160
        args = parse_args(['rai', 'new-juju', '--json-file', 'foobar', QUICK])
197
161
        self.assertEqual(args.json_file, 'foobar')
198
162
 
199
163
    def test_parse_args_suite(self):
200
 
        args = parse_args(['rai', 'new-juju', 'full', 'log-dir'])
 
164
        args = parse_args(['rai', 'new-juju', 'full'])
201
165
        self.assertEqual(args.suite, [FULL])
202
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir'])
 
166
        args = parse_args(['rai', 'new-juju', QUICK])
203
167
        self.assertEqual(args.suite, [QUICK])
204
 
        args = parse_args(['rai', 'new-juju', DENSITY, 'log-dir'])
 
168
        args = parse_args(['rai', 'new-juju', DENSITY])
205
169
        self.assertEqual(args.suite, [DENSITY])
206
 
        args = parse_args(['rai', 'new-juju', BACKUP, 'log-dir'])
 
170
        args = parse_args(['rai', 'new-juju', BACKUP])
207
171
        self.assertEqual(args.suite, [BACKUP])
208
172
        with parse_error(self) as stderr:
209
 
            args = parse_args(['rai', 'new-juju', 'foo', 'log-dir'])
 
173
            args = parse_args(['rai', 'new-juju', 'foo'])
210
174
        self.assertRegexpMatches(
211
175
            stderr.getvalue(), ".*argument suite: invalid choice: 'foo'.*")
212
176
 
213
177
    def test_parse_args_multi_suite(self):
214
 
        args = parse_args(['rai', 'new-juju', 'full,quick', 'log-dir'])
 
178
        args = parse_args(['rai', 'new-juju', 'full,quick'])
215
179
        self.assertEqual(args.suite, [FULL, QUICK])
216
180
        with parse_error(self) as stderr:
217
 
            args = parse_args(['rai', 'new-juju', 'full,foo', 'log-dir'])
 
181
            args = parse_args(['rai', 'new-juju', 'full,foo'])
218
182
        self.assertRegexpMatches(
219
183
            stderr.getvalue(), ".*argument suite: invalid choice: 'foo'.*")
220
184
 
221
185
    def test_parse_args_agent_url(self):
222
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir'])
 
186
        args = parse_args(['rai', 'new-juju', QUICK])
223
187
        self.assertEqual(args.new_agent_url, None)
224
188
        args = parse_args(['rai', 'new-juju', '--new-agent-url',
225
 
                           'http://example.org', QUICK, 'log-dir'])
 
189
                           'http://example.org', QUICK])
226
190
        self.assertEqual(args.new_agent_url, 'http://example.org')
227
191
 
228
192
    def test_parse_args_debug(self):
229
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir'])
 
193
        args = parse_args(['rai', 'new-juju', QUICK])
230
194
        self.assertEqual(args.debug, False)
231
 
        args = parse_args(['rai', 'new-juju', '--debug', QUICK, 'log-dir'])
 
195
        args = parse_args(['rai', 'new-juju', '--debug', QUICK])
232
196
        self.assertEqual(args.debug, True)
233
197
 
234
198
    def test_parse_args_old_stable(self):
235
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir',
236
 
                           '--old-stable', 'asdf'])
 
199
        args = parse_args(['rai', 'new-juju', QUICK, '--old-stable', 'asdf'])
237
200
        self.assertEqual(args.old_stable, 'asdf')
238
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir'])
239
 
        self.assertIs(args.old_stable, None)
240
 
 
241
 
    def test_parse_args_agent_stream(self):
242
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir',
243
 
                           '--agent-stream', 'asdf'])
244
 
        self.assertEqual(args.agent_stream, 'asdf')
245
 
        args = parse_args(['rai', 'new-juju', QUICK, 'log-dir'])
 
201
        args = parse_args(['rai', 'new-juju', QUICK])
246
202
        self.assertIs(args.old_stable, None)
247
203
 
248
204
 
249
205
class FakeStepAttempt:
250
206
 
251
 
    def __init__(self, result, new_path=None):
 
207
    def __init__(self, result):
252
208
        self.result = result
253
 
        self.stage = StageInfo(result[0][0], '{} title'.format(result[0][0]))
254
 
        self.new_path = new_path
255
 
 
256
 
    @classmethod
257
 
    def from_result(cls, old, new, test_id='foo-id', new_path=None):
258
 
        """Alternate constructor for backwards-compatibility.
259
 
 
260
 
        Allows tests that used FakeAttempt to be adapted with minimal changes.
261
 
        """
262
 
        return cls([(test_id, old, new)], new_path)
263
 
 
264
 
    def __eq__(self, other):
265
 
        return (
266
 
            type(self) == type(other) and self.result == other.result)
267
 
 
268
 
    def get_test_info(self):
269
 
        return {self.result[0][0]: {'title': self.result[0][0]}}
270
 
 
271
 
    def get_bootstrap_client(self, client):
272
 
        return client
273
209
 
274
210
    def iter_test_results(self, old, new):
275
211
        return iter(self.result)
276
212
 
277
 
    def iter_steps(self, client):
278
 
        yield self.stage.as_result()
279
 
        if self.new_path is not None and client.full_path == self.new_path:
280
 
            result_value = self.result[0][2]
281
 
        else:
282
 
            result_value = self.result[0][1]
283
 
        if isinstance(result_value, BaseException):
284
 
            raise result_value
285
 
        yield self.stage.as_result(result_value)
 
213
 
 
214
class FakeAttempt(FakeStepAttempt):
 
215
 
 
216
    def __init__(self, old_result, new_result, test_id='foo-id'):
 
217
        super(FakeAttempt, self).__init__([(test_id, old_result, new_result)])
 
218
 
 
219
    def do_stage(self, old_client, new_client):
 
220
        return self.result[0]
286
221
 
287
222
 
288
223
class FakeAttemptClass:
292
227
    normal methods on FakeAttemptClass.
293
228
    """
294
229
 
295
 
    def factory(self, upgrade_sequence, attempt_stream):
 
230
    def factory(self, upgrade_sequence):
296
231
        return self()
297
232
 
298
 
    def __init__(self, title, *result, **kwargs):
 
233
    def __init__(self, title, *result):
299
234
        self.title = title
300
235
        self.test_id = '{}-id'.format(title)
301
236
        self.result = result
302
 
        self.new_path = kwargs.get('new_path')
303
237
 
304
238
    def get_test_info(self):
305
239
        return {self.test_id: {'title': self.title}}
306
240
 
307
241
    def __call__(self):
308
 
        return FakeStepAttempt.from_result(*self.result, test_id=self.test_id,
309
 
                                           new_path=self.new_path)
 
242
        return FakeAttempt(*self.result, test_id=self.test_id)
 
243
 
 
244
 
 
245
class StubJujuClient:
 
246
 
 
247
    def destroy_environment(self, delete_jenv=False):
 
248
        pass
310
249
 
311
250
 
312
251
@contextmanager
318
257
        yield
319
258
 
320
259
 
321
 
def fake_bootstrap_manager(self, temp_env_name, client, *args, **kwargs):
322
 
    return FakeBootstrapManager(client)
323
 
 
324
 
 
325
260
class TestMultiIndustrialTest(TestCase):
326
261
 
327
262
    def test_from_args(self):
328
263
        args = Namespace(
329
264
            env='foo', new_juju_path='new-path', attempts=7, suite=[DENSITY],
330
 
            log_dir='log-dir', new_agent_url=None, debug=False,
331
 
            old_stable=None, agent_stream=None)
 
265
            new_agent_url=None, debug=False, old_stable=None)
332
266
        with temp_env('foo'):
333
267
            mit = MultiIndustrialTest.from_args(args, QUICK)
334
268
        self.assertEqual(mit.env, 'foo')
335
269
        self.assertEqual(mit.new_juju_path, 'new-path')
336
270
        self.assertEqual(mit.attempt_count, 7)
337
271
        self.assertEqual(mit.max_attempts, 14)
338
 
        self.assertEqual(mit.log_parent_dir, 'log-dir')
339
 
        self.assertIs(mit.agent_stream, None)
340
272
        self.assertEqual(
341
 
            mit.stages, AttemptSuiteFactory([]))
 
273
            mit.stages, [BootstrapAttempt, DestroyEnvironmentAttempt])
342
274
        args = Namespace(
343
275
            env='bar', new_juju_path='new-path2', attempts=6, suite=[FULL],
344
 
            log_dir='log-dir2', new_agent_url=None, debug=False,
345
 
            old_stable=None, agent_stream=None)
 
276
            new_agent_url=None, debug=False, old_stable=None)
346
277
        with temp_env('bar'):
347
278
            mit = MultiIndustrialTest.from_args(args, FULL)
348
279
        self.assertEqual(mit.env, 'bar')
349
280
        self.assertEqual(mit.new_juju_path, 'new-path2')
350
281
        self.assertEqual(mit.attempt_count, 6)
351
282
        self.assertEqual(mit.max_attempts, 12)
352
 
        self.assertEqual(mit.log_parent_dir, 'log-dir2')
353
 
        self.assertIs(mit.agent_stream, None)
354
283
        self.assertEqual(
355
 
            mit.stages, AttemptSuiteFactory([
356
 
                UpgradeCharmAttempt, DeployManyAttempt,
357
 
                BackupRestoreAttempt, EnsureAvailabilityAttempt]))
 
284
            mit.stages, [
 
285
                BootstrapAttempt, UpgradeCharmAttempt, DeployManyAttempt,
 
286
                BackupRestoreAttempt, EnsureAvailabilityAttempt,
 
287
                DestroyEnvironmentAttempt])
358
288
 
359
289
    def test_from_args_maas(self):
360
290
        args = Namespace(
361
 
            env='foo', new_juju_path='new-path', log_dir='log-dir',
362
 
            attempts=7, new_agent_url=None, debug=False, old_stable=None,
363
 
            agent_stream=None)
 
291
            env='foo', new_juju_path='new-path', attempts=7,
 
292
            new_agent_url=None, debug=False, old_stable=None)
364
293
        with temp_env('foo', {'type': 'maas'}):
365
294
            mit = MultiIndustrialTest.from_args(args, DENSITY)
366
295
        self.assertEqual(
367
 
            mit.stages, AttemptSuiteFactory([DeployManyAttempt]))
 
296
            mit.stages, [
 
297
                BootstrapAttempt, DeployManyAttempt,
 
298
                DestroyEnvironmentAttempt])
368
299
 
369
300
    def test_from_args_debug(self):
370
301
        args = Namespace(
371
 
            env='foo', new_juju_path='new-path', log_dir='log-dir',
372
 
            attempts=7, new_agent_url=None, debug=False, old_stable=None,
373
 
            agent_stream=None)
 
302
            env='foo', new_juju_path='new-path', attempts=7,
 
303
            new_agent_url=None, debug=False, old_stable=None)
374
304
        with temp_env('foo', {'type': 'maas'}):
375
305
            mit = MultiIndustrialTest.from_args(args, DENSITY)
376
306
            self.assertEqual(mit.debug, False)
380
310
 
381
311
    def test_from_args_really_old_path(self):
382
312
        args = Namespace(
383
 
            env='foo', new_juju_path='new-path', log_dir='log-dir',
384
 
            attempts=7, new_agent_url=None, debug=False,
385
 
            old_stable='really-old-path', agent_stream=None)
 
313
            env='foo', new_juju_path='new-path', attempts=7,
 
314
            new_agent_url=None, debug=False, old_stable='really-old-path')
386
315
        with temp_env('foo'):
387
316
            mit = MultiIndustrialTest.from_args(args, FULL)
388
317
        self.assertEqual(mit.really_old_path, 'really-old-path')
389
318
        args = Namespace(
390
 
            env='bar', new_juju_path='new-path2', log_dir='log-dir',
391
 
            attempts=6, new_agent_url=None, debug=False, old_stable=None,
392
 
            agent_stream=None)
 
319
            env='bar', new_juju_path='new-path2', attempts=6,
 
320
            new_agent_url=None, debug=False, old_stable=None)
393
321
        with temp_env('bar'):
394
322
            mit = MultiIndustrialTest.from_args(args, FULL)
395
323
        self.assertIs(mit.really_old_path, None)
396
324
 
397
 
    def test_from_args_agent_stream(self):
398
 
        args = Namespace(
399
 
            env='foo', new_juju_path='new-path', log_dir='log-dir',
400
 
            attempts=7, new_agent_url=None, debug=False, old_stable=None,
401
 
            agent_stream='foo-stream')
402
 
        with temp_env('foo', {'type': 'maas'}):
403
 
            mit = MultiIndustrialTest.from_args(args, DENSITY)
404
 
            self.assertEqual(mit.debug, False)
405
 
            args.debug = True
406
 
            mit = MultiIndustrialTest.from_args(args, DENSITY)
407
 
            self.assertEqual(mit.agent_stream, 'foo-stream')
 
325
    def test_get_stages(self):
 
326
        self.assertEqual(
 
327
            MultiIndustrialTest.get_stages(QUICK, {'type': 'foo'}),
 
328
            [BootstrapAttempt, DestroyEnvironmentAttempt])
 
329
 
 
330
        self.assertEqual(
 
331
            MultiIndustrialTest.get_stages(FULL, {'type': 'foo'}), [
 
332
                BootstrapAttempt, UpgradeCharmAttempt, DeployManyAttempt,
 
333
                BackupRestoreAttempt, EnsureAvailabilityAttempt,
 
334
                DestroyEnvironmentAttempt])
 
335
        self.assertEqual(
 
336
            MultiIndustrialTest.get_stages(DENSITY, {'type': 'foo'}), [
 
337
                BootstrapAttempt, DeployManyAttempt,
 
338
                DestroyEnvironmentAttempt])
 
339
        self.assertEqual(
 
340
            MultiIndustrialTest.get_stages(BACKUP, {'type': 'foo'}), [
 
341
                BootstrapAttempt, BackupRestoreAttempt,
 
342
                DestroyEnvironmentAttempt])
 
343
 
 
344
    def test_get_stages_maas(self):
 
345
        self.assertEqual(
 
346
            MultiIndustrialTest.get_stages(QUICK, {'type': 'maas'}),
 
347
            [BootstrapAttempt, DestroyEnvironmentAttempt])
 
348
        self.assertEqual(
 
349
            MultiIndustrialTest.get_stages(FULL, {'type': 'maas'}), [
 
350
                BootstrapAttempt, UpgradeCharmAttempt,
 
351
                DeployManyAttempt, BackupRestoreAttempt,
 
352
                EnsureAvailabilityAttempt, DestroyEnvironmentAttempt])
 
353
        self.assertEqual(
 
354
            MultiIndustrialTest.get_stages(DENSITY, {'type': 'maas'}), [
 
355
                BootstrapAttempt, DeployManyAttempt,
 
356
                DestroyEnvironmentAttempt])
408
357
 
409
358
    def test_density_suite(self):
410
359
        args = Namespace(
411
360
            env='foo', new_juju_path='new-path', attempts=7,
412
 
            log_dir='log-dir', new_agent_url=None, debug=False,
413
 
            old_stable=None, agent_stream=None)
 
361
            new_agent_url=None, debug=False, old_stable=None)
414
362
        with temp_env('foo'):
415
363
            mit = MultiIndustrialTest.from_args(args, DENSITY)
416
364
        self.assertEqual(
417
 
            mit.stages, AttemptSuiteFactory([DeployManyAttempt]))
 
365
            mit.stages, [BootstrapAttempt, DeployManyAttempt,
 
366
                         DestroyEnvironmentAttempt])
418
367
 
419
368
    def test_backup_suite(self):
420
369
        args = Namespace(
421
370
            env='foo', new_juju_path='new-path', attempts=7,
422
 
            log_dir='log-dir', new_agent_url=None, debug=False,
423
 
            old_stable=None, agent_stream=None)
 
371
            new_agent_url=None, debug=False, old_stable=None)
424
372
        with temp_env('foo'):
425
373
            mit = MultiIndustrialTest.from_args(args, BACKUP)
426
374
        self.assertEqual(
427
 
            mit.stages, AttemptSuiteFactory([BackupRestoreAttempt]))
 
375
            mit.stages, [BootstrapAttempt, BackupRestoreAttempt,
 
376
                         DestroyEnvironmentAttempt])
428
377
 
429
378
    def test_from_args_new_agent_url(self):
430
379
        args = Namespace(
431
380
            env='foo', new_juju_path='new-path', attempts=7,
432
 
            log_dir='log-dir', new_agent_url='http://example.net',
433
 
            debug=False, old_stable=None, agent_stream=None)
 
381
            new_agent_url='http://example.net', debug=False, old_stable=None)
434
382
        with temp_env('foo'):
435
383
            mit = MultiIndustrialTest.from_args(args, suite=QUICK)
436
384
        self.assertEqual(mit.new_agent_url, 'http://example.net')
437
385
 
438
386
    def test_init(self):
439
387
        mit = MultiIndustrialTest('foo-env', 'bar-path', [
440
 
            DestroyEnvironmentAttempt, BootstrapAttempt], 'log-dir', 5)
 
388
            DestroyEnvironmentAttempt, BootstrapAttempt], 5)
441
389
        self.assertEqual(mit.env, 'foo-env')
442
390
        self.assertEqual(mit.new_juju_path, 'bar-path')
443
391
        self.assertEqual(mit.stages, [DestroyEnvironmentAttempt,
444
392
                                      BootstrapAttempt])
445
393
        self.assertEqual(mit.attempt_count, 5)
446
 
        self.assertEqual(mit.log_parent_dir, 'log-dir')
447
394
 
448
395
    def test_make_results(self):
449
 
        mit = MultiIndustrialTest('foo-env', 'bar-path', AttemptSuiteFactory([
450
 
            DestroyEnvironmentAttempt]), 5)
 
396
        mit = MultiIndustrialTest('foo-env', 'bar-path', [
 
397
            DestroyEnvironmentAttempt, BootstrapAttempt], 5)
451
398
        results = mit.make_results()
452
399
        self.assertEqual(results, {'results': [
453
400
            {'attempts': 0, 'old_failures': 0, 'new_failures': 0,
454
 
             'title': 'bootstrap', 'test_id': 'bootstrap', 'report_on': True},
455
 
            {'attempts': 0, 'old_failures': 0, 'new_failures': 0,
456
 
             'title': 'Prepare suite tests', 'test_id': 'prepare-suite',
457
 
             'report_on': False},
458
 
            {'attempts': 0, 'old_failures': 0, 'new_failures': 0,
459
401
             'title': 'destroy environment', 'test_id': 'destroy-env',
460
402
             'report_on': True},
461
403
            {'attempts': 0, 'old_failures': 0, 'new_failures': 0,
462
404
             'title': 'check substrate clean', 'test_id': 'substrate-clean',
463
405
             'report_on': True},
 
406
            {'attempts': 0, 'old_failures': 0, 'new_failures': 0,
 
407
             'title': 'bootstrap', 'test_id': 'bootstrap', 'report_on': True},
464
408
        ]})
465
409
 
466
410
    def test_make_results_report_on(self):
471
415
                return {'no-report': {
472
416
                    'title': 'No report', 'report_on': False}}
473
417
 
474
 
        mit = MultiIndustrialTest('foo-env', 'bar-path', AttemptSuiteFactory([
475
 
            NoReportOn]), 5)
 
418
        mit = MultiIndustrialTest('foo-env', 'bar-path', [
 
419
            BootstrapAttempt, NoReportOn], 5)
476
420
        results = mit.make_results()
477
421
        self.assertEqual(results, {'results': [
478
422
            {
484
428
                'new_failures': 0,
485
429
            },
486
430
            {
487
 
                'test_id': 'prepare-suite',
488
 
                'title': 'Prepare suite tests',
489
 
                'report_on': False,
490
 
                'attempts': 0,
491
 
                'old_failures': 0,
492
 
                'new_failures': 0,
493
 
            },
494
 
            {
495
431
                'test_id': 'no-report',
496
432
                'title': 'No report',
497
433
                'report_on': False,
499
435
                'old_failures': 0,
500
436
                'new_failures': 0,
501
437
            },
502
 
            {
503
 
                'test_id': 'destroy-env',
504
 
                'title': 'destroy environment',
505
 
                'report_on': True,
506
 
                'attempts': 0,
507
 
                'old_failures': 0,
508
 
                'new_failures': 0,
509
 
            },
510
 
            {
511
 
                'test_id': 'substrate-clean',
512
 
                'title': 'check substrate clean',
513
 
                'report_on': True,
514
 
                'attempts': 0,
515
 
                'old_failures': 0,
516
 
                'new_failures': 0,
517
 
            },
518
438
        ]})
519
439
 
520
440
    @staticmethod
521
441
    @contextmanager
522
442
    def patch_client(by_version):
523
 
        with patch('industrial_test.client_from_config',
524
 
                   side_effect=by_version):
 
443
        with patch('jujupy.EnvJujuClient.by_version', side_effect=by_version):
525
444
            with patch('jujupy.SimpleEnvironment.from_config',
526
445
                       side_effect=lambda x: SimpleEnvironment(x, {})):
527
446
                with patch.object(EnvJujuClient, 'get_full_path',
529
448
                    yield
530
449
 
531
450
    def test_make_industrial_test(self):
532
 
        mit = MultiIndustrialTest('foo-env', 'bar-path', AttemptSuiteFactory([
533
 
            DestroyEnvironmentAttempt]), 'log-dir', 5)
534
 
        with self.patch_client(
535
 
            lambda x, y=None, debug=False: fake_juju_client(
536
 
                JujuData(x, {}, juju_home=''), full_path=y)):
 
451
        mit = MultiIndustrialTest('foo-env', 'bar-path', [
 
452
            DestroyEnvironmentAttempt, BootstrapAttempt], 5)
 
453
        with self.patch_client(lambda x, y=None, debug=False: (x, y)):
537
454
            industrial = mit.make_industrial_test()
538
 
        old_client = industrial.old_client
539
 
        self.assertEqual((old_client.env, old_client.full_path), (
540
 
            JujuData('foo-env-old', {'name': 'foo-env-old'}, juju_home=''),
541
 
            None))
542
 
        new_client = industrial.new_client
543
 
        self.assertEqual((new_client.env, new_client.full_path), (
544
 
            JujuData('foo-env-new', {'name': 'foo-env-new'}, juju_home=''),
545
 
            'bar-path'))
546
 
        self.assertEqual(len(industrial.stage_attempts), 1)
547
 
        self.assertEqual([mit.stages], [sa.attempt_list for sa in
548
 
                         industrial.stage_attempts])
 
455
        self.assertEqual(industrial.old_client,
 
456
                         (SimpleEnvironment('foo-env-old', {}), None))
 
457
        self.assertEqual(industrial.new_client,
 
458
                         (SimpleEnvironment('foo-env-new', {}), 'bar-path'))
 
459
        self.assertEqual(len(industrial.stage_attempts), 2)
 
460
        for stage, attempt in zip(mit.stages, industrial.stage_attempts):
 
461
            self.assertIs(type(attempt), stage)
549
462
 
550
463
    def test_make_industrial_test_new_agent_url(self):
551
 
        mit = MultiIndustrialTest('foo-env', 'bar-path',
552
 
                                  AttemptSuiteFactory([]), 'log-dir',
 
464
        mit = MultiIndustrialTest('foo-env', 'bar-path', [],
553
465
                                  new_agent_url='http://example.com')
554
 
        with self.patch_client(
555
 
                lambda x, y=None, debug=False: fake_juju_client(full_path=y)):
 
466
        with self.patch_client(lambda x, y=None, debug=False: (x, y)):
556
467
            industrial = mit.make_industrial_test()
557
468
        self.assertEqual(
558
 
            (industrial.new_client.env, industrial.new_client.full_path), (
559
 
                JujuData('foo-env-new', {
560
 
                    'type': 'foo',
561
 
                    'default-series': 'angsty',
562
 
                    'region': 'bar',
563
 
                    'name': 'foo-env-new',
564
 
                    'tools-metadata-url': 'http://example.com',
565
 
                    }, 'foo'),
 
469
            industrial.new_client, (
 
470
                SimpleEnvironment('foo-env-new', {
 
471
                    'tools-metadata-url': 'http://example.com'}),
566
472
                'bar-path')
567
473
            )
568
474
 
569
475
    def test_make_industrial_test_debug(self):
570
 
        mit = MultiIndustrialTest('foo-env', 'bar-path',
571
 
                                  AttemptSuiteFactory([]), 'log-dir',
 
476
        mit = MultiIndustrialTest('foo-env', 'bar-path', [],
572
477
                                  new_agent_url='http://example.com')
573
478
 
574
479
        def side_effect(x, y=None, debug=False):
575
 
            return fake_juju_client(env=JujuData(x, {}, juju_home='x'),
576
 
                                    full_path=y, debug=debug)
 
480
            return debug
577
481
 
578
482
        with self.patch_client(side_effect):
579
483
            industrial = mit.make_industrial_test()
580
 
        self.assertEqual(industrial.new_client.debug, False)
581
 
        self.assertEqual(industrial.old_client.debug, False)
 
484
        self.assertEqual(industrial.new_client, False)
 
485
        self.assertEqual(industrial.old_client, False)
582
486
        mit.debug = True
583
487
        with self.patch_client(side_effect):
584
488
            industrial = mit.make_industrial_test()
585
 
        self.assertEqual(industrial.new_client.debug, True)
586
 
        self.assertEqual(industrial.old_client.debug, True)
 
489
        self.assertEqual(industrial.new_client, True)
 
490
        self.assertEqual(industrial.old_client, True)
587
491
 
588
492
    def test_update_results(self):
589
 
        mit = MultiIndustrialTest('foo-env', 'bar-path',
590
 
                                  AttemptSuiteFactory([]), 2)
 
493
        mit = MultiIndustrialTest('foo-env', 'bar-path', [
 
494
            DestroyEnvironmentAttempt, BootstrapAttempt], 2)
591
495
        results = mit.make_results()
592
 
        mit.update_results([('bootstrap', True, False)], results)
 
496
        mit.update_results([('destroy-env', True, False)], results)
593
497
        expected = {'results': [
594
 
            {'title': 'bootstrap', 'test_id': 'bootstrap',
 
498
            {'title': 'destroy environment', 'test_id': 'destroy-env',
595
499
             'attempts': 1, 'new_failures': 1, 'old_failures': 0,
596
500
             'report_on': True},
597
 
            {'title': 'Prepare suite tests', 'test_id': 'prepare-suite',
598
 
             'attempts': 0,
599
 
             'new_failures': 0, 'old_failures': 0, 'report_on': False},
600
 
            {'title': 'destroy environment', 'test_id': 'destroy-env',
601
 
             'attempts': 0,
 
501
            {'title': 'check substrate clean', 'test_id': 'substrate-clean',
 
502
             'attempts': 0, 'new_failures': 0, 'old_failures': 0,
 
503
             'report_on': True},
 
504
            {'title': 'bootstrap', 'test_id': 'bootstrap', 'attempts': 0,
602
505
             'new_failures': 0, 'old_failures': 0, 'report_on': True},
603
 
            {'title': 'check substrate clean', 'test_id': 'substrate-clean',
604
 
             'attempts': 0, 'new_failures': 0, 'old_failures': 0,
605
 
             'report_on': True},
606
506
            ]}
607
507
        self.assertEqual(results, expected)
608
 
        mit.update_results([
609
 
            ('bootstrap', True, True), ('prepare-suite', True, True),
610
 
            ('destroy-env', False, True), ('substrate-clean', True, True)
611
 
            ], results)
 
508
        mit.update_results(
 
509
            [('destroy-env', True, True), ('substrate-clean', True, True),
 
510
             ('bootstrap', False, True)],
 
511
            results)
612
512
        self.assertEqual(results, {'results': [
613
 
            {'title': 'bootstrap', 'test_id': 'bootstrap',
 
513
            {'title': 'destroy environment', 'test_id': 'destroy-env',
614
514
             'attempts': 2, 'new_failures': 1, 'old_failures': 0,
615
515
             'report_on': True},
616
 
            {'title': 'Prepare suite tests', 'test_id': 'prepare-suite',
617
 
             'attempts': 1, 'new_failures': 0, 'old_failures': 0,
618
 
             'report_on': False},
619
 
            {'title': 'destroy environment', 'test_id': 'destroy-env',
620
 
             'attempts': 1, 'new_failures': 0, 'old_failures': 1, 'report_on':
621
 
             True},
622
516
            {'title': 'check substrate clean', 'test_id': 'substrate-clean',
623
517
             'attempts': 1, 'new_failures': 0, 'old_failures': 0,
624
518
             'report_on': True},
 
519
            {'title': 'bootstrap', 'test_id': 'bootstrap', 'attempts': 1,
 
520
             'new_failures': 0, 'old_failures': 1, 'report_on': True},
625
521
            ]})
626
522
        mit.update_results(
627
 
            [('bootstrap', False, False), ('prepare-suite', True, True),
628
 
             ('destroy-env', False, False), ('substrate-clean', True, True)],
 
523
            [('destroy-env', False, False), ('substrate-clean', True, True),
 
524
             ('bootstrap', False, False)],
629
525
            results)
630
526
        expected = {'results': [
631
 
            {'title': 'bootstrap', 'test_id': 'bootstrap',
 
527
            {'title': 'destroy environment', 'test_id': 'destroy-env',
632
528
             'attempts': 2, 'new_failures': 1, 'old_failures': 0,
633
529
             'report_on': True},
634
 
            {'title': 'Prepare suite tests', 'test_id': 'prepare-suite',
635
 
             'attempts': 2, 'new_failures': 0, 'old_failures': 0,
636
 
             'report_on': False},
637
 
            {'title': 'destroy environment', 'test_id': 'destroy-env',
638
 
             'attempts': 2, 'new_failures': 1, 'old_failures': 2,
639
 
             'report_on': True},
640
530
            {'title': 'check substrate clean', 'test_id': 'substrate-clean',
641
531
             'attempts': 2, 'new_failures': 0, 'old_failures': 0,
642
532
             'report_on': True},
 
533
            {'title': 'bootstrap', 'test_id': 'bootstrap', 'attempts': 2,
 
534
             'new_failures': 1, 'old_failures': 2, 'report_on': True},
643
535
            ]}
644
536
        self.assertEqual(results, expected)
645
537
 
646
538
    def test_run_tests(self):
647
 
        log_dir = use_context(self, temp_dir())
648
 
        mit = MultiIndustrialTest('foo-env', 'bar-path', AttemptSuiteFactory([
649
 
            FakeAttemptClass('foo', True, True, new_path='bar-path'),
650
 
            FakeAttemptClass('bar', True, False, new_path='bar-path'),
651
 
            ]), log_dir, 5, 10)
 
539
        mit = MultiIndustrialTest('foo-env', 'bar-path', [
 
540
            FakeAttemptClass('foo', True, True),
 
541
            FakeAttemptClass('bar', True, False),
 
542
            ], 5, 10)
652
543
 
653
 
        def side_effect(env, full_path=None, debug=False):
654
 
            return fake_juju_client(None, full_path, debug)
 
544
        def side_effect(x, y=None, debug=False):
 
545
            return StubJujuClient()
655
546
 
656
547
        with self.patch_client(side_effect):
657
 
            with patch('industrial_test.BootstrapManager',
658
 
                       side_effect=fake_bootstrap_manager):
659
 
                results = mit.run_tests()
 
548
            results = mit.run_tests()
660
549
        self.assertEqual(results, {'results': [
661
 
            {'title': 'bootstrap', 'test_id': 'bootstrap', 'attempts': 5,
662
 
             'old_failures': 0, 'new_failures': 0, 'report_on': True},
663
 
            {'title': 'Prepare suite tests', 'test_id': 'prepare-suite',
664
 
             'attempts': 5, 'old_failures': 0, 'new_failures': 0,
665
 
             'report_on': False},
666
550
            {'title': 'foo', 'test_id': 'foo-id', 'attempts': 5,
667
551
             'old_failures': 0, 'new_failures': 0, 'report_on': True},
668
552
            {'title': 'bar', 'test_id': 'bar-id', 'attempts': 5,
669
553
             'old_failures': 0, 'new_failures': 5, 'report_on': True},
670
 
            {'title': 'destroy environment', 'test_id': 'destroy-env',
671
 
             'attempts': 0, 'old_failures': 0, 'new_failures': 0,
672
 
             'report_on': True},
673
 
            {'title': 'check substrate clean', 'test_id': 'substrate-clean',
674
 
             'attempts': 0, 'old_failures': 0, 'new_failures': 0,
675
 
             'report_on': True},
676
554
            ]})
677
555
 
678
556
    def test_run_tests_max_attempts(self):
679
 
        log_dir = use_context(self, temp_dir())
680
 
        mit = MultiIndustrialTest('foo-env', 'bar-path', AttemptSuiteFactory([
681
 
            FakeAttemptClass('foo', True, False, new_path='bar-path'),
682
 
            FakeAttemptClass('bar', True, False, new_path='bar-path'),
683
 
            ]), log_dir, 5, 6)
 
557
        mit = MultiIndustrialTest('foo-env', 'bar-path', [
 
558
            FakeAttemptClass('foo', True, False),
 
559
            FakeAttemptClass('bar', True, False),
 
560
            ], 5, 6)
684
561
 
685
 
        def side_effect(env, full_path=None, debug=False):
686
 
            return fake_juju_client(None, full_path, debug)
 
562
        def side_effect(x, y=None, debug=False):
 
563
            return StubJujuClient()
687
564
 
688
565
        with self.patch_client(side_effect):
689
 
            with patch('industrial_test.BootstrapManager',
690
 
                       side_effect=fake_bootstrap_manager):
691
 
                results = mit.run_tests()
 
566
            results = mit.run_tests()
692
567
        self.assertEqual(results, {'results': [
693
 
            {'title': 'bootstrap', 'test_id': 'bootstrap', 'attempts': 5,
694
 
             'old_failures': 0, 'new_failures': 0, 'report_on': True},
695
 
            {'title': 'Prepare suite tests', 'test_id': 'prepare-suite',
696
 
             'attempts': 5, 'old_failures': 0, 'new_failures': 0,
697
 
             'report_on': False},
698
568
            {'title': 'foo', 'test_id': 'foo-id', 'attempts': 5,
699
569
             'old_failures': 0, 'new_failures': 5, 'report_on': True},
700
570
            {'title': 'bar', 'test_id': 'bar-id', 'attempts': 0,
701
571
             'old_failures': 0, 'new_failures': 0, 'report_on': True},
702
 
            {'title': 'destroy environment', 'test_id': 'destroy-env',
703
 
             'attempts': 0, 'old_failures': 0, 'new_failures': 0,
704
 
             'report_on': True},
705
 
            {'title': 'check substrate clean', 'test_id': 'substrate-clean',
706
 
             'attempts': 0, 'old_failures': 0, 'new_failures': 0,
707
 
             'report_on': True},
708
572
            ]})
709
573
 
710
574
    def test_run_tests_max_attempts_less_than_attempt_count(self):
711
 
        log_dir = use_context(self, temp_dir())
712
 
        mit = MultiIndustrialTest(
713
 
            'foo-env', 'bar-path', AttemptSuiteFactory([
714
 
                FakeAttemptClass('foo', True, False, new_path='bar-path'),
715
 
                FakeAttemptClass('bar', True, False, new_path='bar-path')],
716
 
                ),
717
 
            log_dir, 5, 4)
 
575
        mit = MultiIndustrialTest('foo-env', 'bar-path', [
 
576
            FakeAttemptClass('foo', True, False),
 
577
            FakeAttemptClass('bar', True, False),
 
578
            ], 5, 4)
718
579
 
719
 
        def side_effect(env, full_path=None, debug=False):
720
 
            return fake_juju_client(None, full_path, debug)
 
580
        def side_effect(x, y=None, debug=False):
 
581
            return StubJujuClient()
721
582
 
722
583
        with self.patch_client(side_effect):
723
 
            with patch('industrial_test.BootstrapManager',
724
 
                       side_effect=fake_bootstrap_manager):
725
 
                results = mit.run_tests()
726
 
        expected = [
727
 
            {'title': 'bootstrap', 'test_id': 'bootstrap', 'attempts': 4,
728
 
             'old_failures': 0, 'new_failures': 0, 'report_on': True},
729
 
            {'title': 'Prepare suite tests', 'test_id': 'prepare-suite',
730
 
             'attempts': 4, 'old_failures': 0, 'new_failures': 0,
731
 
             'report_on': False},
 
584
            results = mit.run_tests()
 
585
        self.assertEqual(results, {'results': [
732
586
            {'title': 'foo', 'test_id': 'foo-id', 'attempts': 4,
733
587
             'old_failures': 0, 'new_failures': 4, 'report_on': True},
734
588
            {'title': 'bar', 'test_id': 'bar-id', 'attempts': 0,
735
589
             'old_failures': 0, 'new_failures': 0, 'report_on': True},
736
 
            {'title': 'destroy environment', 'test_id': 'destroy-env',
737
 
             'attempts': 0, 'old_failures': 0, 'new_failures': 0,
738
 
             'report_on': True},
739
 
            {'title': 'check substrate clean', 'test_id': 'substrate-clean',
740
 
             'attempts': 0, 'old_failures': 0, 'new_failures': 0,
741
 
             'report_on': True},
742
 
            ]
743
 
        self.assertEqual(results, {'results': expected})
 
590
            ]})
744
591
 
745
592
    @staticmethod
746
593
    def get_results_1():
847
694
 
848
695
    def test_from_args(self):
849
696
        def side_effect(x, y=None, debug=False):
850
 
            return fake_juju_client(env=JujuData(x, {}), full_path=y)
851
 
        with patch('industrial_test.client_from_config',
852
 
                   side_effect=side_effect):
853
 
            industrial = IndustrialTest.from_args(
854
 
                'foo', 'new-juju-path', [])
 
697
            return (x, y)
 
698
        with patch('jujupy.EnvJujuClient.by_version', side_effect=side_effect):
 
699
            with patch('jujupy.SimpleEnvironment.from_config',
 
700
                       side_effect=lambda x: SimpleEnvironment(x, {})):
 
701
                industrial = IndustrialTest.from_args(
 
702
                    'foo', 'new-juju-path', [])
855
703
        self.assertIsInstance(industrial, IndustrialTest)
856
 
        old_client = industrial.old_client
857
 
        self.assertEqual((old_client.env, old_client.full_path), (
858
 
            JujuData('foo-old', {'name': 'foo-old'}), None))
859
 
        new_client = industrial.new_client
860
 
        self.assertEqual((new_client.env, new_client.full_path), (
861
 
            JujuData('foo-new', {'name': 'foo-new'}),
862
 
            'new-juju-path'))
863
 
        self.assertNotEqual(old_client.env.environment,
864
 
                            new_client.env.environment)
 
704
        self.assertEqual(industrial.old_client,
 
705
                         (SimpleEnvironment('foo-old', {}), None))
 
706
        self.assertEqual(industrial.new_client,
 
707
                         (SimpleEnvironment('foo-new', {}), 'new-juju-path'))
 
708
        self.assertNotEqual(industrial.old_client[0].environment,
 
709
                            industrial.new_client[0].environment)
865
710
 
866
711
    def test_from_args_debug(self):
867
712
        def side_effect(x, y=None, debug=False):
868
 
            return fake_juju_client(full_path=y, debug=debug)
869
 
        with patch('industrial_test.client_from_config',
870
 
                   side_effect=side_effect):
 
713
            return debug
 
714
        with patch('jujupy.EnvJujuClient.by_version', side_effect=side_effect):
871
715
            with patch('jujupy.SimpleEnvironment.from_config'):
872
716
                industrial = IndustrialTest.from_args(
873
717
                    'foo', 'new-juju-path', [], debug=False)
874
 
                self.assertEqual(industrial.old_client.debug, False)
875
 
                self.assertEqual(industrial.new_client.debug, False)
 
718
                self.assertEqual(industrial.old_client, False)
 
719
                self.assertEqual(industrial.new_client, False)
876
720
                industrial = IndustrialTest.from_args(
877
721
                    'foo', 'new-juju-path', [], debug=True)
878
 
                self.assertEqual(industrial.old_client.debug, True)
879
 
                self.assertEqual(industrial.new_client.debug, True)
 
722
                self.assertEqual(industrial.old_client, True)
 
723
                self.assertEqual(industrial.new_client, True)
880
724
 
881
725
    def test_run_stages(self):
882
726
        old_client = FakeEnvJujuClient('old')
883
727
        new_client = FakeEnvJujuClient('new')
884
728
        industrial = IndustrialTest(old_client, new_client, [
885
 
            FakeStepAttempt.from_result(True, True),
886
 
            FakeStepAttempt.from_result(True, True)])
 
729
            FakeAttempt(True, True), FakeAttempt(True, True)])
887
730
        with patch('subprocess.call') as cc_mock:
888
731
            result = industrial.run_stages()
889
732
            self.assertItemsEqual(result, [('foo-id', True, True),
891
734
        self.assertEqual(len(cc_mock.mock_calls), 0)
892
735
 
893
736
    def test_run_stages_old_fail(self):
894
 
        old_client = fake_juju_client()
895
 
        new_client = fake_juju_client(full_path='bar-path')
 
737
        old_client = FakeEnvJujuClient('old')
 
738
        new_client = FakeEnvJujuClient('new')
896
739
        industrial = IndustrialTest(old_client, new_client, [
897
 
            FakeStepAttempt.from_result(False, True),
898
 
            FakeStepAttempt.from_result(True, True)])
899
 
        suite_factory = AttemptSuiteFactory([
900
 
            FakeAttemptClass('foo', False, True, new_path='bar-path'),
901
 
            FakeAttemptClass('bar', True, True, new_path='bar-path')])
902
 
        log_dir = use_context(self, temp_dir())
903
 
        suite = suite_factory.factory([], log_dir, None)
904
 
        industrial = IndustrialTest(old_client, new_client, [suite])
905
 
        with patch('industrial_test.BootstrapManager',
906
 
                   fake_bootstrap_manager):
 
740
            FakeAttempt(False, True), FakeAttempt(True, True)])
 
741
        with patch('subprocess.call') as cc_mock:
907
742
            result = industrial.run_stages()
908
 
            self.assertItemsEqual(result, [
909
 
                ('bootstrap', True, True),
910
 
                ('prepare-suite', True, True),
911
 
                ('foo-id', False, True)])
912
 
        self.assertEqual('controller-killed',
913
 
                         old_client._backend.controller_state.state)
914
 
        self.assertEqual('controller-killed',
915
 
                         new_client._backend.controller_state.state)
 
743
            self.assertItemsEqual(result, [('foo-id', False, True)])
 
744
        assert_juju_call(self, cc_mock, old_client, get_timeout_prefix(600) + (
 
745
                         'juju', '--show-log', 'destroy-environment', 'old',
 
746
                         '--force', '-y'), 0)
 
747
        assert_juju_call(self, cc_mock, new_client, get_timeout_prefix(600) + (
 
748
                         'juju', '--show-log', 'destroy-environment', 'new',
 
749
                         '--force', '-y'), 1)
916
750
 
917
751
    def test_run_stages_new_fail(self):
918
 
        old_client = fake_juju_client()
919
 
        new_client = fake_juju_client(full_path='bar-path')
920
 
        log_dir = use_context(self, temp_dir())
921
 
        suite_factory = AttemptSuiteFactory([
922
 
            FakeAttemptClass('foo', True, False, new_path='bar-path'),
923
 
            FakeAttemptClass('bar', True, True, new_path='bar-path')])
924
 
        suite = suite_factory.factory([], log_dir, None)
925
 
        industrial = IndustrialTest(old_client, new_client, [suite])
926
 
        with patch('industrial_test.BootstrapManager',
927
 
                   fake_bootstrap_manager):
 
752
        old_client = FakeEnvJujuClient('old')
 
753
        new_client = FakeEnvJujuClient('new')
 
754
        industrial = IndustrialTest(old_client, new_client, [
 
755
            FakeAttempt(True, False), FakeAttempt(True, True)])
 
756
        with patch('subprocess.call') as cc_mock:
928
757
            result = industrial.run_stages()
929
 
            self.assertItemsEqual(result, [
930
 
                ('bootstrap', True, True),
931
 
                ('prepare-suite', True, True),
932
 
                ('foo-id', True, False)])
933
 
        self.assertEqual('controller-killed',
934
 
                         old_client._backend.controller_state.state)
935
 
        self.assertEqual('controller-killed',
936
 
                         new_client._backend.controller_state.state)
 
758
            self.assertItemsEqual(result, [('foo-id', True, False)])
 
759
        assert_juju_call(self, cc_mock, old_client, get_timeout_prefix(600) + (
 
760
                         'juju', '--show-log', 'destroy-environment', 'old',
 
761
                         '--force', '-y'), 0)
 
762
        assert_juju_call(self, cc_mock, new_client, get_timeout_prefix(600) + (
 
763
                         'juju', '--show-log', 'destroy-environment', 'new',
 
764
                         '--force', '-y'), 1)
937
765
 
938
766
    def test_run_stages_both_fail(self):
939
 
        old_client = fake_juju_client()
940
 
        new_client = fake_juju_client()
941
 
        log_dir = use_context(self, temp_dir())
942
 
        suite = AttemptSuiteFactory([
943
 
            FakeAttemptClass('foo', False, False),
944
 
            FakeAttemptClass('bar', True, True)]).factory([], log_dir,
945
 
                                                          'foo-stream')
946
 
        industrial = IndustrialTest(old_client, new_client, [suite])
947
 
        with patch('industrial_test.BootstrapManager',
948
 
                   fake_bootstrap_manager):
 
767
        old_client = FakeEnvJujuClient('old')
 
768
        new_client = FakeEnvJujuClient('new')
 
769
        industrial = IndustrialTest(old_client, new_client, [
 
770
            FakeAttempt(False, False), FakeAttempt(True, True)])
 
771
        with patch('subprocess.call') as cc_mock:
949
772
            result = industrial.run_stages()
950
 
            self.assertItemsEqual(result, [
951
 
                ('bootstrap', True, True),
952
 
                ('prepare-suite', True, True),
953
 
                ('foo-id', False, False)])
954
 
        self.assertEqual('controller-killed',
955
 
                         old_client._backend.controller_state.state)
956
 
        self.assertEqual('controller-killed',
957
 
                         new_client._backend.controller_state.state)
 
773
            self.assertItemsEqual(result, [('foo-id', False, False)])
 
774
        assert_juju_call(self, cc_mock, old_client, get_timeout_prefix(600) + (
 
775
                         'juju', '--show-log', 'destroy-environment', 'old',
 
776
                         '--force', '-y'), 0)
 
777
        assert_juju_call(self, cc_mock, new_client, get_timeout_prefix(600) + (
 
778
                         'juju', '--show-log', 'destroy-environment', 'new',
 
779
                         '--force', '-y'), 1)
958
780
 
959
781
    def test_run_stages_recover_failure(self):
960
 
        old_client = fake_juju_client()
961
 
        new_client = fake_juju_client()
 
782
        old_client = FakeEnvJujuClient('old')
 
783
        new_client = FakeEnvJujuClient('new')
962
784
        fsa = FakeStepAttempt([('foo', True, False), ('bar', True, True)])
963
785
        industrial = IndustrialTest(old_client, new_client, [
964
 
            fsa, FakeStepAttempt.from_result(True, True)])
 
786
            fsa, FakeAttempt(True, True)])
965
787
        self.assertEqual(list(industrial.run_stages()), [
966
788
            ('foo', True, False), ('bar', True, True), ('foo-id', True, True)])
967
789
 
970
792
        new_client = FakeEnvJujuClient('new')
971
793
        fsa = FakeStepAttempt([('foo', True, True), ('bar', False, True)])
972
794
        industrial = IndustrialTest(old_client, new_client, [
973
 
            fsa, FakeStepAttempt.from_result(True, True)])
974
 
        with patch.object(old_client, 'kill_controller'):
975
 
            with patch.object(new_client, 'kill_controller'):
 
795
            fsa, FakeAttempt(True, True)])
 
796
        with patch.object(old_client, 'destroy_environment'):
 
797
            with patch.object(new_client, 'destroy_environment'):
976
798
                self.assertEqual(list(industrial.run_stages()), [
977
799
                    ('foo', True, True), ('bar', False, True)])
978
800
 
979
801
    def test_run_stages_raises_cannot_upgrade_to_old_client(self):
980
802
        old = FakeEnvJujuClient()
981
803
        new = FakeEnvJujuClient()
982
 
        industrial = IndustrialTest(old, new, [PrepareUpgradeJujuAttempt({})])
 
804
        industrial = IndustrialTest(old, new, [UpgradeJujuAttempt({})])
983
805
        with self.assertRaises(CannotUpgradeToOldClient):
984
806
            list(industrial.run_stages())
985
807
 
 
808
    def test_destroy_both_even_with_exception(self):
 
809
        old_client = FakeEnvJujuClient('old')
 
810
        new_client = FakeEnvJujuClient('new')
 
811
        industrial = IndustrialTest(old_client, new_client, [
 
812
            FakeAttempt(False, False), FakeAttempt(True, True)])
 
813
        with patch.object(old_client, 'destroy_environment',
 
814
                          side_effect=Exception) as oc_mock:
 
815
            with patch.object(new_client, 'destroy_environment',
 
816
                              side_effect=Exception) as nc_mock:
 
817
                with self.assertRaises(Exception):
 
818
                    industrial.destroy_both()
 
819
        oc_mock.assert_called_once_with(delete_jenv=True)
 
820
        nc_mock.assert_called_once_with(delete_jenv=True)
 
821
 
986
822
    def test_run_attempt(self):
987
 
        old_client = fake_juju_client()
988
 
        new_client = fake_juju_client()
989
 
        attempt = FakeStepAttempt.from_result(True, True)
990
 
        log_dir = use_context(self, temp_dir())
991
 
        suite = AttemptSuiteFactory([attempt]).factory([], log_dir, None)
992
 
        industrial = IndustrialTest(old_client, new_client,
993
 
                                    [suite])
 
823
        old_client = FakeEnvJujuClient('old')
 
824
        new_client = FakeEnvJujuClient('new')
 
825
        attempt = FakeAttempt(True, True)
 
826
        industrial = IndustrialTest(old_client, new_client, [attempt])
994
827
 
995
828
        def iter_test_results(old, new):
996
829
            raise Exception
999
832
        with patch.object(attempt, 'iter_test_results',
1000
833
                          iter_test_results):
1001
834
            with patch('logging.exception') as le_mock:
1002
 
                with patch('industrial_test.BootstrapManager',
1003
 
                           fake_bootstrap_manager):
1004
 
                    industrial.run_attempt()
1005
 
        self.assertEqual(2, le_mock.call_count)
1006
 
        self.assertEqual('controller-killed',
1007
 
                         old_client._backend.controller_state.state)
1008
 
        self.assertEqual('controller-killed',
1009
 
                         new_client._backend.controller_state.state)
 
835
                with patch.object(industrial, 'destroy_both') as db_mock:
 
836
                    with self.assertRaises(SystemExit):
 
837
                        industrial.run_attempt()
 
838
        self.assertEqual(1, le_mock.call_count)
 
839
        self.assertEqual(db_mock.mock_calls, [call(), call()])
1010
840
 
1011
841
 
1012
842
class TestSteppedStageAttempt(JujuPyTestCase):
1013
843
 
1014
844
    def test__iter_for_result_premature_results(self):
1015
 
        iterator = (x for x in [{'test_id': 'foo-id', 'result': True}])
 
845
        iterator = iter([{'test_id': 'foo-id', 'result': True}])
1016
846
        with self.assertRaisesRegexp(ValueError, 'Result before declaration.'):
1017
847
            list(SteppedStageAttempt._iter_for_result(iterator))
1018
848
 
1019
849
    def test__iter_for_result_many(self):
1020
 
        iterator = (x for x in [
 
850
        iterator = iter([
1021
851
            {'test_id': 'foo-id'},
1022
852
            {'test_id': 'foo-id', 'result': True},
1023
853
            {'test_id': 'bar-id'},
1042
872
        le_mock.assert_called_once_with(error)
1043
873
 
1044
874
    def test_iter_for_result_id_change(self):
1045
 
        iterator = (x for x in [
 
875
        iterator = iter([
1046
876
            {'test_id': 'foo-id'}, {'test_id': 'bar-id'}])
1047
877
        with self.assertRaisesRegexp(ValueError, 'ID changed without result.'):
1048
878
            list(SteppedStageAttempt._iter_for_result(iterator))
1059
889
            list(SteppedStageAttempt._iter_for_result(iterator()))
1060
890
 
1061
891
    def test_iter_for_result_id_change_result(self):
1062
 
        iterator = (x for x in [
 
892
        iterator = iter([
1063
893
            {'test_id': 'foo-id'}, {'test_id': 'bar-id', 'result': True}])
1064
894
        with self.assertRaisesRegexp(ValueError, 'ID changed without result.'):
1065
895
            list(SteppedStageAttempt._iter_for_result(iterator))
1066
896
 
1067
897
    def test__iter_test_results_success(self):
1068
 
        old_iter = (x for x in [
 
898
        old_iter = iter([
1069
899
            None, {'test_id': 'foo-id', 'result': True}])
1070
 
        new_iter = (x for x in [
 
900
        new_iter = iter([
1071
901
            None, {'test_id': 'foo-id', 'result': False}])
1072
902
 
1073
903
        class StubSA(SteppedStageAttempt):
1077
907
                return {'foo-id': {'title': 'foo-id'}}
1078
908
 
1079
909
        self.assertItemsEqual(
1080
 
            StubSA()._iter_test_results(old_iter, new_iter),
 
910
            StubSA._iter_test_results(old_iter, new_iter),
1081
911
            [('foo-id', True, False)])
1082
912
 
1083
913
    def test__iter_test_results_interleaved(self):
1084
914
        # Using a single iterator for both proves that they are interleaved.
1085
915
        # Otherwise, we'd get Result before declaration.
1086
 
        both_iter = (x for x in [
 
916
        both_iter = iter([
1087
917
            None, None,
1088
918
            {'test_id': 'foo-id', 'result': True},
1089
919
            {'test_id': 'foo-id', 'result': False},
1096
926
                return {'foo-id': {'title': 'foo-id'}}
1097
927
 
1098
928
        self.assertItemsEqual(
1099
 
            StubSA()._iter_test_results(both_iter, both_iter),
 
929
            StubSA._iter_test_results(both_iter, both_iter),
1100
930
            [('foo-id', True, False)])
1101
931
 
1102
932
    def test__iter_test_results_id_mismatch(self):
1103
 
        old_iter = (x for x in [
 
933
        old_iter = iter([
1104
934
            None, {'test_id': 'foo-id', 'result': True}])
1105
 
        new_iter = (x for x in [
 
935
        new_iter = iter([
1106
936
            None, {'test_id': 'bar-id', 'result': False}])
1107
 
        with self.assertRaises(LoggedException) as exc:
1108
 
            list(SteppedStageAttempt()._iter_test_results(old_iter, new_iter))
1109
 
        self.assertEqual(ValueError('Test id mismatch: foo-id bar-id').args,
1110
 
                         exc.exception.exception.args)
 
937
        with self.assertRaisesRegexp(ValueError, 'Test id mismatch.'):
 
938
            list(SteppedStageAttempt._iter_test_results(old_iter, new_iter))
1111
939
 
1112
940
    def test__iter_test_results_many(self):
1113
 
        old_iter = (x for x in [
 
941
        old_iter = iter([
1114
942
            None, {'test_id': 'foo-id', 'result': True},
1115
943
            None, {'test_id': 'bar-id', 'result': False},
1116
944
            ])
1117
 
        new_iter = (x for x in [
 
945
        new_iter = iter([
1118
946
            None, {'test_id': 'foo-id', 'result': False},
1119
947
            None, {'test_id': 'bar-id', 'result': False},
1120
948
            ])
1128
956
                    'bar-id': {'title': 'bar-id'},
1129
957
                }
1130
958
        self.assertItemsEqual(
1131
 
            StubSA()._iter_test_results(old_iter, new_iter),
 
959
            StubSA._iter_test_results(old_iter, new_iter),
1132
960
            [('foo-id', True, False), ('bar-id', False, False)])
1133
961
 
1134
962
    def test_iter_test_results(self):
1167
995
            def __init__(self):
1168
996
                super(StubSA, self).__init__()
1169
997
 
1170
 
        self.assertIs(type(StubSA.factory(['a', 'b', 'c'], None)), StubSA)
 
998
        self.assertIs(type(StubSA.factory(['a', 'b', 'c'])), StubSA)
1171
999
 
1172
1000
    def test_get_test_info(self):
1173
1001
 
1183
1011
            ('bar-id', {'title': 'Bar title', 'report_on': False})]))
1184
1012
 
1185
1013
 
1186
 
def FakeEnvJujuClient(name='steve', version='1.2', full_path='/jbin/juju'):
1187
 
    return EnvJujuClient(
1188
 
            JujuData(name, {'type': 'fake', 'region': 'regionx'}),
1189
 
            version, full_path)
1190
 
 
1191
 
 
1192
 
class FakeEnvJujuClient1X(EnvJujuClient1X):
1193
 
 
1194
 
    def __init__(self, name='steve', version='1.2', full_path='/jbin/juju'):
1195
 
        super(FakeEnvJujuClient1X, self).__init__(
1196
 
            SimpleEnvironment(name, {'type': 'fake'}), version, full_path)
 
1014
class FakeEnvJujuClient(EnvJujuClient):
 
1015
 
 
1016
    def __init__(self, name='steve'):
 
1017
        super(FakeEnvJujuClient, self).__init__(
 
1018
            SimpleEnvironment(name, {'type': 'fake'}), '1.2', '/jbin/juju')
1197
1019
 
1198
1020
 
1199
1021
class TestBootstrapAttempt(JujuPyTestCase):
1203
1025
        bootstrap = BootstrapAttempt()
1204
1026
        boot_iter = iter_steps_validate_info(self, bootstrap, client)
1205
1027
        self.assertEqual(boot_iter.next(), {'test_id': 'bootstrap'})
1206
 
        with observable_temp_file() as config_file:
1207
 
            with patch('subprocess.Popen') as popen_mock:
1208
 
                self.assertEqual(boot_iter.next(), {'test_id': 'bootstrap'})
1209
 
            assert_juju_call(self, popen_mock, client, (
1210
 
                'juju', '--show-log', 'bootstrap', '--constraints', 'mem=2G',
1211
 
                'steve', 'fake/regionx', '--config', config_file.name,
1212
 
                '--default-model', 'steve', '--agent-version', '1.2'))
1213
 
            statuses = [
1214
 
                {'machines': {'0': {'agent-state': 'pending'}},
1215
 
                 'applications': {}},
1216
 
                {'machines': {'0': {'agent-state': 'started'}},
1217
 
                 'applicaions': {}},
1218
 
            ]
1219
 
            popen_mock.return_value.wait.return_value = 0
 
1028
        with patch('subprocess.Popen') as popen_mock:
1220
1029
            self.assertEqual(boot_iter.next(), {'test_id': 'bootstrap'})
 
1030
        assert_juju_call(self, popen_mock, client, (
 
1031
            'juju', '--show-log', 'bootstrap', '-e', 'steve',
 
1032
            '--constraints', 'mem=2G'))
 
1033
        statuses = [
 
1034
            {'machines': {'0': {'agent-state': 'pending'}}, 'services': {}},
 
1035
            {'machines': {'0': {'agent-state': 'started'}}, 'services': {}},
 
1036
        ]
 
1037
        popen_mock.return_value.wait.return_value = 0
 
1038
        self.assertEqual(boot_iter.next(), {'test_id': 'bootstrap'})
1221
1039
        with patch_status(client, *statuses) as gs_mock:
1222
1040
            self.assertEqual(boot_iter.next(),
1223
1041
                             {'test_id': 'bootstrap', 'result': True})
1231
1049
        destroy_env = DestroyEnvironmentAttempt()
1232
1050
        iterator = iter_steps_validate_info(self, destroy_env, client)
1233
1051
        self.assertEqual({'test_id': 'destroy-env'}, iterator.next())
1234
 
        with patch.object(client, 'get_jes_command',
1235
 
                          return_value='kill-controller'):
1236
 
            with patch.object(destroy_env, 'get_security_groups') as gsg_mock:
1237
 
                with patch('subprocess.call', return_value=0) as mock_cc:
1238
 
                    self.assertEqual(iterator.next(), {
1239
 
                        'test_id': 'destroy-env', 'result': True})
1240
 
        gsg_mock.assert_called_once_with(client)
1241
 
        assert_juju_call(self, mock_cc, client, get_timeout_prefix(600) + (
1242
 
            'juju', '--show-log', 'kill-controller', 'steve', '-y'))
1243
 
        self.assertEqual(iterator.next(), {'test_id': 'substrate-clean'})
1244
 
        with patch.object(destroy_env, 'check_security_groups') as csg_mock:
1245
 
            self.assertEqual(iterator.next(),
1246
 
                             {'test_id': 'substrate-clean', 'result': True})
1247
 
        csg_mock.assert_called_once_with(client, gsg_mock.return_value)
1248
 
 
1249
 
    def test_iter_steps_non_jes(self):
1250
 
        client = FakeEnvJujuClient1X()
1251
 
        destroy_env = DestroyEnvironmentAttempt()
1252
 
        iterator = iter_steps_validate_info(self, destroy_env, client)
1253
 
        self.assertEqual({'test_id': 'destroy-env'}, iterator.next())
1254
 
        with patch.object(client, 'is_jes_enabled', return_value=False):
1255
 
            with patch.object(destroy_env, 'get_security_groups') as gsg_mock:
1256
 
                with patch('subprocess.call', return_value=0) as mock_cc:
1257
 
                    self.assertEqual(iterator.next(), {
1258
 
                        'test_id': 'destroy-env', 'result': True})
 
1052
        with patch('subprocess.call') as mock_cc:
 
1053
            with patch.object(destroy_env, 'get_security_groups') as gsg_mock:
 
1054
                self.assertEqual(iterator.next(), {
 
1055
                    'test_id': 'destroy-env', 'result': True})
1259
1056
        gsg_mock.assert_called_once_with(client)
1260
1057
        assert_juju_call(self, mock_cc, client, get_timeout_prefix(600) + (
1261
1058
            'juju', '--show-log', 'destroy-environment', 'steve', '-y'))
1269
1066
        client = FakeEnvJujuClient()
1270
1067
        destroy_env = DestroyEnvironmentAttempt()
1271
1068
        with patch('subprocess.call'):
1272
 
            with patch.object(client, 'get_jes_command',
1273
 
                              return_value='kill-controller'):
1274
 
                output = list(destroy_env.iter_test_results(client, client))
 
1069
            output = list(destroy_env.iter_test_results(client, client))
1275
1070
        self.assertEqual(output, [
1276
1071
            ('destroy-env', True, True), ('substrate-clean', True, True)])
1277
1072
 
1278
 
    def test_iter_steps_failure(self):
1279
 
        client = FakeEnvJujuClient()
1280
 
        destroy_env = DestroyEnvironmentAttempt()
1281
 
        iterator = iter_steps_validate_info(self, destroy_env, client)
1282
 
        self.assertEqual({'test_id': 'destroy-env'}, iterator.next())
1283
 
        with patch('subprocess.call', return_value=1) as mock_cc:
1284
 
            with patch.object(client, 'get_jes_command',
1285
 
                              return_value='kill-controller'):
1286
 
                with patch.object(destroy_env,
1287
 
                                  'get_security_groups') as gsg_mock:
1288
 
                    with patch.object(client, 'kill_controller',
1289
 
                                      side_effect=Exception) as kc_mock:
1290
 
                        with self.assertRaises(Exception):
1291
 
                            iterator.next()
1292
 
        kc_mock.assert_called_once_with()
1293
 
        gsg_mock.assert_called_once_with(client)
1294
 
        self.assertEqual(0, mock_cc.call_count)
1295
 
        with self.assertRaises(StopIteration):
1296
 
            iterator.next()
1297
 
 
1298
 
    def test_iter_steps_failure_non_jes(self):
1299
 
        client = FakeEnvJujuClient1X()
1300
 
        destroy_env = DestroyEnvironmentAttempt()
1301
 
        iterator = iter_steps_validate_info(self, destroy_env, client)
1302
 
        self.assertEqual({'test_id': 'destroy-env'}, iterator.next())
1303
 
        with patch('subprocess.call', return_value=1) as mock_cc:
1304
 
            with patch.object(client, 'is_jes_enabled', return_value=False):
1305
 
                with patch.object(destroy_env,
1306
 
                                  'get_security_groups') as gsg_mock:
1307
 
                    self.assertEqual(iterator.next(), {
1308
 
                        'test_id': 'destroy-env', 'result': False})
1309
 
        gsg_mock.assert_called_once_with(client)
1310
 
        assert_juju_call(self, mock_cc, client, get_timeout_prefix(600) + (
1311
 
            'juju', '--show-log', 'destroy-environment', 'steve', '-y'))
1312
 
        with self.assertRaises(StopIteration):
1313
 
            iterator.next()
1314
 
 
1315
 
    def test_iter_steps_kill_controller(self):
1316
 
        client = fake_juju_client()
1317
 
        client.bootstrap()
1318
 
        destroy_env = DestroyEnvironmentAttempt()
1319
 
        iterator = iter_steps_validate_info(self, destroy_env, client)
1320
 
        with closing(iterator):
1321
 
            self.assertEqual({'test_id': 'destroy-env'}, iterator.next())
1322
 
            self.assertEqual(iterator.next(), {
1323
 
                'test_id': 'destroy-env', 'result': True})
1324
 
        self.assertEqual('controller-killed',
1325
 
                         client._backend.controller_state.state)
1326
 
 
1327
1073
    @staticmethod
1328
1074
    def get_aws_client():
1329
1075
        client = FakeEnvJujuClient()
1351
1097
                SecurityGroup(id='quxx-id', name='quxx'),
1352
1098
                ])]),
1353
1099
        ]
1354
 
        aws_client = MagicMock()
1355
 
        aws_client.get_all_instances.return_value = aws_instances
1356
1100
        with patch(
1357
 
                'substrate.ec2.connect_to_region') as gec_mock:
 
1101
                'substrate.AWSAccount.get_ec2_connection') as gec_mock:
1358
1102
            with patch_status(client, status):
1359
1103
                gai_mock = gec_mock.return_value.get_all_instances
1360
1104
                gai_mock.return_value = aws_instances
1361
1105
                self.assertEqual(destroy_env.get_security_groups(client), {
1362
1106
                    'baz': 'qux', 'foo': 'bar', 'quxx-id': 'quxx'
1363
1107
                    })
1364
 
        self.assert_ec2_connection_call(gec_mock)
 
1108
        gec_mock.assert_called_once_with()
1365
1109
        gai_mock.assert_called_once_with(instance_ids=['foo-id'])
1366
1110
 
1367
1111
    def test_get_security_groups_openstack(self):
1397
1141
    def test_check_security_groups_match(self):
1398
1142
        client = self.get_aws_client()
1399
1143
        destroy_env = DestroyEnvironmentAttempt()
1400
 
        aws_client = MagicMock()
1401
 
        aws_client.get_all_security_groups.return_value = list(
1402
 
            self.make_group())
1403
 
        with patch('substrate.ec2.connect_to_region',
1404
 
                   return_value=aws_client) as ctr_mock:
 
1144
        output = (
 
1145
            'GROUP\tfoo-id\t\tfoo-group\n'
 
1146
            'GROUP\tbaz-id\t\tbaz-group\n'
 
1147
        )
 
1148
        with patch('subprocess.check_output', return_value=output) as co_mock:
1405
1149
            with self.assertRaisesRegexp(
1406
1150
                Exception, (
1407
1151
                    r'Security group\(s\) not cleaned up: foo-group.')):
1409
1153
                               lambda x: iter([None])):
1410
1154
                        destroy_env.check_security_groups(
1411
1155
                            client, {'foo-id': 'foo', 'bar-id': 'bar'})
1412
 
        aws_client.get_all_security_groups.assert_called_once_with(
1413
 
            filters={'description': 'juju group'})
1414
 
        self.assert_ec2_connection_call(ctr_mock)
1415
 
 
1416
 
    def make_group(self):
1417
 
        for name in ['foo', 'baz']:
1418
 
            group = MagicMock()
1419
 
            group.name = name + '-group'
1420
 
            group.id = name + '-id'
1421
 
            yield group
 
1156
        with AWSAccount.manager_from_config(client.env.config) as aws:
 
1157
            env = aws.get_environ()
 
1158
        co_mock.assert_called_once_with(
 
1159
            ['euca-describe-groups', '--filter', 'description=juju group'],
 
1160
            env=env)
1422
1161
 
1423
1162
    def test_check_security_groups_no_match(self):
1424
1163
        client = self.get_aws_client()
1425
1164
        destroy_env = DestroyEnvironmentAttempt()
1426
 
        aws_client = MagicMock()
1427
 
        aws_client.get_all_security_groups.return_value = list(
1428
 
            self.make_group())
1429
 
        with patch('substrate.ec2.connect_to_region',
1430
 
                   return_value=aws_client) as ctr_mock:
 
1165
        output = (
 
1166
            'GROUP\tfoo-id\t\tfoo-group\n'
 
1167
            'GROUP\tbaz-id\t\tbaz-group\n'
 
1168
        )
 
1169
        with patch('subprocess.check_output', return_value=output) as co_mock:
1431
1170
                destroy_env.check_security_groups(
1432
1171
                    client, {'bar-id': 'bar'})
1433
 
        aws_client.get_all_security_groups.assert_called_once_with(
1434
 
            filters={'description': 'juju group'})
1435
 
        self.assert_ec2_connection_call(ctr_mock)
1436
 
 
1437
 
    def assert_ec2_connection_call(self, ctr_mock):
1438
 
        ctr_mock.assert_called_once_with(
1439
 
            'ca-west', aws_access_key_id='skeleton-key',
1440
 
            aws_secret_access_key='secret-skeleton-key')
 
1172
        with AWSAccount.manager_from_config(client.env.config) as aws:
 
1173
            env = aws.get_environ()
 
1174
        co_mock.assert_called_once_with(
 
1175
            ['euca-describe-groups', '--filter', 'description=juju group'],
 
1176
            env=env)
1441
1177
 
1442
1178
    def test_check_security_groups_non_aws(self):
1443
1179
        client = FakeEnvJujuClient()
1452
1188
 
1453
1189
    def test_iter_steps(self):
1454
1190
        client = FakeEnvJujuClient()
1455
 
        controller_client = client.get_controller_client()
1456
1191
        ensure_av = EnsureAvailabilityAttempt()
1457
1192
        ensure_iter = iter_steps_validate_info(self, ensure_av, client)
1458
1193
        self.assertEqual(ensure_iter.next(), {
1459
1194
            'test_id': 'ensure-availability-n3'})
1460
1195
        with patch('subprocess.check_call') as cc_mock:
1461
 
            with patch.object(client, 'get_controller_client',
1462
 
                              return_value=controller_client, autospec=True):
1463
 
                self.assertEqual(ensure_iter.next(), {
1464
 
                    'test_id': 'ensure-availability-n3'})
1465
 
        assert_juju_call(
1466
 
            self,
1467
 
            cc_mock, client,
1468
 
            ('juju', '--show-log', 'enable-ha', '-m',
1469
 
             'steve:{}'.format(controller_client.env.environment), '-n', '3'))
 
1196
            self.assertEqual(ensure_iter.next(), {
 
1197
                'test_id': 'ensure-availability-n3'})
 
1198
        assert_juju_call(self, cc_mock, client, (
 
1199
            'juju', '--show-log', 'ensure-availability', '-e', 'steve', '-n',
 
1200
            '3'))
1470
1201
        status = {
1471
1202
            'machines': {
1472
 
                '0': {'controller-member-status': 'has-vote'},
1473
 
                '1': {'controller-member-status': 'has-vote'},
1474
 
                '2': {'controller-member-status': 'has-vote'},
 
1203
                '0': {'state-server-member-status': 'has-vote'},
 
1204
                '1': {'state-server-member-status': 'has-vote'},
 
1205
                '2': {'state-server-member-status': 'has-vote'},
1475
1206
                },
1476
 
            'applications': {},
 
1207
            'services': {},
1477
1208
        }
1478
 
        with patch_status(controller_client, status) as gs_mock:
 
1209
        with patch_status(client, status) as gs_mock:
1479
1210
            self.assertEqual(ensure_iter.next(), {
1480
1211
                'test_id': 'ensure-availability-n3', 'result': True})
1481
 
        gs_mock.assert_called_once_with(controller=True)
 
1212
        gs_mock.assert_called_once_with()
1482
1213
 
1483
1214
    def test_iter_steps_failure(self):
1484
1215
        client = FakeEnvJujuClient()
1486
1217
        ensure_iter = iter_steps_validate_info(self, ensure_av, client)
1487
1218
        ensure_iter.next()
1488
1219
        with patch('subprocess.check_call'):
1489
 
            controller_client = client.get_controller_client()
1490
 
            with patch.object(client, 'get_controller_client',
1491
 
                              return_value=controller_client, autospec=True):
1492
 
                ensure_iter.next()
 
1220
            ensure_iter.next()
1493
1221
        status = {
1494
1222
            'machines': {
1495
1223
                '0': {'state-server-member-status': 'has-vote'},
1496
1224
                '1': {'state-server-member-status': 'has-vote'},
1497
1225
                },
1498
 
            'applications': {},
 
1226
            'services': {},
1499
1227
        }
1500
 
        with patch_status(controller_client, status) as gs_mock:
 
1228
        with patch_status(client, status) as gs_mock:
1501
1229
            with self.assertRaisesRegexp(
1502
1230
                    Exception, 'Timed out waiting for voting to be enabled.'):
1503
1231
                ensure_iter.next()
1506
1234
 
1507
1235
class TestDeployManyAttempt(JujuPyTestCase):
1508
1236
 
1509
 
    def predict_add_machine_calls(self, deploy_many, machine_type):
 
1237
    def predict_add_machine_calls(self, deploy_many):
1510
1238
        for host in range(1, deploy_many.host_count + 1):
1511
1239
            for container in range(deploy_many.container_count):
1512
 
                target = '{}:{}'.format(machine_type, host)
 
1240
                target = 'lxc:{}'.format(host)
1513
1241
                service = 'ubuntu{}x{}'.format(host, container)
1514
 
                yield ('juju', '--show-log', 'deploy', '-m', 'steve:steve',
1515
 
                       'ubuntu', service, '--to', target, '--series', 'angsty')
 
1242
                yield ('juju', '--show-log', 'deploy', '-e', 'steve', '--to',
 
1243
                       target, 'ubuntu', service)
1516
1244
 
1517
1245
    def predict_remove_machine_calls(self, deploy_many):
1518
1246
        total_guests = deploy_many.host_count * deploy_many.container_count
1519
1247
        for guest in range(100, total_guests + 100):
1520
 
            yield ('juju', '--show-log', 'remove-machine', '-m', 'steve:steve',
 
1248
            yield ('juju', '--show-log', 'remove-machine', '-e', 'steve',
1521
1249
                   '--force', str(guest))
1522
1250
 
1523
1251
    def test_iter_steps(self):
1524
 
        machine_started = {'juju-status': {'current': 'idle'}}
1525
 
        unit_started = {'agent-status': {'current': 'idle'}}
1526
 
        client = FakeEnvJujuClient()
1527
 
        client.env.config['default-series'] = 'angsty'
1528
 
        self.do_iter_steps(client, LXD_MACHINE, machine_started, unit_started)
1529
 
 
1530
 
    def test_iter_steps_1x(self):
1531
 
        started_state = {'agent-state': 'started'}
1532
 
        client = FakeEnvJujuClient()
1533
 
        with patch.object(EnvJujuClient, 'supported_container_types',
1534
 
                          frozenset([KVM_MACHINE, LXC_MACHINE])):
1535
 
            client.env.config['default-series'] = 'angsty'
1536
 
            self.do_iter_steps(client, LXC_MACHINE, started_state,
1537
 
                               started_state)
1538
 
 
1539
 
    def do_iter_steps(self, client, machine_type, machine_started,
1540
 
                      unit_started):
 
1252
        client = FakeEnvJujuClient()
1541
1253
        deploy_many = DeployManyAttempt(9, 11)
1542
1254
        deploy_iter = iter_steps_validate_info(self, deploy_many, client)
1543
1255
        self.assertEqual(deploy_iter.next(), {'test_id': 'add-machine-many'})
1544
1256
        status = {
1545
 
            'machines': {'0': dict(machine_started)},
1546
 
            'applications': {},
 
1257
            'machines': {'0': {'agent-state': 'started'}},
 
1258
            'services': {},
1547
1259
        }
1548
1260
        with patch_status(client, status):
1549
1261
            with patch('subprocess.check_call') as mock_cc:
1551
1263
                                 {'test_id': 'add-machine-many'})
1552
1264
        for index in range(deploy_many.host_count):
1553
1265
            assert_juju_call(self, mock_cc, client, (
1554
 
                'juju', '--show-log', 'add-machine',
1555
 
                '-m', 'steve:steve'), index)
 
1266
                'juju', '--show-log', 'add-machine', '-e', 'steve'), index)
1556
1267
 
1557
1268
        status = {
1558
 
            'machines': dict((str(x), dict(machine_started))
 
1269
            'machines': dict((str(x), {'agent-state': 'started'})
1559
1270
                             for x in range(deploy_many.host_count + 1)),
1560
 
            'applications': {},
 
1271
            'services': {},
1561
1272
        }
1562
1273
        with patch_status(client, status):
1563
1274
                self.assertEqual(
1576
1287
            self.assertEqual(deploy_iter.next(),
1577
1288
                             {'test_id': 'deploy-many'})
1578
1289
 
1579
 
        calls = self.predict_add_machine_calls(deploy_many, machine_type)
 
1290
        calls = self.predict_add_machine_calls(deploy_many)
1580
1291
        for num, args in enumerate(calls):
1581
1292
            assert_juju_call(self, mock_cc, client, args, num)
1582
1293
        service_names = []
1583
1294
        for host in range(1, deploy_many.host_count + 1):
1584
1295
            for container in range(deploy_many.container_count):
1585
1296
                service_names.append('ubuntu{}x{}'.format(host, container))
1586
 
        applications = {}
1587
 
        for num, service_name in enumerate(service_names):
1588
 
            foo = {'machine': str(num + 100)}
1589
 
            foo.update(unit_started)
1590
 
            units = {
1591
 
                'foo': foo,
1592
 
                }
1593
 
            applications[service_name] = {'units': units}
 
1297
        services = dict((service_name, {
 
1298
            'units': {
 
1299
                'foo': {'machine': str(num + 100), 'agent-state': 'started'}
 
1300
                }})
 
1301
            for num, service_name in enumerate(service_names))
1594
1302
        status = {
1595
 
            'machines': {'0': dict(machine_started)},
1596
 
            'applications': applications,
 
1303
            'machines': {'0': {'agent-state': 'started'}},
 
1304
            'services': services,
1597
1305
        }
1598
1306
        with patch_status(client, status):
1599
1307
            self.assertEqual(deploy_iter.next(),
1600
1308
                             {'test_id': 'deploy-many', 'result': True})
1601
1309
 
1602
1310
        self.assertEqual(deploy_iter.next(),
1603
 
                         {'test_id': 'remove-machine-many-container'})
 
1311
                         {'test_id': 'remove-machine-many-lxc'})
1604
1312
        with patch_status(client, status):
1605
1313
            with patch('subprocess.check_call') as mock_cc:
1606
1314
                self.assertEqual(
1607
1315
                    deploy_iter.next(),
1608
 
                    {'test_id': 'remove-machine-many-container'})
 
1316
                    {'test_id': 'remove-machine-many-lxc'})
1609
1317
        calls = self.predict_remove_machine_calls(deploy_many)
1610
1318
        for num, args in enumerate(calls):
1611
1319
            assert_juju_call(self, mock_cc, client, args, num)
1612
1320
        statuses = [
1613
 
            {'machines': {'100': dict(machine_started)}, 'applications': {}},
1614
 
            {'machines': {}, 'applications': {}},
 
1321
            {'machines': {'100': {'agent-state': 'started'}}, 'services': {}},
 
1322
            {'machines': {}, 'services': {}},
1615
1323
        ]
1616
1324
        with patch_status(client, *statuses) as status_mock:
1617
1325
            self.assertEqual(
1618
1326
                deploy_iter.next(),
1619
 
                {'test_id': 'remove-machine-many-container', 'result': True})
 
1327
                {'test_id': 'remove-machine-many-lxc', 'result': True})
1620
1328
        self.assertEqual(2, status_mock.call_count)
1621
1329
        self.assertEqual(deploy_iter.next(), {
1622
1330
            'test_id': 'remove-machine-many-instance'})
1626
1334
                {'test_id': 'remove-machine-many-instance'})
1627
1335
        for num in range(deploy_many.host_count):
1628
1336
            assert_juju_call(self, mock_cc, client, (
1629
 
                'juju', '--show-log', 'remove-machine', '-m', 'steve:steve',
 
1337
                'juju', '--show-log', 'remove-machine', '-e', 'steve',
1630
1338
                str(num + 1)), num)
1631
1339
 
1632
1340
        statuses = [
1633
 
            {'machines': {'1': dict(machine_started)}, 'applications': {}},
1634
 
            {'machines': {}, 'applications': {}},
 
1341
            {'machines': {'1': {'agent-state': 'started'}}, 'services': {}},
 
1342
            {'machines': {}, 'services': {}},
1635
1343
        ]
1636
1344
        with patch_status(client, *statuses) as status_mock:
1637
1345
            self.assertEqual(
1642
1350
    def test_iter_step_failure(self):
1643
1351
        deploy_many = DeployManyAttempt()
1644
1352
        client = FakeEnvJujuClient()
1645
 
        client.env.config['default-series'] = 'angsty'
1646
1353
        deploy_iter = iter_steps_validate_info(self, deploy_many, client)
1647
1354
        self.assertEqual(deploy_iter.next(), {'test_id': 'add-machine-many'})
1648
1355
        status = {
1649
1356
            'machines': {'0': {'agent-state': 'started'}},
1650
 
            'applications': {},
 
1357
            'services': {},
1651
1358
        }
1652
1359
        with patch_status(client, status):
1653
1360
            with patch('subprocess.check_call') as mock_cc:
1655
1362
                                 {'test_id': 'add-machine-many'})
1656
1363
        for index in range(deploy_many.host_count):
1657
1364
            assert_juju_call(self, mock_cc, client, (
1658
 
                'juju', '--show-log', 'add-machine',
1659
 
                '-m', 'steve:steve'), index)
 
1365
                'juju', '--show-log', 'add-machine', '-e', 'steve'), index)
1660
1366
 
1661
1367
        status = {
1662
1368
            'machines': dict((str(x), {'agent-state': 'started'})
1663
1369
                             for x in range(deploy_many.host_count + 1)),
1664
 
            'applications': {},
 
1370
            'services': {},
1665
1371
        }
1666
1372
        with patch_status(client, status):
1667
1373
                self.assertEqual(
1683
1389
            'machines': {
1684
1390
                '0': {'agent-state': 'pending'},
1685
1391
                },
1686
 
            'applications': {},
 
1392
            'services': {},
1687
1393
        }
1688
1394
        with patch_status(client, status):
1689
1395
            with self.assertRaisesRegexp(
1694
1400
    def test_iter_step_add_machine_failure(self):
1695
1401
        deploy_many = DeployManyAttempt()
1696
1402
        client = FakeEnvJujuClient()
1697
 
        client.env.config['default-series'] = 'angsty'
1698
1403
        deploy_iter = iter_steps_validate_info(self, deploy_many, client)
1699
1404
        self.assertEqual(deploy_iter.next(), {'test_id': 'add-machine-many'})
1700
1405
        status = {
1701
1406
            'machines': {'0': {'agent-state': 'started'}},
1702
 
            'applications': {},
 
1407
            'services': {},
1703
1408
        }
1704
1409
        with patch_status(client, status) as gs_mock:
1705
1410
            with patch('subprocess.check_call') as mock_cc:
1707
1412
                                 {'test_id': 'add-machine-many'})
1708
1413
        for index in range(deploy_many.host_count):
1709
1414
            assert_juju_call(self, mock_cc, client, (
1710
 
                'juju', '--show-log', 'add-machine',
1711
 
                '-m', 'steve:steve'), index)
 
1415
                'juju', '--show-log', 'add-machine', '-e', 'steve'), index)
1712
1416
        gs_mock.assert_called_once_with()
1713
1417
 
1714
1418
        status = {
1715
1419
            'machines': dict((str(x), {'agent-state': 'pending'})
1716
1420
                             for x in range(deploy_many.host_count + 1)),
1717
 
            'applications': {},
 
1421
            'services': {},
1718
1422
        }
1719
1423
        with patch_status(client, status) as gs_mock:
1720
1424
            self.assertEqual(deploy_iter.next(),
1726
1430
                             deploy_iter.next())
1727
1431
        for x in range(deploy_many.host_count):
1728
1432
            assert_juju_call(self, mock_cc, client, (
1729
 
                'juju', '--show-log', 'remove-machine', '-m', 'steve:steve',
 
1433
                'juju', '--show-log', 'destroy-machine', '-e', 'steve',
1730
1434
                '--force', str((x + 1))), x * 2)
1731
1435
            assert_juju_call(self, mock_cc, client, (
1732
 
                'juju', '--show-log', 'add-machine',
1733
 
                '-m', 'steve:steve'), x * 2 + 1)
 
1436
                'juju', '--show-log', 'add-machine', '-e', 'steve'), x * 2 + 1)
1734
1437
 
1735
1438
        status = {
1736
1439
            'machines': dict((str(x), {'agent-state': 'started'})
1737
1440
                             for x in range(deploy_many.host_count + 1)),
1738
 
            'applications': {},
 
1441
            'services': {},
1739
1442
        }
1740
1443
        with patch_status(client, status) as gs_mock:
1741
1444
            self.assertEqual({'test_id': 'ensure-machines', 'result': True},
1743
1446
        self.assertEqual({'test_id': 'deploy-many'}, deploy_iter.next())
1744
1447
        with patch('subprocess.check_call') as mock_cc:
1745
1448
            self.assertEqual({'test_id': 'deploy-many'}, deploy_iter.next())
1746
 
        calls = self.predict_add_machine_calls(deploy_many, LXD_MACHINE)
 
1449
        calls = self.predict_add_machine_calls(deploy_many)
1747
1450
        for num, args in enumerate(calls):
1748
1451
            assert_juju_call(self, mock_cc, client, args, num)
1749
1452
 
1750
 
    def get_wait_until_removed_timeout(self, container_type):
1751
 
        deploy_many = DeployManyAttempt()
1752
 
        client = fake_juju_client()
1753
 
        client.bootstrap()
1754
 
        deploy_iter = iter_steps_validate_info(self, deploy_many, client)
1755
 
        with patch('industrial_test.wait_until_removed') as wur_mock:
1756
 
            with patch.object(client, 'preferred_container',
1757
 
                              return_value=container_type):
1758
 
                list(deploy_iter)
1759
 
        return wur_mock.mock_calls[0][2]['timeout']
1760
 
 
1761
 
    def test_wait_until_removed_timeout_lxd(self):
1762
 
        self.assertEqual(60, self.get_wait_until_removed_timeout(LXD_MACHINE))
1763
 
 
1764
 
    def test_wait_until_removed_timeout_lxc(self):
1765
 
        self.assertEqual(30, self.get_wait_until_removed_timeout(LXC_MACHINE))
1766
 
 
1767
1453
 
1768
1454
class TestBackupRestoreAttempt(JujuPyTestCase):
1769
1455
 
1775
1461
    def test_iter_steps(self):
1776
1462
        br_attempt = BackupRestoreAttempt()
1777
1463
        client = FakeEnvJujuClient()
1778
 
        aws_env = get_aws_env()
1779
 
        client.env.environment = aws_env.environment
1780
 
        client.env.config = aws_env.config
1781
 
        client.env.juju_home = aws_env.juju_home
1782
 
        controller_client = client.get_controller_client()
 
1464
        client.env = get_aws_env()
1783
1465
        environ = dict(os.environ)
1784
1466
        environ.update(get_euca_env(client.env.config))
1785
1467
 
1786
1468
        def check_output(*args, **kwargs):
1787
 
            if args == ((
1788
 
                    'juju', '--show-log', 'create-backup', '-m',
1789
 
                    'steve:{}'.format(controller_client.env.environment),),):
1790
 
                return FakePopen('juju-backup-24.tgz', '', 0)
 
1469
            if args == (['juju', 'backup'],):
 
1470
                return 'juju-backup-24.tgz'
1791
1471
            self.assertEqual([], args)
1792
1472
        initial_status = {
1793
1473
            'machines': {'0': {
1797
1477
        }
1798
1478
        iterator = iter_steps_validate_info(self, br_attempt, client)
1799
1479
        self.assertEqual(iterator.next(), {'test_id': 'back-up-restore'})
1800
 
        with patch_status(controller_client, initial_status) as gs_mock:
1801
 
            with patch('subprocess.Popen',
 
1480
        with patch_status(client, initial_status) as gs_mock:
 
1481
            with patch('subprocess.check_output',
1802
1482
                       side_effect=check_output) as co_mock:
1803
1483
                with patch('subprocess.check_call') as cc_mock:
1804
 
                    with patch.object(client, 'get_controller_client',
1805
 
                                      return_value=controller_client,
1806
 
                                      autospec=True):
1807
 
                        with patch('sys.stdout'):
1808
 
                            self.assertEqual(
1809
 
                                iterator.next(),
1810
 
                                {'test_id': 'back-up-restore'})
1811
 
        assert_juju_call(
1812
 
            self,
1813
 
            co_mock,
1814
 
            client,
1815
 
            ('juju', '--show-log', 'create-backup',
1816
 
             '-m', 'steve:{}'.format(controller_client.env.environment)),
1817
 
            0)
 
1484
                    with patch('sys.stdout'):
 
1485
                        self.assertEqual(
 
1486
                            iterator.next(),
 
1487
                            {'test_id': 'back-up-restore'})
 
1488
        assert_juju_call(self, co_mock, client, ['juju', 'backup'], 0)
1818
1489
        self.assertEqual(
1819
1490
            cc_mock.mock_calls[0],
1820
1491
            call(['euca-terminate-instances', 'asdf'], env=environ))
1823
1494
                self.assertEqual(iterator.next(),
1824
1495
                                 {'test_id': 'back-up-restore'})
1825
1496
        pn_mock.assert_called_with('Closed.')
1826
 
        with patch.object(controller_client, 'restore_backup') as rb_mock:
 
1497
        with patch('subprocess.Popen') as po_mock:
1827
1498
            self.assertEqual(iterator.next(), {'test_id': 'back-up-restore'})
1828
 
        rb_mock.assert_called_once_with(
1829
 
            os.path.abspath('juju-backup-24.tgz'))
 
1499
        assert_juju_call(
 
1500
            self, po_mock, client, (
 
1501
                'juju', '--show-log', 'restore', '-e', 'baz',
 
1502
                os.path.abspath('juju-backup-24.tgz')))
 
1503
        po_mock.return_value.wait.return_value = 0
1830
1504
        with patch('os.unlink') as ul_mock:
1831
1505
            self.assertEqual(iterator.next(),
1832
1506
                             {'test_id': 'back-up-restore'})
1835
1509
            'machines': {
1836
1510
                '0': {'agent-state': 'started'},
1837
1511
                },
1838
 
            'applications': {},
 
1512
            'services': {},
1839
1513
        }
1840
 
        with patch_status(controller_client, final_status) as gs_mock:
 
1514
        with patch_status(client, final_status) as gs_mock:
1841
1515
            self.assertEqual(iterator.next(),
1842
1516
                             {'test_id': 'back-up-restore', 'result': True})
1843
1517
        gs_mock.assert_called_once_with()
1844
1518
 
1845
1519
 
1846
 
class TestPrepareUpgradeJujuAttempt(JujuPyTestCase):
 
1520
class TestUpgradeJujuAttempt(JujuPyTestCase):
1847
1521
 
1848
1522
    def test_factory(self):
1849
 
        uj_attempt = PrepareUpgradeJujuAttempt.factory(
1850
 
            ['a', 'b', 'c'], None)
1851
 
        self.assertIs(type(uj_attempt), PrepareUpgradeJujuAttempt)
 
1523
        uj_attempt = UpgradeJujuAttempt.factory(['a', 'b', 'c'])
 
1524
        self.assertIs(type(uj_attempt), UpgradeJujuAttempt)
1852
1525
        self.assertEqual(uj_attempt.bootstrap_paths, {'b': 'a', 'c': 'b'})
1853
1526
 
1854
1527
    def test_factory_empty(self):
1855
1528
        with self.assertRaisesRegexp(
1856
1529
                ValueError, 'Not enough paths for upgrade.'):
1857
 
            PrepareUpgradeJujuAttempt.factory(['a'], None)
 
1530
            UpgradeJujuAttempt.factory(['a'])
1858
1531
        with self.assertRaisesRegexp(
1859
1532
                ValueError, 'Not enough paths for upgrade.'):
1860
 
            PrepareUpgradeJujuAttempt.factory([], None)
1861
 
 
1862
 
    def test_get_bootstrap_client(self):
1863
 
        client = fake_juju_client(full_path='c', debug=True)
1864
 
        puj_attempt = PrepareUpgradeJujuAttempt.factory(['a', 'b', 'c'], None)
1865
 
 
1866
 
        def by_version(path):
1867
 
            return fake_juju_client(client.env, path, client.debug)
1868
 
 
1869
 
        with patch.object(client, 'clone_path_cls', by_version):
1870
 
            bootstrap_client = puj_attempt.get_bootstrap_client(client)
1871
 
 
1872
 
        self.assertIsNot(bootstrap_client, client)
1873
 
        self.assertIs(client.debug, bootstrap_client.debug)
1874
 
        self.assertIs(client.env, bootstrap_client.env)
1875
 
        self.assertEqual('b', bootstrap_client.full_path)
 
1533
            UpgradeJujuAttempt.factory([])
1876
1534
 
1877
1535
    def test_iter_steps(self):
1878
 
        future_client = FakeEnvJujuClient(full_path='/future/juju')
1879
 
        present_client = FakeEnvJujuClient(full_path='/present/juju')
1880
 
        puj_attempt = PrepareUpgradeJujuAttempt(
 
1536
        future_client = FakeEnvJujuClient()
 
1537
        future_client.full_path = '/future/juju'
 
1538
        present_client = FakeEnvJujuClient()
 
1539
        present_client.full_path = '/present/juju'
 
1540
        uj_attempt = UpgradeJujuAttempt(
1881
1541
            {future_client.full_path: present_client.full_path})
1882
 
        puj_iterator = iter_steps_validate_info(self, puj_attempt,
1883
 
                                                future_client)
1884
 
        with patch('subprocess.check_output', return_value='2.0-alpha3-a-b'):
1885
 
            with patch('industrial_test.client_from_config',
1886
 
                       return_value=future_client):
1887
 
                self.assertEqual({'test_id': 'prepare-upgrade-juju'},
1888
 
                                 puj_iterator.next())
1889
 
        with observable_temp_file() as config_file:
1890
 
            with patch('subprocess.Popen') as po_mock:
1891
 
                self.assertEqual({'test_id': 'prepare-upgrade-juju'},
1892
 
                                 puj_iterator.next())
1893
 
            assert_juju_call(self, po_mock, future_client, (
1894
 
                'juju', '--show-log', 'bootstrap', '--constraints', 'mem=2G',
1895
 
                'steve', 'fake/regionx', '--config', config_file.name,
1896
 
                '--agent-version', '2.0-alpha3'))
1897
 
            po_mock.return_value.wait.return_value = 0
1898
 
            self.assertEqual(puj_iterator.next(),
1899
 
                             {'test_id': 'prepare-upgrade-juju'})
 
1542
        uj_iterator = iter_steps_validate_info(self, uj_attempt, future_client)
 
1543
        with patch('subprocess.check_output', return_value='foo'):
 
1544
            self.assertEqual({'test_id': 'prepare-upgrade-juju'},
 
1545
                             uj_iterator.next())
 
1546
        with patch('subprocess.Popen') as po_mock:
 
1547
            self.assertEqual({'test_id': 'prepare-upgrade-juju'},
 
1548
                             uj_iterator.next())
 
1549
        assert_juju_call(self, po_mock, present_client, (
 
1550
            'juju', '--show-log', 'bootstrap', '-e', 'steve', '--constraints',
 
1551
            'mem=2G'))
 
1552
        po_mock.return_value.wait.return_value = 0
 
1553
        self.assertEqual(uj_iterator.next(),
 
1554
                         {'test_id': 'prepare-upgrade-juju'})
1900
1555
        b_status = {
1901
1556
            'machines': {'0': {'agent-state': 'started'}},
1902
 
            'applications': {},
 
1557
            'services': {},
1903
1558
        }
1904
1559
        with patch_status(None, b_status):
1905
1560
            self.assertEqual(
1906
 
                puj_iterator.next(),
 
1561
                uj_iterator.next(),
1907
1562
                {'test_id': 'prepare-upgrade-juju', 'result': True})
1908
 
 
1909
 
    def test_iter_steps_no_previous_client(self):
1910
 
        uj_attempt = PrepareUpgradeJujuAttempt({})
1911
 
        client = FakeEnvJujuClient(full_path='/present/juju')
1912
 
        uj_iterator = uj_attempt.iter_steps(client)
1913
 
        with self.assertRaises(CannotUpgradeToClient) as exc_context:
1914
 
            uj_iterator.next()
1915
 
        self.assertIs(exc_context.exception.client, client)
1916
 
 
1917
 
 
1918
 
class TestUpgradeJujuAttempt(JujuPyTestCase):
1919
 
 
1920
 
    def test_iter_steps(self):
1921
 
        future_client = FakeEnvJujuClient(full_path='/future/juju')
1922
 
        uj_attempt = UpgradeJujuAttempt()
1923
 
        uj_iterator = iter_steps_validate_info(self, uj_attempt, future_client)
1924
1563
        self.assertEqual(uj_iterator.next(), {'test_id': 'upgrade-juju'})
1925
1564
        with patch('subprocess.check_call') as cc_mock:
1926
1565
            self.assertEqual({'test_id': 'upgrade-juju'}, uj_iterator.next())
1927
 
        assert_juju_call(
1928
 
            self,
1929
 
            cc_mock,
1930
 
            future_client,
1931
 
            ('juju', '--show-log', 'upgrade-juju',
1932
 
             '-m', 'steve:steve', '--version',
1933
 
             future_client.get_matching_agent_version()))
 
1566
        assert_juju_call(self, cc_mock, future_client, (
 
1567
            'juju', '--show-log', 'upgrade-juju', '-e', 'steve', '--version',
 
1568
            future_client.get_matching_agent_version()))
1934
1569
        version_status = {
1935
1570
            'machines': {'0': {
1936
1571
                'agent-version': future_client.get_matching_agent_version()}},
1937
 
            'applications': {},
 
1572
            'services': {},
1938
1573
        }
1939
1574
        with patch_status(None, version_status):
1940
1575
            self.assertEqual({'test_id': 'upgrade-juju', 'result': True},
1941
1576
                             uj_iterator.next())
1942
1577
 
 
1578
    def test_iter_steps_no_previous_client(self):
 
1579
        uj_attempt = UpgradeJujuAttempt({})
 
1580
        client = FakeEnvJujuClient()
 
1581
        client.full_path = '/present/juju'
 
1582
        uj_iterator = uj_attempt.iter_steps(client)
 
1583
        with self.assertRaises(CannotUpgradeToClient) as exc_context:
 
1584
            uj_iterator.next()
 
1585
        self.assertIs(exc_context.exception.client, client)
 
1586
 
1943
1587
 
1944
1588
class TestUpgradeCharmAttempt(JujuPyTestCase):
1945
1589
 
1950
1594
        self.assertEqual(0o755, mode & 0o777)
1951
1595
 
1952
1596
    def test_iter_steps(self):
1953
 
        client = FakeEnvJujuClient(version='2.0.0', full_path='/future/juju')
1954
 
        self._iter_steps(client)
1955
 
 
1956
 
    def test_iter_steps_juju_1x(self):
1957
 
        client = FakeEnvJujuClient1X(version='1.25.0',
1958
 
                                     full_path='/future/juju')
1959
 
        self._iter_steps(client)
1960
 
 
1961
 
    def _iter_steps(self, client):
1962
 
        self.assertEqual(client.full_path, '/future/juju')
 
1597
        client = FakeEnvJujuClient()
 
1598
        client.full_path = '/future/juju'
1963
1599
        uc_attempt = UpgradeCharmAttempt()
1964
1600
        uc_iterator = iter_steps_validate_info(self, uc_attempt, client)
1965
1601
        self.assertEqual(uc_iterator.next(),
1976
1612
        self.assertEqual(metadata['name'], 'mycharm')
1977
1613
        self.assertIn('summary', metadata)
1978
1614
        self.assertIn('description', metadata)
1979
 
        self.assertEqual(['trusty'], metadata['series'])
1980
 
        if client.version.startswith('1.'):
1981
 
            charm_path = os.path.join('local:trusty', 'mycharm')
1982
 
            assert_juju_call(self, cc_mock, client, (
1983
 
                'juju', '--show-log', 'deploy', '-e', 'steve', charm_path,
1984
 
                '--repository', temp_repository))
1985
 
            option = '-e'
1986
 
        else:
1987
 
            charm_path = os.path.join(temp_repository, 'trusty', 'mycharm')
1988
 
            assert_juju_call(self, cc_mock, client, (
1989
 
                'juju', '--show-log', 'deploy',
1990
 
                '-m', 'steve:steve', charm_path))
1991
 
            option = '-m'
1992
 
        self.assertNotIn('min-juju-version', metadata)
 
1615
        assert_juju_call(self, cc_mock, client, (
 
1616
            'juju', '--show-log', 'deploy', '-e', 'steve',
 
1617
            'local:trusty/mycharm', '--repository', temp_repository))
1993
1618
        status = {
1994
1619
            'machines': {'0': {'agent-state': 'started'}},
1995
 
            'applications': {},
 
1620
            'services': {},
1996
1621
        }
1997
1622
        with patch_status(client, status):
1998
1623
            self.assertEqual(uc_iterator.next(),
2017
1642
        self.assertEqual(uc_iterator.next(), {'test_id': 'upgrade-charm'})
2018
1643
        with patch('subprocess.check_call') as cc_mock:
2019
1644
            self.assertEqual(uc_iterator.next(), {'test_id': 'upgrade-charm'})
2020
 
        if client.version.startswith('1.'):
2021
 
            assert_juju_call(self, cc_mock, client, (
2022
 
                'juju', '--show-log', 'upgrade-charm', option, 'steve',
2023
 
                'mycharm', '--repository', temp_repository))
2024
 
        else:
2025
 
            assert_juju_call(self, cc_mock, client, (
2026
 
                'juju', '--show-log', 'upgrade-charm', option, 'steve:steve',
2027
 
                'mycharm', '--path', os.path.join(temp_repository, 'trusty',
2028
 
                                                  'mycharm')))
 
1645
        assert_juju_call(self, cc_mock, client, (
 
1646
            'juju', '--show-log', 'upgrade-charm', '-e', 'steve',
 
1647
            'mycharm', '--repository', temp_repository))
2029
1648
        status = {
2030
1649
            'machines': {'0': {'agent-state': 'started'}},
2031
 
            'applications': {'mycharm': {'units': {'mycharm/0': {
 
1650
            'services': {'mycharm': {'units': {'mycharm/0': {
2032
1651
                'open-ports': ['42/tcp', '34/tcp'],
2033
1652
                }}}},
2034
1653
        }
2064
1683
class TestMakeSubstrate(JujuPyTestCase):
2065
1684
 
2066
1685
    def test_make_substrate_manager_no_support(self):
2067
 
        client = EnvJujuClient(JujuData('foo', {'type': 'foo'}),
 
1686
        client = EnvJujuClient(SimpleEnvironment('foo', {'type': 'foo'}),
2068
1687
                               '', '')
2069
1688
        with make_substrate_manager(client, []) as substrate:
2070
1689
            self.assertIs(substrate, None)
2071
1690
 
2072
1691
    def test_make_substrate_no_requirements(self):
2073
 
        client = EnvJujuClient(get_aws_juju_data(), '', '')
 
1692
        client = EnvJujuClient(get_aws_env(), '', '')
2074
1693
        with make_substrate_manager(client, []) as substrate:
2075
1694
            self.assertIs(type(substrate), AWSAccount)
2076
1695
 
2077
1696
    def test_make_substrate_manager_unsatisifed_requirements(self):
2078
 
        client = EnvJujuClient(get_aws_juju_data(), '', '')
 
1697
        client = EnvJujuClient(get_aws_env(), '', '')
2079
1698
        with make_substrate_manager(client, ['foo']) as substrate:
2080
1699
            self.assertIs(substrate, None)
2081
1700
        with make_substrate_manager(
2083
1702
            self.assertIs(substrate, None)
2084
1703
 
2085
1704
    def test_make_substrate_satisfied_requirements(self):
2086
 
        client = EnvJujuClient(get_aws_juju_data(), '', '')
 
1705
        client = EnvJujuClient(get_aws_env(), '', '')
2087
1706
        with make_substrate_manager(
2088
1707
                client, ['iter_security_groups']) as substrate:
2089
1708
            self.assertIs(type(substrate), AWSAccount)
2122
1741
                         {'test_id': 'foo-id', 'result': True})
2123
1742
        self.assertEqual(si.as_result(False),
2124
1743
                         {'test_id': 'foo-id', 'result': False})
2125
 
 
2126
 
 
2127
 
class TestAttemptSuiteFactory(TestCase):
2128
 
 
2129
 
    def test_factory(self):
2130
 
        fake_bootstrap = FakeAttemptClass('bootstrap')
2131
 
        factory = AttemptSuiteFactory([],
2132
 
                                      bootstrap_attempt=fake_bootstrap)
2133
 
        attempt_suite = factory.factory(['1', '2'], 'log-1', 'foo-stream')
2134
 
        self.assertEqual(factory, attempt_suite.attempt_list)
2135
 
        self.assertEqual(['1', '2'], attempt_suite.upgrade_sequence)
2136
 
        self.assertEqual('log-1', attempt_suite.log_dir)
2137
 
        self.assertEqual('foo-stream', attempt_suite.agent_stream)
2138
 
 
2139
 
    def test_get_test_info(self):
2140
 
        fake_bootstrap = FakeAttemptClass('fake-bootstrap')
2141
 
        fake_1 = FakeAttemptClass('fake-1')
2142
 
        fake_2 = FakeAttemptClass('fake-2')
2143
 
        factory = AttemptSuiteFactory([fake_1, fake_2],
2144
 
                                      bootstrap_attempt=fake_bootstrap)
2145
 
        self.assertEqual(OrderedDict([
2146
 
            ('fake-bootstrap-id', {'title': 'fake-bootstrap'}),
2147
 
            ('prepare-suite', {'title': 'Prepare suite tests',
2148
 
                               'report_on': False}),
2149
 
            ('fake-1-id', {'title': 'fake-1'}),
2150
 
            ('fake-2-id', {'title': 'fake-2'}),
2151
 
            ('destroy-env', {'title': 'destroy environment',
2152
 
                             'report_on': True}),
2153
 
            ('substrate-clean', {'title': 'check substrate clean',
2154
 
                                 'report_on': True}),
2155
 
            ]), factory.get_test_info())
2156
 
 
2157
 
 
2158
 
class TestAttemptSuite(TestCase):
2159
 
 
2160
 
    def test_get_test_info(self):
2161
 
        fake_bootstrap = FakeAttemptClass('fake-bootstrap')
2162
 
        fake_1 = FakeAttemptClass('fake-1')
2163
 
        fake_2 = FakeAttemptClass('fake-2')
2164
 
        factory = AttemptSuiteFactory([fake_1, fake_2],
2165
 
                                      bootstrap_attempt=fake_bootstrap)
2166
 
        attempt_suite = AttemptSuite(factory, None, None, None)
2167
 
        self.assertEqual(OrderedDict([
2168
 
            ('fake-bootstrap-id', {'title': 'fake-bootstrap'}),
2169
 
            ('prepare-suite', {'title': 'Prepare suite tests',
2170
 
                               'report_on': False}),
2171
 
            ('fake-1-id', {'title': 'fake-1'}),
2172
 
            ('fake-2-id', {'title': 'fake-2'}),
2173
 
            ('destroy-env', {'title': 'destroy environment',
2174
 
                             'report_on': True}),
2175
 
            ('substrate-clean', {'title': 'check substrate clean',
2176
 
                                 'report_on': True}),
2177
 
            ]), attempt_suite.get_test_info())
2178
 
 
2179
 
    @contextmanager
2180
 
    def iter_steps_cxt(self, attempt_suite):
2181
 
        with patch('industrial_test.BootstrapManager') as mock_bm:
2182
 
            with patch.object(attempt_suite,
2183
 
                              '_iter_bs_manager_steps') as mock_ibms:
2184
 
                with patch('industrial_test.make_log_dir',
2185
 
                           return_value='qux-1'):
2186
 
                    yield (mock_ibms, mock_bm)
2187
 
 
2188
 
    def test_iter_steps(self):
2189
 
        fake_bootstrap = FakeAttemptClass('fake-bootstrap', '1', '2')
2190
 
        factory = AttemptSuiteFactory([], bootstrap_attempt=fake_bootstrap)
2191
 
        attempt_suite = AttemptSuite(factory, None, 'asdf', None)
2192
 
        with self.iter_steps_cxt(attempt_suite) as (mock_ibms, mock_bm):
2193
 
            client = fake_juju_client()
2194
 
            attempt_suite.iter_steps(client)
2195
 
        mock_bm.assert_called_once_with(
2196
 
            'name', client, client, agent_stream=None, agent_url=None,
2197
 
            bootstrap_host=None, jes_enabled=True, keep_env=True,
2198
 
            log_dir='qux-1', machines=[], permanent=True,
2199
 
            region=None, series=None)
2200
 
 
2201
 
    def test_iter_steps_agent_stream(self):
2202
 
        fake_bootstrap = FakeAttemptClass('fake-bootstrap', '1', '2')
2203
 
        factory = AttemptSuiteFactory([], bootstrap_attempt=fake_bootstrap)
2204
 
        attempt_suite = AttemptSuite(factory, None, 'asdf', 'bar-stream')
2205
 
        with self.iter_steps_cxt(attempt_suite) as (mock_ibms, mock_bm):
2206
 
            client = fake_juju_client()
2207
 
            iterator = attempt_suite.iter_steps(client)
2208
 
        self.assertEqual(iterator, mock_ibms.return_value)
2209
 
        mock_bm.assert_called_once_with(
2210
 
            'name', client, client, agent_stream='bar-stream', agent_url=None,
2211
 
            bootstrap_host=None, jes_enabled=True, keep_env=True,
2212
 
            log_dir='qux-1', machines=[], permanent=True,
2213
 
            region=None, series=None)
2214
 
 
2215
 
    def test__iter_bs_manager_steps(self):
2216
 
        fake_bootstrap = FakeAttemptClass('fake-bootstrap', '1', '2')
2217
 
        fake_1 = FakeAttemptClass('fake-1', '1', '2')
2218
 
        fake_2 = FakeAttemptClass('fake-2', '1', '2')
2219
 
        factory = AttemptSuiteFactory([fake_1, fake_2],
2220
 
                                      bootstrap_attempt=fake_bootstrap)
2221
 
        attempt_suite = AttemptSuite(factory, None, None, None)
2222
 
        client = fake_juju_client()
2223
 
        bs_manager = FakeBootstrapManager(client)
2224
 
        steps = list(attempt_suite._iter_bs_manager_steps(
2225
 
            bs_manager, client, fake_bootstrap(), True))
2226
 
        self.assertEqual([
2227
 
            {'test_id': 'fake-bootstrap-id'},
2228
 
            {'test_id': 'fake-bootstrap-id', 'result': '1'},
2229
 
            {'test_id': 'prepare-suite'},
2230
 
            {'test_id': 'prepare-suite', 'result': True},
2231
 
            {'test_id': 'fake-1-id'},
2232
 
            {'test_id': 'fake-1-id', 'result': '1'},
2233
 
            {'test_id': 'fake-2-id'},
2234
 
            {'test_id': 'fake-2-id', 'result': '1'},
2235
 
            {'test_id': 'destroy-env'},
2236
 
            {'test_id': 'destroy-env', 'result': True},
2237
 
            {'test_id': 'substrate-clean'},
2238
 
            {'test_id': 'substrate-clean', 'result': True},
2239
 
            ], steps)
2240
 
 
2241
 
    def test__iter_bs_manager_steps_teardown_in_runtime(self):
2242
 
        fake_bootstrap = FakeAttemptClass('fake-bootstrap', '1', '2')
2243
 
        fake_1 = FakeAttemptClass('fake-1', Exception('fake exception'), '2')
2244
 
        factory = AttemptSuiteFactory([fake_1],
2245
 
                                      bootstrap_attempt=fake_bootstrap)
2246
 
        attempt_suite = AttemptSuite(factory, None, None, None)
2247
 
        client = fake_juju_client()
2248
 
        bs_manager = FakeBootstrapManager(client, keep_env=True)
2249
 
        with self.assertRaisesRegexp(Exception, 'fake exception'):
2250
 
            list(attempt_suite._iter_bs_manager_steps(
2251
 
                bs_manager, client, fake_bootstrap(), True))
2252
 
        self.assertIs(True, bs_manager.torn_down)