~andrewjbeach/juju-ci-tools/make-local-patcher

« back to all changes in this revision

Viewing changes to test_chaos.py

  • Committer: Aaron Bentley
  • Date: 2015-08-19 15:07:08 UTC
  • mto: This revision was merged to the branch mainline in revision 1069.
  • Revision ID: aaron.bentley@canonical.com-20150819150708-88xesx4iardg12b4
Wait for proc to exit after signalling.

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
    NamedTemporaryFile,
6
6
    mkdtemp,
7
7
    )
8
 
import unittest
 
8
from unittest import TestCase
9
9
 
10
 
from mock import (
11
 
    call,
12
 
    patch,
13
 
)
 
10
from mock import patch
14
11
import yaml
15
12
 
16
13
from chaos import (
19
16
    )
20
17
from jujupy import (
21
18
    EnvJujuClient,
22
 
    JujuData,
 
19
    SimpleEnvironment,
23
20
    )
24
21
from remote import SSHRemote
25
 
from tests import FakeHomeTestCase
26
22
from test_jujupy import (
27
23
    assert_juju_call,
28
24
    )
29
25
 
30
26
 
31
 
class TestBackgroundChaos(FakeHomeTestCase):
 
27
def fake_EnvJujuClient_by_version(env, path=None, debug=None):
 
28
    return EnvJujuClient(env=env, version='1.2.3.4', full_path=path)
 
29
 
 
30
 
 
31
def fake_SimpleEnvironment_from_config(name):
 
32
    return SimpleEnvironment(name, {})
 
33
 
 
34
 
 
35
class TestBackgroundChaos(TestCase):
32
36
 
33
37
    def test_background_chaos(self):
34
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo/juju')
 
38
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo/juju')
35
39
        with patch('chaos.MonkeyRunner.deploy_chaos_monkey',
36
40
                   autospec=True) as d_mock:
