42
42
raise jujuclient.EnvError({'Error': 'bad wolf'})
45
class FakeFuture(object):
46
def __init__(self, cancelled=False, exception=None):
47
self._cancelled = cancelled
48
self._exception = exception
51
return self._cancelled
54
return self._exception
45
57
@mock.patch('time.time', mock.Mock(return_value=42))
46
58
class TestDeployer(helpers.BundlesTestMixin, AsyncTestCase):
108
120
deployer = self.make_deployer()
109
121
with self.patch_import_bundle():
110
122
deployment_id = deployer.import_bundle(
111
self.user, 'bundle', self.bundle, test_callback=self.stop)
123
self.user, 'bundle', self.bundle, bundle_id=None,
124
test_callback=self.stop)
112
125
self.assertIsInstance(deployment_id, int)
113
126
# Wait for the deployment to be completed.
118
131
deployer = self.make_deployer()
119
132
with self.patch_import_bundle() as mock_import_bundle:
120
133
deployer.import_bundle(
121
self.user, 'bundle', self.bundle, test_callback=self.stop)
134
self.user, 'bundle', self.bundle, bundle_id=None,
135
test_callback=self.stop)
122
136
# Wait for the deployment to be completed.
124
138
mock_import_bundle.assert_called_once_with(
140
154
deployer = self.make_deployer()
141
155
with self.patch_import_bundle():
142
156
deployment_id = deployer.import_bundle(
143
self.user, 'bundle', self.bundle, test_callback=self.stop)
157
self.user, 'bundle', self.bundle, bundle_id=None,
158
test_callback=self.stop)
144
159
watcher_id = deployer.watch(deployment_id)
145
160
self.assertIsInstance(watcher_id, int)
146
161
# Wait for the deployment to be completed.
157
172
deployer = self.make_deployer()
158
173
with self.patch_import_bundle():
159
174
deployment_id = deployer.import_bundle(
160
self.user, 'bundle', self.bundle, test_callback=self.stop)
175
self.user, 'bundle', self.bundle, bundle_id=None,
176
test_callback=self.stop)
161
177
watcher_id = deployer.watch(deployment_id)
162
178
# A first change is received notifying that the deployment is started.
163
179
changes = yield deployer.next(watcher_id)
178
194
deployer = self.make_deployer()
179
195
with self.patch_import_bundle():
180
196
deployment1 = deployer.import_bundle(
181
self.user, 'bundle', self.bundle)
197
self.user, 'bundle', self.bundle, bundle_id=None)
182
198
deployment2 = deployer.import_bundle(
183
self.user, 'bundle', self.bundle, test_callback=self.stop)
199
self.user, 'bundle', self.bundle, bundle_id=None,
200
test_callback=self.stop)
184
201
watcher1 = deployer.watch(deployment1)
185
202
watcher2 = deployer.watch(deployment2)
186
203
# The first deployment is started.
205
222
deployer = self.make_deployer()
206
223
with self.patch_import_bundle(side_effect=RuntimeError('bad wolf')):
207
224
deployment_id = deployer.import_bundle(
208
self.user, 'bundle', self.bundle, test_callback=self.stop)
225
self.user, 'bundle', self.bundle, bundle_id=None,
226
test_callback=self.stop)
209
227
watcher_id = deployer.watch(deployment_id)
210
228
# We expect two changes: the second one should include the error.
211
229
yield deployer.next(watcher_id)
222
240
import_bundle_path = 'guiserver.bundles.base.blocking.import_bundle'
223
241
with mock.patch(import_bundle_path, import_bundle_mock):
224
242
deployer.import_bundle(
225
self.user, 'bundle', self.bundle, test_callback=self.stop)
243
self.user, 'bundle', self.bundle, bundle_id=None,
244
test_callback=self.stop)
226
245
# Wait for the deployment to be completed.
228
247
status = deployer.status()
249
268
# The test callback is passed to the first deployment because we
250
269
# expect the second one to be immediately cancelled.
251
270
deployer.import_bundle(
252
self.user, 'bundle', self.bundle, test_callback=self.stop)
271
self.user, 'bundle', self.bundle, bundle_id=None,
272
test_callback=self.stop)
253
273
deployment_id = deployer.import_bundle(
254
self.user, 'bundle', self.bundle)
274
self.user, 'bundle', self.bundle, bundle_id=None)
255
275
watcher_id = deployer.watch(deployment_id)
256
276
self.assertIsNone(deployer.cancel(deployment_id))
257
277
# We expect two changes: the second one should notify the deployment
274
294
deployer = self.make_deployer()
275
295
with self.patch_import_bundle():
276
296
deployment_id = deployer.import_bundle(
277
self.user, 'bundle', self.bundle, test_callback=self.stop)
297
self.user, 'bundle', self.bundle, bundle_id=None,
298
test_callback=self.stop)
278
299
watcher_id = deployer.watch(deployment_id)
279
300
# Assume the deployment is completed after two changes.
280
301
yield deployer.next(watcher_id)
291
312
deployer = self.make_deployer()
292
313
with self.patch_import_bundle() as mock_import_bundle:
293
314
deployment_id = deployer.import_bundle(
294
self.user, 'bundle', self.bundle, test_callback=self.stop)
315
self.user, 'bundle', self.bundle, bundle_id=None,
316
test_callback=self.stop)
295
317
watcher_id = deployer.watch(deployment_id)
296
318
# Wait until the deployment is started.
297
319
yield deployer.next(watcher_id)
314
336
deployer = self.make_deployer()
315
337
with self.patch_import_bundle():
316
338
deployment1 = deployer.import_bundle(
317
self.user, 'bundle', self.bundle)
339
self.user, 'bundle', self.bundle, bundle_id=None)
318
340
deployment2 = deployer.import_bundle(
319
self.user, 'bundle', self.bundle, test_callback=self.stop)
341
self.user, 'bundle', self.bundle, bundle_id=None,
342
test_callback=self.stop)
320
343
# Wait for the deployment to be completed.
322
345
# At this point we expect two completed deployments.
326
349
self.assertEqual(deployment1, change1['DeploymentId'])
327
350
self.assertEqual(deployment2, change2['DeploymentId'])
352
def test_import_callback_cancelled(self):
353
deployer = self.make_deployer()
355
deployer._queue.append(deployer_id)
356
deployer._futures[deployer_id] = None
357
mock_path = 'guiserver.bundles.utils.increment_deployment_counter'
358
future = FakeFuture(True)
359
with mock.patch.object(
360
deployer._observer, 'notify_cancelled') as mock_notify:
361
with mock.patch(mock_path) as mock_incrementer:
362
deployer._import_callback(deployer_id, None, future)
363
mock_notify.assert_called_with(deployer_id)
364
self.assertFalse(mock_incrementer.called)
366
def test_import_callback_error(self):
367
deployer = self.make_deployer()
369
deployer._queue.append(deployer_id)
370
deployer._futures[deployer_id] = None
371
mock_path = 'guiserver.bundles.utils.increment_deployment_counter'
372
future = FakeFuture(exception='aiiee')
373
with mock.patch.object(
374
deployer._observer, 'notify_completed') as mock_notify:
375
with mock.patch(mock_path) as mock_incrementer:
376
deployer._import_callback(deployer_id, None, future)
377
mock_notify.assert_called_with(deployer_id, error='aiiee')
378
self.assertFalse(mock_incrementer.called)
380
def test_import_callback_no_bundleid(self):
381
deployer = self.make_deployer()
383
deployer._queue.append(deployer_id)
384
deployer._futures[deployer_id] = None
385
mock_path = 'guiserver.bundles.utils.increment_deployment_counter'
386
future = FakeFuture()
387
with mock.patch.object(
388
deployer._observer, 'notify_completed') as mock_notify:
389
with mock.patch(mock_path) as mock_incrementer:
390
deployer._import_callback(deployer_id, None, future)
391
mock_notify.assert_called_with(deployer_id, error=None)
392
self.assertFalse(mock_incrementer.called)
394
def test_import_callback_success(self):
395
deployer = self.make_deployer()
397
bundle_id = '~jorge/basket/bundle'
398
deployer._charmworldurl = 'http://cw.example.com'
399
deployer._queue.append(deployer_id)
400
deployer._futures[deployer_id] = None
401
mock_path = 'guiserver.bundles.utils.increment_deployment_counter'
402
future = FakeFuture()
403
with mock.patch.object(
404
deployer._observer, 'notify_completed') as mock_notify:
405
with mock.patch(mock_path) as mock_incrementer:
406
deployer._import_callback(deployer_id, bundle_id, future)
407
mock_notify.assert_called_with(deployer_id, error=None)
408
mock_incrementer.assert_called_with(bundle_id, deployer._charmworldurl)
330
411
class TestDeployMiddleware(helpers.BundlesTestMixin, AsyncTestCase):