1 # Copyright 2020 Canonical Ltd.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 from juju
.errors
import JujuAPIError
20 from .utils
import FakeN2VC
, FakeMachine
, FakeApplication
21 from n2vc
.libjuju
import Libjuju
22 from n2vc
.exceptions
import (
23 JujuControllerFailedConnecting
,
24 JujuModelAlreadyExists
,
26 JujuApplicationNotFound
,
28 JujuApplicationExists
,
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")
39 mock__get_api_endpoints_db
=None,
42 mock_update_endpoints
=None,
44 loop
= asyncio
.get_event_loop()
46 mock__get_api_endpoints_db
.return_value
= ["127.0.0.1:17070"]
47 endpoints
= "127.0.0.1:17070"
51 -----BEGIN CERTIFICATE-----
53 -----END CERTIFICATE-----"""
54 self
.libjuju
= Libjuju(
56 "192.168.0.155:17070",
64 apt_mirror
="192.168.0.100",
65 enable_os_upgrade
=True,
67 logging
.disable(logging
.CRITICAL
)
68 loop
.run_until_complete(self
.libjuju
.disconnect())
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"]),
76 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._update_api_endpoints_db")
77 class GetControllerTest(LibjujuTestCase
):
79 super(GetControllerTest
, self
).setUp()
81 def test_diff_endpoint(
82 self
, mock__update_api_endpoints_db
, mock_api_endpoints
, mock_connect
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
)
89 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
92 mock_disconnect_controller
,
93 mock__update_api_endpoints_db
,
97 self
.libjuju
.endpoints
= []
98 mock__update_api_endpoints_db
.side_effect
= Exception()
100 with self
.assertRaises(JujuControllerFailedConnecting
):
101 controller
= self
.loop
.run_until_complete(self
.libjuju
.get_controller())
102 self
.assertIsNone(controller
)
103 mock_disconnect_controller
.assert_called_once()
105 def test_same_endpoint_get_controller(
106 self
, mock__update_api_endpoints_db
, mock_api_endpoints
, mock_connect
108 self
.libjuju
.endpoints
= ["127.0.0.1:17070"]
109 controller
= self
.loop
.run_until_complete(self
.libjuju
.get_controller())
110 mock__update_api_endpoints_db
.assert_not_called()
111 self
.assertIsInstance(controller
, juju
.controller
.Controller
)
114 class DisconnectTest(LibjujuTestCase
):
116 super(DisconnectTest
, self
).setUp()
118 @asynctest.mock
.patch("juju.model.Model.disconnect")
119 def test_disconnect_model(self
, mock_disconnect
):
120 self
.loop
.run_until_complete(self
.libjuju
.disconnect_model(juju
.model
.Model()))
121 mock_disconnect
.assert_called_once()
123 @asynctest.mock
.patch("juju.controller.Controller.disconnect")
124 def test_disconnect_controller(self
, mock_disconnect
):
125 self
.loop
.run_until_complete(
126 self
.libjuju
.disconnect_controller(juju
.controller
.Controller())
128 mock_disconnect
.assert_called_once()
131 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
132 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.model_exists")
133 @asynctest.mock
.patch("juju.controller.Controller.add_model")
134 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
135 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
136 class AddModelTest(LibjujuTestCase
):
138 super(AddModelTest
, self
).setUp()
140 def test_existing_model(
142 mock_disconnect_model
,
143 mock_disconnect_controller
,
148 mock_model_exists
.return_value
= True
150 with self
.assertRaises(JujuModelAlreadyExists
):
151 self
.loop
.run_until_complete(
152 self
.libjuju
.add_model("existing_model", "cloud")
155 mock_disconnect_controller
.assert_called()
157 # TODO Check two job executing at the same time and one returning without doing anything.
159 def test_non_existing_model(
161 mock_disconnect_model
,
162 mock_disconnect_controller
,
167 mock_model_exists
.return_value
= False
168 mock_get_controller
.return_value
= juju
.controller
.Controller()
170 self
.loop
.run_until_complete(
171 self
.libjuju
.add_model("nonexisting_model", "cloud")
174 mock_add_model
.assert_called_once()
175 mock_disconnect_controller
.assert_called()
176 mock_disconnect_model
.assert_called()
179 @asynctest.mock
.patch("juju.controller.Controller.get_model")
180 class GetModelTest(LibjujuTestCase
):
182 super(GetModelTest
, self
).setUp()
185 self
, mock_get_model
,
187 mock_get_model
.return_value
= juju
.model
.Model()
188 model
= self
.loop
.run_until_complete(
189 self
.libjuju
.get_model(juju
.controller
.Controller(), "model")
191 self
.assertIsInstance(model
, juju
.model
.Model
)
194 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
195 @asynctest.mock
.patch("juju.controller.Controller.list_models")
196 class ModelExistsTest(LibjujuTestCase
):
198 super(ModelExistsTest
, self
).setUp()
200 async def test_existing_model(
201 self
, mock_list_models
, mock_get_controller
,
203 mock_list_models
.return_value
= ["existing_model"]
205 await self
.libjuju
.model_exists(
206 "existing_model", juju
.controller
.Controller()
210 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
211 async def test_no_controller(
212 self
, mock_disconnect_controller
, mock_list_models
, mock_get_controller
,
214 mock_list_models
.return_value
= ["existing_model"]
215 mock_get_controller
.return_value
= juju
.controller
.Controller()
216 self
.assertTrue(await self
.libjuju
.model_exists("existing_model"))
217 mock_disconnect_controller
.assert_called_once()
219 async def test_non_existing_model(
220 self
, mock_list_models
, mock_get_controller
,
222 mock_list_models
.return_value
= ["existing_model"]
224 await self
.libjuju
.model_exists(
225 "not_existing_model", juju
.controller
.Controller()
230 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
231 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
232 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
233 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
234 @asynctest.mock
.patch("juju.model.Model.get_status")
235 class GetModelStatusTest(LibjujuTestCase
):
237 super(GetModelStatusTest
, self
).setUp()
242 mock_disconnect_controller
,
243 mock_disconnect_model
,
247 mock_get_model
.return_value
= juju
.model
.Model()
248 mock_get_status
.return_value
= {"status"}
250 status
= self
.loop
.run_until_complete(self
.libjuju
.get_model_status("model"))
252 mock_get_status
.assert_called_once()
253 mock_disconnect_controller
.assert_called_once()
254 mock_disconnect_model
.assert_called_once()
256 self
.assertEqual(status
, {"status"})
261 mock_disconnect_controller
,
262 mock_disconnect_model
,
266 mock_get_model
.return_value
= juju
.model
.Model()
267 mock_get_status
.side_effect
= Exception()
269 with self
.assertRaises(Exception):
270 status
= self
.loop
.run_until_complete(
271 self
.libjuju
.get_model_status("model")
274 mock_disconnect_controller
.assert_called_once()
275 mock_disconnect_model
.assert_called_once()
277 self
.assertIsNone(status
)
280 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
281 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
282 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
283 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
284 @asynctest.mock
.patch("juju.model.Model.get_machines")
285 @asynctest.mock
.patch("juju.model.Model.add_machine")
286 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
287 class CreateMachineTest(LibjujuTestCase
):
289 super(CreateMachineTest
, self
).setUp()
291 def test_existing_machine(
296 mock_disconnect_controller
,
297 mock_disconnect_model
,
301 mock_get_model
.return_value
= juju
.model
.Model()
302 mock_get_machines
.return_value
= {"existing_machine": FakeMachine()}
303 machine
, bool_res
= self
.loop
.run_until_complete(
304 self
.libjuju
.create_machine("model", "existing_machine")
307 self
.assertIsInstance(machine
, FakeMachine
)
308 self
.assertFalse(bool_res
)
310 mock_disconnect_controller
.assert_called()
311 mock_disconnect_model
.assert_called()
313 def test_non_existing_machine(
318 mock_disconnect_controller
,
319 mock_disconnect_model
,
325 mock_get_model
.return_value
= juju
.model
.Model()
326 with self
.assertRaises(JujuMachineNotFound
):
327 machine
, bool_res
= self
.loop
.run_until_complete(
328 self
.libjuju
.create_machine("model", "non_existing_machine")
330 self
.assertIsNone(machine
)
331 self
.assertIsNone(bool_res
)
333 mock_disconnect_controller
.assert_called()
334 mock_disconnect_model
.assert_called()
341 mock_disconnect_controller
,
342 mock_disconnect_model
,
346 mock_get_model
.return_value
= juju
.model
.Model()
347 mock_add_machine
.return_value
= FakeMachine()
349 machine
, bool_res
= self
.loop
.run_until_complete(
350 self
.libjuju
.create_machine("model")
353 self
.assertIsInstance(machine
, FakeMachine
)
354 self
.assertTrue(bool_res
)
356 mock_wait_for
.assert_called_once()
357 mock_add_machine
.assert_called_once()
359 mock_disconnect_controller
.assert_called()
360 mock_disconnect_model
.assert_called()
363 # TODO test provision machine
366 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
367 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
368 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
369 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
370 @asynctest.mock
.patch(
371 "juju.model.Model.applications", new_callable
=asynctest
.PropertyMock
373 @asynctest.mock
.patch("juju.model.Model.machines", new_callable
=asynctest
.PropertyMock
)
374 @asynctest.mock
.patch("juju.model.Model.deploy")
375 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
376 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.create_machine")
377 class DeployCharmTest(LibjujuTestCase
):
379 super(DeployCharmTest
, self
).setUp()
381 def test_existing_app(
388 mock_disconnect_controller
,
389 mock_disconnect_model
,
393 mock_get_model
.return_value
= juju
.model
.Model()
394 mock_applications
.return_value
= {"existing_app"}
397 with self
.assertRaises(JujuApplicationExists
):
398 application
= self
.loop
.run_until_complete(
399 self
.libjuju
.deploy_charm("existing_app", "path", "model", "machine",)
401 self
.assertIsNone(application
)
403 mock_disconnect_controller
.assert_called()
404 mock_disconnect_model
.assert_called()
406 def test_non_existing_machine(
413 mock_disconnect_controller
,
414 mock_disconnect_model
,
418 mock_get_model
.return_value
= juju
.model
.Model()
419 mock_machines
.return_value
= {"existing_machine": FakeMachine()}
421 with self
.assertRaises(JujuMachineNotFound
):
422 application
= self
.loop
.run_until_complete(
423 self
.libjuju
.deploy_charm("app", "path", "model", "machine",)
426 self
.assertIsNone(application
)
428 mock_disconnect_controller
.assert_called()
429 mock_disconnect_model
.assert_called()
438 mock_disconnect_controller
,
439 mock_disconnect_model
,
443 mock_get_model
.return_value
= juju
.model
.Model()
444 mock_machines
.return_value
= {"existing_machine": FakeMachine()}
445 mock_create_machine
.return_value
= (FakeMachine(), "other")
446 mock_deploy
.return_value
= FakeApplication()
447 application
= self
.loop
.run_until_complete(
448 self
.libjuju
.deploy_charm(
449 "app", "path", "model", "existing_machine", num_units
=2,
453 self
.assertIsInstance(application
, FakeApplication
)
455 mock_deploy
.assert_called_once()
456 mock_wait_for
.assert_called_once()
458 mock_create_machine
.assert_called_once()
460 mock_disconnect_controller
.assert_called()
461 mock_disconnect_model
.assert_called()
470 mock_disconnect_controller
,
471 mock_disconnect_model
,
475 mock_get_model
.return_value
= juju
.model
.Model()
476 mock_machines
.return_value
= {"existing_machine": FakeMachine()}
477 mock_deploy
.return_value
= FakeApplication()
478 application
= self
.loop
.run_until_complete(
479 self
.libjuju
.deploy_charm("app", "path", "model", "existing_machine")
482 self
.assertIsInstance(application
, FakeApplication
)
484 mock_deploy
.assert_called_once()
485 mock_wait_for
.assert_called_once()
487 mock_disconnect_controller
.assert_called()
488 mock_disconnect_model
.assert_called()
491 @asynctest.mock
.patch(
492 "juju.model.Model.applications", new_callable
=asynctest
.PropertyMock
494 class GetApplicationTest(LibjujuTestCase
):
496 super(GetApplicationTest
, self
).setUp()
498 def test_existing_application(
499 self
, mock_applications
,
501 mock_applications
.return_value
= {"existing_app": "exists"}
502 model
= juju
.model
.Model()
503 result
= self
.libjuju
._get
_application
(model
, "existing_app")
504 self
.assertEqual(result
, "exists")
506 def test_non_existing_application(
507 self
, mock_applications
,
509 mock_applications
.return_value
= {"existing_app": "exists"}
510 model
= juju
.model
.Model()
511 result
= self
.libjuju
._get
_application
(model
, "nonexisting_app")
512 self
.assertIsNone(result
)
515 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
516 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
517 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
518 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
519 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
520 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
521 @asynctest.mock
.patch("juju.model.Model.get_action_output")
522 @asynctest.mock
.patch("juju.model.Model.get_action_status")
523 class ExecuteActionTest(LibjujuTestCase
):
525 super(ExecuteActionTest
, self
).setUp()
527 def test_no_application(
529 mock_get_action_status
,
530 mock_get_action_output
,
532 mock__get_application
,
533 mock_disconnect_controller
,
534 mock_disconnect_model
,
538 mock__get_application
.return_value
= None
539 mock_get_model
.return_value
= juju
.model
.Model()
542 with self
.assertRaises(JujuApplicationNotFound
):
543 output
, status
= self
.loop
.run_until_complete(
544 self
.libjuju
.execute_action("app", "model", "action",)
546 self
.assertIsNone(output
)
547 self
.assertIsNone(status
)
549 mock_disconnect_controller
.assert_called()
550 mock_disconnect_model
.assert_called()
554 mock_get_action_status
,
555 mock_get_action_output
,
557 mock__get_application
,
558 mock_disconnect_controller
,
559 mock_disconnect_model
,
564 mock_get_model
.return_value
= juju
.model
.Model()
565 mock__get_application
.return_value
= FakeApplication()
568 with self
.assertRaises(JujuActionNotFound
):
569 output
, status
= self
.loop
.run_until_complete(
570 self
.libjuju
.execute_action("app", "model", "action",)
572 self
.assertIsNone(output
)
573 self
.assertIsNone(status
)
575 mock_disconnect_controller
.assert_called()
576 mock_disconnect_model
.assert_called()
578 # TODO no leader unit found exception
580 def test_succesful_exec(
582 mock_get_action_status
,
583 mock_get_action_output
,
585 mock__get_application
,
586 mock_disconnect_controller
,
587 mock_disconnect_model
,
591 mock_get_model
.return_value
= juju
.model
.Model()
592 mock__get_application
.return_value
= FakeApplication()
593 mock_get_action_output
.return_value
= "output"
594 mock_get_action_status
.return_value
= {"id": "status"}
595 output
, status
= self
.loop
.run_until_complete(
596 self
.libjuju
.execute_action("app", "model", "existing_action")
598 self
.assertEqual(output
, "output")
599 self
.assertEqual(status
, "status")
601 mock_wait_for
.assert_called_once()
603 mock_disconnect_controller
.assert_called()
604 mock_disconnect_model
.assert_called()
607 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
608 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
609 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
610 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
611 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
612 class GetActionTest(LibjujuTestCase
):
614 super(GetActionTest
, self
).setUp()
618 mock_get_application
,
619 mock_disconnect_controller
,
620 mock_disconnect_model
,
624 mock_get_application
.side_effect
= Exception()
626 with self
.assertRaises(Exception):
627 actions
= self
.loop
.run_until_complete(
628 self
.libjuju
.get_actions("app", "model")
631 self
.assertIsNone(actions
)
632 mock_disconnect_controller
.assert_called_once()
633 mock_disconnect_model
.assert_called_once()
637 mock_get_application
,
638 mock_disconnect_controller
,
639 mock_disconnect_model
,
643 mock_get_application
.return_value
= FakeApplication()
645 actions
= self
.loop
.run_until_complete(self
.libjuju
.get_actions("app", "model"))
647 self
.assertEqual(actions
, ["existing_action"])
649 mock_get_controller
.assert_called_once()
650 mock_get_model
.assert_called_once()
651 mock_disconnect_controller
.assert_called_once()
652 mock_disconnect_model
.assert_called_once()
655 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
656 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
657 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
658 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
659 @asynctest.mock
.patch("juju.application.Application.get_metrics")
660 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
661 class GetMetricsTest(LibjujuTestCase
):
663 super(GetMetricsTest
, self
).setUp()
665 def test_get_metrics_success(
667 mock_get_application
,
669 mock_disconnect_controller
,
670 mock_disconnect_model
,
674 mock_get_application
.return_value
= FakeApplication()
675 mock_get_model
.return_value
= juju
.model
.Model()
677 self
.loop
.run_until_complete(self
.libjuju
.get_metrics("model", "app1"))
679 mock_disconnect_controller
.assert_called_once()
680 mock_disconnect_model
.assert_called_once()
682 def test_get_metrics_exception(
684 mock_get_application
,
686 mock_disconnect_controller
,
687 mock_disconnect_model
,
691 mock_get_model
.return_value
= juju
.model
.Model()
692 mock_get_metrics
.side_effect
= Exception()
693 with self
.assertRaises(Exception):
694 self
.loop
.run_until_complete(self
.libjuju
.get_metrics("model", "app1"))
696 mock_disconnect_controller
.assert_called_once()
697 mock_disconnect_model
.assert_called_once()
699 def test_missing_args_exception(
701 mock_get_application
,
703 mock_disconnect_controller
,
704 mock_disconnect_model
,
708 mock_get_model
.return_value
= juju
.model
.Model()
710 with self
.assertRaises(Exception):
711 self
.loop
.run_until_complete(self
.libjuju
.get_metrics("", ""))
713 mock_get_controller
.assert_not_called()
714 mock_get_model
.assert_not_called()
715 mock_disconnect_controller
.assert_not_called()
716 mock_disconnect_model
.assert_not_called()
719 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
720 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
721 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
722 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
723 @asynctest.mock
.patch("juju.model.Model.add_relation")
724 class AddRelationTest(LibjujuTestCase
):
726 super(AddRelationTest
, self
).setUp()
728 @asynctest.mock
.patch("logging.Logger.warning")
733 mock_disconnect_controller
,
734 mock_disconnect_model
,
738 # TODO in libjuju.py should this fail only with a log message?
739 result
= {"error": "not found", "response": "response", "request-id": 1}
741 mock_get_model
.return_value
= juju
.model
.Model()
742 mock_add_relation
.side_effect
= JujuAPIError(result
)
744 self
.loop
.run_until_complete(
745 self
.libjuju
.add_relation("model", "app1:relation1", "app2:relation2",)
748 mock_warning
.assert_called_with("Relation not found: not found")
749 mock_disconnect_controller
.assert_called_once()
750 mock_disconnect_model
.assert_called_once()
752 @asynctest.mock
.patch("logging.Logger.warning")
753 def test_already_exists(
757 mock_disconnect_controller
,
758 mock_disconnect_model
,
762 # TODO in libjuju.py should this fail silently?
763 result
= {"error": "already exists", "response": "response", "request-id": 1}
765 mock_get_model
.return_value
= juju
.model
.Model()
766 mock_add_relation
.side_effect
= JujuAPIError(result
)
768 self
.loop
.run_until_complete(
769 self
.libjuju
.add_relation("model", "app1:relation1", "app2:relation2",)
772 mock_warning
.assert_called_with("Relation already exists: already exists")
773 mock_disconnect_controller
.assert_called_once()
774 mock_disconnect_model
.assert_called_once()
779 mock_disconnect_controller
,
780 mock_disconnect_model
,
784 mock_get_model
.return_value
= juju
.model
.Model()
785 result
= {"error": "", "response": "response", "request-id": 1}
786 mock_add_relation
.side_effect
= JujuAPIError(result
)
788 with self
.assertRaises(JujuAPIError
):
789 self
.loop
.run_until_complete(
790 self
.libjuju
.add_relation("model", "app1:relation1", "app2:relation2",)
793 mock_disconnect_controller
.assert_called_once()
794 mock_disconnect_model
.assert_called_once()
799 mock_disconnect_controller
,
800 mock_disconnect_model
,
804 mock_get_model
.return_value
= juju
.model
.Model()
806 self
.loop
.run_until_complete(
807 self
.libjuju
.add_relation("model", "app1:relation1", "app2:relation2",)
810 mock_add_relation
.assert_called_with("app1:relation1", "app2:relation2")
811 mock_disconnect_controller
.assert_called_once()
812 mock_disconnect_model
.assert_called_once()
817 mock_disconnect_controller
,
818 mock_disconnect_model
,
822 mock_get_model
.return_value
= juju
.model
.Model()
824 self
.loop
.run_until_complete(
825 self
.libjuju
.add_relation("model", "app1:relation1", "saas_name",)
828 mock_add_relation
.assert_called_with("app1:relation1", "saas_name")
829 mock_disconnect_controller
.assert_called_once()
830 mock_disconnect_model
.assert_called_once()
833 # TODO destroy_model testcase
836 @asynctest.mock
.patch("juju.model.Model.get_machines")
837 @asynctest.mock
.patch("logging.Logger.debug")
838 class DestroyMachineTest(LibjujuTestCase
):
840 super(DestroyMachineTest
, self
).setUp()
843 self
, mock_debug
, mock_get_machines
,
845 mock_get_machines
.side_effect
= [
846 {"machine": FakeMachine()},
847 {"machine": FakeMachine()},
850 self
.loop
.run_until_complete(
851 self
.libjuju
.destroy_machine(juju
.model
.Model(), "machine", 2,)
854 asynctest
.call("Waiting for machine machine is destroyed"),
855 asynctest
.call("Machine destroyed: machine"),
857 mock_debug
.assert_has_calls(calls
)
860 self
, mock_debug
, mock_get_machines
,
862 mock_get_machines
.return_value
= {}
863 self
.loop
.run_until_complete(
864 self
.libjuju
.destroy_machine(juju
.model
.Model(), "machine", 2,)
866 mock_debug
.assert_called_with("Machine not found: machine")
869 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
870 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
871 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
872 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
873 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
874 class ConfigureApplicationTest(LibjujuTestCase
):
876 super(ConfigureApplicationTest
, self
).setUp()
880 mock_get_application
,
881 mock_disconnect_controller
,
882 mock_disconnect_model
,
887 mock_get_application
.return_value
= FakeApplication()
889 self
.loop
.run_until_complete(
890 self
.libjuju
.configure_application("model", "app", {"config"},)
892 mock_get_application
.assert_called_once()
893 mock_disconnect_controller
.assert_called_once()
894 mock_disconnect_model
.assert_called_once()
898 mock_get_application
,
899 mock_disconnect_controller
,
900 mock_disconnect_model
,
905 mock_get_application
.side_effect
= Exception()
907 with self
.assertRaises(Exception):
908 self
.loop
.run_until_complete(
909 self
.libjuju
.configure_application("model", "app", {"config"},)
911 mock_disconnect_controller
.assert_called_once()
912 mock_disconnect_model
.assert_called_once()
915 # TODO _get_api_endpoints_db test case
916 # TODO _update_api_endpoints_db test case
917 # TODO healthcheck test case
920 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
921 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
922 @asynctest.mock
.patch("juju.controller.Controller.list_models")
923 class ListModelsTest(LibjujuTestCase
):
925 super(ListModelsTest
, self
).setUp()
928 self
, mock_list_models
, mock_disconnect_controller
, mock_get_controller
,
930 mock_get_controller
.return_value
= juju
.controller
.Controller()
931 mock_list_models
.return_value
= ["existingmodel"]
932 models
= self
.loop
.run_until_complete(self
.libjuju
.list_models("existing"))
934 mock_disconnect_controller
.assert_called_once()
935 self
.assertEquals(models
, ["existingmodel"])
937 def test_not_containing(
938 self
, mock_list_models
, mock_disconnect_controller
, mock_get_controller
,
940 mock_get_controller
.return_value
= juju
.controller
.Controller()
941 mock_list_models
.return_value
= ["existingmodel", "model"]
942 models
= self
.loop
.run_until_complete(self
.libjuju
.list_models("mdl"))
944 mock_disconnect_controller
.assert_called_once()
945 self
.assertEquals(models
, [])
947 def test_no_contains_arg(
948 self
, mock_list_models
, mock_disconnect_controller
, mock_get_controller
,
950 mock_get_controller
.return_value
= juju
.controller
.Controller()
951 mock_list_models
.return_value
= ["existingmodel", "model"]
952 models
= self
.loop
.run_until_complete(self
.libjuju
.list_models())
954 mock_disconnect_controller
.assert_called_once()
955 self
.assertEquals(models
, ["existingmodel", "model"])
958 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.list_models")
959 class ModelsExistTest(LibjujuTestCase
):
961 super(ModelsExistTest
, self
).setUp()
963 def test_model_names_none(self
, mock_list_models
):
964 mock_list_models
.return_value
= []
965 with self
.assertRaises(Exception):
966 self
.loop
.run_until_complete(self
.libjuju
.models_exist(None))
968 def test_model_names_empty(self
, mock_list_models
):
969 mock_list_models
.return_value
= []
970 with self
.assertRaises(Exception):
971 (exist
, non_existing_models
) = self
.loop
.run_until_complete(
972 self
.libjuju
.models_exist([])
975 def test_model_names_not_existing(self
, mock_list_models
):
976 mock_list_models
.return_value
= ["prometheus", "grafana"]
977 (exist
, non_existing_models
) = self
.loop
.run_until_complete(
978 self
.libjuju
.models_exist(["prometheus2", "grafana"])
980 self
.assertFalse(exist
)
981 self
.assertEqual(non_existing_models
, ["prometheus2"])
983 def test_model_names_exist(self
, mock_list_models
):
984 mock_list_models
.return_value
= ["prometheus", "grafana"]
985 (exist
, non_existing_models
) = self
.loop
.run_until_complete(
986 self
.libjuju
.models_exist(["prometheus", "grafana"])
988 self
.assertTrue(exist
)
989 self
.assertEqual(non_existing_models
, [])
992 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
993 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
994 @asynctest.mock
.patch("juju.controller.Controller.list_offers")
995 class ListOffers(LibjujuTestCase
):
997 super(ListOffers
, self
).setUp()
999 def test_disconnect_controller(
1000 self
, mock_list_offers
, mock_disconnect_controller
, mock_get_controller
,
1002 mock_get_controller
.return_value
= juju
.controller
.Controller()
1003 mock_list_offers
.side_effect
= Exception()
1004 with self
.assertRaises(Exception):
1005 self
.loop
.run_until_complete(self
.libjuju
.list_offers("model"))
1006 mock_disconnect_controller
.assert_called_once()
1008 def test_empty_list(
1009 self
, mock_list_offers
, mock_disconnect_controller
, mock_get_controller
,
1011 mock_get_controller
.return_value
= juju
.controller
.Controller()
1012 mock_list_offers
.return_value
= []
1013 offers
= self
.loop
.run_until_complete(self
.libjuju
.list_offers("model"))
1014 self
.assertEqual(offers
, [])
1015 mock_disconnect_controller
.assert_called_once()
1017 def test_non_empty_list(
1018 self
, mock_list_offers
, mock_disconnect_controller
, mock_get_controller
,
1020 mock_get_controller
.return_value
= juju
.controller
.Controller()
1021 mock_list_offers
.return_value
= ["offer"]
1022 offers
= self
.loop
.run_until_complete(self
.libjuju
.list_offers("model"))
1023 self
.assertEqual(offers
, ["offer"])
1024 mock_disconnect_controller
.assert_called_once()
1027 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1028 @asynctest.mock
.patch("juju.controller.Controller.get_model")
1029 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1030 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1031 @asynctest.mock
.patch("juju.model.Model.consume")
1032 class ConsumeTest(LibjujuTestCase
):
1034 super(ConsumeTest
, self
).setUp()
1039 mock_disconnect_controller
,
1040 mock_disconnect_model
,
1042 mock_get_controller
,
1044 mock_get_controller
.return_value
= juju
.controller
.Controller()
1045 mock_get_model
.return_value
= juju
.model
.Model()
1047 self
.loop
.run_until_complete(self
.libjuju
.consume("offer_url", "model_name"))
1048 mock_consume
.assert_called_once()
1049 mock_disconnect_model
.assert_called_once()
1050 mock_disconnect_controller
.assert_called_once()
1052 def test_parsing_error_exception(
1055 mock_disconnect_controller
,
1056 mock_disconnect_model
,
1058 mock_get_controller
,
1060 mock_get_controller
.return_value
= juju
.controller
.Controller()
1061 mock_get_model
.return_value
= juju
.model
.Model()
1062 mock_consume
.side_effect
= juju
.offerendpoints
.ParseError("")
1064 with self
.assertRaises(juju
.offerendpoints
.ParseError
):
1065 self
.loop
.run_until_complete(
1066 self
.libjuju
.consume("offer_url", "model_name")
1068 mock_consume
.assert_called_once()
1069 mock_disconnect_model
.assert_called_once()
1070 mock_disconnect_controller
.assert_called_once()
1072 def test_juju_error_exception(
1075 mock_disconnect_controller
,
1076 mock_disconnect_model
,
1078 mock_get_controller
,
1080 mock_get_controller
.return_value
= juju
.controller
.Controller()
1081 mock_get_model
.return_value
= juju
.model
.Model()
1082 mock_consume
.side_effect
= juju
.errors
.JujuError("")
1084 with self
.assertRaises(juju
.errors
.JujuError
):
1085 self
.loop
.run_until_complete(
1086 self
.libjuju
.consume("offer_url", "model_name")
1088 mock_consume
.assert_called_once()
1089 mock_disconnect_model
.assert_called_once()
1090 mock_disconnect_controller
.assert_called_once()
1092 def test_juju_api_error_exception(
1095 mock_disconnect_controller
,
1096 mock_disconnect_model
,
1098 mock_get_controller
,
1100 mock_get_controller
.return_value
= juju
.controller
.Controller()
1101 mock_get_model
.return_value
= juju
.model
.Model()
1102 mock_consume
.side_effect
= juju
.errors
.JujuAPIError(
1103 {"error": "", "response": "", "request-id": ""}
1106 with self
.assertRaises(juju
.errors
.JujuAPIError
):
1107 self
.loop
.run_until_complete(
1108 self
.libjuju
.consume("offer_url", "model_name")
1110 mock_consume
.assert_called_once()
1111 mock_disconnect_model
.assert_called_once()
1112 mock_disconnect_controller
.assert_called_once()
1115 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.add_cloud")
1116 class AddK8sTest(LibjujuTestCase
):
1118 super(AddK8sTest
, self
).setUp()
1120 "server": "https://192.168.0.21:16443",
1125 def test_add_k8s(self
, mock_add_cloud
):
1126 self
.loop
.run_until_complete(
1127 self
.libjuju
.add_k8s("cloud", self
.auth_data
, "storage_class")
1129 mock_add_cloud
.assert_called_once()
1131 def test_add_k8s_exception(self
, mock_add_cloud
):
1132 mock_add_cloud
.side_effect
= Exception()
1133 with self
.assertRaises(Exception):
1134 self
.loop
.run_until_complete(
1135 self
.libjuju
.add_k8s("cloud", self
.auth_data
, "storage_class")
1137 mock_add_cloud
.assert_called_once()
1139 def test_add_k8s_missing_name(self
, mock_add_cloud
):
1140 with self
.assertRaises(Exception):
1141 self
.loop
.run_until_complete(
1142 self
.libjuju
.add_k8s("", self
.auth_data
, "storage_class")
1144 mock_add_cloud
.assert_not_called()
1146 def test_add_k8s_missing_storage_name(self
, mock_add_cloud
):
1147 with self
.assertRaises(Exception):
1148 self
.loop
.run_until_complete(
1149 self
.libjuju
.add_k8s("cloud", self
.auth_data
, "")
1151 mock_add_cloud
.assert_not_called()
1153 def test_add_k8s_missing_auth_data_keys(self
, mock_add_cloud
):
1154 with self
.assertRaises(Exception):
1155 self
.loop
.run_until_complete(self
.libjuju
.add_k8s("cloud", {}, ""))
1156 mock_add_cloud
.assert_not_called()
1159 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1160 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1161 @asynctest.mock
.patch("juju.controller.Controller.add_cloud")
1162 @asynctest.mock
.patch("juju.controller.Controller.add_credential")
1163 class AddCloudTest(LibjujuTestCase
):
1165 super(AddCloudTest
, self
).setUp()
1166 self
.cloud
= juju
.client
.client
.Cloud()
1167 self
.credential
= juju
.client
.client
.CloudCredential()
1169 def test_add_cloud_with_credential(
1171 mock_add_credential
,
1173 mock_disconnect_controller
,
1174 mock_get_controller
,
1176 mock_get_controller
.return_value
= juju
.controller
.Controller()
1178 cloud
= self
.loop
.run_until_complete(
1179 self
.libjuju
.add_cloud("cloud", self
.cloud
, credential
=self
.credential
)
1181 self
.assertEqual(cloud
, self
.cloud
)
1182 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
1183 mock_add_credential
.assert_called_once_with(
1184 "cloud", credential
=self
.credential
, cloud
="cloud"
1186 mock_disconnect_controller
.assert_called_once()
1188 def test_add_cloud_no_credential(
1190 mock_add_credential
,
1192 mock_disconnect_controller
,
1193 mock_get_controller
,
1195 mock_get_controller
.return_value
= juju
.controller
.Controller()
1197 cloud
= self
.loop
.run_until_complete(
1198 self
.libjuju
.add_cloud("cloud", self
.cloud
)
1200 self
.assertEqual(cloud
, self
.cloud
)
1201 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
1202 mock_add_credential
.assert_not_called()
1203 mock_disconnect_controller
.assert_called_once()
1205 def test_add_cloud_exception(
1207 mock_add_credential
,
1209 mock_disconnect_controller
,
1210 mock_get_controller
,
1212 mock_get_controller
.return_value
= juju
.controller
.Controller()
1213 mock_add_cloud
.side_effect
= Exception()
1214 with self
.assertRaises(Exception):
1215 self
.loop
.run_until_complete(
1216 self
.libjuju
.add_cloud("cloud", self
.cloud
, credential
=self
.credential
)
1219 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
1220 mock_add_credential
.assert_not_called()
1221 mock_disconnect_controller
.assert_called_once()
1223 def test_add_credential_exception(
1225 mock_add_credential
,
1227 mock_disconnect_controller
,
1228 mock_get_controller
,
1230 mock_get_controller
.return_value
= juju
.controller
.Controller()
1231 mock_add_credential
.side_effect
= Exception()
1232 with self
.assertRaises(Exception):
1233 self
.loop
.run_until_complete(
1234 self
.libjuju
.add_cloud("cloud", self
.cloud
, credential
=self
.credential
)
1237 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
1238 mock_add_credential
.assert_called_once_with(
1239 "cloud", credential
=self
.credential
, cloud
="cloud"
1241 mock_disconnect_controller
.assert_called_once()
1244 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1245 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1246 @asynctest.mock
.patch("juju.controller.Controller.remove_cloud")
1247 class RemoveCloudTest(LibjujuTestCase
):
1249 super(RemoveCloudTest
, self
).setUp()
1251 def test_remove_cloud(
1252 self
, mock_remove_cloud
, mock_disconnect_controller
, mock_get_controller
,
1254 mock_get_controller
.return_value
= juju
.controller
.Controller()
1256 self
.loop
.run_until_complete(self
.libjuju
.remove_cloud("cloud"))
1257 mock_remove_cloud
.assert_called_once_with("cloud")
1258 mock_disconnect_controller
.assert_called_once()
1260 def test_remove_cloud_exception(
1261 self
, mock_remove_cloud
, mock_disconnect_controller
, mock_get_controller
,
1263 mock_get_controller
.return_value
= juju
.controller
.Controller()
1264 mock_remove_cloud
.side_effect
= Exception()
1266 with self
.assertRaises(Exception):
1267 self
.loop
.run_until_complete(self
.libjuju
.remove_cloud("cloud"))
1268 mock_remove_cloud
.assert_called_once_with("cloud")
1269 mock_disconnect_controller
.assert_called_once()