219
209
def test_check_token(self):
220
210
env = JujuData('foo', {'type': 'local'})
221
211
client = EnvJujuClient(env, None, None)
222
status = Status.from_text("""\
229
message: Token is token
232
212
remote = SSHRemote(client, 'unit', None, series='xenial')
233
213
with patch('deploy_stack.remote_from_unit', autospec=True,
234
214
return_value=remote):
235
215
with patch.object(remote, 'run', autospec=True,
236
216
return_value='token') as rr_mock:
237
with patch.object(client, 'get_status', autospec=True,
238
return_value=status):
239
check_token(client, 'token', timeout=0)
217
check_token(client, 'token', timeout=0)
240
218
rr_mock.assert_called_once_with(GET_TOKEN_SCRIPT)
241
219
self.assertTrue(remote.use_juju_ssh)
242
220
self.assertEqual(
243
['INFO Waiting for applications to reach ready.',
244
'INFO Retrieving token.',
221
['INFO Retrieving token.',
245
222
"INFO Token matches expected 'token'"],
246
223
self.log_stream.getvalue().splitlines())
248
225
def test_check_token_not_found(self):
249
226
env = JujuData('foo', {'type': 'local'})
250
227
client = EnvJujuClient(env, None, None)
251
status = Status.from_text("""\
258
message: Waiting for token
261
228
remote = SSHRemote(client, 'unit', None, series='xenial')
262
229
with patch('deploy_stack.remote_from_unit', autospec=True,
263
230
return_value=remote):
265
232
return_value='') as rr_mock:
266
233
with patch.object(remote, 'get_address',
267
234
autospec=True) as ga_mock:
268
with patch.object(client, 'get_status', autospec=True,
269
return_value=status):
270
with self.assertRaisesRegexp(ValueError,
272
check_token(client, 'token', timeout=0)
235
with self.assertRaisesRegexp(ValueError, "Token is ''"):
236
check_token(client, 'token', timeout=0)
273
237
self.assertEqual(2, rr_mock.call_count)
274
238
rr_mock.assert_called_with(GET_TOKEN_SCRIPT)
275
239
ga_mock.assert_called_once_with()
276
240
self.assertFalse(remote.use_juju_ssh)
277
241
self.assertEqual(
278
['INFO Waiting for applications to reach ready.',
279
'INFO Retrieving token.'],
242
['INFO Retrieving token.'],
280
243
self.log_stream.getvalue().splitlines())
282
245
def test_check_token_not_found_juju_ssh_broken(self):
283
246
env = JujuData('foo', {'type': 'local'})
284
247
client = EnvJujuClient(env, None, None)
285
status = Status.from_text("""\
292
message: Token is token
295
248
remote = SSHRemote(client, 'unit', None, series='xenial')
296
249
with patch('deploy_stack.remote_from_unit', autospec=True,
297
250
return_value=remote):
299
252
side_effect=['', 'token']) as rr_mock:
300
253
with patch.object(remote, 'get_address',
301
254
autospec=True) as ga_mock:
302
with patch.object(client, 'get_status', autospec=True,
303
return_value=status):
304
with self.assertRaisesRegexp(ValueError,
306
check_token(client, 'token', timeout=0)
255
with self.assertRaisesRegexp(ValueError,
257
check_token(client, 'token', timeout=0)
307
258
self.assertEqual(2, rr_mock.call_count)
308
259
rr_mock.assert_called_with(GET_TOKEN_SCRIPT)
309
260
ga_mock.assert_called_once_with()
310
261
self.assertFalse(remote.use_juju_ssh)
311
262
self.assertEqual(
312
['INFO Waiting for applications to reach ready.',
313
'INFO Retrieving token.',
263
['INFO Retrieving token.',
314
264
"INFO Token matches expected 'token'",
315
265
'ERROR juju ssh to unit is broken.'],
316
266
self.log_stream.getvalue().splitlines())
318
def test_check_token_win_status(self):
319
env = JujuData('foo', {'type': 'azure'})
320
client = EnvJujuClient(env, None, None)
321
remote = MagicMock(spec=['cat', 'is_windows'])
322
remote.is_windows.return_value = True
323
status = Status.from_text("""\
330
message: Token is token
333
with patch('deploy_stack.remote_from_unit', autospec=True,
334
return_value=remote):
335
with patch.object(client, 'get_status', autospec=True,
336
return_value=status):
337
check_token(client, 'token', timeout=0)
338
# application-status had the token.
339
self.assertEqual(0, remote.cat.call_count)
341
['INFO Waiting for applications to reach ready.',
342
'INFO Retrieving token.',
343
"INFO Token matches expected 'token'"],
344
self.log_stream.getvalue().splitlines())
346
def test_check_token_win_remote(self):
347
env = JujuData('foo', {'type': 'azure'})
348
client = EnvJujuClient(env, None, None)
349
remote = MagicMock(spec=['cat', 'is_windows'])
350
remote.is_windows.return_value = True
351
remote.cat.return_value = 'token'
352
status = Status.from_text("""\
360
with patch('deploy_stack.remote_from_unit', autospec=True,
361
return_value=remote):
362
with patch.object(client, 'get_status', autospec=True,
363
return_value=status):
364
check_token(client, 'token', timeout=0)
365
# application-status did not have the token, winrm did.
366
remote.cat.assert_called_once_with('%ProgramData%\\dummy-sink\\token')
368
['INFO Waiting for applications to reach ready.',
369
'INFO Retrieving token.',
370
"INFO Token matches expected 'token'"],
371
self.log_stream.getvalue().splitlines())
373
def test_check_token_win_remote_failure(self):
374
env = JujuData('foo', {'type': 'azure'})
375
client = EnvJujuClient(env, None, None)
376
remote = MagicMock(spec=['cat', 'is_windows'])
377
remote.is_windows.return_value = True
378
remote.cat.side_effect = winrm.exceptions.WinRMTransportError(
380
status = Status.from_text("""\
388
with patch('deploy_stack.remote_from_unit', autospec=True,
389
return_value=remote):
390
with patch.object(client, 'get_status', autospec=True,
391
return_value=status):
392
check_token(client, 'token', timeout=0)
393
# application-status did not have the token, winrm did.
394
remote.cat.assert_called_once_with('%ProgramData%\\dummy-sink\\token')
396
['INFO Waiting for applications to reach ready.',
397
'INFO Retrieving token.',
398
'WARNING Skipping token check because of: '
399
'500 WinRMTransport. oops'],
400
self.log_stream.getvalue().splitlines())
402
268
log_level = logging.DEBUG
525
382
archive_logs(log_dir)
526
383
self.assertEquals(cc_mock.call_count, 0)
528
def test_archive_logs_multiple(self):
529
with temp_dir() as log_dir:
531
with open(os.path.join(log_dir, 'fake.log'), 'w') as f:
532
f.write('log contents')
533
log_paths.append(os.path.join(log_dir, 'fake.log'))
534
subdir = os.path.join(log_dir, "subdir")
536
with open(os.path.join(subdir, 'syslog'), 'w') as f:
537
f.write('syslog contents')
538
log_paths.append(os.path.join(subdir, 'syslog'))
539
with patch('subprocess.check_call', autospec=True) as cc_mock:
540
archive_logs(log_dir)
541
self.assertEqual(1, cc_mock.call_count)
542
call_args, call_kwargs = cc_mock.call_args
543
gzip_args = call_args[0]
544
self.assertEqual(0, len(call_kwargs))
545
self.assertEqual(gzip_args[:3], ['gzip', '--best', '-f'])
546
self.assertEqual(set(gzip_args[3:]), set(log_paths))
548
385
def test_copy_local_logs(self):
549
386
# Relevent local log files are copied, after changing their permissions
550
387
# to allow access by non-root user.
999
836
def ds_cxt(self):
1000
837
env = JujuData('foo', {})
1001
838
client = fake_EnvJujuClient(env)
1002
bc_cxt = patch('deploy_stack.client_from_config',
839
bc_cxt = patch('jujupy.EnvJujuClient.by_version',
1003
840
return_value=client)
1004
841
fc_cxt = patch('jujupy.SimpleEnvironment.from_config',
1005
842
return_value=env)
1006
843
mgr = MagicMock()
1007
844
bm_cxt = patch('deploy_stack.BootstrapManager', autospec=True,
1008
845
return_value=mgr)
1009
juju_cxt = patch('jujupy.EnvJujuClient.juju', autospec=True)
846
juju_cxt = patch('deploy_stack.EnvJujuClient.juju', autospec=True)
1010
847
ajr_cxt = patch('deploy_stack.assess_juju_run', autospec=True)
1011
848
dds_cxt = patch('deploy_stack.deploy_dummy_stack', autospec=True)
1012
849
with bc_cxt, fc_cxt, bm_cxt as bm_mock, juju_cxt, ajr_cxt, dds_cxt:
1110
947
'juju', '--show-log', 'show-status', '-m', 'foo:foo',
1111
948
'--format', 'yaml')
1112
CONTROLLER_STATUS = (
1113
'juju', '--show-log', 'show-status', '-m', 'foo:controller',
1115
GET_ENV = ('juju', '--show-log', 'model-config', '-m', 'foo:foo',
1116
'agent-metadata-url')
1117
GET_CONTROLLER_ENV = (
1118
'juju', '--show-log', 'model-config', '-m', 'foo:controller',
1119
'agent-metadata-url')
1121
'juju', '--show-log', 'list-models', '-c', 'foo', '--format', 'yaml')
949
GET_ENV = ('juju', '--show-log', 'get-model-config', '-m', 'foo:foo',
950
'tools-metadata-url')
1124
953
def upgrade_output(cls, args, **kwargs):
1125
954
status = yaml.safe_dump({
1126
955
'machines': {'0': {
1127
956
'agent-state': 'started',
1128
'agent-version': '2.0-rc2'}},
957
'agent-version': '2.0-alpha3'}},
1129
958
'services': {}})
1130
959
juju_run_out = json.dumps([
1131
960
{"MachineId": "1", "Stdout": "Linux\n"},
1132
961
{"MachineId": "2", "Stdout": "Linux\n"}])
1133
list_models = json.dumps(
1135
{'name': 'controller'},
1139
963
cls.STATUS: status,
1140
cls.CONTROLLER_STATUS: status,
1141
964
cls.RUN_UNAME: juju_run_out,
1142
cls.GET_ENV: 'testing',
1143
cls.GET_CONTROLLER_ENV: 'testing',
1144
cls.LIST_MODELS: list_models,
965
cls.GET_ENV: 'testing'
1146
967
return FakePopen(output[args], '', 0)
1167
985
with self.upgrade_mocks() as (co_mock, cc_mock):
1168
986
assess_upgrade(old_client, '/bar/juju')
1169
987
new_client = EnvJujuClient(env, None, '/bar/juju')
1170
# Needs to upgrade the controller first.
1171
assert_juju_call(self, cc_mock, new_client, (
1172
'juju', '--show-log', 'upgrade-juju', '-m', 'foo:controller',
1173
'--agent-version', '2.0-rc2'), 0)
1174
assert_juju_call(self, cc_mock, new_client, (
1175
'juju', '--show-log', 'upgrade-juju', '-m', 'foo:foo',
1176
'--agent-version', '2.0-rc2'), 1)
1177
self.assertEqual(cc_mock.call_count, 2)
1178
assert_juju_call(self, co_mock, new_client, self.LIST_MODELS, 0)
1179
assert_juju_call(self, co_mock, new_client, self.GET_CONTROLLER_ENV, 1)
1180
assert_juju_call(self, co_mock, new_client, self.GET_CONTROLLER_ENV, 2)
1181
assert_juju_call(self, co_mock, new_client, self.CONTROLLER_STATUS, 3)
1182
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 4)
1183
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 5)
1184
assert_juju_call(self, co_mock, new_client, self.STATUS, 6)
1185
self.assertEqual(co_mock.call_count, 7)
1187
def test__get_clients_to_upgrade_returns_new_version_class(self):
1188
env = SimpleEnvironment('foo', {'type': 'foo'})
1189
old_client = fake_juju_client(
1190
env, '/foo/juju', version='1.25', cls=EnvJujuClient25)
1191
with patch('jujupy.EnvJujuClient.get_version',
1192
return_value='1.26-arch-series'):
1193
with patch('jujupy.EnvJujuClient26._get_models', return_value=[]):
1194
[new_client] = _get_clients_to_upgrade(
1195
old_client, '/foo/newer/juju')
1197
self.assertIs(type(new_client), EnvJujuClient26)
1199
def test__get_clients_to_upgrade_returns_controller_and_model(self):
1200
old_client = fake_juju_client()
1201
old_client.bootstrap()
1203
with patch('jujupy.EnvJujuClient.get_version',
1204
return_value='2.0-rc2-arch-series'):
1205
new_clients = _get_clients_to_upgrade(
1206
old_client, '/foo/newer/juju')
1208
self.assertEqual(len(new_clients), 2)
1209
self.assertEqual(new_clients[0].model_name, 'controller')
1210
self.assertEqual(new_clients[1].model_name, 'name')
988
assert_juju_call(self, cc_mock, new_client, (
989
'juju', '--show-log', 'upgrade-juju', '-m', 'foo:foo', '--version',
991
self.assertEqual(cc_mock.call_count, 1)
992
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 0)
993
assert_juju_call(self, co_mock, new_client, self.GET_ENV, 1)
994
assert_juju_call(self, co_mock, new_client, self.STATUS, 2)
995
self.assertEqual(co_mock.call_count, 3)
1212
997
def test_mass_timeout(self):
1213
998
config = {'type': 'foo'}
1215
1000
with self.upgrade_mocks():
1216
1001
with patch.object(EnvJujuClient, 'wait_for_version') as wfv_mock:
1217
1002
assess_upgrade(old_client, '/bar/juju')
1218
wfv_mock.assert_has_calls([call('2.0-rc2', 600)] * 2)
1003
wfv_mock.assert_called_once_with('2.0-alpha3', 600)
1219
1004
config['type'] = 'maas'
1220
1005
with patch.object(EnvJujuClient, 'wait_for_version') as wfv_mock:
1221
1006
assess_upgrade(old_client, '/bar/juju')
1222
wfv_mock.assert_has_calls([call('2.0-rc2', 1200)] * 2)
1007
wfv_mock.assert_called_once_with('2.0-alpha3', 1200)
1225
1010
class TestBootstrapManager(FakeHomeTestCase):
1227
1012
def test_from_args(self):
1228
deadline = datetime(2012, 11, 10, 9, 8, 7)
1229
1013
args = Namespace(
1230
1014
env='foo', juju_bin='bar', debug=True, temp_env_name='baz',
1231
1015
bootstrap_host='example.org', machine=['example.com'],
1232
1016
series='angsty', agent_url='qux', agent_stream='escaped',
1233
region='eu-west-northwest-5', logs='pine', keep_env=True,
1235
with patch('deploy_stack.client_from_config') as fc_mock:
1236
bs_manager = BootstrapManager.from_args(args)
1237
fc_mock.assert_called_once_with('foo', 'bar', debug=True,
1238
soft_deadline=deadline)
1017
region='eu-west-northwest-5', logs='pine', keep_env=True)
1018
with patch.object(SimpleEnvironment, 'from_config') as fc_mock:
1019
with patch.object(EnvJujuClient, 'by_version') as bv_mock:
1020
bs_manager = BootstrapManager.from_args(args)
1021
fc_mock.assert_called_once_with('foo')
1022
bv_mock.assert_called_once_with(fc_mock.return_value, 'bar',
1239
1024
self.assertEqual('baz', bs_manager.temp_env_name)
1240
self.assertIs(fc_mock.return_value, bs_manager.client)
1241
self.assertIs(fc_mock.return_value, bs_manager.tear_down_client)
1025
self.assertIs(bv_mock.return_value, bs_manager.client)
1026
self.assertIs(bv_mock.return_value, bs_manager.tear_down_client)
1242
1027
self.assertEqual('example.org', bs_manager.bootstrap_host)
1243
1028
self.assertEqual(['example.com'], bs_manager.machines)
1244
1029
self.assertEqual('angsty', bs_manager.series)
1252
1037
self.assertEqual(jes_enabled, bs_manager.jes_enabled)
1253
1038
self.assertEqual({'0': 'example.org'}, bs_manager.known_hosts)
1255
def test_no_args(self):
1257
env='foo', juju_bin='bar', debug=True, temp_env_name='baz',
1258
bootstrap_host='example.org', machine=['example.com'],
1259
series='angsty', agent_url='qux', agent_stream='escaped',
1260
region='eu-west-northwest-5', logs=None, keep_env=True,
1262
with patch('deploy_stack.client_from_config') as fc_mock:
1263
with patch('utility.os.makedirs'):
1264
bs_manager = BootstrapManager.from_args(args)
1265
fc_mock.assert_called_once_with('foo', 'bar', debug=True,
1267
self.assertEqual('baz', bs_manager.temp_env_name)
1268
self.assertIs(fc_mock.return_value, bs_manager.client)
1269
self.assertIs(fc_mock.return_value, bs_manager.tear_down_client)
1270
self.assertEqual('example.org', bs_manager.bootstrap_host)
1271
self.assertEqual(['example.com'], bs_manager.machines)
1272
self.assertEqual('angsty', bs_manager.series)
1273
self.assertEqual('qux', bs_manager.agent_url)
1274
self.assertEqual('escaped', bs_manager.agent_stream)
1275
self.assertEqual('eu-west-northwest-5', bs_manager.region)
1276
self.assertIs(True, bs_manager.keep_env)
1277
logs_arg = bs_manager.log_dir.split("/")
1278
logs_ts = logs_arg[4]
1279
self.assertEqual(logs_arg[1:4], ['tmp', 'baz', 'logs'])
1280
self.assertTrue(logs_ts, datetime.strptime(logs_ts, "%Y%m%d%H%M%S"))
1281
jes_enabled = bs_manager.client.is_jes_enabled.return_value
1282
self.assertEqual(jes_enabled, bs_manager.permanent)
1283
self.assertEqual(jes_enabled, bs_manager.jes_enabled)
1284
self.assertEqual({'0': 'example.org'}, bs_manager.known_hosts)
1286
1040
def test_jes_not_permanent(self):
1287
1041
with self.assertRaisesRegexp(ValueError, 'Cannot set permanent False'
1288
1042
' if jes_enabled is True.'):
1310
1064
env='foo', juju_bin='bar', debug=True, temp_env_name='baz',
1311
1065
bootstrap_host=None, machine=['example.com'],
1312
1066
series='angsty', agent_url='qux', agent_stream='escaped',
1313
region='eu-west-northwest-5', logs='pine', keep_env=True,
1315
with patch('deploy_stack.client_from_config'):
1316
bs_manager = BootstrapManager.from_args(args)
1067
region='eu-west-northwest-5', logs='pine', keep_env=True)
1068
with patch.object(SimpleEnvironment, 'from_config'):
1069
with patch.object(EnvJujuClient, 'by_version'):
1070
bs_manager = BootstrapManager.from_args(args)
1317
1071
self.assertIs(None, bs_manager.bootstrap_host)
1318
1072
self.assertEqual({}, bs_manager.known_hosts)
1470
1224
wfp_mock.assert_called_once_with(
1471
1225
'bootstrap.example.org', 22, timeout=120)
1473
def test_handle_bootstrap_exceptions_ignores_soft_deadline(self):
1474
env = JujuData('foo', {'type': 'nonlocal'})
1475
client = EnvJujuClient(env, None, None)
1476
tear_down_client = EnvJujuClient(env, None, None)
1477
soft_deadline = datetime(2015, 1, 2, 3, 4, 6)
1478
now = soft_deadline + timedelta(seconds=1)
1479
client.env.juju_home = use_context(self, temp_dir())
1480
bs_manager = BootstrapManager(
1481
'foobar', client, tear_down_client, None, [], None, None, None,
1482
None, client.env.juju_home, False, permanent=True,
1485
def do_check(*args, **kwargs):
1486
with client.check_timeouts():
1487
with tear_down_client.check_timeouts():
1490
with patch.object(bs_manager.tear_down_client, 'juju',
1491
side_effect=do_check, autospec=True):
1492
with patch.object(client._backend, '_now', return_value=now):
1493
fake_exception = Exception()
1494
with self.assertRaises(LoggedException) as exc:
1495
with bs_manager.handle_bootstrap_exceptions():
1496
client._backend.soft_deadline = soft_deadline
1497
tear_down_client._backend.soft_deadline = soft_deadline
1498
raise fake_exception
1499
self.assertIs(fake_exception, exc.exception.exception)
1501
1227
def test_tear_down_requires_same_env(self):
1502
1228
client = self.make_client()
1503
1229
client.env.juju_home = 'foobar'
1596
1322
'2': 'example.org',
1599
def test_runtime_context_raises_logged_exception(self):
1600
client = fake_juju_client()
1602
bs_manager = BootstrapManager(
1603
'foobar', client, client,
1604
None, [], None, None, None, None, client.env.juju_home, False,
1606
test_error = Exception("Some exception")
1607
test_error.output = "a stdout value"
1608
test_error.stderr = "a stderr value"
1609
with patch.object(bs_manager, 'dump_all_logs', autospec=True):
1610
with self.assertRaises(LoggedException) as err_ctx:
1611
with bs_manager.runtime_context([]):
1613
self.assertIs(err_ctx.exception.exception, test_error)
1614
self.assertIn("a stdout value", self.log_stream.getvalue())
1615
self.assertIn("a stderr value", self.log_stream.getvalue())
1617
1325
def test_runtime_context_looks_up_host(self):
1618
1326
client = fake_juju_client()
1619
1327
client.bootstrap()
1702
1410
wfp_mock.assert_called_once_with(
1703
1411
'bootstrap.example.org', 22, timeout=120)
1706
def booted_to_bootstrap(self, bs_manager):
1707
"""Preform patches to focus on the call to bootstrap."""
1708
with patch.object(bs_manager, 'dump_all_logs'):
1709
with patch.object(bs_manager, 'runtime_context'):
1710
with patch.object(bs_manager.client, 'juju'):
1711
with patch.object(bs_manager.client, 'bootstrap') as mock:
1714
def test_booted_context_kwargs(self):
1715
client = fake_juju_client()
1716
with temp_dir() as root:
1717
log_dir = os.path.join(root, 'log-dir')
1719
bs_manager = BootstrapManager(
1720
'foobar', client, client,
1721
None, [], None, None, None, None, log_dir, False,
1723
juju_home = os.path.join(root, 'juju-home')
1725
client.env.juju_home = juju_home
1726
with self.booted_to_bootstrap(bs_manager) as bootstrap_mock:
1727
with bs_manager.booted_context(False, to='test'):
1728
bootstrap_mock.assert_called_once_with(
1729
upload_tools=False, to='test', bootstrap_series=None)
1730
with self.booted_to_bootstrap(bs_manager) as bootstrap_mock:
1731
with bs_manager.existing_booted_context(False, to='test'):
1732
bootstrap_mock.assert_called_once_with(
1733
upload_tools=False, to='test', bootstrap_series=None)
1735
def test_runtime_context_teardown_ignores_soft_deadline(self):
1736
env = JujuData('foo', {'type': 'nonlocal'})
1737
soft_deadline = datetime(2015, 1, 2, 3, 4, 6)
1738
now = soft_deadline + timedelta(seconds=1)
1739
client = EnvJujuClient(env, None, None)
1740
tear_down_client = EnvJujuClient(env, None, None)
1742
def do_check_client(*args, **kwargs):
1743
with client.check_timeouts():
1746
def do_check_teardown_client(*args, **kwargs):
1747
with tear_down_client.check_timeouts():
1750
with temp_dir() as log_dir:
1751
bs_manager = BootstrapManager(
1752
'foobar', client, tear_down_client,
1753
None, [], None, None, None, None, log_dir, False,
1755
bs_manager.known_hosts['0'] = 'example.org'
1756
with patch.object(bs_manager.client, 'juju',
1757
side_effect=do_check_client, autospec=True):
1758
with patch.object(bs_manager.client, 'iter_model_clients',
1759
side_effect=do_check_client, autospec=True,
1761
with patch.object(bs_manager, 'tear_down',
1762
do_check_teardown_client):
1763
with patch.object(client._backend, '_now',
1765
with bs_manager.runtime_context(['baz']):
1766
client._backend.soft_deadline = soft_deadline
1767
td_backend = tear_down_client._backend
1768
td_backend.soft_deadline = soft_deadline
1771
def make_bootstrap_manager(self):
1772
client = fake_juju_client()
1773
with temp_dir() as log_dir:
1774
bs_manager = BootstrapManager(
1775
'foobar', client, client,
1776
None, [], None, None, None, None, log_dir, False,
1780
def test_top_context_dumps_timings(self):
1781
with self.make_bootstrap_manager() as bs_manager:
1782
with patch('deploy_stack.dump_juju_timings') as djt_mock:
1783
with bs_manager.top_context():
1785
djt_mock.assert_called_once_with(bs_manager.client, bs_manager.log_dir)
1787
def test_top_context_dumps_timings_on_exception(self):
1788
with self.make_bootstrap_manager() as bs_manager:
1789
with patch('deploy_stack.dump_juju_timings') as djt_mock:
1790
with self.assertRaises(ValueError):
1791
with bs_manager.top_context():
1793
djt_mock.assert_called_once_with(bs_manager.client, bs_manager.log_dir)
1795
def test_top_context_no_log_dir_skips_timings(self):
1796
with self.make_bootstrap_manager() as bs_manager:
1797
bs_manager.log_dir = None
1798
with patch('deploy_stack.dump_juju_timings') as djt_mock:
1799
with bs_manager.top_context():
1801
self.assertEqual(djt_mock.call_count, 0)
1804
1414
class TestBootContext(FakeHomeTestCase):