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 unittest
.mock
import Mock
, patch
21 from juju
.errors
import JujuAPIError
24 from n2vc
.definitions
import Offer
, RelationEndpoint
31 from n2vc
.libjuju
import Libjuju
32 from n2vc
.exceptions
import (
33 JujuControllerFailedConnecting
,
35 JujuApplicationNotFound
,
37 JujuApplicationExists
,
38 JujuInvalidK8sConfiguration
,
39 JujuLeaderUnitNotFound
,
42 from n2vc
.k8s_juju_conn
import generate_rbac_id
43 from n2vc
.tests
.unit
.utils
import AsyncMock
44 from n2vc
.vca
.connection
import Connection
45 from n2vc
.vca
.connection_data
import ConnectionData
48 cacert
= """-----BEGIN CERTIFICATE-----
50 -----END CERTIFICATE-----"""
53 @asynctest.mock
.patch("n2vc.libjuju.Controller")
54 class LibjujuTestCase(asynctest
.TestCase
):
55 @asynctest.mock
.patch("n2vc.vca.connection_data.base64_to_cacert")
58 mock_base64_to_cacert
=None,
60 self
.loop
= asyncio
.get_event_loop()
62 mock_base64_to_cacert
.return_value
= cacert
63 # Connection._load_vca_connection_data = Mock()
64 vca_connection
= Connection(AsyncMock())
65 vca_connection
._data
= ConnectionData(
67 "endpoints": ["1.2.3.4:17070"],
73 "lxd-credentials": "credentials",
74 "k8s-cloud": "k8s_cloud",
75 "k8s-credentials": "k8s_credentials",
77 "api-proxy": "api_proxy",
80 logging
.disable(logging
.CRITICAL
)
81 self
.libjuju
= Libjuju(vca_connection
, self
.loop
)
82 self
.loop
.run_until_complete(self
.libjuju
.disconnect())
85 @asynctest.mock
.patch("juju.controller.Controller.connect")
86 @asynctest.mock
.patch(
87 "juju.controller.Controller.api_endpoints",
88 new_callable
=asynctest
.CoroutineMock(return_value
=["127.0.0.1:17070"]),
90 class GetControllerTest(LibjujuTestCase
):
92 super(GetControllerTest
, self
).setUp()
94 def test_diff_endpoint(self
, mock_api_endpoints
, mock_connect
):
95 self
.libjuju
.endpoints
= []
96 controller
= self
.loop
.run_until_complete(self
.libjuju
.get_controller())
97 self
.assertIsInstance(controller
, juju
.controller
.Controller
)
99 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
102 mock_disconnect_controller
,
106 self
.libjuju
.endpoints
= []
108 mock_connect
.side_effect
= Exception()
110 with self
.assertRaises(JujuControllerFailedConnecting
):
111 controller
= self
.loop
.run_until_complete(self
.libjuju
.get_controller())
112 self
.assertIsNone(controller
)
113 mock_disconnect_controller
.assert_called()
115 def test_same_endpoint_get_controller(self
, mock_api_endpoints
, mock_connect
):
116 self
.libjuju
.endpoints
= ["127.0.0.1:17070"]
117 controller
= self
.loop
.run_until_complete(self
.libjuju
.get_controller())
118 self
.assertIsInstance(controller
, juju
.controller
.Controller
)
121 class DisconnectTest(LibjujuTestCase
):
123 super(DisconnectTest
, self
).setUp()
125 @asynctest.mock
.patch("juju.model.Model.disconnect")
126 def test_disconnect_model(self
, mock_disconnect
):
127 self
.loop
.run_until_complete(self
.libjuju
.disconnect_model(juju
.model
.Model()))
128 mock_disconnect
.assert_called_once()
130 @asynctest.mock
.patch("juju.controller.Controller.disconnect")
131 def test_disconnect_controller(self
, mock_disconnect
):
132 self
.loop
.run_until_complete(
133 self
.libjuju
.disconnect_controller(juju
.controller
.Controller())
135 mock_disconnect
.assert_called_once()
138 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
139 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.model_exists")
140 @asynctest.mock
.patch("juju.controller.Controller.add_model")
141 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
142 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
143 class AddModelTest(LibjujuTestCase
):
145 super(AddModelTest
, self
).setUp()
147 def test_existing_model(
149 mock_disconnect_model
,
150 mock_disconnect_controller
,
155 mock_model_exists
.return_value
= True
157 # This should not raise an exception
158 self
.loop
.run_until_complete(self
.libjuju
.add_model("existing_model", "cloud"))
160 mock_disconnect_controller
.assert_called()
162 # TODO Check two job executing at the same time and one returning without doing anything.
164 def test_non_existing_model(
166 mock_disconnect_model
,
167 mock_disconnect_controller
,
172 mock_model_exists
.return_value
= False
173 mock_get_controller
.return_value
= juju
.controller
.Controller()
175 self
.loop
.run_until_complete(
176 self
.libjuju
.add_model("nonexisting_model", Mock())
179 mock_add_model
.assert_called_once()
180 mock_disconnect_controller
.assert_called()
181 mock_disconnect_model
.assert_called()
184 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
185 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
186 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
187 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
188 @asynctest.mock
.patch(
189 "juju.model.Model.applications", new_callable
=asynctest
.PropertyMock
191 @asynctest.mock
.patch("juju.model.Model.get_action_status")
192 @asynctest.mock
.patch("juju.model.Model.get_action_output")
193 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_actions")
194 class GetExecutedActionsTest(LibjujuTestCase
):
196 super(GetExecutedActionsTest
, self
).setUp()
201 mock_get_action_output
,
202 mock_get_action_status
,
204 mock_disconnect_controller
,
205 mock_disconnect_model
,
209 mock_get_model
.return_value
= None
210 with self
.assertRaises(JujuError
):
211 self
.loop
.run_until_complete(self
.libjuju
.get_executed_actions("model"))
213 mock_get_controller
.assert_called_once()
214 mock_disconnect_controller
.assert_called_once()
215 mock_get_model
.assert_called_once()
216 mock_disconnect_model
.assert_not_called()
221 mock_get_action_output
,
222 mock_get_action_status
,
224 mock_disconnect_controller
,
225 mock_disconnect_model
,
229 mock_get_model
.return_value
= juju
.model
.Model()
230 mock_applications
.return_value
= {"existing_app"}
231 mock_get_actions
.return_value
= {"action_name": "description"}
232 mock_get_action_status
.return_value
= {"id": "status"}
233 mock_get_action_output
.return_value
= {"output": "completed"}
235 executed_actions
= self
.loop
.run_until_complete(
236 self
.libjuju
.get_executed_actions("model")
241 "action": "action_name",
243 "output": "completed",
246 self
.assertListEqual(expected_result
, executed_actions
)
247 self
.assertIsInstance(executed_actions
, list)
249 mock_get_controller
.assert_called_once()
250 mock_get_model
.assert_called_once()
251 mock_disconnect_controller
.assert_called_once()
252 mock_disconnect_model
.assert_called_once()
255 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
256 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
257 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
258 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
259 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
260 class GetApplicationConfigsTest(LibjujuTestCase
):
262 super(GetApplicationConfigsTest
, self
).setUp()
266 mock_get_application
,
267 mock_disconnect_controller
,
268 mock_disconnect_model
,
272 mock_get_model
.return_value
= None
273 with self
.assertRaises(JujuError
):
274 self
.loop
.run_until_complete(
275 self
.libjuju
.get_application_configs("model", "app")
278 mock_get_controller
.assert_called_once()
279 mock_disconnect_controller
.assert_called_once()
280 mock_get_model
.assert_called_once()
281 mock_disconnect_model
.assert_not_called()
285 mock_get_application
,
286 mock_disconnect_controller
,
287 mock_disconnect_model
,
291 mock_get_application
.return_value
= FakeApplication()
292 application_configs
= self
.loop
.run_until_complete(
293 self
.libjuju
.get_application_configs("model", "app")
296 self
.assertEqual(application_configs
, ["app_config"])
298 mock_get_controller
.assert_called_once()
299 mock_get_model
.assert_called_once()
300 mock_disconnect_controller
.assert_called_once()
301 mock_disconnect_model
.assert_called_once()
304 @asynctest.mock
.patch("juju.controller.Controller.get_model")
305 class GetModelTest(LibjujuTestCase
):
307 super(GetModelTest
, self
).setUp()
313 mock_get_model
.return_value
= juju
.model
.Model()
314 model
= self
.loop
.run_until_complete(
315 self
.libjuju
.get_model(juju
.controller
.Controller(), "model")
317 self
.assertIsInstance(model
, juju
.model
.Model
)
320 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
321 @asynctest.mock
.patch("juju.controller.Controller.list_models")
322 class ModelExistsTest(LibjujuTestCase
):
324 super(ModelExistsTest
, self
).setUp()
326 async def test_existing_model(
331 mock_list_models
.return_value
= ["existing_model"]
333 await self
.libjuju
.model_exists(
334 "existing_model", juju
.controller
.Controller()
338 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
339 async def test_no_controller(
341 mock_disconnect_controller
,
345 mock_list_models
.return_value
= ["existing_model"]
346 mock_get_controller
.return_value
= juju
.controller
.Controller()
347 self
.assertTrue(await self
.libjuju
.model_exists("existing_model"))
348 mock_disconnect_controller
.assert_called_once()
350 async def test_non_existing_model(
355 mock_list_models
.return_value
= ["existing_model"]
357 await self
.libjuju
.model_exists(
358 "not_existing_model", juju
.controller
.Controller()
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("juju.model.Model.get_status")
368 class GetModelStatusTest(LibjujuTestCase
):
370 super(GetModelStatusTest
, self
).setUp()
375 mock_disconnect_controller
,
376 mock_disconnect_model
,
380 mock_get_model
.return_value
= juju
.model
.Model()
381 mock_get_status
.return_value
= {"status"}
383 status
= self
.loop
.run_until_complete(self
.libjuju
.get_model_status("model"))
385 mock_get_status
.assert_called_once()
386 mock_disconnect_controller
.assert_called_once()
387 mock_disconnect_model
.assert_called_once()
389 self
.assertEqual(status
, {"status"})
394 mock_disconnect_controller
,
395 mock_disconnect_model
,
399 mock_get_model
.return_value
= juju
.model
.Model()
400 mock_get_status
.side_effect
= Exception()
402 with self
.assertRaises(Exception):
403 status
= self
.loop
.run_until_complete(
404 self
.libjuju
.get_model_status("model")
407 mock_disconnect_controller
.assert_called_once()
408 mock_disconnect_model
.assert_called_once()
410 self
.assertIsNone(status
)
413 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
414 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
415 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
416 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
417 @asynctest.mock
.patch("juju.model.Model.get_machines")
418 @asynctest.mock
.patch("juju.model.Model.add_machine")
419 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
420 class CreateMachineTest(LibjujuTestCase
):
422 super(CreateMachineTest
, self
).setUp()
424 def test_existing_machine(
429 mock_disconnect_controller
,
430 mock_disconnect_model
,
434 mock_get_model
.return_value
= juju
.model
.Model()
435 mock_get_machines
.return_value
= {"existing_machine": FakeMachine()}
436 machine
, bool_res
= self
.loop
.run_until_complete(
437 self
.libjuju
.create_machine("model", "existing_machine")
440 self
.assertIsInstance(machine
, FakeMachine
)
441 self
.assertFalse(bool_res
)
443 mock_disconnect_controller
.assert_called()
444 mock_disconnect_model
.assert_called()
446 def test_non_existing_machine(
451 mock_disconnect_controller
,
452 mock_disconnect_model
,
458 mock_get_model
.return_value
= juju
.model
.Model()
459 with self
.assertRaises(JujuMachineNotFound
):
460 machine
, bool_res
= self
.loop
.run_until_complete(
461 self
.libjuju
.create_machine("model", "non_existing_machine")
463 self
.assertIsNone(machine
)
464 self
.assertIsNone(bool_res
)
466 mock_disconnect_controller
.assert_called()
467 mock_disconnect_model
.assert_called()
474 mock_disconnect_controller
,
475 mock_disconnect_model
,
479 mock_get_model
.return_value
= juju
.model
.Model()
480 mock_add_machine
.return_value
= FakeMachine()
482 machine
, bool_res
= self
.loop
.run_until_complete(
483 self
.libjuju
.create_machine("model")
486 self
.assertIsInstance(machine
, FakeMachine
)
487 self
.assertTrue(bool_res
)
489 mock_wait_for
.assert_called_once()
490 mock_add_machine
.assert_called_once()
492 mock_disconnect_controller
.assert_called()
493 mock_disconnect_model
.assert_called()
496 # TODO test provision machine
499 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
500 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
501 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
502 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
503 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
504 @asynctest.mock
.patch("juju.model.Model.deploy")
505 class DeployTest(LibjujuTestCase
):
507 super(DeployTest
, self
).setUp()
513 mock_disconnect_controller
,
514 mock_disconnect_model
,
518 mock_get_model
.return_value
= juju
.model
.Model()
519 self
.loop
.run_until_complete(
520 self
.libjuju
.deploy("cs:osm", "model", wait
=True, timeout
=0)
522 mock_deploy
.assert_called_once()
523 mock_wait_for_model
.assert_called_once()
524 mock_disconnect_controller
.assert_called_once()
525 mock_disconnect_model
.assert_called_once()
527 def test_deploy_no_wait(
531 mock_disconnect_controller
,
532 mock_disconnect_model
,
536 mock_get_model
.return_value
= juju
.model
.Model()
537 self
.loop
.run_until_complete(
538 self
.libjuju
.deploy("cs:osm", "model", wait
=False, timeout
=0)
540 mock_deploy
.assert_called_once()
541 mock_wait_for_model
.assert_not_called()
542 mock_disconnect_controller
.assert_called_once()
543 mock_disconnect_model
.assert_called_once()
545 def test_deploy_exception(
549 mock_disconnect_controller
,
550 mock_disconnect_model
,
554 mock_deploy
.side_effect
= Exception()
555 mock_get_model
.return_value
= juju
.model
.Model()
556 with self
.assertRaises(Exception):
557 self
.loop
.run_until_complete(self
.libjuju
.deploy("cs:osm", "model"))
558 mock_deploy
.assert_called_once()
559 mock_wait_for_model
.assert_not_called()
560 mock_disconnect_controller
.assert_called_once()
561 mock_disconnect_model
.assert_called_once()
564 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
565 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
566 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
567 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
568 @asynctest.mock
.patch(
569 "juju.model.Model.applications", new_callable
=asynctest
.PropertyMock
571 @asynctest.mock
.patch("juju.model.Model.machines", new_callable
=asynctest
.PropertyMock
)
572 @asynctest.mock
.patch("juju.model.Model.deploy")
573 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
574 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.create_machine")
575 class DeployCharmTest(LibjujuTestCase
):
577 super(DeployCharmTest
, self
).setUp()
579 def test_existing_app(
586 mock_disconnect_controller
,
587 mock_disconnect_model
,
591 mock_get_model
.return_value
= juju
.model
.Model()
592 mock_applications
.return_value
= {"existing_app"}
595 with self
.assertRaises(JujuApplicationExists
):
596 application
= self
.loop
.run_until_complete(
597 self
.libjuju
.deploy_charm(
604 self
.assertIsNone(application
)
606 mock_disconnect_controller
.assert_called()
607 mock_disconnect_model
.assert_called()
609 def test_non_existing_machine(
616 mock_disconnect_controller
,
617 mock_disconnect_model
,
621 mock_get_model
.return_value
= juju
.model
.Model()
622 mock_machines
.return_value
= {"existing_machine": FakeMachine()}
624 with self
.assertRaises(JujuMachineNotFound
):
625 application
= self
.loop
.run_until_complete(
626 self
.libjuju
.deploy_charm(
634 self
.assertIsNone(application
)
636 mock_disconnect_controller
.assert_called()
637 mock_disconnect_model
.assert_called()
646 mock_disconnect_controller
,
647 mock_disconnect_model
,
651 mock_get_model
.return_value
= juju
.model
.Model()
652 mock_machines
.return_value
= {"existing_machine": FakeMachine()}
653 mock_create_machine
.return_value
= (FakeMachine(), "other")
654 mock_deploy
.return_value
= FakeApplication()
655 application
= self
.loop
.run_until_complete(
656 self
.libjuju
.deploy_charm(
665 self
.assertIsInstance(application
, FakeApplication
)
667 mock_deploy
.assert_called_once()
668 mock_wait_for
.assert_called_once()
670 mock_create_machine
.assert_called_once()
672 mock_disconnect_controller
.assert_called()
673 mock_disconnect_model
.assert_called()
682 mock_disconnect_controller
,
683 mock_disconnect_model
,
687 mock_get_model
.return_value
= juju
.model
.Model()
688 mock_machines
.return_value
= {"existing_machine": FakeMachine()}
689 mock_deploy
.return_value
= FakeApplication()
690 application
= self
.loop
.run_until_complete(
691 self
.libjuju
.deploy_charm("app", "path", "model", "existing_machine")
694 self
.assertIsInstance(application
, FakeApplication
)
696 mock_deploy
.assert_called_once()
697 mock_wait_for
.assert_called_once()
699 mock_disconnect_controller
.assert_called()
700 mock_disconnect_model
.assert_called()
703 @asynctest.mock
.patch(
704 "juju.model.Model.applications", new_callable
=asynctest
.PropertyMock
706 class GetApplicationTest(LibjujuTestCase
):
708 super(GetApplicationTest
, self
).setUp()
710 def test_existing_application(
714 mock_applications
.return_value
= {"existing_app": "exists"}
715 model
= juju
.model
.Model()
716 result
= self
.libjuju
._get
_application
(model
, "existing_app")
717 self
.assertEqual(result
, "exists")
719 def test_non_existing_application(
723 mock_applications
.return_value
= {"existing_app": "exists"}
724 model
= juju
.model
.Model()
725 result
= self
.libjuju
._get
_application
(model
, "nonexisting_app")
726 self
.assertIsNone(result
)
729 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
730 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
731 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
732 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
733 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
734 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
735 @asynctest.mock
.patch("juju.model.Model.get_action_output")
736 @asynctest.mock
.patch("juju.model.Model.get_action_status")
737 class ExecuteActionTest(LibjujuTestCase
):
739 super(ExecuteActionTest
, self
).setUp()
741 def test_no_application(
743 mock_get_action_status
,
744 mock_get_action_output
,
746 mock__get_application
,
747 mock_disconnect_controller
,
748 mock_disconnect_model
,
752 mock__get_application
.return_value
= None
753 mock_get_model
.return_value
= juju
.model
.Model()
756 with self
.assertRaises(JujuApplicationNotFound
):
757 output
, status
= self
.loop
.run_until_complete(
758 self
.libjuju
.execute_action(
764 self
.assertIsNone(output
)
765 self
.assertIsNone(status
)
767 mock_disconnect_controller
.assert_called()
768 mock_disconnect_model
.assert_called()
772 mock_get_action_status
,
773 mock_get_action_output
,
775 mock__get_application
,
776 mock_disconnect_controller
,
777 mock_disconnect_model
,
781 mock_get_model
.return_value
= juju
.model
.Model()
782 mock__get_application
.return_value
= FakeApplication()
785 with self
.assertRaises(JujuActionNotFound
):
786 output
, status
= self
.loop
.run_until_complete(
787 self
.libjuju
.execute_action(
793 self
.assertIsNone(output
)
794 self
.assertIsNone(status
)
796 mock_disconnect_controller
.assert_called()
797 mock_disconnect_model
.assert_called()
799 @asynctest.mock
.patch("asyncio.sleep")
800 @asynctest.mock
.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
803 mock_is_leader_from_status
,
805 mock_get_action_status
,
806 mock_get_action_output
,
808 mock__get_application
,
809 mock_disconnect_controller
,
810 mock_disconnect_model
,
814 mock_get_model
.return_value
= juju
.model
.Model()
815 mock__get_application
.return_value
= FakeApplication()
816 mock_is_leader_from_status
.return_value
= False
819 with self
.assertRaises(JujuLeaderUnitNotFound
):
820 output
, status
= self
.loop
.run_until_complete(
821 self
.libjuju
.execute_action(
827 self
.assertIsNone(output
)
828 self
.assertIsNone(status
)
830 mock_disconnect_controller
.assert_called()
831 mock_disconnect_model
.assert_called()
833 def test_successful_exec(
835 mock_get_action_status
,
836 mock_get_action_output
,
838 mock__get_application
,
839 mock_disconnect_controller
,
840 mock_disconnect_model
,
844 mock_get_model
.return_value
= juju
.model
.Model()
845 mock__get_application
.return_value
= FakeApplication()
846 mock_get_action_output
.return_value
= "output"
847 mock_get_action_status
.return_value
= {"id": "status"}
848 output
, status
= self
.loop
.run_until_complete(
849 self
.libjuju
.execute_action("app", "model", "existing_action")
851 self
.assertEqual(output
, "output")
852 self
.assertEqual(status
, "status")
854 mock_wait_for
.assert_called_once()
856 mock_disconnect_controller
.assert_called()
857 mock_disconnect_model
.assert_called()
860 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
861 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
862 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
863 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
864 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
865 class GetActionTest(LibjujuTestCase
):
867 super(GetActionTest
, self
).setUp()
871 mock_get_application
,
872 mock_disconnect_controller
,
873 mock_disconnect_model
,
877 mock_get_application
.side_effect
= Exception()
879 with self
.assertRaises(Exception):
880 actions
= self
.loop
.run_until_complete(
881 self
.libjuju
.get_actions("app", "model")
884 self
.assertIsNone(actions
)
885 mock_disconnect_controller
.assert_called_once()
886 mock_disconnect_model
.assert_called_once()
890 mock_get_application
,
891 mock_disconnect_controller
,
892 mock_disconnect_model
,
896 mock_get_application
.return_value
= FakeApplication()
898 actions
= self
.loop
.run_until_complete(self
.libjuju
.get_actions("app", "model"))
900 self
.assertEqual(actions
, ["existing_action"])
902 mock_get_controller
.assert_called_once()
903 mock_get_model
.assert_called_once()
904 mock_disconnect_controller
.assert_called_once()
905 mock_disconnect_model
.assert_called_once()
908 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
909 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
910 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
911 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
912 @asynctest.mock
.patch("juju.application.Application.get_metrics")
913 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
914 class GetMetricsTest(LibjujuTestCase
):
916 super(GetMetricsTest
, self
).setUp()
918 def test_get_metrics_success(
920 mock_get_application
,
922 mock_disconnect_controller
,
923 mock_disconnect_model
,
927 mock_get_application
.return_value
= FakeApplication()
928 mock_get_model
.return_value
= juju
.model
.Model()
930 self
.loop
.run_until_complete(self
.libjuju
.get_metrics("model", "app1"))
932 mock_disconnect_controller
.assert_called_once()
933 mock_disconnect_model
.assert_called_once()
935 def test_get_metrics_exception(
937 mock_get_application
,
939 mock_disconnect_controller
,
940 mock_disconnect_model
,
944 mock_get_model
.return_value
= juju
.model
.Model()
945 mock_get_metrics
.side_effect
= Exception()
946 with self
.assertRaises(Exception):
947 self
.loop
.run_until_complete(self
.libjuju
.get_metrics("model", "app1"))
949 mock_disconnect_controller
.assert_called_once()
950 mock_disconnect_model
.assert_called_once()
952 def test_missing_args_exception(
954 mock_get_application
,
956 mock_disconnect_controller
,
957 mock_disconnect_model
,
961 mock_get_model
.return_value
= juju
.model
.Model()
963 with self
.assertRaises(Exception):
964 self
.loop
.run_until_complete(self
.libjuju
.get_metrics("", ""))
966 mock_get_controller
.assert_not_called()
967 mock_get_model
.assert_not_called()
968 mock_disconnect_controller
.assert_not_called()
969 mock_disconnect_model
.assert_not_called()
972 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
973 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
974 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
975 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
976 @asynctest.mock
.patch("juju.model.Model.add_relation")
977 class AddRelationTest(LibjujuTestCase
):
979 super(AddRelationTest
, self
).setUp()
981 @asynctest.mock
.patch("logging.Logger.warning")
986 mock_disconnect_controller
,
987 mock_disconnect_model
,
991 # TODO in libjuju.py should this fail only with a log message?
992 result
= {"error": "not found", "response": "response", "request-id": 1}
994 mock_get_model
.return_value
= juju
.model
.Model()
995 mock_add_relation
.side_effect
= JujuAPIError(result
)
997 self
.loop
.run_until_complete(
998 self
.libjuju
.add_relation(
1005 mock_warning
.assert_called_with("Relation not found: not found")
1006 mock_disconnect_controller
.assert_called_once()
1007 mock_disconnect_model
.assert_called_once()
1009 @asynctest.mock
.patch("logging.Logger.warning")
1010 def test_already_exists(
1014 mock_disconnect_controller
,
1015 mock_disconnect_model
,
1017 mock_get_controller
,
1019 # TODO in libjuju.py should this fail silently?
1020 result
= {"error": "already exists", "response": "response", "request-id": 1}
1022 mock_get_model
.return_value
= juju
.model
.Model()
1023 mock_add_relation
.side_effect
= JujuAPIError(result
)
1025 self
.loop
.run_until_complete(
1026 self
.libjuju
.add_relation(
1033 mock_warning
.assert_called_with("Relation already exists: already exists")
1034 mock_disconnect_controller
.assert_called_once()
1035 mock_disconnect_model
.assert_called_once()
1040 mock_disconnect_controller
,
1041 mock_disconnect_model
,
1043 mock_get_controller
,
1045 mock_get_model
.return_value
= juju
.model
.Model()
1046 result
= {"error": "", "response": "response", "request-id": 1}
1047 mock_add_relation
.side_effect
= JujuAPIError(result
)
1049 with self
.assertRaises(JujuAPIError
):
1050 self
.loop
.run_until_complete(
1051 self
.libjuju
.add_relation(
1058 mock_disconnect_controller
.assert_called_once()
1059 mock_disconnect_model
.assert_called_once()
1064 mock_disconnect_controller
,
1065 mock_disconnect_model
,
1067 mock_get_controller
,
1069 mock_get_model
.return_value
= juju
.model
.Model()
1071 self
.loop
.run_until_complete(
1072 self
.libjuju
.add_relation(
1079 mock_add_relation
.assert_called_with("app1:relation1", "app2:relation2")
1080 mock_disconnect_controller
.assert_called_once()
1081 mock_disconnect_model
.assert_called_once()
1086 mock_disconnect_controller
,
1087 mock_disconnect_model
,
1089 mock_get_controller
,
1091 mock_get_model
.return_value
= juju
.model
.Model()
1093 self
.loop
.run_until_complete(
1094 self
.libjuju
.add_relation(
1101 mock_add_relation
.assert_called_with("app1:relation1", "saas_name")
1102 mock_disconnect_controller
.assert_called_once()
1103 mock_disconnect_model
.assert_called_once()
1106 # TODO destroy_model testcase
1109 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1110 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
1111 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1112 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
1113 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1114 class DestroyApplicationTest(LibjujuTestCase
):
1116 super(DestroyApplicationTest
, self
).setUp()
1120 mock_get_controller
,
1122 mock_disconnect_controller
,
1123 mock_get_application
,
1124 mock_disconnect_model
,
1126 mock_get_application
.return_value
= FakeApplication()
1127 mock_get_model
.return_value
= None
1128 self
.loop
.run_until_complete(
1129 self
.libjuju
.destroy_application(
1135 mock_get_application
.assert_called()
1136 mock_disconnect_controller
.assert_called_once()
1137 mock_disconnect_model
.assert_called_once()
1139 def test_no_application(
1141 mock_get_controller
,
1143 mock_disconnect_controller
,
1144 mock_get_application
,
1145 mock_disconnect_model
,
1147 mock_get_model
.return_value
= None
1148 mock_get_application
.return_value
= None
1150 self
.loop
.run_until_complete(
1151 self
.libjuju
.destroy_application(
1157 mock_get_application
.assert_called()
1161 mock_get_controller
,
1163 mock_disconnect_controller
,
1164 mock_get_application
,
1165 mock_disconnect_model
,
1167 mock_get_application
.return_value
= FakeApplication
1168 mock_get_model
.return_value
= None
1170 with self
.assertRaises(Exception):
1171 self
.loop
.run_until_complete(
1172 self
.libjuju
.destroy_application(
1178 mock_get_application
.assert_called_once()
1181 # @asynctest.mock.patch("juju.model.Model.get_machines")
1182 # @asynctest.mock.patch("logging.Logger.debug")
1183 # class DestroyMachineTest(LibjujuTestCase):
1185 # super(DestroyMachineTest, self).setUp()
1187 # def test_success_manual_machine(
1188 # self, mock_debug, mock_get_machines,
1190 # mock_get_machines.side_effect = [
1191 # {"machine": FakeManualMachine()},
1192 # {"machine": FakeManualMachine()},
1195 # self.loop.run_until_complete(
1196 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
1199 # asynctest.call("Waiting for machine machine is destroyed"),
1200 # asynctest.call("Machine destroyed: machine"),
1202 # mock_debug.assert_has_calls(calls)
1204 # def test_no_machine(
1205 # self, mock_debug, mock_get_machines,
1207 # mock_get_machines.return_value = {}
1208 # self.loop.run_until_complete(
1209 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
1211 # mock_debug.assert_called_with("Machine not found: machine")
1214 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1215 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
1216 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1217 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1218 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
1219 class ConfigureApplicationTest(LibjujuTestCase
):
1221 super(ConfigureApplicationTest
, self
).setUp()
1225 mock_get_application
,
1226 mock_disconnect_controller
,
1227 mock_disconnect_model
,
1229 mock_get_controller
,
1231 mock_get_application
.return_value
= FakeApplication()
1233 self
.loop
.run_until_complete(
1234 self
.libjuju
.configure_application(
1240 mock_get_application
.assert_called_once()
1241 mock_disconnect_controller
.assert_called_once()
1242 mock_disconnect_model
.assert_called_once()
1246 mock_get_application
,
1247 mock_disconnect_controller
,
1248 mock_disconnect_model
,
1250 mock_get_controller
,
1252 mock_get_application
.side_effect
= Exception()
1254 with self
.assertRaises(Exception):
1255 self
.loop
.run_until_complete(
1256 self
.libjuju
.configure_application(
1262 mock_disconnect_controller
.assert_called_once()
1263 mock_disconnect_model
.assert_called_once()
1265 def test_controller_exception(
1267 mock_get_application
,
1268 mock_disconnect_controller
,
1269 mock_disconnect_model
,
1271 mock_get_controller
,
1273 result
= {"error": "not found", "response": "response", "request-id": 1}
1275 mock_get_controller
.side_effect
= JujuAPIError(result
)
1277 with self
.assertRaises(JujuAPIError
):
1278 self
.loop
.run_until_complete(
1279 self
.libjuju
.configure_application(
1285 mock_get_model
.assert_not_called()
1286 mock_disconnect_controller
.assert_not_called()
1287 mock_disconnect_model
.assert_not_called()
1289 def test_get_model_exception(
1291 mock_get_application
,
1292 mock_disconnect_controller
,
1293 mock_disconnect_model
,
1295 mock_get_controller
,
1297 result
= {"error": "not found", "response": "response", "request-id": 1}
1298 mock_get_model
.side_effect
= JujuAPIError(result
)
1300 with self
.assertRaises(JujuAPIError
):
1301 self
.loop
.run_until_complete(
1302 self
.libjuju
.configure_application(
1308 mock_get_model
.assert_called_once()
1309 mock_disconnect_controller
.assert_called_once()
1310 mock_disconnect_model
.assert_not_called()
1313 # TODO _get_api_endpoints_db test case
1314 # TODO _update_api_endpoints_db test case
1315 # TODO healthcheck test case
1318 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1319 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1320 @asynctest.mock
.patch("juju.controller.Controller.list_models")
1321 class ListModelsTest(LibjujuTestCase
):
1323 super(ListModelsTest
, self
).setUp()
1325 def test_containing(
1328 mock_disconnect_controller
,
1329 mock_get_controller
,
1331 mock_get_controller
.return_value
= juju
.controller
.Controller()
1332 mock_list_models
.return_value
= ["existingmodel"]
1333 models
= self
.loop
.run_until_complete(self
.libjuju
.list_models("existing"))
1335 mock_disconnect_controller
.assert_called_once()
1336 self
.assertEquals(models
, ["existingmodel"])
1338 def test_not_containing(
1341 mock_disconnect_controller
,
1342 mock_get_controller
,
1344 mock_get_controller
.return_value
= juju
.controller
.Controller()
1345 mock_list_models
.return_value
= ["existingmodel", "model"]
1346 models
= self
.loop
.run_until_complete(self
.libjuju
.list_models("mdl"))
1348 mock_disconnect_controller
.assert_called_once()
1349 self
.assertEquals(models
, [])
1351 def test_no_contains_arg(
1354 mock_disconnect_controller
,
1355 mock_get_controller
,
1357 mock_get_controller
.return_value
= juju
.controller
.Controller()
1358 mock_list_models
.return_value
= ["existingmodel", "model"]
1359 models
= self
.loop
.run_until_complete(self
.libjuju
.list_models())
1361 mock_disconnect_controller
.assert_called_once()
1362 self
.assertEquals(models
, ["existingmodel", "model"])
1365 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.list_models")
1366 class ModelsExistTest(LibjujuTestCase
):
1368 super(ModelsExistTest
, self
).setUp()
1370 def test_model_names_none(self
, mock_list_models
):
1371 mock_list_models
.return_value
= []
1372 with self
.assertRaises(Exception):
1373 self
.loop
.run_until_complete(self
.libjuju
.models_exist(None))
1375 def test_model_names_empty(self
, mock_list_models
):
1376 mock_list_models
.return_value
= []
1377 with self
.assertRaises(Exception):
1378 (exist
, non_existing_models
) = self
.loop
.run_until_complete(
1379 self
.libjuju
.models_exist([])
1382 def test_model_names_not_existing(self
, mock_list_models
):
1383 mock_list_models
.return_value
= ["prometheus", "grafana"]
1384 (exist
, non_existing_models
) = self
.loop
.run_until_complete(
1385 self
.libjuju
.models_exist(["prometheus2", "grafana"])
1387 self
.assertFalse(exist
)
1388 self
.assertEqual(non_existing_models
, ["prometheus2"])
1390 def test_model_names_exist(self
, mock_list_models
):
1391 mock_list_models
.return_value
= ["prometheus", "grafana"]
1392 (exist
, non_existing_models
) = self
.loop
.run_until_complete(
1393 self
.libjuju
.models_exist(["prometheus", "grafana"])
1395 self
.assertTrue(exist
)
1396 self
.assertEqual(non_existing_models
, [])
1399 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1400 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1401 @asynctest.mock
.patch("juju.controller.Controller.list_offers")
1402 class ListOffers(LibjujuTestCase
):
1404 super(ListOffers
, self
).setUp()
1406 def test_disconnect_controller(
1409 mock_disconnect_controller
,
1410 mock_get_controller
,
1412 mock_get_controller
.return_value
= juju
.controller
.Controller()
1413 mock_list_offers
.side_effect
= Exception()
1414 with self
.assertRaises(Exception):
1415 self
.loop
.run_until_complete(self
.libjuju
._list
_offers
("model"))
1416 mock_disconnect_controller
.assert_called_once()
1418 def test_empty_list(
1421 mock_disconnect_controller
,
1422 mock_get_controller
,
1424 mock_get_controller
.return_value
= juju
.controller
.Controller()
1425 offer_results
= Mock()
1426 offer_results
.results
= []
1427 mock_list_offers
.return_value
= offer_results
1428 offers
= self
.loop
.run_until_complete(self
.libjuju
._list
_offers
("model"))
1429 self
.assertEqual(offers
, [])
1430 mock_disconnect_controller
.assert_called_once()
1432 def test_non_empty_list(
1435 mock_disconnect_controller
,
1436 mock_get_controller
,
1438 mock_get_controller
.return_value
= juju
.controller
.Controller()
1440 offer_results
= Mock()
1441 offer_results
.results
= [offer
]
1442 mock_list_offers
.return_value
= offer_results
1443 offers
= self
.loop
.run_until_complete(self
.libjuju
._list
_offers
("model"))
1444 self
.assertEqual(offers
, [offer
])
1445 mock_disconnect_controller
.assert_called_once()
1447 def test_matching_offer_name(
1450 mock_disconnect_controller
,
1451 mock_get_controller
,
1453 mock_get_controller
.return_value
= juju
.controller
.Controller()
1455 offer_1
.offer_name
= "offer1"
1457 offer_2
.offer_name
= "offer2"
1458 offer_results
= Mock()
1459 offer_results
.results
= [offer_1
, offer_2
]
1460 mock_list_offers
.return_value
= offer_results
1461 offers
= self
.loop
.run_until_complete(
1462 self
.libjuju
._list
_offers
("model", offer_name
="offer2")
1464 self
.assertEqual(offers
, [offer_2
])
1465 mock_disconnect_controller
.assert_called_once()
1467 def test_not_matching_offer_name(
1470 mock_disconnect_controller
,
1471 mock_get_controller
,
1473 mock_get_controller
.return_value
= juju
.controller
.Controller()
1475 offer_1
.offer_name
= "offer1"
1477 offer_2
.offer_name
= "offer2"
1478 offer_results
= Mock()
1479 offer_results
.results
= [offer_1
, offer_2
]
1480 mock_list_offers
.return_value
= offer_results
1481 offers
= self
.loop
.run_until_complete(
1482 self
.libjuju
._list
_offers
("model", offer_name
="offer3")
1484 self
.assertEqual(offers
, [])
1485 mock_disconnect_controller
.assert_called_once()
1488 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1489 @asynctest.mock
.patch("juju.controller.Controller.get_model")
1490 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1491 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1492 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._list_offers")
1493 @asynctest.mock
.patch("juju.model.Model.create_offer")
1494 class OfferTest(LibjujuTestCase
):
1496 super(OfferTest
, self
).setUp()
1502 mock_disconnect_controller
,
1503 mock_disconnect_model
,
1505 mock_get_controller
,
1507 controller
= juju
.controller
.Controller()
1508 model
= juju
.model
.Model()
1509 mock_get_controller
.return_value
= controller
1510 mock_get_model
.return_value
= model
1511 endpoint
= RelationEndpoint("model.app-name.0", "vca", "endpoint")
1512 self
.loop
.run_until_complete(self
.libjuju
.offer(endpoint
))
1513 mock_create_offer
.assert_called_with(
1514 "app-name:endpoint", offer_name
="app-name-endpoint"
1516 mock_disconnect_model
.assert_called_once_with(model
)
1517 mock_disconnect_controller
.assert_called_once_with(controller
)
1519 def test_offer_exception(
1523 mock_disconnect_controller
,
1524 mock_disconnect_model
,
1526 mock_get_controller
,
1528 controller
= juju
.controller
.Controller()
1529 model
= juju
.model
.Model()
1530 mock_get_controller
.return_value
= controller
1531 mock_get_model
.return_value
= model
1532 mock__list_offers
.return_value
= []
1533 endpoint
= RelationEndpoint("model.app-name.0", "vca", "endpoint")
1534 with self
.assertRaises(Exception):
1535 self
.loop
.run_until_complete(self
.libjuju
.offer(endpoint
))
1536 mock_create_offer
.assert_called_with(
1537 "app-name:endpoint", offer_name
="app-name-endpoint"
1539 mock_disconnect_model
.assert_called_once_with(model
)
1540 mock_disconnect_controller
.assert_called_once_with(controller
)
1543 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1544 @asynctest.mock
.patch("juju.controller.Controller.get_model")
1545 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1546 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1547 @asynctest.mock
.patch("juju.model.Model.consume")
1548 class ConsumeTest(LibjujuTestCase
):
1550 self
.offer_url
= "admin/model.offer_name"
1551 super(ConsumeTest
, self
).setUp()
1552 self
.provider_libjuju
= self
.libjuju
1557 mock_disconnect_controller
,
1558 mock_disconnect_model
,
1560 mock_get_controller
,
1562 self_controller
= juju
.controller
.Controller()
1563 provider_controller
= juju
.controller
.Controller()
1564 mock_get_controller
.side_effect
= [self_controller
, provider_controller
]
1565 mock_get_model
.return_value
= juju
.model
.Model()
1567 self
.loop
.run_until_complete(
1568 self
.libjuju
.consume(
1570 Offer(self
.offer_url
, vca_id
="vca-id"),
1571 self
.provider_libjuju
,
1574 mock_consume
.assert_called_once_with(
1575 "admin/model.offer_name",
1576 application_alias
="offer_name-model-vca-id",
1577 controller
=provider_controller
,
1579 mock_disconnect_model
.assert_called_once()
1580 self
.assertEqual(mock_disconnect_controller
.call_count
, 2)
1582 def test_parsing_error_exception(
1585 mock_disconnect_controller
,
1586 mock_disconnect_model
,
1588 mock_get_controller
,
1590 mock_get_controller
.return_value
= juju
.controller
.Controller()
1591 mock_get_model
.return_value
= juju
.model
.Model()
1592 mock_consume
.side_effect
= juju
.offerendpoints
.ParseError("")
1594 with self
.assertRaises(juju
.offerendpoints
.ParseError
):
1595 self
.loop
.run_until_complete(
1596 self
.libjuju
.consume(
1597 "model_name", Offer(self
.offer_url
), self
.provider_libjuju
1600 mock_consume
.assert_called_once()
1601 mock_disconnect_model
.assert_called_once()
1602 self
.assertEqual(mock_disconnect_controller
.call_count
, 2)
1604 def test_juju_error_exception(
1607 mock_disconnect_controller
,
1608 mock_disconnect_model
,
1610 mock_get_controller
,
1612 mock_get_controller
.return_value
= juju
.controller
.Controller()
1613 mock_get_model
.return_value
= juju
.model
.Model()
1614 mock_consume
.side_effect
= juju
.errors
.JujuError("")
1616 with self
.assertRaises(juju
.errors
.JujuError
):
1617 self
.loop
.run_until_complete(
1618 self
.libjuju
.consume(
1619 "model_name", Offer(self
.offer_url
), self
.provider_libjuju
1622 mock_consume
.assert_called_once()
1623 mock_disconnect_model
.assert_called_once()
1624 self
.assertEqual(mock_disconnect_controller
.call_count
, 2)
1626 def test_juju_api_error_exception(
1629 mock_disconnect_controller
,
1630 mock_disconnect_model
,
1632 mock_get_controller
,
1634 mock_get_controller
.return_value
= juju
.controller
.Controller()
1635 mock_get_model
.return_value
= juju
.model
.Model()
1636 mock_consume
.side_effect
= juju
.errors
.JujuAPIError(
1637 {"error": "", "response": "", "request-id": ""}
1640 with self
.assertRaises(juju
.errors
.JujuAPIError
):
1641 self
.loop
.run_until_complete(
1642 self
.libjuju
.consume(
1643 "model_name", Offer(self
.offer_url
), self
.provider_libjuju
1646 mock_consume
.assert_called_once()
1647 mock_disconnect_model
.assert_called_once()
1648 self
.assertEqual(mock_disconnect_controller
.call_count
, 2)
1651 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
1652 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.add_cloud")
1653 class AddK8sTest(LibjujuTestCase
):
1655 super(AddK8sTest
, self
).setUp()
1657 rbac_id
= generate_rbac_id()
1659 client_cert_data
= "cert"
1660 configuration
= kubernetes
.client
.configuration
.Configuration()
1661 storage_class
= "storage_class"
1662 credential_name
= name
1664 self
._add
_k
8s
_args
= {
1668 "client_cert_data": client_cert_data
,
1669 "configuration": configuration
,
1670 "storage_class": storage_class
,
1671 "credential_name": credential_name
,
1674 def test_add_k8s(self
, mock_add_cloud
, mock_get_k8s_cloud_credential
):
1675 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
1676 mock_add_cloud
.assert_called_once()
1677 mock_get_k8s_cloud_credential
.assert_called_once()
1679 def test_add_k8s_exception(self
, mock_add_cloud
, mock_get_k8s_cloud_credential
):
1680 mock_add_cloud
.side_effect
= Exception()
1681 with self
.assertRaises(Exception):
1682 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
1683 mock_add_cloud
.assert_called_once()
1684 mock_get_k8s_cloud_credential
.assert_called_once()
1686 def test_add_k8s_missing_name(self
, mock_add_cloud
, mock_get_k8s_cloud_credential
):
1687 self
._add
_k
8s
_args
["name"] = ""
1688 with self
.assertRaises(Exception):
1689 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
1690 mock_add_cloud
.assert_not_called()
1692 def test_add_k8s_missing_storage_name(
1693 self
, mock_add_cloud
, mock_get_k8s_cloud_credential
1695 self
._add
_k
8s
_args
["storage_class"] = ""
1696 with self
.assertRaises(Exception):
1697 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
1698 mock_add_cloud
.assert_not_called()
1700 def test_add_k8s_missing_configuration_keys(
1701 self
, mock_add_cloud
, mock_get_k8s_cloud_credential
1703 self
._add
_k
8s
_args
["configuration"] = None
1704 with self
.assertRaises(Exception):
1705 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
1706 mock_add_cloud
.assert_not_called()
1709 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1710 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1711 @asynctest.mock
.patch("juju.controller.Controller.add_cloud")
1712 @asynctest.mock
.patch("juju.controller.Controller.add_credential")
1713 class AddCloudTest(LibjujuTestCase
):
1715 super(AddCloudTest
, self
).setUp()
1716 self
.cloud
= juju
.client
.client
.Cloud()
1717 self
.credential
= juju
.client
.client
.CloudCredential()
1719 def test_add_cloud_with_credential(
1721 mock_add_credential
,
1723 mock_disconnect_controller
,
1724 mock_get_controller
,
1726 mock_get_controller
.return_value
= juju
.controller
.Controller()
1728 cloud
= self
.loop
.run_until_complete(
1729 self
.libjuju
.add_cloud("cloud", self
.cloud
, credential
=self
.credential
)
1731 self
.assertEqual(cloud
, self
.cloud
)
1732 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
1733 mock_add_credential
.assert_called_once_with(
1734 "cloud", credential
=self
.credential
, cloud
="cloud"
1736 mock_disconnect_controller
.assert_called_once()
1738 def test_add_cloud_no_credential(
1740 mock_add_credential
,
1742 mock_disconnect_controller
,
1743 mock_get_controller
,
1745 mock_get_controller
.return_value
= juju
.controller
.Controller()
1747 cloud
= self
.loop
.run_until_complete(
1748 self
.libjuju
.add_cloud("cloud", self
.cloud
)
1750 self
.assertEqual(cloud
, self
.cloud
)
1751 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
1752 mock_add_credential
.assert_not_called()
1753 mock_disconnect_controller
.assert_called_once()
1755 def test_add_cloud_exception(
1757 mock_add_credential
,
1759 mock_disconnect_controller
,
1760 mock_get_controller
,
1762 mock_get_controller
.return_value
= juju
.controller
.Controller()
1763 mock_add_cloud
.side_effect
= Exception()
1764 with self
.assertRaises(Exception):
1765 self
.loop
.run_until_complete(
1766 self
.libjuju
.add_cloud("cloud", self
.cloud
, credential
=self
.credential
)
1769 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
1770 mock_add_credential
.assert_not_called()
1771 mock_disconnect_controller
.assert_called_once()
1773 def test_add_credential_exception(
1775 mock_add_credential
,
1777 mock_disconnect_controller
,
1778 mock_get_controller
,
1780 mock_get_controller
.return_value
= juju
.controller
.Controller()
1781 mock_add_credential
.side_effect
= Exception()
1782 with self
.assertRaises(Exception):
1783 self
.loop
.run_until_complete(
1784 self
.libjuju
.add_cloud("cloud", self
.cloud
, credential
=self
.credential
)
1787 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
1788 mock_add_credential
.assert_called_once_with(
1789 "cloud", credential
=self
.credential
, cloud
="cloud"
1791 mock_disconnect_controller
.assert_called_once()
1794 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1795 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1796 @asynctest.mock
.patch("juju.controller.Controller.remove_cloud")
1797 class RemoveCloudTest(LibjujuTestCase
):
1799 super(RemoveCloudTest
, self
).setUp()
1801 def test_remove_cloud(
1804 mock_disconnect_controller
,
1805 mock_get_controller
,
1807 mock_get_controller
.return_value
= juju
.controller
.Controller()
1809 self
.loop
.run_until_complete(self
.libjuju
.remove_cloud("cloud"))
1810 mock_remove_cloud
.assert_called_once_with("cloud")
1811 mock_disconnect_controller
.assert_called_once()
1813 def test_remove_cloud_exception(
1816 mock_disconnect_controller
,
1817 mock_get_controller
,
1819 mock_get_controller
.return_value
= juju
.controller
.Controller()
1820 mock_remove_cloud
.side_effect
= Exception()
1822 with self
.assertRaises(Exception):
1823 self
.loop
.run_until_complete(self
.libjuju
.remove_cloud("cloud"))
1824 mock_remove_cloud
.assert_called_once_with("cloud")
1825 mock_disconnect_controller
.assert_called_once()
1828 @asynctest.mock
.patch("kubernetes.client.configuration.Configuration")
1829 class GetK8sCloudCredentials(LibjujuTestCase
):
1831 super(GetK8sCloudCredentials
, self
).setUp()
1832 self
.cert_data
= "cert"
1833 self
.token
= "token"
1835 @asynctest.mock
.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1836 def test_not_supported(self
, mock_exception
, mock_configuration
):
1837 mock_configuration
.username
= ""
1838 mock_configuration
.password
= ""
1839 mock_configuration
.ssl_ca_cert
= None
1840 mock_configuration
.cert_file
= None
1841 mock_configuration
.key_file
= None
1842 exception_raised
= False
1844 self
.cert_data
= None
1846 _
= self
.libjuju
.get_k8s_cloud_credential(
1851 except JujuInvalidK8sConfiguration
as e
:
1852 exception_raised
= True
1855 "authentication method not supported",
1857 self
.assertTrue(exception_raised
)
1859 def test_user_pass(self
, mock_configuration
):
1860 mock_configuration
.username
= "admin"
1861 mock_configuration
.password
= "admin"
1862 mock_configuration
.ssl_ca_cert
= None
1863 mock_configuration
.cert_file
= None
1864 mock_configuration
.key_file
= None
1866 self
.cert_data
= None
1867 credential
= self
.libjuju
.get_k8s_cloud_credential(
1874 juju
.client
._definitions
.CloudCredential(
1875 attrs
={"username": "admin", "password": "admin"}, auth_type
="userpass"
1879 def test_user_pass_with_cert(self
, mock_configuration
):
1880 mock_configuration
.username
= "admin"
1881 mock_configuration
.password
= "admin"
1882 mock_configuration
.ssl_ca_cert
= None
1883 mock_configuration
.cert_file
= None
1884 mock_configuration
.key_file
= None
1886 credential
= self
.libjuju
.get_k8s_cloud_credential(
1893 juju
.client
._definitions
.CloudCredential(
1895 "ClientCertificateData": self
.cert_data
,
1896 "username": "admin",
1897 "password": "admin",
1899 auth_type
="userpasswithcert",
1903 def test_user_no_pass(self
, mock_configuration
):
1904 mock_configuration
.username
= "admin"
1905 mock_configuration
.password
= ""
1906 mock_configuration
.ssl_ca_cert
= None
1907 mock_configuration
.cert_file
= None
1908 mock_configuration
.key_file
= None
1910 self
.cert_data
= None
1911 with patch
.object(self
.libjuju
.log
, "debug") as mock_debug
:
1912 credential
= self
.libjuju
.get_k8s_cloud_credential(
1919 juju
.client
._definitions
.CloudCredential(
1920 attrs
={"username": "admin", "password": ""}, auth_type
="userpass"
1923 mock_debug
.assert_called_once_with(
1924 "credential for user admin has empty password"
1927 def test_cert(self
, mock_configuration
):
1928 mock_configuration
.username
= ""
1929 mock_configuration
.password
= ""
1930 mock_configuration
.api_key
= {"authorization": "Bearer Token"}
1931 ssl_ca_cert
= tempfile
.NamedTemporaryFile()
1932 with
open(ssl_ca_cert
.name
, "w") as ssl_ca_cert_file
:
1933 ssl_ca_cert_file
.write("cacert")
1934 mock_configuration
.ssl_ca_cert
= ssl_ca_cert
.name
1935 mock_configuration
.cert_file
= None
1936 mock_configuration
.key_file
= None
1937 credential
= self
.libjuju
.get_k8s_cloud_credential(
1944 juju
.client
._definitions
.CloudCredential(
1945 attrs
={"ClientCertificateData": self
.cert_data
, "Token": self
.token
},
1946 auth_type
="certificate",
1950 # TODO: Fix this test when oauth authentication is supported
1951 # def test_oauth2(self, mock_configuration):
1952 # mock_configuration.username = ""
1953 # mock_configuration.password = ""
1954 # mock_configuration.api_key = {"authorization": "Bearer Token"}
1955 # key = tempfile.NamedTemporaryFile()
1956 # with open(key.name, "w") as key_file:
1957 # key_file.write("key")
1958 # mock_configuration.ssl_ca_cert = None
1959 # mock_configuration.cert_file = None
1960 # mock_configuration.key_file = key.name
1961 # credential = self.libjuju.get_k8s_cloud_credential(
1962 # mock_configuration,
1968 # juju.client._definitions.CloudCredential(
1969 # attrs={"ClientKeyData": "key", "Token": "Token"},
1970 # auth_type="oauth2",
1974 # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1975 # def test_oauth2_missing_token(self, mock_exception, mock_configuration):
1976 # mock_configuration.username = ""
1977 # mock_configuration.password = ""
1978 # key = tempfile.NamedTemporaryFile()
1979 # with open(key.name, "w") as key_file:
1980 # key_file.write("key")
1981 # mock_configuration.ssl_ca_cert = None
1982 # mock_configuration.cert_file = None
1983 # mock_configuration.key_file = key.name
1984 # exception_raised = False
1986 # _ = self.libjuju.get_k8s_cloud_credential(
1987 # mock_configuration,
1991 # except JujuInvalidK8sConfiguration as e:
1992 # exception_raised = True
1995 # "missing token for auth type oauth2",
1997 # self.assertTrue(exception_raised)
1999 def test_exception_cannot_set_token_and_userpass(self
, mock_configuration
):
2000 mock_configuration
.username
= "admin"
2001 mock_configuration
.password
= "pass"
2002 mock_configuration
.api_key
= {"authorization": "No_bearer_token"}
2003 mock_configuration
.ssl_ca_cert
= None
2004 mock_configuration
.cert_file
= None
2005 mock_configuration
.key_file
= None
2006 exception_raised
= False
2008 _
= self
.libjuju
.get_k8s_cloud_credential(
2013 except JujuInvalidK8sConfiguration
as e
:
2014 exception_raised
= True
2017 "Cannot set both token and user/pass",
2019 self
.assertTrue(exception_raised
)
2022 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2023 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
2024 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2025 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
2026 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2027 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
2028 class ScaleApplicationTest(LibjujuTestCase
):
2030 super(ScaleApplicationTest
, self
).setUp()
2032 @asynctest.mock
.patch("asyncio.sleep")
2033 def test_scale_application(
2036 mock_wait_for_model
,
2037 mock_disconnect_controller
,
2038 mock_disconnect_model
,
2039 mock_get_application
,
2041 mock_get_controller
,
2043 mock_get_model
.return_value
= juju
.model
.Model()
2044 mock_get_application
.return_value
= FakeApplication()
2045 self
.loop
.run_until_complete(self
.libjuju
.scale_application("model", "app", 2))
2046 mock_wait_for_model
.assert_called_once()
2047 mock_disconnect_controller
.assert_called_once()
2048 mock_disconnect_model
.assert_called_once()
2050 def test_no_application(
2053 mock_disconnect_controller
,
2054 mock_disconnect_model
,
2055 mock_get_application
,
2057 mock_get_controller
,
2059 mock_get_application
.return_value
= None
2060 mock_get_model
.return_value
= juju
.model
.Model()
2061 with self
.assertRaises(JujuApplicationNotFound
):
2062 self
.loop
.run_until_complete(
2063 self
.libjuju
.scale_application("model", "app", 2)
2065 mock_disconnect_controller
.assert_called()
2066 mock_disconnect_model
.assert_called()
2071 mock_disconnect_controller
,
2072 mock_disconnect_model
,
2073 mock_get_application
,
2075 mock_get_controller
,
2077 mock_get_model
.return_value
= None
2078 mock_get_application
.return_value
= FakeApplication()
2079 with self
.assertRaises(Exception):
2080 self
.loop
.run_until_complete(
2081 self
.libjuju
.scale_application("model", "app", 2, total_timeout
=0)
2083 mock_disconnect_controller
.assert_called_once()
2086 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2087 class GetUnitNumberTest(LibjujuTestCase
):
2089 super(GetUnitNumberTest
, self
).setUp()
2091 def test_successful_get_unit_number(
2093 mock_get_applications
,
2095 mock_get_applications
.return_value
= FakeApplication()
2096 model
= juju
.model
.Model()
2097 result
= self
.libjuju
._get
_application
_count
(model
, "app")
2098 self
.assertEqual(result
, 2)
2100 def test_non_existing_application(
2102 mock_get_applications
,
2104 mock_get_applications
.return_value
= None
2105 model
= juju
.model
.Model()
2106 result
= self
.libjuju
._get
_application
_count
(model
, "app")
2107 self
.assertEqual(result
, None)
2110 @asynctest.mock
.patch("juju.model.Model.machines", new_callable
=asynctest
.PropertyMock
)
2111 class GetMachineInfoTest(LibjujuTestCase
):
2113 super(GetMachineInfoTest
, self
).setUp()
2115 def test_successful(
2119 machine_id
= "existing_machine"
2120 model
= juju
.model
.Model()
2121 mock_machines
.return_value
= {"existing_machine": FakeManualMachine()}
2122 machine
, series
= self
.libjuju
._get
_machine
_info
(
2123 machine_id
=machine_id
,
2126 self
.assertIsNotNone(machine
, series
)
2132 machine_id
= "not_existing_machine"
2133 machine
= series
= None
2134 model
= juju
.model
.Model()
2135 mock_machines
.return_value
= {"existing_machine": FakeManualMachine()}
2136 with self
.assertRaises(JujuMachineNotFound
):
2137 machine
, series
= self
.libjuju
._get
_machine
_info
(
2138 machine_id
=machine_id
,
2141 self
.assertIsNone(machine
, series
)
2144 class GetUnitTest(LibjujuTestCase
):
2146 super(GetUnitTest
, self
).setUp()
2148 def test_successful(self
):
2149 result
= self
.libjuju
._get
_unit
(FakeApplication(), "existing_machine_id")
2150 self
.assertIsInstance(result
, FakeUnit
)
2152 def test_return_none(self
):
2153 result
= self
.libjuju
._get
_unit
(FakeApplication(), "not_existing_machine_id")
2154 self
.assertIsNone(result
)
2157 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2158 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
2159 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
2160 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2161 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2162 class CheckApplicationExists(LibjujuTestCase
):
2164 super(CheckApplicationExists
, self
).setUp()
2166 def test_successful(
2168 mock_get_application
,
2169 mock_disconnect_controller
,
2170 mock_disconnect_model
,
2172 mock_get_controller
,
2174 mock_get_model
.return_value
= juju
.model
.Model()
2175 mock_get_application
.return_value
= FakeApplication()
2176 result
= self
.loop
.run_until_complete(
2177 self
.libjuju
.check_application_exists(
2182 self
.assertEqual(result
, True)
2184 mock_get_application
.assert_called_once()
2185 mock_get_controller
.assert_called_once()
2186 mock_get_model
.assert_called_once()
2187 mock_disconnect_controller
.assert_called_once()
2188 mock_disconnect_model
.assert_called_once()
2190 def test_no_application(
2192 mock_get_application
,
2193 mock_disconnect_controller
,
2194 mock_disconnect_model
,
2196 mock_get_controller
,
2198 mock_get_model
.return_value
= juju
.model
.Model()
2199 mock_get_application
.return_value
= None
2200 result
= self
.loop
.run_until_complete(
2201 self
.libjuju
.check_application_exists(
2206 self
.assertEqual(result
, False)
2208 mock_get_application
.assert_called_once()
2209 mock_get_controller
.assert_called_once()
2210 mock_get_model
.assert_called_once()
2211 mock_disconnect_controller
.assert_called_once()
2212 mock_disconnect_model
.assert_called_once()
2215 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2216 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
2217 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
2218 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2219 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2220 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_machine_info")
2221 class AddUnitTest(LibjujuTestCase
):
2223 super(AddUnitTest
, self
).setUp()
2225 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
2226 @asynctest.mock
.patch("asyncio.sleep")
2227 def test_successful(
2231 mock_get_machine_info
,
2232 mock_get_application
,
2233 mock_disconnect_controller
,
2234 mock_disconnect_model
,
2236 mock_get_controller
,
2238 mock_get_model
.return_value
= juju
.model
.Model()
2239 mock_get_application
.return_value
= FakeApplication()
2240 mock_get_machine_info
.return_value
= FakeMachine(), "series"
2241 self
.loop
.run_until_complete(
2242 self
.libjuju
.add_unit(
2249 mock_wait_for
.assert_called_once()
2250 mock_get_application
.assert_called_once()
2251 mock_get_controller
.assert_called_once()
2252 mock_get_model
.assert_called_once()
2253 mock_disconnect_controller
.assert_called_once()
2254 mock_disconnect_model
.assert_called_once()
2258 mock_get_machine_info
,
2259 mock_get_application
,
2260 mock_disconnect_controller
,
2261 mock_disconnect_model
,
2263 mock_get_controller
,
2265 mock_get_model
.return_value
= juju
.model
.Model()
2266 mock_get_application
.return_value
= None
2267 with self
.assertRaises(JujuApplicationNotFound
):
2268 self
.loop
.run_until_complete(
2269 self
.libjuju
.add_unit(
2276 mock_get_application
.assert_called_once()
2277 mock_get_controller
.assert_called_once()
2278 mock_get_model
.assert_called_once()
2279 mock_disconnect_controller
.assert_called_once()
2280 mock_disconnect_model
.assert_called_once()
2282 def test_no_machine(
2284 mock_get_machine_info
,
2285 mock_get_application
,
2286 mock_disconnect_controller
,
2287 mock_disconnect_model
,
2289 mock_get_controller
,
2291 mock_get_model
.return_value
= juju
.model
.Model()
2292 mock_get_application
.return_value
= FakeApplication()
2293 mock_get_machine_info
.side_effect
= JujuMachineNotFound()
2294 with self
.assertRaises(JujuMachineNotFound
):
2295 self
.loop
.run_until_complete(
2296 self
.libjuju
.add_unit(
2303 mock_get_application
.assert_called_once()
2304 mock_get_controller
.assert_called_once()
2305 mock_get_model
.assert_called_once()
2306 mock_disconnect_controller
.assert_called_once()
2307 mock_disconnect_model
.assert_called_once()
2310 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2311 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
2312 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
2313 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2314 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2315 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_unit")
2316 class DestroyUnitTest(LibjujuTestCase
):
2318 super(DestroyUnitTest
, self
).setUp()
2320 @asynctest.mock
.patch("asyncio.sleep")
2321 def test_successful(
2325 mock_get_application
,
2326 mock_disconnect_controller
,
2327 mock_disconnect_model
,
2329 mock_get_controller
,
2331 mock_get_model
.return_value
= juju
.model
.Model()
2332 mock_get_application
.return_value
= FakeApplication()
2334 self
.loop
.run_until_complete(
2335 self
.libjuju
.destroy_unit("app", "model", "machine", 0)
2338 mock_get_unit
.assert_called()
2339 mock_get_application
.assert_called_once()
2340 mock_get_controller
.assert_called_once()
2341 mock_get_model
.assert_called_once()
2342 mock_disconnect_controller
.assert_called_once()
2343 mock_disconnect_model
.assert_called_once()
2348 mock_get_application
,
2349 mock_disconnect_controller
,
2350 mock_disconnect_model
,
2352 mock_get_controller
,
2354 mock_get_model
.return_value
= juju
.model
.Model()
2355 mock_get_application
.return_value
= None
2357 with self
.assertRaises(JujuApplicationNotFound
):
2358 self
.loop
.run_until_complete(
2359 self
.libjuju
.destroy_unit("app", "model", "machine")
2362 mock_get_application
.assert_called_once()
2363 mock_get_controller
.assert_called_once()
2364 mock_get_model
.assert_called_once()
2365 mock_disconnect_controller
.assert_called_once()
2366 mock_disconnect_model
.assert_called_once()
2371 mock_get_application
,
2372 mock_disconnect_controller
,
2373 mock_disconnect_model
,
2375 mock_get_controller
,
2377 mock_get_model
.return_value
= juju
.model
.Model()
2378 mock_get_application
.return_value
= FakeApplication()
2379 mock_get_unit
.return_value
= None
2381 with self
.assertRaises(JujuError
):
2382 self
.loop
.run_until_complete(
2383 self
.libjuju
.destroy_unit("app", "model", "machine")
2386 mock_get_unit
.assert_called_once()
2387 mock_get_application
.assert_called_once()
2388 mock_get_controller
.assert_called_once()
2389 mock_get_model
.assert_called_once()
2390 mock_disconnect_controller
.assert_called_once()
2391 mock_disconnect_model
.assert_called_once()