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