blob: b9cc5290ee46af9bb5214bd3cc271377a34c0751 [file] [log] [blame]
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +02001# 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
15import asyncio
16import asynctest
17import juju
18from juju.errors import JujuAPIError
19import logging
20from .utils import FakeN2VC, FakeMachine, FakeApplication
21from n2vc.libjuju import Libjuju
22from n2vc.exceptions import (
23 JujuControllerFailedConnecting,
24 JujuModelAlreadyExists,
25 JujuMachineNotFound,
26 JujuApplicationNotFound,
27 JujuActionNotFound,
28 JujuApplicationExists,
29)
30
31
32class 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")
77class 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
113class 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")
135class 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")
179class 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")
195class 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")
234class 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")
286class 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")
374class 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)
489class 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")
518class 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")
604class 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")
652class 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
David Garcia4a8ed1c2020-09-29 19:48:13 +0200756# @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()
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +0200761
David Garcia4a8ed1c2020-09-29 19:48:13 +0200762# def test_success_manual_machine(
763# self, mock_debug, mock_get_machines,
764# ):
765# mock_get_machines.side_effect = [
766# {"machine": FakeManualMachine()},
767# {"machine": FakeManualMachine()},
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)
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +0200778
David Garcia4a8ed1c2020-09-29 19:48:13 +0200779# 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")
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +0200787
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")
794class 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")
843class 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"])