2f9ea1ea7b3d470c2c12423ab4b6f51111fbecac
[osm/N2VC.git] / n2vc / tests / unit / test_libjuju.py
1 # Copyright 2020 Canonical Ltd.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import asyncio
16 import asynctest
17 import juju
18 from juju.errors import JujuAPIError
19 import logging
20 from .utils import FakeN2VC, FakeMachine, FakeApplication
21 from n2vc.libjuju import Libjuju
22 from n2vc.exceptions import (
23 JujuControllerFailedConnecting,
24 JujuModelAlreadyExists,
25 JujuMachineNotFound,
26 JujuApplicationNotFound,
27 JujuActionNotFound,
28 JujuApplicationExists,
29 JujuError,
30 )
31
32
33 class LibjujuTestCase(asynctest.TestCase):
34 @asynctest.mock.patch("juju.controller.Controller.update_endpoints")
35 @asynctest.mock.patch("juju.client.connector.Connector.connect")
36 @asynctest.mock.patch("juju.controller.Controller.connection")
37 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_api_endpoints_db")
38 def setUp(
39 self,
40 mock__get_api_endpoints_db=None,
41 mock_connection=None,
42 mock_connect=None,
43 mock_update_endpoints=None,
44 ):
45 loop = asyncio.get_event_loop()
46 n2vc = FakeN2VC()
47 mock__get_api_endpoints_db.return_value = ["127.0.0.1:17070"]
48 endpoints = "127.0.0.1:17070"
49 username = "admin"
50 password = "secret"
51 cacert = """
52 -----BEGIN CERTIFICATE-----
53 SOMECERT
54 -----END CERTIFICATE-----"""
55 self.libjuju = Libjuju(
56 endpoints,
57 "192.168.0.155:17070",
58 username,
59 password,
60 cacert,
61 loop,
62 log=None,
63 db={"get_one": []},
64 n2vc=n2vc,
65 apt_mirror="192.168.0.100",
66 enable_os_upgrade=True,
67 )
68 logging.disable(logging.CRITICAL)
69 loop.run_until_complete(self.libjuju.disconnect())
70
71
72 @asynctest.mock.patch("juju.controller.Controller.connect")
73 @asynctest.mock.patch(
74 "juju.controller.Controller.api_endpoints",
75 new_callable=asynctest.CoroutineMock(return_value=["127.0.0.1:17070"]),
76 )
77 @asynctest.mock.patch("n2vc.libjuju.Libjuju._update_api_endpoints_db")
78 class GetControllerTest(LibjujuTestCase):
79 def setUp(self):
80 super(GetControllerTest, self).setUp()
81
82 def test_diff_endpoint(
83 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
84 ):
85 self.libjuju.endpoints = []
86 controller = self.loop.run_until_complete(self.libjuju.get_controller())
87 mock__update_api_endpoints_db.assert_called_once_with(["127.0.0.1:17070"])
88 self.assertIsInstance(controller, juju.controller.Controller)
89
90 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
91 def test_exception(
92 self,
93 mock_disconnect_controller,
94 mock__update_api_endpoints_db,
95 mock_api_endpoints,
96 mock_connect,
97 ):
98 self.libjuju.endpoints = []
99 mock__update_api_endpoints_db.side_effect = Exception()
100 with self.assertRaises(JujuControllerFailedConnecting):
101 controller = self.loop.run_until_complete(self.libjuju.get_controller())
102 self.assertIsNone(controller)
103 mock_disconnect_controller.assert_called_once()
104
105 def test_same_endpoint_get_controller(
106 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
107 ):
108 self.libjuju.endpoints = ["127.0.0.1:17070"]
109 controller = self.loop.run_until_complete(self.libjuju.get_controller())
110 mock__update_api_endpoints_db.assert_not_called()
111 self.assertIsInstance(controller, juju.controller.Controller)
112
113
114 class DisconnectTest(LibjujuTestCase):
115 def setUp(self):
116 super(DisconnectTest, self).setUp()
117
118 @asynctest.mock.patch("juju.model.Model.disconnect")
119 def test_disconnect_model(self, mock_disconnect):
120 self.loop.run_until_complete(self.libjuju.disconnect_model(juju.model.Model()))
121 mock_disconnect.assert_called_once()
122
123 @asynctest.mock.patch("juju.controller.Controller.disconnect")
124 def test_disconnect_controller(self, mock_disconnect):
125 self.loop.run_until_complete(
126 self.libjuju.disconnect_controller(juju.controller.Controller())
127 )
128 mock_disconnect.assert_called_once()
129
130
131 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
132 @asynctest.mock.patch("n2vc.libjuju.Libjuju.model_exists")
133 @asynctest.mock.patch("juju.controller.Controller.add_model")
134 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
135 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
136 class AddModelTest(LibjujuTestCase):
137 def setUp(self):
138 super(AddModelTest, self).setUp()
139
140 def test_existing_model(
141 self,
142 mock_disconnect_model,
143 mock_disconnect_controller,
144 mock_add_model,
145 mock_model_exists,
146 mock_get_controller,
147 ):
148 mock_model_exists.return_value = True
149
150 with self.assertRaises(JujuModelAlreadyExists):
151 self.loop.run_until_complete(
152 self.libjuju.add_model("existing_model", "cloud")
153 )
154
155 mock_disconnect_controller.assert_called()
156
157 # TODO Check two job executing at the same time and one returning without doing anything.
158
159 def test_non_existing_model(
160 self,
161 mock_disconnect_model,
162 mock_disconnect_controller,
163 mock_add_model,
164 mock_model_exists,
165 mock_get_controller,
166 ):
167 mock_model_exists.return_value = False
168 mock_get_controller.return_value = juju.controller.Controller()
169
170 self.loop.run_until_complete(
171 self.libjuju.add_model("nonexisting_model", "cloud")
172 )
173
174 mock_add_model.assert_called_once()
175 mock_disconnect_controller.assert_called()
176 mock_disconnect_model.assert_called()
177
178
179 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
180 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
181 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
182 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
183 @asynctest.mock.patch(
184 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
185 )
186 @asynctest.mock.patch("juju.model.Model.get_action_status")
187 @asynctest.mock.patch("juju.model.Model.get_action_output")
188 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_actions")
189 class GetExecutedActionsTest(LibjujuTestCase):
190 def setUp(self):
191 super(GetExecutedActionsTest, self).setUp()
192
193 def test_exception(
194 self,
195 mock_get_actions,
196 mock_get_action_output,
197 mock_get_action_status,
198 mock_applications,
199 mock_disconnect_controller,
200 mock_disconnect_model,
201 mock_get_model,
202 mock_get_controller,
203 ):
204 mock_get_model.return_value = None
205 with self.assertRaises(JujuError):
206 self.loop.run_until_complete(self.libjuju.get_executed_actions("model"))
207
208 mock_get_controller.assert_called_once()
209 mock_disconnect_controller.assert_called_once()
210 mock_get_model.assert_called_once()
211 mock_disconnect_model.assert_not_called()
212
213 def test_success(
214 self,
215 mock_get_actions,
216 mock_get_action_output,
217 mock_get_action_status,
218 mock_applications,
219 mock_disconnect_controller,
220 mock_disconnect_model,
221 mock_get_model,
222 mock_get_controller,
223 ):
224 mock_get_model.return_value = juju.model.Model()
225 mock_applications.return_value = {"existing_app"}
226 mock_get_actions.return_value = {"action_name": "description"}
227 mock_get_action_status.return_value = {"id": "status"}
228 mock_get_action_output.return_value = {"output": "completed"}
229
230 executed_actions = self.loop.run_until_complete(
231 self.libjuju.get_executed_actions("model")
232 )
233 expected_result = [{'id': 'id', 'action': 'action_name',
234 'status': 'status', 'output': 'completed'}]
235 self.assertListEqual(expected_result, executed_actions)
236 self.assertIsInstance(executed_actions, list)
237
238 mock_get_controller.assert_called_once()
239 mock_get_model.assert_called_once()
240 mock_disconnect_controller.assert_called_once()
241 mock_disconnect_model.assert_called_once()
242
243
244 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
245 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
246 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
247 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
248 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
249 class GetApplicationConfigsTest(LibjujuTestCase):
250 def setUp(self):
251 super(GetApplicationConfigsTest, self).setUp()
252
253 def test_exception(
254 self,
255 mock_get_application,
256 mock_disconnect_controller,
257 mock_disconnect_model,
258 mock_get_model,
259 mock_get_controller,
260 ):
261 mock_get_model.return_value = None
262 with self.assertRaises(JujuError):
263 self.loop.run_until_complete(
264 self.libjuju.get_application_configs("model", "app"))
265
266 mock_get_controller.assert_called_once()
267 mock_disconnect_controller.assert_called_once()
268 mock_get_model.assert_called_once()
269 mock_disconnect_model.assert_not_called()
270
271 def test_success(
272 self,
273 mock_get_application,
274 mock_disconnect_controller,
275 mock_disconnect_model,
276 mock_get_model,
277 mock_get_controller,
278 ):
279 mock_get_application.return_value = FakeApplication()
280 application_configs = self.loop.run_until_complete(self.libjuju
281 .get_application_configs("model", "app"))
282
283 self.assertEqual(application_configs, ["app_config"])
284
285 mock_get_controller.assert_called_once()
286 mock_get_model.assert_called_once()
287 mock_disconnect_controller.assert_called_once()
288 mock_disconnect_model.assert_called_once()
289
290
291 @asynctest.mock.patch("juju.controller.Controller.get_model")
292 class GetModelTest(LibjujuTestCase):
293 def setUp(self):
294 super(GetModelTest, self).setUp()
295
296 def test_get_model(
297 self, mock_get_model,
298 ):
299 mock_get_model.return_value = juju.model.Model()
300 model = self.loop.run_until_complete(
301 self.libjuju.get_model(juju.controller.Controller(), "model")
302 )
303 self.assertIsInstance(model, juju.model.Model)
304
305
306 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
307 @asynctest.mock.patch("juju.controller.Controller.list_models")
308 class ModelExistsTest(LibjujuTestCase):
309 def setUp(self):
310 super(ModelExistsTest, self).setUp()
311
312 async def test_existing_model(
313 self, mock_list_models, mock_get_controller,
314 ):
315 mock_list_models.return_value = ["existing_model"]
316 self.assertTrue(
317 await self.libjuju.model_exists(
318 "existing_model", juju.controller.Controller()
319 )
320 )
321
322 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
323 async def test_no_controller(
324 self, mock_disconnect_controller, mock_list_models, mock_get_controller,
325 ):
326 mock_list_models.return_value = ["existing_model"]
327 mock_get_controller.return_value = juju.controller.Controller()
328 self.assertTrue(await self.libjuju.model_exists("existing_model"))
329 mock_disconnect_controller.assert_called_once()
330
331 async def test_non_existing_model(
332 self, mock_list_models, mock_get_controller,
333 ):
334 mock_list_models.return_value = ["existing_model"]
335 self.assertFalse(
336 await self.libjuju.model_exists(
337 "not_existing_model", juju.controller.Controller()
338 )
339 )
340
341
342 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
343 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
344 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
345 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
346 @asynctest.mock.patch("juju.model.Model.get_status")
347 class GetModelStatusTest(LibjujuTestCase):
348 def setUp(self):
349 super(GetModelStatusTest, self).setUp()
350
351 def test_success(
352 self,
353 mock_get_status,
354 mock_disconnect_controller,
355 mock_disconnect_model,
356 mock_get_model,
357 mock_get_controller,
358 ):
359 mock_get_model.return_value = juju.model.Model()
360 mock_get_status.return_value = {"status"}
361
362 status = self.loop.run_until_complete(self.libjuju.get_model_status("model"))
363
364 mock_get_status.assert_called_once()
365 mock_disconnect_controller.assert_called_once()
366 mock_disconnect_model.assert_called_once()
367
368 self.assertEqual(status, {"status"})
369
370 def test_excpetion(
371 self,
372 mock_get_status,
373 mock_disconnect_controller,
374 mock_disconnect_model,
375 mock_get_model,
376 mock_get_controller,
377 ):
378 mock_get_model.return_value = juju.model.Model()
379 mock_get_status.side_effect = Exception()
380
381 with self.assertRaises(Exception):
382 status = self.loop.run_until_complete(
383 self.libjuju.get_model_status("model")
384 )
385
386 mock_disconnect_controller.assert_called_once()
387 mock_disconnect_model.assert_called_once()
388
389 self.assertIsNone(status)
390
391
392 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
393 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
394 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
395 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
396 @asynctest.mock.patch("juju.model.Model.get_machines")
397 @asynctest.mock.patch("juju.model.Model.add_machine")
398 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
399 class CreateMachineTest(LibjujuTestCase):
400 def setUp(self):
401 super(CreateMachineTest, self).setUp()
402
403 def test_existing_machine(
404 self,
405 mock_wait_for,
406 mock_add_machine,
407 mock_get_machines,
408 mock_disconnect_controller,
409 mock_disconnect_model,
410 mock_get_model,
411 mock_get_controller,
412 ):
413 mock_get_model.return_value = juju.model.Model()
414 mock_get_machines.return_value = {"existing_machine": FakeMachine()}
415 machine, bool_res = self.loop.run_until_complete(
416 self.libjuju.create_machine("model", "existing_machine")
417 )
418
419 self.assertIsInstance(machine, FakeMachine)
420 self.assertFalse(bool_res)
421
422 mock_disconnect_controller.assert_called()
423 mock_disconnect_model.assert_called()
424
425 def test_non_existing_machine(
426 self,
427 mock_wait_for,
428 mock_add_machine,
429 mock_get_machines,
430 mock_disconnect_controller,
431 mock_disconnect_model,
432 mock_get_model,
433 mock_get_controller,
434 ):
435 mock_get_model.return_value = juju.model.Model()
436 with self.assertRaises(JujuMachineNotFound):
437 machine, bool_res = self.loop.run_until_complete(
438 self.libjuju.create_machine("model", "non_existing_machine")
439 )
440 self.assertIsNone(machine)
441 self.assertIsNone(bool_res)
442
443 mock_disconnect_controller.assert_called()
444 mock_disconnect_model.assert_called()
445
446 def test_no_machine(
447 self,
448 mock_wait_for,
449 mock_add_machine,
450 mock_get_machines,
451 mock_disconnect_controller,
452 mock_disconnect_model,
453 mock_get_model,
454 mock_get_controller,
455 ):
456 mock_get_model.return_value = juju.model.Model()
457 mock_add_machine.return_value = FakeMachine()
458
459 machine, bool_res = self.loop.run_until_complete(
460 self.libjuju.create_machine("model")
461 )
462
463 self.assertIsInstance(machine, FakeMachine)
464 self.assertTrue(bool_res)
465
466 mock_wait_for.assert_called_once()
467 mock_add_machine.assert_called_once()
468
469 mock_disconnect_controller.assert_called()
470 mock_disconnect_model.assert_called()
471
472
473 # TODO test provision machine
474
475
476 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
477 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
478 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
479 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
480 @asynctest.mock.patch(
481 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
482 )
483 @asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
484 @asynctest.mock.patch("juju.model.Model.deploy")
485 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
486 @asynctest.mock.patch("n2vc.libjuju.Libjuju.create_machine")
487 class DeployCharmTest(LibjujuTestCase):
488 def setUp(self):
489 super(DeployCharmTest, self).setUp()
490
491 def test_existing_app(
492 self,
493 mock_create_machine,
494 mock_wait_for,
495 mock_deploy,
496 mock_machines,
497 mock_applications,
498 mock_disconnect_controller,
499 mock_disconnect_model,
500 mock_get_model,
501 mock_get_controller,
502 ):
503 mock_get_model.return_value = juju.model.Model()
504 mock_applications.return_value = {"existing_app"}
505
506 with self.assertRaises(JujuApplicationExists):
507 application = self.loop.run_until_complete(
508 self.libjuju.deploy_charm("existing_app", "path", "model", "machine",)
509 )
510 self.assertIsNone(application)
511
512 mock_disconnect_controller.assert_called()
513 mock_disconnect_model.assert_called()
514
515 def test_non_existing_machine(
516 self,
517 mock_create_machine,
518 mock_wait_for,
519 mock_deploy,
520 mock_machines,
521 mock_applications,
522 mock_disconnect_controller,
523 mock_disconnect_model,
524 mock_get_model,
525 mock_get_controller,
526 ):
527 mock_get_model.return_value = juju.model.Model()
528 mock_machines.return_value = {"existing_machine": FakeMachine()}
529 with self.assertRaises(JujuMachineNotFound):
530 application = self.loop.run_until_complete(
531 self.libjuju.deploy_charm("app", "path", "model", "machine",)
532 )
533
534 self.assertIsNone(application)
535
536 mock_disconnect_controller.assert_called()
537 mock_disconnect_model.assert_called()
538
539 def test_2_units(
540 self,
541 mock_create_machine,
542 mock_wait_for,
543 mock_deploy,
544 mock_machines,
545 mock_applications,
546 mock_disconnect_controller,
547 mock_disconnect_model,
548 mock_get_model,
549 mock_get_controller,
550 ):
551 mock_get_model.return_value = juju.model.Model()
552 mock_machines.return_value = {"existing_machine": FakeMachine()}
553 mock_create_machine.return_value = (FakeMachine(), "other")
554 mock_deploy.return_value = FakeApplication()
555 application = self.loop.run_until_complete(
556 self.libjuju.deploy_charm(
557 "app", "path", "model", "existing_machine", num_units=2,
558 )
559 )
560
561 self.assertIsInstance(application, FakeApplication)
562
563 mock_deploy.assert_called_once()
564 mock_wait_for.assert_called_once()
565
566 mock_create_machine.assert_called_once()
567
568 mock_disconnect_controller.assert_called()
569 mock_disconnect_model.assert_called()
570
571 def test_1_unit(
572 self,
573 mock_create_machine,
574 mock_wait_for,
575 mock_deploy,
576 mock_machines,
577 mock_applications,
578 mock_disconnect_controller,
579 mock_disconnect_model,
580 mock_get_model,
581 mock_get_controller,
582 ):
583 mock_get_model.return_value = juju.model.Model()
584 mock_machines.return_value = {"existing_machine": FakeMachine()}
585 mock_deploy.return_value = FakeApplication()
586 application = self.loop.run_until_complete(
587 self.libjuju.deploy_charm("app", "path", "model", "existing_machine")
588 )
589
590 self.assertIsInstance(application, FakeApplication)
591
592 mock_deploy.assert_called_once()
593 mock_wait_for.assert_called_once()
594
595 mock_disconnect_controller.assert_called()
596 mock_disconnect_model.assert_called()
597
598
599 @asynctest.mock.patch(
600 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
601 )
602 class GetApplicationTest(LibjujuTestCase):
603 def setUp(self):
604 super(GetApplicationTest, self).setUp()
605
606 def test_existing_application(
607 self, mock_applications,
608 ):
609 mock_applications.return_value = {"existing_app": "exists"}
610 model = juju.model.Model()
611 result = self.libjuju._get_application(model, "existing_app")
612 self.assertEqual(result, "exists")
613
614 def test_non_existing_application(
615 self, mock_applications,
616 ):
617 mock_applications.return_value = {"existing_app": "exists"}
618 model = juju.model.Model()
619 result = self.libjuju._get_application(model, "nonexisting_app")
620 self.assertIsNone(result)
621
622
623 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
624 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
625 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
626 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
627 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
628 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
629 @asynctest.mock.patch("juju.model.Model.get_action_output")
630 @asynctest.mock.patch("juju.model.Model.get_action_status")
631 class ExecuteActionTest(LibjujuTestCase):
632 def setUp(self):
633 super(ExecuteActionTest, self).setUp()
634
635 def test_no_application(
636 self,
637 mock_get_action_status,
638 mock_get_action_output,
639 mock_wait_for,
640 mock__get_application,
641 mock_disconnect_controller,
642 mock_disconnect_model,
643 mock_get_model,
644 mock_get_controller,
645 ):
646 mock__get_application.return_value = None
647 mock_get_model.return_value = juju.model.Model()
648
649 with self.assertRaises(JujuApplicationNotFound):
650 output, status = self.loop.run_until_complete(
651 self.libjuju.execute_action("app", "model", "action",)
652 )
653 self.assertIsNone(output)
654 self.assertIsNone(status)
655
656 mock_disconnect_controller.assert_called()
657 mock_disconnect_model.assert_called()
658
659 def test_no_action(
660 self,
661 mock_get_action_status,
662 mock_get_action_output,
663 mock_wait_for,
664 mock__get_application,
665 mock_disconnect_controller,
666 mock_disconnect_model,
667 mock_get_model,
668 mock_get_controller,
669 ):
670
671 mock_get_model.return_value = juju.model.Model()
672 mock__get_application.return_value = FakeApplication()
673 with self.assertRaises(JujuActionNotFound):
674 output, status = self.loop.run_until_complete(
675 self.libjuju.execute_action("app", "model", "action",)
676 )
677 self.assertIsNone(output)
678 self.assertIsNone(status)
679
680 mock_disconnect_controller.assert_called()
681 mock_disconnect_model.assert_called()
682
683 # TODO no leader unit found exception
684
685 def test_succesful_exec(
686 self,
687 mock_get_action_status,
688 mock_get_action_output,
689 mock_wait_for,
690 mock__get_application,
691 mock_disconnect_controller,
692 mock_disconnect_model,
693 mock_get_model,
694 mock_get_controller,
695 ):
696 mock_get_model.return_value = juju.model.Model()
697 mock__get_application.return_value = FakeApplication()
698 mock_get_action_output.return_value = "output"
699 mock_get_action_status.return_value = {"id": "status"}
700 output, status = self.loop.run_until_complete(
701 self.libjuju.execute_action("app", "model", "existing_action")
702 )
703 self.assertEqual(output, "output")
704 self.assertEqual(status, "status")
705
706 mock_wait_for.assert_called_once()
707
708 mock_disconnect_controller.assert_called()
709 mock_disconnect_model.assert_called()
710
711
712 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
713 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
714 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
715 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
716 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
717 class GetActionTest(LibjujuTestCase):
718 def setUp(self):
719 super(GetActionTest, self).setUp()
720
721 def test_exception(
722 self,
723 mock_get_application,
724 mock_disconnect_controller,
725 mock_disconnect_model,
726 mock_get_model,
727 mock_get_controller,
728 ):
729 mock_get_application.side_effect = Exception()
730
731 with self.assertRaises(Exception):
732 actions = self.loop.run_until_complete(
733 self.libjuju.get_actions("app", "model")
734 )
735
736 self.assertIsNone(actions)
737 mock_disconnect_controller.assert_called_once()
738 mock_disconnect_model.assert_called_once()
739
740 def test_success(
741 self,
742 mock_get_application,
743 mock_disconnect_controller,
744 mock_disconnect_model,
745 mock_get_model,
746 mock_get_controller,
747 ):
748 mock_get_application.return_value = FakeApplication()
749
750 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
751
752 self.assertEqual(actions, ["existing_action"])
753
754 mock_get_controller.assert_called_once()
755 mock_get_model.assert_called_once()
756 mock_disconnect_controller.assert_called_once()
757 mock_disconnect_model.assert_called_once()
758
759
760 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
761 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
762 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
763 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
764 @asynctest.mock.patch("juju.model.Model.add_relation")
765 class AddRelationTest(LibjujuTestCase):
766 def setUp(self):
767 super(AddRelationTest, self).setUp()
768
769 @asynctest.mock.patch("logging.Logger.warning")
770 def test_not_found(
771 self,
772 mock_warning,
773 mock_add_relation,
774 mock_disconnect_controller,
775 mock_disconnect_model,
776 mock_get_model,
777 mock_get_controller,
778 ):
779 # TODO in libjuju.py should this fail only with a log message?
780 result = {"error": "not found", "response": "response", "request-id": 1}
781
782 mock_get_model.return_value = juju.model.Model()
783 mock_add_relation.side_effect = JujuAPIError(result)
784
785 self.loop.run_until_complete(
786 self.libjuju.add_relation(
787 "model", "app1", "app2", "relation1", "relation2",
788 )
789 )
790
791 mock_warning.assert_called_with("Relation not found: not found")
792 mock_disconnect_controller.assert_called_once()
793 mock_disconnect_model.assert_called_once()
794
795 @asynctest.mock.patch("logging.Logger.warning")
796 def test_already_exists(
797 self,
798 mock_warning,
799 mock_add_relation,
800 mock_disconnect_controller,
801 mock_disconnect_model,
802 mock_get_model,
803 mock_get_controller,
804 ):
805 # TODO in libjuju.py should this fail silently?
806 result = {"error": "already exists", "response": "response", "request-id": 1}
807
808 mock_get_model.return_value = juju.model.Model()
809 mock_add_relation.side_effect = JujuAPIError(result)
810
811 self.loop.run_until_complete(
812 self.libjuju.add_relation(
813 "model", "app1", "app2", "relation1", "relation2",
814 )
815 )
816
817 mock_warning.assert_called_with("Relation already exists: already exists")
818 mock_disconnect_controller.assert_called_once()
819 mock_disconnect_model.assert_called_once()
820
821 def test_exception(
822 self,
823 mock_add_relation,
824 mock_disconnect_controller,
825 mock_disconnect_model,
826 mock_get_model,
827 mock_get_controller,
828 ):
829 mock_get_model.return_value = juju.model.Model()
830 result = {"error": "", "response": "response", "request-id": 1}
831 mock_add_relation.side_effect = JujuAPIError(result)
832
833 with self.assertRaises(JujuAPIError):
834 self.loop.run_until_complete(
835 self.libjuju.add_relation(
836 "model", "app1", "app2", "relation1", "relation2",
837 )
838 )
839
840 mock_disconnect_controller.assert_called_once()
841 mock_disconnect_model.assert_called_once()
842
843 def test_success(
844 self,
845 mock_add_relation,
846 mock_disconnect_controller,
847 mock_disconnect_model,
848 mock_get_model,
849 mock_get_controller,
850 ):
851 mock_get_model.return_value = juju.model.Model()
852
853 self.loop.run_until_complete(
854 self.libjuju.add_relation(
855 "model", "app1", "app2", "relation1", "relation2",
856 )
857 )
858
859 mock_add_relation.assert_called_with(
860 relation1="app1:relation1", relation2="app2:relation2"
861 )
862 mock_disconnect_controller.assert_called_once()
863 mock_disconnect_model.assert_called_once()
864
865
866 # TODO destroy_model testcase
867
868
869 # @asynctest.mock.patch("juju.model.Model.get_machines")
870 # @asynctest.mock.patch("logging.Logger.debug")
871 # class DestroyMachineTest(LibjujuTestCase):
872 # def setUp(self):
873 # super(DestroyMachineTest, self).setUp()
874
875 # def test_success_manual_machine(
876 # self, mock_debug, mock_get_machines,
877 # ):
878 # mock_get_machines.side_effect = [
879 # {"machine": FakeManualMachine()},
880 # {"machine": FakeManualMachine()},
881 # {},
882 # ]
883 # self.loop.run_until_complete(
884 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
885 # )
886 # calls = [
887 # asynctest.call("Waiting for machine machine is destroyed"),
888 # asynctest.call("Machine destroyed: machine"),
889 # ]
890 # mock_debug.assert_has_calls(calls)
891
892 # def test_no_machine(
893 # self, mock_debug, mock_get_machines,
894 # ):
895 # mock_get_machines.return_value = {}
896 # self.loop.run_until_complete(
897 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
898 # )
899 # mock_debug.assert_called_with("Machine not found: machine")
900
901
902 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
903 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
904 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
905 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
906 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
907 class ConfigureApplicationTest(LibjujuTestCase):
908 def setUp(self):
909 super(ConfigureApplicationTest, self).setUp()
910
911 def test_success(
912 self,
913 mock_get_application,
914 mock_disconnect_controller,
915 mock_disconnect_model,
916 mock_get_model,
917 mock_get_controller,
918 ):
919
920 mock_get_application.return_value = FakeApplication()
921
922 self.loop.run_until_complete(
923 self.libjuju.configure_application("model", "app", {"config"},)
924 )
925 mock_get_application.assert_called_once()
926 mock_disconnect_controller.assert_called_once()
927 mock_disconnect_model.assert_called_once()
928
929 def test_exception(
930 self,
931 mock_get_application,
932 mock_disconnect_controller,
933 mock_disconnect_model,
934 mock_get_model,
935 mock_get_controller,
936 ):
937
938 mock_get_application.side_effect = Exception()
939
940 with self.assertRaises(Exception):
941 self.loop.run_until_complete(
942 self.libjuju.configure_application("model", "app", {"config"},)
943 )
944 mock_disconnect_controller.assert_called_once()
945 mock_disconnect_model.assert_called_once()
946
947
948 # TODO _get_api_endpoints_db test case
949 # TODO _update_api_endpoints_db test case
950 # TODO healthcheck test case
951
952
953 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
954 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
955 @asynctest.mock.patch("juju.controller.Controller.list_models")
956 class ListModelsTest(LibjujuTestCase):
957 def setUp(self):
958 super(ListModelsTest, self).setUp()
959
960 def test_containing(
961 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
962 ):
963 mock_get_controller.return_value = juju.controller.Controller()
964 mock_list_models.return_value = ["existingmodel"]
965 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
966
967 mock_disconnect_controller.assert_called_once()
968 self.assertEquals(models, ["existingmodel"])
969
970 def test_not_containing(
971 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
972 ):
973 mock_get_controller.return_value = juju.controller.Controller()
974 mock_list_models.return_value = ["existingmodel", "model"]
975 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
976
977 mock_disconnect_controller.assert_called_once()
978 self.assertEquals(models, [])
979
980 def test_no_contains_arg(
981 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
982 ):
983 mock_get_controller.return_value = juju.controller.Controller()
984 mock_list_models.return_value = ["existingmodel", "model"]
985 models = self.loop.run_until_complete(self.libjuju.list_models())
986
987 mock_disconnect_controller.assert_called_once()
988 self.assertEquals(models, ["existingmodel", "model"])