37
41
            with patch('chaos.MonkeyRunner.unleash_once',
51
55
        self.assertEqual(1, ru_mock.call_count)
52
56
        self.assertEqual(1, rc_mock.call_count)
53
57
        self.assertEqual({'state': 'start'}, w_mock.mock_calls[0][2])
54
 
        self.assertEqual({'state': 'complete', 'timeout': 1},
55
 
                         w_mock.mock_calls[1][2])
 
58
        self.assertEqual({'state': 'complete'}, w_mock.mock_calls[1][2])
56
59
 
57
60
    def test_background_chaos_exits(self):
58
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo/juju')
 
61
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo/juju')
59
62
        with patch('chaos.MonkeyRunner.deploy_chaos_monkey',
60
63
                   autospec=True):
61
64
            with patch('chaos.MonkeyRunner.unleash_once',
75
78
        sm.assert_called_once_with(1)
76
79
 
77
80
 
78
 
class TestRunChaosMonkey(FakeHomeTestCase):
 
81
class TestRunChaosMonkey(TestCase):
79
82
 
80
83
    def test_deploy_chaos_monkey(self):
81
 
        def output(*args, **kwargs):
 
84
        def output(args, **kwargs):
82
85
            status = yaml.safe_dump({
83
86
                'machines': {
84
87
                    '0': {'agent-state': 'started'}
85
88
                },
86
 
                'applications': {
 
89
                'services': {
87
90
                    'ser1': {
88
91
                        'units': {
89
92
                            'bar': {
99
102
                }
100
103
            })
101
104
            output = {
102
 
                ('show-status', '--format', 'yaml'): status,
 
105
                ('juju', '--show-log', 'status', '-e', 'foo'): status,
103
106
                }
104
107
            return output[args]
105
 
        client = EnvJujuClient(JujuData('foo', {}), '1.25.0', '/foo/juju')
106
 
        with patch.object(client, 'get_juju_output', side_effect=output,
107
 
                          autospec=True) as gjo_mock:
 
108
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo/juju')
 
109
        with patch('subprocess.check_output', side_effect=output,
 
110
                   autospec=True) as co_mock:
108
111
            with patch('subprocess.check_call', autospec=True) as cc_mock:
109
112
                monkey_runner = MonkeyRunner('foo', client, service='ser1')
110
 
                with patch('jujupy.GroupReporter._write', autospec=True):
 
113
                with patch('sys.stdout', autospec=True):
111
114
                    monkey_runner.deploy_chaos_monkey()
112
 
        assert_juju_call(
113
 
            self,
114
 
            cc_mock,
115
 
            client,
116
 
            ('juju', '--show-log', 'deploy',
117
 
             '-m', 'foo:foo', 'local:chaos-monkey'),
 
115
        assert_juju_call(self, cc_mock, client, (
 
116
            'juju', '--show-log', 'deploy', '-e', 'foo', 'local:chaos-monkey'),
118
117
            0)
119
118
        assert_juju_call(self, cc_mock, client, (
120
 
            'juju', '--show-log', 'add-relation', '-m', 'foo:foo', 'ser1',
 
119
            'juju', '--show-log', 'add-relation', '-e', 'foo', 'ser1',
121
120
            'chaos-monkey'), 1)
122
121
        self.assertEqual(cc_mock.call_count, 2)
123
 
        self.assertEqual(gjo_mock.call_count, 2)
 
122
        self.assertEqual(co_mock.call_count, 2)
124
123
 
125
124
    def test_iter_chaos_monkey_units(self):
126
 
        def output(*args, **kwargs):
 
125
        def output(args, **kwargs):
127
126
            status = yaml.safe_dump({
128
127
                'machines': {
129
128
                    '0': {'agent-state': 'started'}
130
129
                },
131
 
                'applications': {
 
130
                'services': {
132
131
                    'jenkins': {
133
132
                        'units': {
134
133
                            'foo': {
147
146
                }
148
147
            })
149
148
            output = {
150
 
                ('show-status', '--format', 'yaml'): status,
 
149
                ('juju', '--show-log', 'status', '-e', 'foo'): status,
151
150
                }
152
151
            return output[args]
153
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo/juju')
 
152
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo/juju')
154
153
        runner = MonkeyRunner('foo', client, service='jenkins')
155
 
        with patch.object(client, 'get_juju_output', side_effect=output,
156
 
                          autospec=True):
 
154
        with patch('subprocess.check_output', side_effect=output,
 
155
                   autospec=True):
157
156
            monkey_units = dict((k, v) for k, v in
158
157
                                runner.iter_chaos_monkey_units())
159
158
        expected = {
163
162
        self.assertEqual(expected, monkey_units)
164
163
 
165
164
    def test_get_unit_status(self):
166
 
        def output(*args, **kwargs):
 
165
        def output(args, **kwargs):
167
166
            status = yaml.safe_dump({
168
167
                'machines': {
169
168
                    '0': {'agent-state': 'started'}
170
169
                },
171
 
                'applications': {
 
170
                'services': {
172
171
                    'jenkins': {
173
172
                        'units': {
174
173
                            'foo': {
199
198
                }
200
199
            })
201
200
            output = {
202
 
                ('status',): status,
203
 
                ('config', 'chaos-monkey'): charm_config,
 
201
                ('juju', '--show-log', 'status', '-e', 'foo'): status,
 
202
                ('juju', '--show-log', 'get', '-e', 'foo', 'chaos-monkey'
 
203
                 ): charm_config,
204
204
                }
205
205
            return output[args]
206
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo')
 
206
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo')
207
207
        monkey_runner = MonkeyRunner('foo', client, service='jenkins')
208
208
        monkey_runner.monkey_ids = {
209
209
            'chaos-monkey/0': 'workspace0',
210
210
            'chaos-monkey/1': 'workspace1'
211
211
        }
212
 
        with patch.object(client, 'get_juju_output', side_effect=output,
213
 
                          autospec=True):
 
212
        with patch('subprocess.check_output', side_effect=output,
 
213
                   autospec=True):
214
214
            with patch('subprocess.call', autospec=True,
215
215
                       return_value=0) as call_mock:
216
216
                for unit_name in ['chaos-monkey/1', 'chaos-monkey/0']:
217
 
                    self.assertEqual(monkey_runner.get_unit_status(unit_name),
218
 
                                     'running')
 
217
                    with patch('sys.stdout', autospec=True):
 
218
                        self.assertEqual(
 
219
                            monkey_runner.get_unit_status(unit_name),
 
220
                            'running')
219
221
            self.assertEqual(call_mock.call_count, 2)
220
 
        with patch.object(client, 'get_juju_output', side_effect=output,
221
 
                          autospec=True):
 
222
        with patch('subprocess.check_output', side_effect=output,
 
223
                   autospec=True):
222
224
            with patch('subprocess.call', autospec=True,
223
225
                       return_value=1) as call_mock:
224
226
                for unit_name in ['chaos-monkey/1', 'chaos-monkey/0']:
225
 
                    self.assertEqual(monkey_runner.get_unit_status(unit_name),
226
 
                                     'done')
 
227
                    with patch('sys.stdout', autospec=True):
 
228
                        self.assertEqual(
 
229
                            monkey_runner.get_unit_status(unit_name),
 
230
                            'done')
227
231
            self.assertEqual(call_mock.call_count, 2)
228
232
 
229
233
 
230
 
class TestUnleashOnce(FakeHomeTestCase):
 
234
class TestUnleashOnce(TestCase):
231
235
 
232
236
    def test_unleash_once(self):
233
 
        def output(*args, **kwargs):
 
237
        def output(args, **kwargs):
234
238
            status = yaml.safe_dump({
235
239
                'machines': {
236
240
                    '0': {'agent-state': 'started'}
237
241
                },
238
 
                'applications': {
 
242
                'services': {
239
243
                    'jenkins': {
240
244
                        'units': {
241
245
                            'foo': {
266
270
                }
267
271
            })
268
272
            output = {
269
 
                ('show-status', '--format', 'yaml'): status,
270
 
                ('get', 'jenkins'): charm_config,
271
 
                ('run-action', 'chaos-monkey/0', 'start', 'mode=single',
272
 
                 'enablement-timeout=120'
273
 
                 ): ('Action queued with id: '
274
 
                     'abcdabcdabcdabcdabcdabcdabcdabcdabcd'),
275
 
                ('run-action', 'chaos-monkey/0', 'start', 'mode=single',
276
 
                 'enablement-timeout=120',
277
 
                 'monkey-id=abcdabcdabcdabcdabcdabcdabcdabcdabcd'
278
 
                 ): ('Action queued with id: '
279
 
                     'efabefabefabefabefabefabefabefabefab'),
280
 
                ('run-action', 'chaos-monkey/1', 'start', 'mode=single',
281
 
                 'enablement-timeout=120'
282
 
                 ): ('Action queued with id: '
283
 
                     '123412341234123412341234123412341234'),
284
 
                ('run-action', 'chaos-monkey/1', 'start', 'mode=single',
285
 
                 'enablement-timeout=120',
286
 
                 'monkey-id=123412341234123412341234123412341234'
287
 
                 ): ('Action queued with id: '
288
 
                     '567856785678567856785678567856785678'),
 
273
                ('juju', '--show-log', 'status', '-e', 'foo'): status,
 
274
                ('juju', '--show-log', 'get', '-e', 'foo', 'jenkins'
 
275
                 ): charm_config,
 
276
                ('juju', '--show-log', 'action', 'do', '-e', 'foo',
 
277
                 'chaos-monkey/0', 'start', 'mode=single',
 
278
                 'enablement-timeout=120'
 
279
                 ): 'Action queued with id: abcd',
 
280
                ('juju', '--show-log', 'action', 'do', '-e', 'foo',
 
281
                 'chaos-monkey/0', 'start', 'mode=single',
 
282
                 'enablement-timeout=120', 'monkey-id=abcd'
 
283
                 ): 'Action queued with id: efgh',
 
284
                ('juju', '--show-log', 'action', 'do', '-e', 'foo',
 
285
                 'chaos-monkey/1', 'start', 'mode=single',
 
286
                 'enablement-timeout=120'
 
287
                 ): 'Action queued with id: 1234',
 
288
                ('juju', '--show-log', 'action', 'do', '-e', 'foo',
 
289
                 'chaos-monkey/1', 'start', 'mode=single',
 
290
                 'enablement-timeout=120', 'monkey-id=1234'
 
291
                 ): 'Action queued with id: 5678',
289
292
                }
290
293
            return output[args]
291
294
 
292
 
        def output2(*args, **kwargs):
 
295
        def output2(args, **kwargs):
293
296
            status = yaml.safe_dump({
294
297
                'machines': {
295
298
                    '0': {'agent-state': 'started'}
296
299
                },
297
 
                'applications': {
 
300
                'services': {
298
301
                    'jenkins': {
299
302
                        'units': {
300
303
                            'bar': {
307
310
                }
308
311
            })
309
312
            output = {
310
 
                ('show-status', '--format', 'yaml'): status,
311
 
                ('run-action', 'chaos-monkey/1', 'start', 'mode=single',
312
 
                 'enablement-timeout=120',
313
 
                 'monkey-id=123412341234123412341234123412341234'
314
 
                 ): ('Action queued with id: '
315
 
                     'abcdabcdabcdabcdabcdabcdabcdabcdabcd'),
 
313
                ('juju', '--show-log', 'status', '-e', 'foo'): status,
 
314
                ('juju', '--show-log', 'action', 'do', '-e', 'foo',
 
315
                 'chaos-monkey/1', 'start', 'mode=single',
 
316
                 'enablement-timeout=120', 'monkey-id=1234'
 
317
                 ): 'Action queued with id: abcd',
316
318
                }
317
319
            return output[args]
318
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo/juju')
 
320
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo/juju')
319
321
        monkey_runner = MonkeyRunner('foo', client, service='jenkins')
320
 
        with patch.object(client, 'get_juju_output', side_effect=output,
321
 
                          autospec=True) as gjo_mock:
 
322
        with patch('subprocess.check_output', side_effect=output,
 
323
                   autospec=True) as co_mock:
322
324
            returned = monkey_runner.unleash_once()
323
 
        expected = ['abcd' * 9, '1234' * 9]
324
 
        self.assertEqual(
325
 
            [
326
 
                call('show-status', '--format', 'yaml', controller=False),
327
 
                call('run-action', 'chaos-monkey/1', 'start', 'mode=single',
328
 
                     'enablement-timeout=120'),
329
 
                call('run-action', 'chaos-monkey/0', 'start', 'mode=single',
330
 
                     'enablement-timeout=120'),
331
 
            ],
332
 
            gjo_mock.call_args_list)
 
325
        expected = ['abcd', '1234']
 
326
        assert_juju_call(self, co_mock, client, (
 
327
            'juju', '--show-log', 'action', 'do', '-e', 'foo',
 
328
            'chaos-monkey/1', 'start', 'mode=single',
 
329
            'enablement-timeout=120'), 1, True)
 
330
        assert_juju_call(self, co_mock, client, (
 
331
            'juju', '--show-log', 'action', 'do', '-e', 'foo',
 
332
            'chaos-monkey/0', 'start', 'mode=single',
 
333
            'enablement-timeout=120'), 2, True)
333
334
        self.assertEqual(['chaos-monkey/1', 'chaos-monkey/0'],
334
335
                         monkey_runner.monkey_ids.keys())
335
336
        self.assertEqual(len(monkey_runner.monkey_ids), 2)
 
337
        self.assertEqual(co_mock.call_count, 3)
336
338
        self.assertItemsEqual(returned, expected)
337
 
        with patch.object(client, 'get_juju_output', side_effect=output,
338
 
                          autospec=True) as gjo_mock:
 
339
        with patch('subprocess.check_output', side_effect=output,
 
340
                   autospec=True) as co_mock:
339
341
            monkey_runner.unleash_once()
340
 
        self.assertEqual(
341
 
            [
342
 
                call('show-status', '--format', 'yaml', controller=False),
343
 
                call('run-action',
344
 
                     'chaos-monkey/1', 'start', 'mode=single',
345
 
                     'enablement-timeout=120',
346
 
                     'monkey-id=123412341234123412341234123412341234'),
347
 
                call('run-action',
348
 
                     'chaos-monkey/0', 'start', 'mode=single',
349
 
                     'enablement-timeout=120',
350
 
                     'monkey-id=abcdabcdabcdabcdabcdabcdabcdabcdabcd'),
351
 
            ],
352
 
            gjo_mock.call_args_list)
 
342
        assert_juju_call(self, co_mock, client, (
 
343
            'juju', '--show-log', 'action', 'do', '-e', 'foo',
 
344
            'chaos-monkey/1', 'start', 'mode=single', 'enablement-timeout=120',
 
345
            'monkey-id=1234'), 1, True)
 
346
        assert_juju_call(self, co_mock, client, (
 
347
            'juju', '--show-log', 'action', 'do', '-e', 'foo',
 
348
            'chaos-monkey/0', 'start', 'mode=single', 'enablement-timeout=120',
 
349
            'monkey-id=abcd'), 2, True)
353
350
        self.assertTrue('1234', monkey_runner.monkey_ids['chaos-monkey/1'])
354
351
        # Test monkey_ids.get(unit_name) does not change on second call to
355
352
        # unleash_once()
356
 
        with patch.object(client, 'get_juju_output', side_effect=output2,
357
 
                          autospec=True):
 
353
        with patch('subprocess.check_output', side_effect=output2,
 
354
                   autospec=True):
358
355
            monkey_runner.unleash_once()
359
 
        self.assertEqual('1234' * 9,
360
 
                         monkey_runner.monkey_ids['chaos-monkey/1'])
 
356
        self.assertEqual('1234', monkey_runner.monkey_ids['chaos-monkey/1'])
361
357
 
362
358
    def test_unleash_once_raises_for_unexpected_action_output(self):
363
 
        def output(*args, **kwargs):
 
359
        def output(args, **kwargs):
364
360
            status = yaml.safe_dump({
365
361
                'machines': {
366
362
                    '0': {'agent-state': 'started'}
367
363
                },
368
 
                'applications': {
 
364
                'services': {
369
365
                    'jenkins': {
370
366
                        'units': {
371
367
                            'foo': {
378
374
                }
379
375
            })
380
376
            output = {
381
 
                ('show-status', '--format', 'yaml'): status,
382
 
                ('run-action', 'chaos-monkey/0', 'start', 'mode=single',
 
377
                ('juju', '--show-log', 'status', '-e', 'foo'): status,
 
378
                ('juju', '--show-log', 'action', 'do', '-e', 'foo',
 
379
                 'chaos-monkey/0', 'start', 'mode=single',
383
380
                 'enablement-timeout=120'
384
381
                 ): 'Action fail',
385
382
                }
386
383
            return output[args]
387
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo/juju')
 
384
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo/juju')
388
385
        monkey_runner = MonkeyRunner('foo', client, service='jenkins')
389
 
        with patch.object(client, 'get_juju_output', side_effect=output,
390
 
                          autospec=True):
 
386
        with patch('subprocess.check_output', side_effect=output,
 
387
                   autospec=True):
391
388
            with self.assertRaisesRegexp(
392
 
                    Exception, 'Action id not found in output: Action fail'):
 
389
                    Exception, 'Unexpected output from "juju action do":'):
393
390
                monkey_runner.unleash_once()
394
391
 
395
392
 
396
 
class TestIsHealthy(unittest.TestCase):
 
393
class TestIsHealthy(TestCase):
397
394
 
398
395
    def test_is_healthy(self):
399
396
        SCRIPT = """#!/bin/bash\necho -n 'PASS'\nexit 0"""
400
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo/juju')
 
397
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo/juju')
401
398
        with NamedTemporaryFile(delete=False) as health_script:
402
399
            health_script.write(SCRIPT)
403
400
            os.fchmod(health_script.fileno(), stat.S_IEXEC | stat.S_IREAD)
413
410
 
414
411
    def test_is_healthy_fail(self):
415
412
        SCRIPT = """#!/bin/bash\necho -n 'FAIL'\nexit 1"""
416
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo/juju')
 
413
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo/juju')
417
414
        with NamedTemporaryFile(delete=False) as health_script:
418
415
            health_script.write(SCRIPT)
419
416
            os.fchmod(health_script.fileno(), stat.S_IEXEC | stat.S_IREAD)
428
425
 
429
426
    def test_is_healthy_with_no_execute_perms(self):
430
427
        SCRIPT = """#!/bin/bash\nexit 0"""
431
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo/juju')
 
428
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo/juju')
432
429
        with NamedTemporaryFile(delete=False) as health_script:
433
430
            health_script.write(SCRIPT)
434
431
            os.fchmod(health_script.fileno(), stat.S_IREAD)
444
441
            r'The health check failed to execute with: \[Errno 13\].*')
445
442
 
446
443
 
447
 
class TestWaitForChaos(FakeHomeTestCase):
 
444
class TestWaitForChaos(TestCase):
448
445
 
449
446
    def test_wait_for_chaos_complete(self):
450
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo')
 
447
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo')
451
448
        runner = MonkeyRunner('foo', client)
452
449
        units = [('blib', 'blab')]
453
450
        with patch.object(runner, 'iter_chaos_monkey_units', autospec=True,
460
457
        self.assertEqual(us_mock.call_count, 1)
461
458
 
462
459
    def test_wait_for_chaos_complete_timesout(self):
463
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo')
 
460
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo')
464
461
        runner = MonkeyRunner('foo', client)
465
462
        with self.assertRaisesRegexp(
466
463
                Exception, 'Chaos operations did not complete.'):
467
464
            runner.wait_for_chaos(timeout=0)
468
465
 
469
466
    def test_wait_for_chaos_started(self):
470
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo')
 
467
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo')
471
468
        runner = MonkeyRunner('foo', client)
472
469
        units = [('blib', 'blab')]
473
470
        with patch.object(runner, 'iter_chaos_monkey_units', autospec=True,
481
478
        self.assertEqual(us_mock.call_count, 1)
482
479
 
483
480
    def test_wait_for_chaos_unexpected_state(self):
484
 
        client = EnvJujuClient(JujuData('foo', {}), None, '/foo')
 
481
        client = EnvJujuClient(SimpleEnvironment('foo', {}), None, '/foo')
485
482
        runner = MonkeyRunner('foo', client)
486
483
        with self.assertRaisesRegexp(
487
484
                Exception, 'Unexpected state value: foo'):