Change add_relation function in libjuju.py to accept saas
[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("model", "app1:relation1", "app2:relation2",)
674 )
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(
697 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
698 )
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(
718 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
719 )
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(
735 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
736 )
737
738 mock_add_relation.assert_called_with(
739 "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"
760 )
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")
770 class 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")
806 class 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")
855 class 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"])
888
889
890 @asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
891 class 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, [])
922
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")
927 class 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()