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("os.remove")
500 @asynctest.mock
.patch("n2vc.libjuju.yaml.dump")
501 @asynctest.mock
.patch("builtins.open", create
=True)
502 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
503 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
504 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
505 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
506 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
507 @asynctest.mock
.patch("juju.model.Model.deploy")
508 @asynctest.mock
.patch("juju.model.CharmhubDeployType.resolve")
509 @asynctest.mock
.patch("n2vc.libjuju.BundleHandler")
510 @asynctest.mock
.patch("juju.url.URL.parse")
511 class DeployTest(LibjujuTestCase
):
513 super(DeployTest
, self
).setUp()
514 self
.instantiation_params
= {"applications": {"squid": {"scale": 2}}}
515 self
.architecture
= "amd64"
517 self
.url
= AsyncMock()
518 self
.url
.schema
= juju
.url
.Schema
.CHARM_HUB
519 self
.bundle_instance
= None
521 def setup_bundle_download_mocks(
522 self
, mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
524 mock_url_parse
.return_value
= self
.url
525 mock_bundle
.return_value
= AsyncMock()
526 mock_resolve
.return_value
= AsyncMock()
527 mock_resolve
.origin
= AsyncMock()
528 mock_get_model
.return_value
= juju
.model
.Model()
529 self
.bundle_instance
= mock_bundle
.return_value
530 self
.bundle_instance
.applications
= {"squid"}
532 def assert_overlay_file_is_written(self
, filename
, mocked_file
, mock_yaml
, mock_os
):
533 mocked_file
.assert_called_once_with(filename
, "w")
534 mock_yaml
.assert_called_once_with(
535 self
.instantiation_params
, mocked_file
.return_value
.__enter
__.return_value
537 mock_os
.assert_called_once_with(filename
)
539 def assert_overlay_file_is_not_written(self
, mocked_file
, mock_yaml
, mock_os
):
540 mocked_file
.assert_not_called()
541 mock_yaml
.assert_not_called()
542 mock_os
.assert_not_called()
544 def assert_bundle_is_downloaded(self
, mock_resolve
, mock_url_parse
):
545 mock_resolve
.assert_called_once_with(
546 self
.url
, self
.architecture
, entity_url
=self
.uri
548 mock_url_parse
.assert_called_once_with(self
.uri
)
549 self
.bundle_instance
.fetch_plan
.assert_called_once_with(
550 self
.url
, mock_resolve
.origin
553 def assert_bundle_is_not_downloaded(self
, mock_resolve
, mock_url_parse
):
554 mock_resolve
.assert_not_called()
555 mock_url_parse
.assert_not_called()
556 self
.bundle_instance
.fetch_plan
.assert_not_called()
565 mock_disconnect_controller
,
566 mock_disconnect_model
,
573 self
.setup_bundle_download_mocks(
574 mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
576 model_name
= "model1"
578 self
.loop
.run_until_complete(
584 instantiation_params
=None,
587 self
.assert_overlay_file_is_not_written(mocked_file
, mock_yaml
, mock_os
)
588 self
.assert_bundle_is_not_downloaded(mock_resolve
, mock_url_parse
)
589 mock_deploy
.assert_called_once_with("cs:osm", trust
=True, overlays
=[])
590 mock_wait_for_model
.assert_called_once()
591 mock_disconnect_controller
.assert_called_once()
592 mock_disconnect_model
.assert_called_once()
594 def test_deploy_no_wait(
601 mock_disconnect_controller
,
602 mock_disconnect_model
,
609 self
.setup_bundle_download_mocks(
610 mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
612 self
.loop
.run_until_complete(
614 "cs:osm", "model", wait
=False, timeout
=0, instantiation_params
={}
617 self
.assert_overlay_file_is_not_written(mocked_file
, mock_yaml
, mock_os
)
618 self
.assert_bundle_is_not_downloaded(mock_resolve
, mock_url_parse
)
619 mock_deploy
.assert_called_once_with("cs:osm", trust
=True, overlays
=[])
620 mock_wait_for_model
.assert_not_called()
621 mock_disconnect_controller
.assert_called_once()
622 mock_disconnect_model
.assert_called_once()
624 def test_deploy_exception(
631 mock_disconnect_controller
,
632 mock_disconnect_model
,
639 self
.setup_bundle_download_mocks(
640 mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
642 mock_deploy
.side_effect
= Exception()
643 with self
.assertRaises(Exception):
644 self
.loop
.run_until_complete(self
.libjuju
.deploy("cs:osm", "model"))
645 self
.assert_overlay_file_is_not_written(mocked_file
, mock_yaml
, mock_os
)
646 self
.assert_bundle_is_not_downloaded(mock_resolve
, mock_url_parse
)
647 mock_deploy
.assert_called_once()
648 mock_wait_for_model
.assert_not_called()
649 mock_disconnect_controller
.assert_called_once()
650 mock_disconnect_model
.assert_called_once()
652 def test_deploy_with_instantiation_params(
659 mock_disconnect_controller
,
660 mock_disconnect_model
,
667 self
.setup_bundle_download_mocks(
668 mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
670 model_name
= "model1"
671 expected_filename
= "{}-overlay.yaml".format(model_name
)
672 self
.loop
.run_until_complete(
678 instantiation_params
=self
.instantiation_params
,
681 self
.assert_overlay_file_is_written(
682 expected_filename
, mocked_file
, mock_yaml
, mock_os
684 self
.assert_bundle_is_downloaded(mock_resolve
, mock_url_parse
)
685 mock_deploy
.assert_called_once_with(
686 self
.uri
, trust
=True, overlays
=[expected_filename
]
688 mock_wait_for_model
.assert_called_once()
689 mock_disconnect_controller
.assert_called_once()
690 mock_disconnect_model
.assert_called_once()
692 def test_deploy_with_instantiation_params_no_applications(
699 mock_disconnect_controller
,
700 mock_disconnect_model
,
707 self
.instantiation_params
= {"applications": {}}
708 self
.setup_bundle_download_mocks(
709 mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
712 model_name
= "model3"
713 expected_filename
= "{}-overlay.yaml".format(model_name
)
714 self
.loop
.run_until_complete(
720 instantiation_params
=self
.instantiation_params
,
724 self
.assert_overlay_file_is_written(
725 expected_filename
, mocked_file
, mock_yaml
, mock_os
727 self
.assert_bundle_is_not_downloaded(mock_resolve
, mock_url_parse
)
728 mock_deploy
.assert_called_once_with(
729 self
.uri
, trust
=True, overlays
=[expected_filename
]
731 mock_wait_for_model
.assert_not_called()
732 mock_disconnect_controller
.assert_called_once()
733 mock_disconnect_model
.assert_called_once()
735 def test_deploy_with_instantiation_params_applications_not_found(
742 mock_disconnect_controller
,
743 mock_disconnect_model
,
750 self
.instantiation_params
= {"some_key": {"squid": {"scale": 2}}}
751 self
.setup_bundle_download_mocks(
752 mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
755 with self
.assertRaises(JujuError
):
756 self
.loop
.run_until_complete(
762 instantiation_params
=self
.instantiation_params
,
766 self
.assert_overlay_file_is_not_written(mocked_file
, mock_yaml
, mock_os
)
767 self
.assert_bundle_is_not_downloaded(mock_resolve
, mock_url_parse
)
768 mock_deploy
.assert_not_called()
769 mock_wait_for_model
.assert_not_called()
770 mock_disconnect_controller
.assert_called_once()
771 mock_disconnect_model
.assert_called_once()
773 def test_deploy_overlay_contains_invalid_app(
780 mock_disconnect_controller
,
781 mock_disconnect_model
,
788 self
.setup_bundle_download_mocks(
789 mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
791 self
.bundle_instance
.applications
= {"new_app"}
793 with self
.assertRaises(JujuApplicationNotFound
) as error
:
794 self
.loop
.run_until_complete(
800 instantiation_params
=self
.instantiation_params
,
803 error_msg
= "Cannot find application ['squid'] in original bundle {'new_app'}"
804 self
.assertEqual(str(error
.exception
), error_msg
)
806 self
.assert_overlay_file_is_not_written(mocked_file
, mock_yaml
, mock_os
)
807 self
.assert_bundle_is_downloaded(mock_resolve
, mock_url_parse
)
808 mock_deploy
.assert_not_called()
809 mock_wait_for_model
.assert_not_called()
810 mock_disconnect_controller
.assert_called_once()
811 mock_disconnect_model
.assert_called_once()
813 def test_deploy_exception_with_instantiation_params(
820 mock_disconnect_controller
,
821 mock_disconnect_model
,
828 self
.setup_bundle_download_mocks(
829 mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
832 mock_deploy
.side_effect
= Exception()
833 model_name
= "model2"
834 expected_filename
= "{}-overlay.yaml".format(model_name
)
835 with self
.assertRaises(Exception):
836 self
.loop
.run_until_complete(
840 instantiation_params
=self
.instantiation_params
,
844 self
.assert_overlay_file_is_written(
845 expected_filename
, mocked_file
, mock_yaml
, mock_os
847 self
.assert_bundle_is_downloaded(mock_resolve
, mock_url_parse
)
848 mock_deploy
.assert_called_once_with(
849 self
.uri
, trust
=True, overlays
=[expected_filename
]
851 mock_wait_for_model
.assert_not_called()
852 mock_disconnect_controller
.assert_called_once()
853 mock_disconnect_model
.assert_called_once()
855 @asynctest.mock
.patch("logging.Logger.warning")
856 def test_deploy_exception_when_deleting_file_is_not_propagated(
864 mock_disconnect_controller
,
865 mock_disconnect_model
,
872 self
.setup_bundle_download_mocks(
873 mock_url_parse
, mock_bundle
, mock_resolve
, mock_get_model
876 mock_os
.side_effect
= OSError("Error")
877 model_name
= "model2"
878 expected_filename
= "{}-overlay.yaml".format(model_name
)
879 self
.loop
.run_until_complete(
883 instantiation_params
=self
.instantiation_params
,
887 self
.assert_overlay_file_is_written(
888 expected_filename
, mocked_file
, mock_yaml
, mock_os
890 self
.assert_bundle_is_downloaded(mock_resolve
, mock_url_parse
)
891 mock_deploy
.assert_called_once_with(
892 self
.uri
, trust
=True, overlays
=[expected_filename
]
894 mock_wait_for_model
.assert_called_once()
895 mock_disconnect_controller
.assert_called_once()
896 mock_disconnect_model
.assert_called_once()
897 mock_warning
.assert_called_with(
898 "Overlay file {} could not be removed: Error".format(expected_filename
)
902 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
903 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
904 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
905 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
906 @asynctest.mock
.patch(
907 "juju.model.Model.applications", new_callable
=asynctest
.PropertyMock
909 @asynctest.mock
.patch("juju.model.Model.machines", new_callable
=asynctest
.PropertyMock
)
910 @asynctest.mock
.patch("juju.model.Model.deploy")
911 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
912 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.create_machine")
913 class DeployCharmTest(LibjujuTestCase
):
915 super(DeployCharmTest
, self
).setUp()
917 def test_existing_app(
924 mock_disconnect_controller
,
925 mock_disconnect_model
,
929 mock_get_model
.return_value
= juju
.model
.Model()
930 mock_applications
.return_value
= {"existing_app"}
933 with self
.assertRaises(JujuApplicationExists
):
934 application
= self
.loop
.run_until_complete(
935 self
.libjuju
.deploy_charm(
942 self
.assertIsNone(application
)
944 mock_disconnect_controller
.assert_called()
945 mock_disconnect_model
.assert_called()
947 def test_non_existing_machine(
954 mock_disconnect_controller
,
955 mock_disconnect_model
,
959 mock_get_model
.return_value
= juju
.model
.Model()
960 mock_machines
.return_value
= {"existing_machine": FakeMachine()}
962 with self
.assertRaises(JujuMachineNotFound
):
963 application
= self
.loop
.run_until_complete(
964 self
.libjuju
.deploy_charm(
972 self
.assertIsNone(application
)
974 mock_disconnect_controller
.assert_called()
975 mock_disconnect_model
.assert_called()
984 mock_disconnect_controller
,
985 mock_disconnect_model
,
989 mock_get_model
.return_value
= juju
.model
.Model()
990 mock_machines
.return_value
= {"existing_machine": FakeMachine()}
991 mock_create_machine
.return_value
= (FakeMachine(), "other")
992 mock_deploy
.return_value
= FakeApplication()
993 application
= self
.loop
.run_until_complete(
994 self
.libjuju
.deploy_charm(
1003 self
.assertIsInstance(application
, FakeApplication
)
1005 mock_deploy
.assert_called_once()
1006 mock_wait_for
.assert_called_once()
1008 mock_create_machine
.assert_called_once()
1010 mock_disconnect_controller
.assert_called()
1011 mock_disconnect_model
.assert_called()
1015 mock_create_machine
,
1020 mock_disconnect_controller
,
1021 mock_disconnect_model
,
1023 mock_get_controller
,
1025 mock_get_model
.return_value
= juju
.model
.Model()
1026 mock_machines
.return_value
= {"existing_machine": FakeMachine()}
1027 mock_deploy
.return_value
= FakeApplication()
1028 application
= self
.loop
.run_until_complete(
1029 self
.libjuju
.deploy_charm("app", "path", "model", "existing_machine")
1032 self
.assertIsInstance(application
, FakeApplication
)
1034 mock_deploy
.assert_called_once()
1035 mock_wait_for
.assert_called_once()
1037 mock_disconnect_controller
.assert_called()
1038 mock_disconnect_model
.assert_called()
1041 @asynctest.mock
.patch(
1042 "juju.model.Model.applications", new_callable
=asynctest
.PropertyMock
1044 class GetApplicationTest(LibjujuTestCase
):
1046 super(GetApplicationTest
, self
).setUp()
1048 def test_existing_application(
1052 mock_applications
.return_value
= {"existing_app": "exists"}
1053 model
= juju
.model
.Model()
1054 result
= self
.libjuju
._get
_application
(model
, "existing_app")
1055 self
.assertEqual(result
, "exists")
1057 def test_non_existing_application(
1061 mock_applications
.return_value
= {"existing_app": "exists"}
1062 model
= juju
.model
.Model()
1063 result
= self
.libjuju
._get
_application
(model
, "nonexisting_app")
1064 self
.assertIsNone(result
)
1067 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1068 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
1069 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1070 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1071 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
1072 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
1073 @asynctest.mock
.patch("juju.model.Model.get_action_output")
1074 @asynctest.mock
.patch("juju.model.Model.get_action_status")
1075 class ExecuteActionTest(LibjujuTestCase
):
1077 super(ExecuteActionTest
, self
).setUp()
1079 def test_no_application(
1081 mock_get_action_status
,
1082 mock_get_action_output
,
1084 mock__get_application
,
1085 mock_disconnect_controller
,
1086 mock_disconnect_model
,
1088 mock_get_controller
,
1090 mock__get_application
.return_value
= None
1091 mock_get_model
.return_value
= juju
.model
.Model()
1094 with self
.assertRaises(JujuApplicationNotFound
):
1095 output
, status
= self
.loop
.run_until_complete(
1096 self
.libjuju
.execute_action(
1102 self
.assertIsNone(output
)
1103 self
.assertIsNone(status
)
1105 mock_disconnect_controller
.assert_called()
1106 mock_disconnect_model
.assert_called()
1110 mock_get_action_status
,
1111 mock_get_action_output
,
1113 mock__get_application
,
1114 mock_disconnect_controller
,
1115 mock_disconnect_model
,
1117 mock_get_controller
,
1119 mock_get_model
.return_value
= juju
.model
.Model()
1120 mock__get_application
.return_value
= FakeApplication()
1123 with self
.assertRaises(JujuActionNotFound
):
1124 output
, status
= self
.loop
.run_until_complete(
1125 self
.libjuju
.execute_action(
1131 self
.assertIsNone(output
)
1132 self
.assertIsNone(status
)
1134 mock_disconnect_controller
.assert_called()
1135 mock_disconnect_model
.assert_called()
1137 @asynctest.mock
.patch("asyncio.sleep")
1138 @asynctest.mock
.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
1141 mock_is_leader_from_status
,
1143 mock_get_action_status
,
1144 mock_get_action_output
,
1146 mock__get_application
,
1147 mock_disconnect_controller
,
1148 mock_disconnect_model
,
1150 mock_get_controller
,
1152 mock_get_model
.return_value
= juju
.model
.Model()
1153 mock__get_application
.return_value
= FakeApplication()
1154 mock_is_leader_from_status
.return_value
= False
1157 with self
.assertRaises(JujuLeaderUnitNotFound
):
1158 output
, status
= self
.loop
.run_until_complete(
1159 self
.libjuju
.execute_action(
1165 self
.assertIsNone(output
)
1166 self
.assertIsNone(status
)
1168 mock_disconnect_controller
.assert_called()
1169 mock_disconnect_model
.assert_called()
1171 def test_successful_exec(
1173 mock_get_action_status
,
1174 mock_get_action_output
,
1176 mock__get_application
,
1177 mock_disconnect_controller
,
1178 mock_disconnect_model
,
1180 mock_get_controller
,
1182 mock_get_model
.return_value
= juju
.model
.Model()
1183 mock__get_application
.return_value
= FakeApplication()
1184 mock_get_action_output
.return_value
= "output"
1185 mock_get_action_status
.return_value
= {"id": "status"}
1186 output
, status
= self
.loop
.run_until_complete(
1187 self
.libjuju
.execute_action("app", "model", "existing_action")
1189 self
.assertEqual(output
, "output")
1190 self
.assertEqual(status
, "status")
1192 mock_wait_for
.assert_called_once()
1194 mock_disconnect_controller
.assert_called()
1195 mock_disconnect_model
.assert_called()
1198 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1199 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
1200 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1201 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1202 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
1203 class GetActionTest(LibjujuTestCase
):
1205 super(GetActionTest
, self
).setUp()
1209 mock_get_application
,
1210 mock_disconnect_controller
,
1211 mock_disconnect_model
,
1213 mock_get_controller
,
1215 mock_get_application
.side_effect
= Exception()
1217 with self
.assertRaises(Exception):
1218 actions
= self
.loop
.run_until_complete(
1219 self
.libjuju
.get_actions("app", "model")
1222 self
.assertIsNone(actions
)
1223 mock_disconnect_controller
.assert_called_once()
1224 mock_disconnect_model
.assert_called_once()
1228 mock_get_application
,
1229 mock_disconnect_controller
,
1230 mock_disconnect_model
,
1232 mock_get_controller
,
1234 mock_get_application
.return_value
= FakeApplication()
1236 actions
= self
.loop
.run_until_complete(self
.libjuju
.get_actions("app", "model"))
1238 self
.assertEqual(actions
, ["existing_action"])
1240 mock_get_controller
.assert_called_once()
1241 mock_get_model
.assert_called_once()
1242 mock_disconnect_controller
.assert_called_once()
1243 mock_disconnect_model
.assert_called_once()
1246 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1247 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
1248 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1249 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1250 @asynctest.mock
.patch("juju.application.Application.get_metrics")
1251 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
1252 class GetMetricsTest(LibjujuTestCase
):
1254 super(GetMetricsTest
, self
).setUp()
1256 def test_get_metrics_success(
1258 mock_get_application
,
1260 mock_disconnect_controller
,
1261 mock_disconnect_model
,
1263 mock_get_controller
,
1265 mock_get_application
.return_value
= FakeApplication()
1266 mock_get_model
.return_value
= juju
.model
.Model()
1268 self
.loop
.run_until_complete(self
.libjuju
.get_metrics("model", "app1"))
1270 mock_disconnect_controller
.assert_called_once()
1271 mock_disconnect_model
.assert_called_once()
1273 def test_get_metrics_exception(
1275 mock_get_application
,
1277 mock_disconnect_controller
,
1278 mock_disconnect_model
,
1280 mock_get_controller
,
1282 mock_get_model
.return_value
= juju
.model
.Model()
1283 mock_get_metrics
.side_effect
= Exception()
1284 with self
.assertRaises(Exception):
1285 self
.loop
.run_until_complete(self
.libjuju
.get_metrics("model", "app1"))
1287 mock_disconnect_controller
.assert_called_once()
1288 mock_disconnect_model
.assert_called_once()
1290 def test_missing_args_exception(
1292 mock_get_application
,
1294 mock_disconnect_controller
,
1295 mock_disconnect_model
,
1297 mock_get_controller
,
1299 mock_get_model
.return_value
= juju
.model
.Model()
1301 with self
.assertRaises(Exception):
1302 self
.loop
.run_until_complete(self
.libjuju
.get_metrics("", ""))
1304 mock_get_controller
.assert_not_called()
1305 mock_get_model
.assert_not_called()
1306 mock_disconnect_controller
.assert_not_called()
1307 mock_disconnect_model
.assert_not_called()
1310 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1311 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
1312 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1313 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1314 @asynctest.mock
.patch("juju.model.Model.add_relation")
1315 class AddRelationTest(LibjujuTestCase
):
1317 super(AddRelationTest
, self
).setUp()
1319 @asynctest.mock
.patch("logging.Logger.warning")
1324 mock_disconnect_controller
,
1325 mock_disconnect_model
,
1327 mock_get_controller
,
1329 # TODO in libjuju.py should this fail only with a log message?
1330 result
= {"error": "not found", "response": "response", "request-id": 1}
1332 mock_get_model
.return_value
= juju
.model
.Model()
1333 mock_add_relation
.side_effect
= JujuAPIError(result
)
1335 self
.loop
.run_until_complete(
1336 self
.libjuju
.add_relation(
1343 mock_warning
.assert_called_with("Relation not found: not found")
1344 mock_disconnect_controller
.assert_called_once()
1345 mock_disconnect_model
.assert_called_once()
1347 @asynctest.mock
.patch("logging.Logger.warning")
1348 def test_not_found_in_error_code(
1352 mock_disconnect_controller
,
1353 mock_disconnect_model
,
1355 mock_get_controller
,
1358 "error": "relation cannot be added",
1359 "error-code": "not found",
1360 "response": "response",
1364 mock_get_model
.return_value
= juju
.model
.Model()
1365 mock_add_relation
.side_effect
= JujuAPIError(result
)
1367 self
.loop
.run_until_complete(
1368 self
.libjuju
.add_relation(
1375 mock_warning
.assert_called_with("Relation not found: relation cannot be added")
1376 mock_disconnect_controller
.assert_called_once()
1377 mock_disconnect_model
.assert_called_once()
1379 @asynctest.mock
.patch("logging.Logger.warning")
1380 def test_already_exists(
1384 mock_disconnect_controller
,
1385 mock_disconnect_model
,
1387 mock_get_controller
,
1389 # TODO in libjuju.py should this fail silently?
1390 result
= {"error": "already exists", "response": "response", "request-id": 1}
1392 mock_get_model
.return_value
= juju
.model
.Model()
1393 mock_add_relation
.side_effect
= JujuAPIError(result
)
1395 self
.loop
.run_until_complete(
1396 self
.libjuju
.add_relation(
1403 mock_warning
.assert_called_with("Relation already exists: already exists")
1404 mock_disconnect_controller
.assert_called_once()
1405 mock_disconnect_model
.assert_called_once()
1407 @asynctest.mock
.patch("logging.Logger.warning")
1408 def test_already_exists_error_code(
1412 mock_disconnect_controller
,
1413 mock_disconnect_model
,
1415 mock_get_controller
,
1418 "error": "relation cannot be added",
1419 "error-code": "already exists",
1420 "response": "response",
1424 mock_get_model
.return_value
= juju
.model
.Model()
1425 mock_add_relation
.side_effect
= JujuAPIError(result
)
1427 self
.loop
.run_until_complete(
1428 self
.libjuju
.add_relation(
1435 mock_warning
.assert_called_with(
1436 "Relation already exists: relation cannot be added"
1438 mock_disconnect_controller
.assert_called_once()
1439 mock_disconnect_model
.assert_called_once()
1444 mock_disconnect_controller
,
1445 mock_disconnect_model
,
1447 mock_get_controller
,
1449 mock_get_model
.return_value
= juju
.model
.Model()
1450 result
= {"error": "", "response": "response", "request-id": 1}
1451 mock_add_relation
.side_effect
= JujuAPIError(result
)
1453 with self
.assertRaises(JujuAPIError
):
1454 self
.loop
.run_until_complete(
1455 self
.libjuju
.add_relation(
1462 mock_disconnect_controller
.assert_called_once()
1463 mock_disconnect_model
.assert_called_once()
1468 mock_disconnect_controller
,
1469 mock_disconnect_model
,
1471 mock_get_controller
,
1473 mock_get_model
.return_value
= juju
.model
.Model()
1475 self
.loop
.run_until_complete(
1476 self
.libjuju
.add_relation(
1483 mock_add_relation
.assert_called_with("app1:relation1", "app2:relation2")
1484 mock_disconnect_controller
.assert_called_once()
1485 mock_disconnect_model
.assert_called_once()
1490 mock_disconnect_controller
,
1491 mock_disconnect_model
,
1493 mock_get_controller
,
1495 mock_get_model
.return_value
= juju
.model
.Model()
1497 self
.loop
.run_until_complete(
1498 self
.libjuju
.add_relation(
1505 mock_add_relation
.assert_called_with("app1:relation1", "saas_name")
1506 mock_disconnect_controller
.assert_called_once()
1507 mock_disconnect_model
.assert_called_once()
1510 # TODO destroy_model testcase
1513 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1514 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
1515 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1516 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
1517 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1518 class DestroyApplicationTest(LibjujuTestCase
):
1520 super(DestroyApplicationTest
, self
).setUp()
1524 mock_get_controller
,
1526 mock_disconnect_controller
,
1527 mock_get_application
,
1528 mock_disconnect_model
,
1530 mock_get_application
.return_value
= FakeApplication()
1531 mock_get_model
.return_value
= None
1532 self
.loop
.run_until_complete(
1533 self
.libjuju
.destroy_application(
1539 mock_get_application
.assert_called()
1540 mock_disconnect_controller
.assert_called_once()
1541 mock_disconnect_model
.assert_called_once()
1543 def test_no_application(
1545 mock_get_controller
,
1547 mock_disconnect_controller
,
1548 mock_get_application
,
1549 mock_disconnect_model
,
1551 mock_get_model
.return_value
= None
1552 mock_get_application
.return_value
= None
1554 self
.loop
.run_until_complete(
1555 self
.libjuju
.destroy_application(
1561 mock_get_application
.assert_called()
1565 mock_get_controller
,
1567 mock_disconnect_controller
,
1568 mock_get_application
,
1569 mock_disconnect_model
,
1571 mock_get_application
.return_value
= FakeApplication
1572 mock_get_model
.return_value
= None
1574 with self
.assertRaises(Exception):
1575 self
.loop
.run_until_complete(
1576 self
.libjuju
.destroy_application(
1582 mock_get_application
.assert_called_once()
1585 # @asynctest.mock.patch("juju.model.Model.get_machines")
1586 # @asynctest.mock.patch("logging.Logger.debug")
1587 # class DestroyMachineTest(LibjujuTestCase):
1589 # super(DestroyMachineTest, self).setUp()
1591 # def test_success_manual_machine(
1592 # self, mock_debug, mock_get_machines,
1594 # mock_get_machines.side_effect = [
1595 # {"machine": FakeManualMachine()},
1596 # {"machine": FakeManualMachine()},
1599 # self.loop.run_until_complete(
1600 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
1603 # asynctest.call("Waiting for machine machine is destroyed"),
1604 # asynctest.call("Machine destroyed: machine"),
1606 # mock_debug.assert_has_calls(calls)
1608 # def test_no_machine(
1609 # self, mock_debug, mock_get_machines,
1611 # mock_get_machines.return_value = {}
1612 # self.loop.run_until_complete(
1613 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
1615 # mock_debug.assert_called_with("Machine not found: machine")
1618 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1619 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
1620 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1621 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1622 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
1623 class ConfigureApplicationTest(LibjujuTestCase
):
1625 super(ConfigureApplicationTest
, self
).setUp()
1629 mock_get_application
,
1630 mock_disconnect_controller
,
1631 mock_disconnect_model
,
1633 mock_get_controller
,
1635 mock_get_application
.return_value
= FakeApplication()
1637 self
.loop
.run_until_complete(
1638 self
.libjuju
.configure_application(
1644 mock_get_application
.assert_called_once()
1645 mock_disconnect_controller
.assert_called_once()
1646 mock_disconnect_model
.assert_called_once()
1650 mock_get_application
,
1651 mock_disconnect_controller
,
1652 mock_disconnect_model
,
1654 mock_get_controller
,
1656 mock_get_application
.side_effect
= Exception()
1658 with self
.assertRaises(Exception):
1659 self
.loop
.run_until_complete(
1660 self
.libjuju
.configure_application(
1666 mock_disconnect_controller
.assert_called_once()
1667 mock_disconnect_model
.assert_called_once()
1669 def test_controller_exception(
1671 mock_get_application
,
1672 mock_disconnect_controller
,
1673 mock_disconnect_model
,
1675 mock_get_controller
,
1677 result
= {"error": "not found", "response": "response", "request-id": 1}
1679 mock_get_controller
.side_effect
= JujuAPIError(result
)
1681 with self
.assertRaises(JujuAPIError
):
1682 self
.loop
.run_until_complete(
1683 self
.libjuju
.configure_application(
1689 mock_get_model
.assert_not_called()
1690 mock_disconnect_controller
.assert_not_called()
1691 mock_disconnect_model
.assert_not_called()
1693 def test_get_model_exception(
1695 mock_get_application
,
1696 mock_disconnect_controller
,
1697 mock_disconnect_model
,
1699 mock_get_controller
,
1701 result
= {"error": "not found", "response": "response", "request-id": 1}
1702 mock_get_model
.side_effect
= JujuAPIError(result
)
1704 with self
.assertRaises(JujuAPIError
):
1705 self
.loop
.run_until_complete(
1706 self
.libjuju
.configure_application(
1712 mock_get_model
.assert_called_once()
1713 mock_disconnect_controller
.assert_called_once()
1714 mock_disconnect_model
.assert_not_called()
1717 # TODO _get_api_endpoints_db test case
1718 # TODO _update_api_endpoints_db test case
1719 # TODO healthcheck test case
1722 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1723 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1724 @asynctest.mock
.patch("juju.controller.Controller.list_models")
1725 class ListModelsTest(LibjujuTestCase
):
1727 super(ListModelsTest
, self
).setUp()
1729 def test_containing(
1732 mock_disconnect_controller
,
1733 mock_get_controller
,
1735 mock_get_controller
.return_value
= juju
.controller
.Controller()
1736 mock_list_models
.return_value
= ["existingmodel"]
1737 models
= self
.loop
.run_until_complete(self
.libjuju
.list_models("existing"))
1739 mock_disconnect_controller
.assert_called_once()
1740 self
.assertEquals(models
, ["existingmodel"])
1742 def test_not_containing(
1745 mock_disconnect_controller
,
1746 mock_get_controller
,
1748 mock_get_controller
.return_value
= juju
.controller
.Controller()
1749 mock_list_models
.return_value
= ["existingmodel", "model"]
1750 models
= self
.loop
.run_until_complete(self
.libjuju
.list_models("mdl"))
1752 mock_disconnect_controller
.assert_called_once()
1753 self
.assertEquals(models
, [])
1755 def test_no_contains_arg(
1758 mock_disconnect_controller
,
1759 mock_get_controller
,
1761 mock_get_controller
.return_value
= juju
.controller
.Controller()
1762 mock_list_models
.return_value
= ["existingmodel", "model"]
1763 models
= self
.loop
.run_until_complete(self
.libjuju
.list_models())
1765 mock_disconnect_controller
.assert_called_once()
1766 self
.assertEquals(models
, ["existingmodel", "model"])
1769 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.list_models")
1770 class ModelsExistTest(LibjujuTestCase
):
1772 super(ModelsExistTest
, self
).setUp()
1774 def test_model_names_none(self
, mock_list_models
):
1775 mock_list_models
.return_value
= []
1776 with self
.assertRaises(Exception):
1777 self
.loop
.run_until_complete(self
.libjuju
.models_exist(None))
1779 def test_model_names_empty(self
, mock_list_models
):
1780 mock_list_models
.return_value
= []
1781 with self
.assertRaises(Exception):
1782 (exist
, non_existing_models
) = self
.loop
.run_until_complete(
1783 self
.libjuju
.models_exist([])
1786 def test_model_names_not_existing(self
, mock_list_models
):
1787 mock_list_models
.return_value
= ["prometheus", "grafana"]
1788 (exist
, non_existing_models
) = self
.loop
.run_until_complete(
1789 self
.libjuju
.models_exist(["prometheus2", "grafana"])
1791 self
.assertFalse(exist
)
1792 self
.assertEqual(non_existing_models
, ["prometheus2"])
1794 def test_model_names_exist(self
, mock_list_models
):
1795 mock_list_models
.return_value
= ["prometheus", "grafana"]
1796 (exist
, non_existing_models
) = self
.loop
.run_until_complete(
1797 self
.libjuju
.models_exist(["prometheus", "grafana"])
1799 self
.assertTrue(exist
)
1800 self
.assertEqual(non_existing_models
, [])
1803 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1804 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1805 @asynctest.mock
.patch("juju.controller.Controller.list_offers")
1806 class ListOffers(LibjujuTestCase
):
1808 super(ListOffers
, self
).setUp()
1810 def test_disconnect_controller(
1813 mock_disconnect_controller
,
1814 mock_get_controller
,
1816 mock_get_controller
.return_value
= juju
.controller
.Controller()
1817 mock_list_offers
.side_effect
= Exception()
1818 with self
.assertRaises(Exception):
1819 self
.loop
.run_until_complete(self
.libjuju
._list
_offers
("model"))
1820 mock_disconnect_controller
.assert_called_once()
1822 def test_empty_list(
1825 mock_disconnect_controller
,
1826 mock_get_controller
,
1828 mock_get_controller
.return_value
= juju
.controller
.Controller()
1829 offer_results
= Mock()
1830 offer_results
.results
= []
1831 mock_list_offers
.return_value
= offer_results
1832 offers
= self
.loop
.run_until_complete(self
.libjuju
._list
_offers
("model"))
1833 self
.assertEqual(offers
, [])
1834 mock_disconnect_controller
.assert_called_once()
1836 def test_non_empty_list(
1839 mock_disconnect_controller
,
1840 mock_get_controller
,
1842 mock_get_controller
.return_value
= juju
.controller
.Controller()
1844 offer_results
= Mock()
1845 offer_results
.results
= [offer
]
1846 mock_list_offers
.return_value
= offer_results
1847 offers
= self
.loop
.run_until_complete(self
.libjuju
._list
_offers
("model"))
1848 self
.assertEqual(offers
, [offer
])
1849 mock_disconnect_controller
.assert_called_once()
1851 def test_matching_offer_name(
1854 mock_disconnect_controller
,
1855 mock_get_controller
,
1857 mock_get_controller
.return_value
= juju
.controller
.Controller()
1859 offer_1
.offer_name
= "offer1"
1861 offer_2
.offer_name
= "offer2"
1862 offer_results
= Mock()
1863 offer_results
.results
= [offer_1
, offer_2
]
1864 mock_list_offers
.return_value
= offer_results
1865 offers
= self
.loop
.run_until_complete(
1866 self
.libjuju
._list
_offers
("model", offer_name
="offer2")
1868 self
.assertEqual(offers
, [offer_2
])
1869 mock_disconnect_controller
.assert_called_once()
1871 def test_not_matching_offer_name(
1874 mock_disconnect_controller
,
1875 mock_get_controller
,
1877 mock_get_controller
.return_value
= juju
.controller
.Controller()
1879 offer_1
.offer_name
= "offer1"
1881 offer_2
.offer_name
= "offer2"
1882 offer_results
= Mock()
1883 offer_results
.results
= [offer_1
, offer_2
]
1884 mock_list_offers
.return_value
= offer_results
1885 offers
= self
.loop
.run_until_complete(
1886 self
.libjuju
._list
_offers
("model", offer_name
="offer3")
1888 self
.assertEqual(offers
, [])
1889 mock_disconnect_controller
.assert_called_once()
1892 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1893 @asynctest.mock
.patch("juju.controller.Controller.get_model")
1894 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1895 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1896 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._list_offers")
1897 @asynctest.mock
.patch("juju.model.Model.create_offer")
1898 class OfferTest(LibjujuTestCase
):
1900 super(OfferTest
, self
).setUp()
1906 mock_disconnect_controller
,
1907 mock_disconnect_model
,
1909 mock_get_controller
,
1911 controller
= juju
.controller
.Controller()
1912 model
= juju
.model
.Model()
1913 mock_get_controller
.return_value
= controller
1914 mock_get_model
.return_value
= model
1915 endpoint
= RelationEndpoint("model.app-name.0", "vca", "endpoint")
1916 self
.loop
.run_until_complete(self
.libjuju
.offer(endpoint
))
1917 mock_create_offer
.assert_called_with(
1918 "app-name:endpoint", offer_name
="app-name-endpoint"
1920 mock_disconnect_model
.assert_called_once_with(model
)
1921 mock_disconnect_controller
.assert_called_once_with(controller
)
1923 def test_offer_exception(
1927 mock_disconnect_controller
,
1928 mock_disconnect_model
,
1930 mock_get_controller
,
1932 controller
= juju
.controller
.Controller()
1933 model
= juju
.model
.Model()
1934 mock_get_controller
.return_value
= controller
1935 mock_get_model
.return_value
= model
1936 mock__list_offers
.return_value
= []
1937 endpoint
= RelationEndpoint("model.app-name.0", "vca", "endpoint")
1938 with self
.assertRaises(Exception):
1939 self
.loop
.run_until_complete(self
.libjuju
.offer(endpoint
))
1940 mock_create_offer
.assert_called_with(
1941 "app-name:endpoint", offer_name
="app-name-endpoint"
1943 mock_disconnect_model
.assert_called_once_with(model
)
1944 mock_disconnect_controller
.assert_called_once_with(controller
)
1947 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
1948 @asynctest.mock
.patch("juju.controller.Controller.get_model")
1949 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
1950 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1951 @asynctest.mock
.patch("juju.model.Model.consume")
1952 class ConsumeTest(LibjujuTestCase
):
1954 self
.offer_url
= "admin/model.offer_name"
1955 super(ConsumeTest
, self
).setUp()
1956 self
.provider_libjuju
= self
.libjuju
1961 mock_disconnect_controller
,
1962 mock_disconnect_model
,
1964 mock_get_controller
,
1966 self_controller
= juju
.controller
.Controller()
1967 provider_controller
= juju
.controller
.Controller()
1968 mock_get_controller
.side_effect
= [self_controller
, provider_controller
]
1969 mock_get_model
.return_value
= juju
.model
.Model()
1971 self
.loop
.run_until_complete(
1972 self
.libjuju
.consume(
1974 Offer(self
.offer_url
, vca_id
="vca-id"),
1975 self
.provider_libjuju
,
1978 mock_consume
.assert_called_once_with(
1979 "admin/model.offer_name",
1980 application_alias
="offer_name-model-vca-id",
1981 controller
=provider_controller
,
1983 mock_disconnect_model
.assert_called_once()
1984 self
.assertEqual(mock_disconnect_controller
.call_count
, 2)
1986 def test_parsing_error_exception(
1989 mock_disconnect_controller
,
1990 mock_disconnect_model
,
1992 mock_get_controller
,
1994 mock_get_controller
.return_value
= juju
.controller
.Controller()
1995 mock_get_model
.return_value
= juju
.model
.Model()
1996 mock_consume
.side_effect
= juju
.offerendpoints
.ParseError("")
1998 with self
.assertRaises(juju
.offerendpoints
.ParseError
):
1999 self
.loop
.run_until_complete(
2000 self
.libjuju
.consume(
2001 "model_name", Offer(self
.offer_url
), self
.provider_libjuju
2004 mock_consume
.assert_called_once()
2005 mock_disconnect_model
.assert_called_once()
2006 self
.assertEqual(mock_disconnect_controller
.call_count
, 2)
2008 def test_juju_error_exception(
2011 mock_disconnect_controller
,
2012 mock_disconnect_model
,
2014 mock_get_controller
,
2016 mock_get_controller
.return_value
= juju
.controller
.Controller()
2017 mock_get_model
.return_value
= juju
.model
.Model()
2018 mock_consume
.side_effect
= juju
.errors
.JujuError("")
2020 with self
.assertRaises(juju
.errors
.JujuError
):
2021 self
.loop
.run_until_complete(
2022 self
.libjuju
.consume(
2023 "model_name", Offer(self
.offer_url
), self
.provider_libjuju
2026 mock_consume
.assert_called_once()
2027 mock_disconnect_model
.assert_called_once()
2028 self
.assertEqual(mock_disconnect_controller
.call_count
, 2)
2030 def test_juju_api_error_exception(
2033 mock_disconnect_controller
,
2034 mock_disconnect_model
,
2036 mock_get_controller
,
2038 mock_get_controller
.return_value
= juju
.controller
.Controller()
2039 mock_get_model
.return_value
= juju
.model
.Model()
2040 mock_consume
.side_effect
= juju
.errors
.JujuAPIError(
2041 {"error": "", "response": "", "request-id": ""}
2044 with self
.assertRaises(juju
.errors
.JujuAPIError
):
2045 self
.loop
.run_until_complete(
2046 self
.libjuju
.consume(
2047 "model_name", Offer(self
.offer_url
), self
.provider_libjuju
2050 mock_consume
.assert_called_once()
2051 mock_disconnect_model
.assert_called_once()
2052 self
.assertEqual(mock_disconnect_controller
.call_count
, 2)
2055 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
2056 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.add_cloud")
2057 class AddK8sTest(LibjujuTestCase
):
2059 super(AddK8sTest
, self
).setUp()
2061 rbac_id
= generate_rbac_id()
2063 client_cert_data
= "cert"
2064 configuration
= kubernetes
.client
.configuration
.Configuration()
2065 storage_class
= "storage_class"
2066 credential_name
= name
2068 self
._add
_k
8s
_args
= {
2072 "client_cert_data": client_cert_data
,
2073 "configuration": configuration
,
2074 "storage_class": storage_class
,
2075 "credential_name": credential_name
,
2078 def test_add_k8s(self
, mock_add_cloud
, mock_get_k8s_cloud_credential
):
2079 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
2080 mock_add_cloud
.assert_called_once()
2081 mock_get_k8s_cloud_credential
.assert_called_once()
2083 def test_add_k8s_exception(self
, mock_add_cloud
, mock_get_k8s_cloud_credential
):
2084 mock_add_cloud
.side_effect
= Exception()
2085 with self
.assertRaises(Exception):
2086 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
2087 mock_add_cloud
.assert_called_once()
2088 mock_get_k8s_cloud_credential
.assert_called_once()
2090 def test_add_k8s_missing_name(self
, mock_add_cloud
, mock_get_k8s_cloud_credential
):
2091 self
._add
_k
8s
_args
["name"] = ""
2092 with self
.assertRaises(Exception):
2093 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
2094 mock_add_cloud
.assert_not_called()
2096 def test_add_k8s_missing_storage_name(
2097 self
, mock_add_cloud
, mock_get_k8s_cloud_credential
2099 self
._add
_k
8s
_args
["storage_class"] = ""
2100 with self
.assertRaises(Exception):
2101 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
2102 mock_add_cloud
.assert_not_called()
2104 def test_add_k8s_missing_configuration_keys(
2105 self
, mock_add_cloud
, mock_get_k8s_cloud_credential
2107 self
._add
_k
8s
_args
["configuration"] = None
2108 with self
.assertRaises(Exception):
2109 self
.loop
.run_until_complete(self
.libjuju
.add_k8s(**self
._add
_k
8s
_args
))
2110 mock_add_cloud
.assert_not_called()
2113 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2114 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2115 @asynctest.mock
.patch("juju.controller.Controller.add_cloud")
2116 @asynctest.mock
.patch("juju.controller.Controller.add_credential")
2117 class AddCloudTest(LibjujuTestCase
):
2119 super(AddCloudTest
, self
).setUp()
2120 self
.cloud
= juju
.client
.client
.Cloud()
2121 self
.credential
= juju
.client
.client
.CloudCredential()
2123 def test_add_cloud_with_credential(
2125 mock_add_credential
,
2127 mock_disconnect_controller
,
2128 mock_get_controller
,
2130 mock_get_controller
.return_value
= juju
.controller
.Controller()
2132 cloud
= self
.loop
.run_until_complete(
2133 self
.libjuju
.add_cloud("cloud", self
.cloud
, credential
=self
.credential
)
2135 self
.assertEqual(cloud
, self
.cloud
)
2136 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
2137 mock_add_credential
.assert_called_once_with(
2138 "cloud", credential
=self
.credential
, cloud
="cloud"
2140 mock_disconnect_controller
.assert_called_once()
2142 def test_add_cloud_no_credential(
2144 mock_add_credential
,
2146 mock_disconnect_controller
,
2147 mock_get_controller
,
2149 mock_get_controller
.return_value
= juju
.controller
.Controller()
2151 cloud
= self
.loop
.run_until_complete(
2152 self
.libjuju
.add_cloud("cloud", self
.cloud
)
2154 self
.assertEqual(cloud
, self
.cloud
)
2155 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
2156 mock_add_credential
.assert_not_called()
2157 mock_disconnect_controller
.assert_called_once()
2159 def test_add_cloud_exception(
2161 mock_add_credential
,
2163 mock_disconnect_controller
,
2164 mock_get_controller
,
2166 mock_get_controller
.return_value
= juju
.controller
.Controller()
2167 mock_add_cloud
.side_effect
= Exception()
2168 with self
.assertRaises(Exception):
2169 self
.loop
.run_until_complete(
2170 self
.libjuju
.add_cloud("cloud", self
.cloud
, credential
=self
.credential
)
2173 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
2174 mock_add_credential
.assert_not_called()
2175 mock_disconnect_controller
.assert_called_once()
2177 def test_add_credential_exception(
2179 mock_add_credential
,
2181 mock_disconnect_controller
,
2182 mock_get_controller
,
2184 mock_get_controller
.return_value
= juju
.controller
.Controller()
2185 mock_add_credential
.side_effect
= Exception()
2186 with self
.assertRaises(Exception):
2187 self
.loop
.run_until_complete(
2188 self
.libjuju
.add_cloud("cloud", self
.cloud
, credential
=self
.credential
)
2191 mock_add_cloud
.assert_called_once_with("cloud", self
.cloud
)
2192 mock_add_credential
.assert_called_once_with(
2193 "cloud", credential
=self
.credential
, cloud
="cloud"
2195 mock_disconnect_controller
.assert_called_once()
2198 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2199 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2200 @asynctest.mock
.patch("juju.controller.Controller.remove_cloud")
2201 class RemoveCloudTest(LibjujuTestCase
):
2203 super(RemoveCloudTest
, self
).setUp()
2205 def test_remove_cloud(
2208 mock_disconnect_controller
,
2209 mock_get_controller
,
2211 mock_get_controller
.return_value
= juju
.controller
.Controller()
2213 self
.loop
.run_until_complete(self
.libjuju
.remove_cloud("cloud"))
2214 mock_remove_cloud
.assert_called_once_with("cloud")
2215 mock_disconnect_controller
.assert_called_once()
2217 def test_remove_cloud_exception(
2220 mock_disconnect_controller
,
2221 mock_get_controller
,
2223 mock_get_controller
.return_value
= juju
.controller
.Controller()
2224 mock_remove_cloud
.side_effect
= Exception()
2226 with self
.assertRaises(Exception):
2227 self
.loop
.run_until_complete(self
.libjuju
.remove_cloud("cloud"))
2228 mock_remove_cloud
.assert_called_once_with("cloud")
2229 mock_disconnect_controller
.assert_called_once()
2232 @asynctest.mock
.patch("kubernetes.client.configuration.Configuration")
2233 class GetK8sCloudCredentials(LibjujuTestCase
):
2235 super(GetK8sCloudCredentials
, self
).setUp()
2236 self
.cert_data
= "cert"
2237 self
.token
= "token"
2239 @asynctest.mock
.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
2240 def test_not_supported(self
, mock_exception
, mock_configuration
):
2241 mock_configuration
.username
= ""
2242 mock_configuration
.password
= ""
2243 mock_configuration
.ssl_ca_cert
= None
2244 mock_configuration
.cert_file
= None
2245 mock_configuration
.key_file
= None
2246 exception_raised
= False
2248 self
.cert_data
= None
2250 _
= self
.libjuju
.get_k8s_cloud_credential(
2255 except JujuInvalidK8sConfiguration
as e
:
2256 exception_raised
= True
2259 "authentication method not supported",
2261 self
.assertTrue(exception_raised
)
2263 def test_user_pass(self
, mock_configuration
):
2264 mock_configuration
.username
= "admin"
2265 mock_configuration
.password
= "admin"
2266 mock_configuration
.ssl_ca_cert
= None
2267 mock_configuration
.cert_file
= None
2268 mock_configuration
.key_file
= None
2270 self
.cert_data
= None
2271 credential
= self
.libjuju
.get_k8s_cloud_credential(
2278 juju
.client
._definitions
.CloudCredential(
2279 attrs
={"username": "admin", "password": "admin"}, auth_type
="userpass"
2283 def test_user_pass_with_cert(self
, mock_configuration
):
2284 mock_configuration
.username
= "admin"
2285 mock_configuration
.password
= "admin"
2286 mock_configuration
.ssl_ca_cert
= None
2287 mock_configuration
.cert_file
= None
2288 mock_configuration
.key_file
= None
2290 credential
= self
.libjuju
.get_k8s_cloud_credential(
2297 juju
.client
._definitions
.CloudCredential(
2299 "ClientCertificateData": self
.cert_data
,
2300 "username": "admin",
2301 "password": "admin",
2303 auth_type
="userpasswithcert",
2307 def test_user_no_pass(self
, mock_configuration
):
2308 mock_configuration
.username
= "admin"
2309 mock_configuration
.password
= ""
2310 mock_configuration
.ssl_ca_cert
= None
2311 mock_configuration
.cert_file
= None
2312 mock_configuration
.key_file
= None
2314 self
.cert_data
= None
2315 with patch
.object(self
.libjuju
.log
, "debug") as mock_debug
:
2316 credential
= self
.libjuju
.get_k8s_cloud_credential(
2323 juju
.client
._definitions
.CloudCredential(
2324 attrs
={"username": "admin", "password": ""}, auth_type
="userpass"
2327 mock_debug
.assert_called_once_with(
2328 "credential for user admin has empty password"
2331 def test_cert(self
, mock_configuration
):
2332 mock_configuration
.username
= ""
2333 mock_configuration
.password
= ""
2334 mock_configuration
.api_key
= {"authorization": "Bearer Token"}
2335 ssl_ca_cert
= tempfile
.NamedTemporaryFile()
2336 with
open(ssl_ca_cert
.name
, "w") as ssl_ca_cert_file
:
2337 ssl_ca_cert_file
.write("cacert")
2338 mock_configuration
.ssl_ca_cert
= ssl_ca_cert
.name
2339 mock_configuration
.cert_file
= None
2340 mock_configuration
.key_file
= None
2341 credential
= self
.libjuju
.get_k8s_cloud_credential(
2348 juju
.client
._definitions
.CloudCredential(
2349 attrs
={"ClientCertificateData": self
.cert_data
, "Token": self
.token
},
2350 auth_type
="certificate",
2354 # TODO: Fix this test when oauth authentication is supported
2355 # def test_oauth2(self, mock_configuration):
2356 # mock_configuration.username = ""
2357 # mock_configuration.password = ""
2358 # mock_configuration.api_key = {"authorization": "Bearer Token"}
2359 # key = tempfile.NamedTemporaryFile()
2360 # with open(key.name, "w") as key_file:
2361 # key_file.write("key")
2362 # mock_configuration.ssl_ca_cert = None
2363 # mock_configuration.cert_file = None
2364 # mock_configuration.key_file = key.name
2365 # credential = self.libjuju.get_k8s_cloud_credential(
2366 # mock_configuration,
2372 # juju.client._definitions.CloudCredential(
2373 # attrs={"ClientKeyData": "key", "Token": "Token"},
2374 # auth_type="oauth2",
2378 # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
2379 # def test_oauth2_missing_token(self, mock_exception, mock_configuration):
2380 # mock_configuration.username = ""
2381 # mock_configuration.password = ""
2382 # key = tempfile.NamedTemporaryFile()
2383 # with open(key.name, "w") as key_file:
2384 # key_file.write("key")
2385 # mock_configuration.ssl_ca_cert = None
2386 # mock_configuration.cert_file = None
2387 # mock_configuration.key_file = key.name
2388 # exception_raised = False
2390 # _ = self.libjuju.get_k8s_cloud_credential(
2391 # mock_configuration,
2395 # except JujuInvalidK8sConfiguration as e:
2396 # exception_raised = True
2399 # "missing token for auth type oauth2",
2401 # self.assertTrue(exception_raised)
2403 def test_exception_cannot_set_token_and_userpass(self
, mock_configuration
):
2404 mock_configuration
.username
= "admin"
2405 mock_configuration
.password
= "pass"
2406 mock_configuration
.api_key
= {"authorization": "No_bearer_token"}
2407 mock_configuration
.ssl_ca_cert
= None
2408 mock_configuration
.cert_file
= None
2409 mock_configuration
.key_file
= None
2410 exception_raised
= False
2412 _
= self
.libjuju
.get_k8s_cloud_credential(
2417 except JujuInvalidK8sConfiguration
as e
:
2418 exception_raised
= True
2421 "Cannot set both token and user/pass",
2423 self
.assertTrue(exception_raised
)
2426 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2427 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
2428 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2429 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
2430 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2431 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
2432 class ScaleApplicationTest(LibjujuTestCase
):
2434 super(ScaleApplicationTest
, self
).setUp()
2436 @asynctest.mock
.patch("asyncio.sleep")
2437 def test_scale_application(
2440 mock_wait_for_model
,
2441 mock_disconnect_controller
,
2442 mock_disconnect_model
,
2443 mock_get_application
,
2445 mock_get_controller
,
2447 mock_get_model
.return_value
= juju
.model
.Model()
2448 mock_get_application
.return_value
= FakeApplication()
2449 self
.loop
.run_until_complete(self
.libjuju
.scale_application("model", "app", 2))
2450 mock_wait_for_model
.assert_called_once()
2451 mock_disconnect_controller
.assert_called_once()
2452 mock_disconnect_model
.assert_called_once()
2454 def test_no_application(
2457 mock_disconnect_controller
,
2458 mock_disconnect_model
,
2459 mock_get_application
,
2461 mock_get_controller
,
2463 mock_get_application
.return_value
= None
2464 mock_get_model
.return_value
= juju
.model
.Model()
2465 with self
.assertRaises(JujuApplicationNotFound
):
2466 self
.loop
.run_until_complete(
2467 self
.libjuju
.scale_application("model", "app", 2)
2469 mock_disconnect_controller
.assert_called()
2470 mock_disconnect_model
.assert_called()
2475 mock_disconnect_controller
,
2476 mock_disconnect_model
,
2477 mock_get_application
,
2479 mock_get_controller
,
2481 mock_get_model
.return_value
= None
2482 mock_get_application
.return_value
= FakeApplication()
2483 with self
.assertRaises(Exception):
2484 self
.loop
.run_until_complete(
2485 self
.libjuju
.scale_application("model", "app", 2, total_timeout
=0)
2487 mock_disconnect_controller
.assert_called_once()
2490 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2491 class GetUnitNumberTest(LibjujuTestCase
):
2493 super(GetUnitNumberTest
, self
).setUp()
2495 def test_successful_get_unit_number(
2497 mock_get_applications
,
2499 mock_get_applications
.return_value
= FakeApplication()
2500 model
= juju
.model
.Model()
2501 result
= self
.libjuju
._get
_application
_count
(model
, "app")
2502 self
.assertEqual(result
, 2)
2504 def test_non_existing_application(
2506 mock_get_applications
,
2508 mock_get_applications
.return_value
= None
2509 model
= juju
.model
.Model()
2510 result
= self
.libjuju
._get
_application
_count
(model
, "app")
2511 self
.assertEqual(result
, None)
2514 @asynctest.mock
.patch("juju.model.Model.machines", new_callable
=asynctest
.PropertyMock
)
2515 class GetMachineInfoTest(LibjujuTestCase
):
2517 super(GetMachineInfoTest
, self
).setUp()
2519 def test_successful(
2523 machine_id
= "existing_machine"
2524 model
= juju
.model
.Model()
2525 mock_machines
.return_value
= {"existing_machine": FakeManualMachine()}
2526 machine
, series
= self
.libjuju
._get
_machine
_info
(
2527 machine_id
=machine_id
,
2530 self
.assertIsNotNone(machine
, series
)
2536 machine_id
= "not_existing_machine"
2537 machine
= series
= None
2538 model
= juju
.model
.Model()
2539 mock_machines
.return_value
= {"existing_machine": FakeManualMachine()}
2540 with self
.assertRaises(JujuMachineNotFound
):
2541 machine
, series
= self
.libjuju
._get
_machine
_info
(
2542 machine_id
=machine_id
,
2545 self
.assertIsNone(machine
, series
)
2548 class GetUnitTest(LibjujuTestCase
):
2550 super(GetUnitTest
, self
).setUp()
2552 def test_successful(self
):
2553 result
= self
.libjuju
._get
_unit
(FakeApplication(), "existing_machine_id")
2554 self
.assertIsInstance(result
, FakeUnit
)
2556 def test_return_none(self
):
2557 result
= self
.libjuju
._get
_unit
(FakeApplication(), "not_existing_machine_id")
2558 self
.assertIsNone(result
)
2561 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2562 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
2563 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
2564 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2565 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2566 class CheckApplicationExists(LibjujuTestCase
):
2568 super(CheckApplicationExists
, self
).setUp()
2570 def test_successful(
2572 mock_get_application
,
2573 mock_disconnect_controller
,
2574 mock_disconnect_model
,
2576 mock_get_controller
,
2578 mock_get_model
.return_value
= juju
.model
.Model()
2579 mock_get_application
.return_value
= FakeApplication()
2580 result
= self
.loop
.run_until_complete(
2581 self
.libjuju
.check_application_exists(
2586 self
.assertEqual(result
, True)
2588 mock_get_application
.assert_called_once()
2589 mock_get_controller
.assert_called_once()
2590 mock_get_model
.assert_called_once()
2591 mock_disconnect_controller
.assert_called_once()
2592 mock_disconnect_model
.assert_called_once()
2594 def test_no_application(
2596 mock_get_application
,
2597 mock_disconnect_controller
,
2598 mock_disconnect_model
,
2600 mock_get_controller
,
2602 mock_get_model
.return_value
= juju
.model
.Model()
2603 mock_get_application
.return_value
= None
2604 result
= self
.loop
.run_until_complete(
2605 self
.libjuju
.check_application_exists(
2610 self
.assertEqual(result
, False)
2612 mock_get_application
.assert_called_once()
2613 mock_get_controller
.assert_called_once()
2614 mock_get_model
.assert_called_once()
2615 mock_disconnect_controller
.assert_called_once()
2616 mock_disconnect_model
.assert_called_once()
2619 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2620 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
2621 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
2622 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2623 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2624 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_machine_info")
2625 class AddUnitTest(LibjujuTestCase
):
2627 super(AddUnitTest
, self
).setUp()
2629 @asynctest.mock
.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
2630 @asynctest.mock
.patch("asyncio.sleep")
2631 def test_successful(
2635 mock_get_machine_info
,
2636 mock_get_application
,
2637 mock_disconnect_controller
,
2638 mock_disconnect_model
,
2640 mock_get_controller
,
2642 mock_get_model
.return_value
= juju
.model
.Model()
2643 mock_get_application
.return_value
= FakeApplication()
2644 mock_get_machine_info
.return_value
= FakeMachine(), "series"
2645 self
.loop
.run_until_complete(
2646 self
.libjuju
.add_unit(
2653 mock_wait_for
.assert_called_once()
2654 mock_get_application
.assert_called_once()
2655 mock_get_controller
.assert_called_once()
2656 mock_get_model
.assert_called_once()
2657 mock_disconnect_controller
.assert_called_once()
2658 mock_disconnect_model
.assert_called_once()
2662 mock_get_machine_info
,
2663 mock_get_application
,
2664 mock_disconnect_controller
,
2665 mock_disconnect_model
,
2667 mock_get_controller
,
2669 mock_get_model
.return_value
= juju
.model
.Model()
2670 mock_get_application
.return_value
= None
2671 with self
.assertRaises(JujuApplicationNotFound
):
2672 self
.loop
.run_until_complete(
2673 self
.libjuju
.add_unit(
2680 mock_get_application
.assert_called_once()
2681 mock_get_controller
.assert_called_once()
2682 mock_get_model
.assert_called_once()
2683 mock_disconnect_controller
.assert_called_once()
2684 mock_disconnect_model
.assert_called_once()
2686 def test_no_machine(
2688 mock_get_machine_info
,
2689 mock_get_application
,
2690 mock_disconnect_controller
,
2691 mock_disconnect_model
,
2693 mock_get_controller
,
2695 mock_get_model
.return_value
= juju
.model
.Model()
2696 mock_get_application
.return_value
= FakeApplication()
2697 mock_get_machine_info
.side_effect
= JujuMachineNotFound()
2698 with self
.assertRaises(JujuMachineNotFound
):
2699 self
.loop
.run_until_complete(
2700 self
.libjuju
.add_unit(
2707 mock_get_application
.assert_called_once()
2708 mock_get_controller
.assert_called_once()
2709 mock_get_model
.assert_called_once()
2710 mock_disconnect_controller
.assert_called_once()
2711 mock_disconnect_model
.assert_called_once()
2714 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_controller")
2715 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.get_model")
2716 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_model")
2717 @asynctest.mock
.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2718 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_application")
2719 @asynctest.mock
.patch("n2vc.libjuju.Libjuju._get_unit")
2720 class DestroyUnitTest(LibjujuTestCase
):
2722 super(DestroyUnitTest
, self
).setUp()
2724 @asynctest.mock
.patch("asyncio.sleep")
2725 def test_successful(
2729 mock_get_application
,
2730 mock_disconnect_controller
,
2731 mock_disconnect_model
,
2733 mock_get_controller
,
2735 mock_get_model
.return_value
= juju
.model
.Model()
2736 mock_get_application
.return_value
= FakeApplication()
2738 self
.loop
.run_until_complete(
2739 self
.libjuju
.destroy_unit("app", "model", "machine", 0)
2742 mock_get_unit
.assert_called()
2743 mock_get_application
.assert_called_once()
2744 mock_get_controller
.assert_called_once()
2745 mock_get_model
.assert_called_once()
2746 mock_disconnect_controller
.assert_called_once()
2747 mock_disconnect_model
.assert_called_once()
2752 mock_get_application
,
2753 mock_disconnect_controller
,
2754 mock_disconnect_model
,
2756 mock_get_controller
,
2758 mock_get_model
.return_value
= juju
.model
.Model()
2759 mock_get_application
.return_value
= None
2761 with self
.assertRaises(JujuApplicationNotFound
):
2762 self
.loop
.run_until_complete(
2763 self
.libjuju
.destroy_unit("app", "model", "machine")
2766 mock_get_application
.assert_called_once()
2767 mock_get_controller
.assert_called_once()
2768 mock_get_model
.assert_called_once()
2769 mock_disconnect_controller
.assert_called_once()
2770 mock_disconnect_model
.assert_called_once()
2775 mock_get_application
,
2776 mock_disconnect_controller
,
2777 mock_disconnect_model
,
2779 mock_get_controller
,
2781 mock_get_model
.return_value
= juju
.model
.Model()
2782 mock_get_application
.return_value
= FakeApplication()
2783 mock_get_unit
.return_value
= None
2785 with self
.assertRaises(JujuError
):
2786 self
.loop
.run_until_complete(
2787 self
.libjuju
.destroy_unit("app", "model", "machine")
2790 mock_get_unit
.assert_called_once()
2791 mock_get_application
.assert_called_once()
2792 mock_get_controller
.assert_called_once()
2793 mock_get_model
.assert_called_once()
2794 mock_disconnect_controller
.assert_called_once()
2795 mock_disconnect_model
.assert_called_once()