blob: a789bc8d0e5390307864109ef057f0ed3d98c7c8 [file] [log] [blame]
Dominik Fleischmann7ff392f2020-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(
David Garcia8331f7c2020-08-25 16:10:07 +0200673 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200674 )
675
676 mock_warning.assert_called_with("Relation not found: not found")
677 mock_disconnect_controller.assert_called_once()
678 mock_disconnect_model.assert_called_once()
679
680 @asynctest.mock.patch("logging.Logger.warning")
681 def test_already_exists(
682 self,
683 mock_warning,
684 mock_add_relation,
685 mock_disconnect_controller,
686 mock_disconnect_model,
687 mock_get_model,
688 mock_get_controller,
689 ):
690 # TODO in libjuju.py should this fail silently?
691 result = {"error": "already exists", "response": "response", "request-id": 1}
692
693 mock_get_model.return_value = juju.model.Model()
694 mock_add_relation.side_effect = JujuAPIError(result)
695
696 self.loop.run_until_complete(
David Garcia8331f7c2020-08-25 16:10:07 +0200697 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200698 )
699
700 mock_warning.assert_called_with("Relation already exists: already exists")
701 mock_disconnect_controller.assert_called_once()
702 mock_disconnect_model.assert_called_once()
703
704 def test_exception(
705 self,
706 mock_add_relation,
707 mock_disconnect_controller,
708 mock_disconnect_model,
709 mock_get_model,
710 mock_get_controller,
711 ):
712 mock_get_model.return_value = juju.model.Model()
713 result = {"error": "", "response": "response", "request-id": 1}
714 mock_add_relation.side_effect = JujuAPIError(result)
715
716 with self.assertRaises(JujuAPIError):
717 self.loop.run_until_complete(
David Garcia8331f7c2020-08-25 16:10:07 +0200718 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200719 )
720
721 mock_disconnect_controller.assert_called_once()
722 mock_disconnect_model.assert_called_once()
723
724 def test_success(
725 self,
726 mock_add_relation,
727 mock_disconnect_controller,
728 mock_disconnect_model,
729 mock_get_model,
730 mock_get_controller,
731 ):
732 mock_get_model.return_value = juju.model.Model()
733
734 self.loop.run_until_complete(
David Garcia8331f7c2020-08-25 16:10:07 +0200735 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200736 )
737
738 mock_add_relation.assert_called_with(
David Garcia8331f7c2020-08-25 16:10:07 +0200739 "app1:relation1", "app2:relation2"
740 )
741 mock_disconnect_controller.assert_called_once()
742 mock_disconnect_model.assert_called_once()
743
744 def test_saas(
745 self,
746 mock_add_relation,
747 mock_disconnect_controller,
748 mock_disconnect_model,
749 mock_get_model,
750 mock_get_controller,
751 ):
752 mock_get_model.return_value = juju.model.Model()
753
754 self.loop.run_until_complete(
755 self.libjuju.add_relation("model", "app1:relation1", "saas_name",)
756 )
757
758 mock_add_relation.assert_called_with(
759 "app1:relation1", "saas_name"
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200760 )
761 mock_disconnect_controller.assert_called_once()
762 mock_disconnect_model.assert_called_once()
763
764
765# TODO destroy_model testcase
766
767
768@asynctest.mock.patch("juju.model.Model.get_machines")
769@asynctest.mock.patch("logging.Logger.debug")
770class DestroyMachineTest(LibjujuTestCase):
771 def setUp(self):
772 super(DestroyMachineTest, self).setUp()
773
774 def test_success(
775 self, mock_debug, mock_get_machines,
776 ):
777 mock_get_machines.side_effect = [
778 {"machine": FakeMachine()},
779 {"machine": FakeMachine()},
780 {},
781 ]
782 self.loop.run_until_complete(
783 self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
784 )
785 calls = [
786 asynctest.call("Waiting for machine machine is destroyed"),
787 asynctest.call("Machine destroyed: machine"),
788 ]
789 mock_debug.assert_has_calls(calls)
790
791 def test_no_machine(
792 self, mock_debug, mock_get_machines,
793 ):
794 mock_get_machines.return_value = {}
795 self.loop.run_until_complete(
796 self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
797 )
798 mock_debug.assert_called_with("Machine not found: machine")
799
800
801@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
802@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
803@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
804@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
805@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
806class ConfigureApplicationTest(LibjujuTestCase):
807 def setUp(self):
808 super(ConfigureApplicationTest, self).setUp()
809
810 def test_success(
811 self,
812 mock_get_application,
813 mock_disconnect_controller,
814 mock_disconnect_model,
815 mock_get_model,
816 mock_get_controller,
817 ):
818
819 mock_get_application.return_value = FakeApplication()
820
821 self.loop.run_until_complete(
822 self.libjuju.configure_application("model", "app", {"config"},)
823 )
824 mock_get_application.assert_called_once()
825 mock_disconnect_controller.assert_called_once()
826 mock_disconnect_model.assert_called_once()
827
828 def test_exception(
829 self,
830 mock_get_application,
831 mock_disconnect_controller,
832 mock_disconnect_model,
833 mock_get_model,
834 mock_get_controller,
835 ):
836
837 mock_get_application.side_effect = Exception()
838
839 with self.assertRaises(Exception):
840 self.loop.run_until_complete(
841 self.libjuju.configure_application("model", "app", {"config"},)
842 )
843 mock_disconnect_controller.assert_called_once()
844 mock_disconnect_model.assert_called_once()
845
846
847# TODO _get_api_endpoints_db test case
848# TODO _update_api_endpoints_db test case
849# TODO healthcheck test case
850
851
852@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
853@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
854@asynctest.mock.patch("juju.controller.Controller.list_models")
855class ListModelsTest(LibjujuTestCase):
856 def setUp(self):
857 super(ListModelsTest, self).setUp()
858
859 def test_containing(
860 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
861 ):
862 mock_get_controller.return_value = juju.controller.Controller()
863 mock_list_models.return_value = ["existingmodel"]
864 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
865
866 mock_disconnect_controller.assert_called_once()
867 self.assertEquals(models, ["existingmodel"])
868
869 def test_not_containing(
870 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
871 ):
872 mock_get_controller.return_value = juju.controller.Controller()
873 mock_list_models.return_value = ["existingmodel", "model"]
874 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
875
876 mock_disconnect_controller.assert_called_once()
877 self.assertEquals(models, [])
878
879 def test_no_contains_arg(
880 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
881 ):
882 mock_get_controller.return_value = juju.controller.Controller()
883 mock_list_models.return_value = ["existingmodel", "model"]
884 models = self.loop.run_until_complete(self.libjuju.list_models())
885
886 mock_disconnect_controller.assert_called_once()
887 self.assertEquals(models, ["existingmodel", "model"])
David Garcia42f328a2020-08-25 15:03:01 +0200888
889
890@asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
891class ModelsExistTest(LibjujuTestCase):
892 def setUp(self):
893 super(ModelsExistTest, self).setUp()
894
895 def test_model_names_none(self, mock_list_models):
896 mock_list_models.return_value = []
897 with self.assertRaises(Exception):
898 self.loop.run_until_complete(self.libjuju.models_exist(None))
899
900 def test_model_names_empty(self, mock_list_models):
901 mock_list_models.return_value = []
902 with self.assertRaises(Exception):
903 (exist, non_existing_models) = self.loop.run_until_complete(
904 self.libjuju.models_exist([])
905 )
906
907 def test_model_names_not_existing(self, mock_list_models):
908 mock_list_models.return_value = ["prometheus", "grafana"]
909 (exist, non_existing_models) = self.loop.run_until_complete(
910 self.libjuju.models_exist(["prometheus2", "grafana"])
911 )
912 self.assertFalse(exist)
913 self.assertEqual(non_existing_models, ["prometheus2"])
914
915 def test_model_names_exist(self, mock_list_models):
916 mock_list_models.return_value = ["prometheus", "grafana"]
917 (exist, non_existing_models) = self.loop.run_until_complete(
918 self.libjuju.models_exist(["prometheus", "grafana"])
919 )
920 self.assertTrue(exist)
921 self.assertEqual(non_existing_models, [])
David Garciabc538e42020-08-25 15:22:30 +0200922
923
924@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
925@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
926@asynctest.mock.patch("juju.controller.Controller.list_offers")
927class ListOffers(LibjujuTestCase):
928 def setUp(self):
929 super(ListOffers, self).setUp()
930
931 def test_disconnect_controller(
932 self, mock_list_offers, mock_disconnect_controller, mock_get_controller,
933 ):
934 mock_get_controller.return_value = juju.controller.Controller()
935 mock_list_offers.side_effect = Exception()
936 with self.assertRaises(Exception):
937 self.loop.run_until_complete(self.libjuju.list_offers("model"))
938 mock_disconnect_controller.assert_called_once()
939
940 def test_empty_list(
941 self, mock_list_offers, mock_disconnect_controller, mock_get_controller,
942 ):
943 mock_get_controller.return_value = juju.controller.Controller()
944 mock_list_offers.return_value = []
945 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
946 self.assertEqual(offers, [])
947 mock_disconnect_controller.assert_called_once()
948
949 def test_non_empty_list(
950 self, mock_list_offers, mock_disconnect_controller, mock_get_controller,
951 ):
952 mock_get_controller.return_value = juju.controller.Controller()
953 mock_list_offers.return_value = ["offer"]
954 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
955 self.assertEqual(offers, ["offer"])
956 mock_disconnect_controller.assert_called_once()