1bbe55623ea355fc588871454a3431b33ec99d1a
[osm/N2VC.git] / n2vc / tests / unit / test_libjuju.py
1 # Copyright 2020 Canonical Ltd.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import asyncio
16 import asynctest
17 import tempfile
18 from unittest.mock import Mock, patch
19 import juju
20 import kubernetes
21 from juju.errors import JujuAPIError
22 import logging
23
24 from n2vc.definitions import Offer, RelationEndpoint
25 from .utils import (
26 FakeApplication,
27 FakeMachine,
28 FakeManualMachine,
29 FakeUnit,
30 )
31 from n2vc.libjuju import Libjuju
32 from n2vc.exceptions import (
33 JujuControllerFailedConnecting,
34 JujuMachineNotFound,
35 JujuApplicationNotFound,
36 JujuActionNotFound,
37 JujuApplicationExists,
38 JujuInvalidK8sConfiguration,
39 JujuLeaderUnitNotFound,
40 JujuError,
41 )
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
46
47
48 cacert = """-----BEGIN CERTIFICATE-----
49 SOMECERT
50 -----END CERTIFICATE-----"""
51
52
53 @asynctest.mock.patch("n2vc.libjuju.Controller")
54 class LibjujuTestCase(asynctest.TestCase):
55 @asynctest.mock.patch("n2vc.vca.connection_data.base64_to_cacert")
56 def setUp(
57 self,
58 mock_base64_to_cacert=None,
59 ):
60 self.loop = asyncio.get_event_loop()
61 self.db = Mock()
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(
66 **{
67 "endpoints": ["1.2.3.4:17070"],
68 "user": "user",
69 "secret": "secret",
70 "cacert": "cacert",
71 "pubkey": "pubkey",
72 "lxd-cloud": "cloud",
73 "lxd-credentials": "credentials",
74 "k8s-cloud": "k8s_cloud",
75 "k8s-credentials": "k8s_credentials",
76 "model-config": {},
77 "api-proxy": "api_proxy",
78 }
79 )
80 logging.disable(logging.CRITICAL)
81 self.libjuju = Libjuju(vca_connection, self.loop)
82 self.loop.run_until_complete(self.libjuju.disconnect())
83
84
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"]),
89 )
90 class GetControllerTest(LibjujuTestCase):
91 def setUp(self):
92 super(GetControllerTest, self).setUp()
93
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)
98
99 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
100 def test_exception(
101 self,
102 mock_disconnect_controller,
103 mock_api_endpoints,
104 mock_connect,
105 ):
106 self.libjuju.endpoints = []
107
108 mock_connect.side_effect = Exception()
109 controller = None
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()
114
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)
119
120
121 class DisconnectTest(LibjujuTestCase):
122 def setUp(self):
123 super(DisconnectTest, self).setUp()
124
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()
129
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())
134 )
135 mock_disconnect.assert_called_once()
136
137
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):
144 def setUp(self):
145 super(AddModelTest, self).setUp()
146
147 def test_existing_model(
148 self,
149 mock_disconnect_model,
150 mock_disconnect_controller,
151 mock_add_model,
152 mock_model_exists,
153 mock_get_controller,
154 ):
155 mock_model_exists.return_value = True
156
157 # This should not raise an exception
158 self.loop.run_until_complete(self.libjuju.add_model("existing_model", "cloud"))
159
160 mock_disconnect_controller.assert_called()
161
162 # TODO Check two job executing at the same time and one returning without doing anything.
163
164 def test_non_existing_model(
165 self,
166 mock_disconnect_model,
167 mock_disconnect_controller,
168 mock_add_model,
169 mock_model_exists,
170 mock_get_controller,
171 ):
172 mock_model_exists.return_value = False
173 mock_get_controller.return_value = juju.controller.Controller()
174
175 self.loop.run_until_complete(
176 self.libjuju.add_model("nonexisting_model", Mock())
177 )
178
179 mock_add_model.assert_called_once()
180 mock_disconnect_controller.assert_called()
181 mock_disconnect_model.assert_called()
182
183
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
190 )
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):
195 def setUp(self):
196 super(GetExecutedActionsTest, self).setUp()
197
198 def test_exception(
199 self,
200 mock_get_actions,
201 mock_get_action_output,
202 mock_get_action_status,
203 mock_applications,
204 mock_disconnect_controller,
205 mock_disconnect_model,
206 mock_get_model,
207 mock_get_controller,
208 ):
209 mock_get_model.return_value = None
210 with self.assertRaises(JujuError):
211 self.loop.run_until_complete(self.libjuju.get_executed_actions("model"))
212
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()
217
218 def test_success(
219 self,
220 mock_get_actions,
221 mock_get_action_output,
222 mock_get_action_status,
223 mock_applications,
224 mock_disconnect_controller,
225 mock_disconnect_model,
226 mock_get_model,
227 mock_get_controller,
228 ):
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"}
234
235 executed_actions = self.loop.run_until_complete(
236 self.libjuju.get_executed_actions("model")
237 )
238 expected_result = [
239 {
240 "id": "id",
241 "action": "action_name",
242 "status": "status",
243 "output": "completed",
244 }
245 ]
246 self.assertListEqual(expected_result, executed_actions)
247 self.assertIsInstance(executed_actions, list)
248
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()
253
254
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):
261 def setUp(self):
262 super(GetApplicationConfigsTest, self).setUp()
263
264 def test_exception(
265 self,
266 mock_get_application,
267 mock_disconnect_controller,
268 mock_disconnect_model,
269 mock_get_model,
270 mock_get_controller,
271 ):
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")
276 )
277
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()
282
283 def test_success(
284 self,
285 mock_get_application,
286 mock_disconnect_controller,
287 mock_disconnect_model,
288 mock_get_model,
289 mock_get_controller,
290 ):
291 mock_get_application.return_value = FakeApplication()
292 application_configs = self.loop.run_until_complete(
293 self.libjuju.get_application_configs("model", "app")
294 )
295
296 self.assertEqual(application_configs, ["app_config"])
297
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()
302
303
304 @asynctest.mock.patch("juju.controller.Controller.get_model")
305 class GetModelTest(LibjujuTestCase):
306 def setUp(self):
307 super(GetModelTest, self).setUp()
308
309 def test_get_model(
310 self,
311 mock_get_model,
312 ):
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")
316 )
317 self.assertIsInstance(model, juju.model.Model)
318
319
320 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
321 @asynctest.mock.patch("juju.controller.Controller.list_models")
322 class ModelExistsTest(LibjujuTestCase):
323 def setUp(self):
324 super(ModelExistsTest, self).setUp()
325
326 async def test_existing_model(
327 self,
328 mock_list_models,
329 mock_get_controller,
330 ):
331 mock_list_models.return_value = ["existing_model"]
332 self.assertTrue(
333 await self.libjuju.model_exists(
334 "existing_model", juju.controller.Controller()
335 )
336 )
337
338 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
339 async def test_no_controller(
340 self,
341 mock_disconnect_controller,
342 mock_list_models,
343 mock_get_controller,
344 ):
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()
349
350 async def test_non_existing_model(
351 self,
352 mock_list_models,
353 mock_get_controller,
354 ):
355 mock_list_models.return_value = ["existing_model"]
356 self.assertFalse(
357 await self.libjuju.model_exists(
358 "not_existing_model", juju.controller.Controller()
359 )
360 )
361
362
363 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
364 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
365 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
366 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
367 @asynctest.mock.patch("juju.model.Model.get_status")
368 class GetModelStatusTest(LibjujuTestCase):
369 def setUp(self):
370 super(GetModelStatusTest, self).setUp()
371
372 def test_success(
373 self,
374 mock_get_status,
375 mock_disconnect_controller,
376 mock_disconnect_model,
377 mock_get_model,
378 mock_get_controller,
379 ):
380 mock_get_model.return_value = juju.model.Model()
381 mock_get_status.return_value = {"status"}
382
383 status = self.loop.run_until_complete(self.libjuju.get_model_status("model"))
384
385 mock_get_status.assert_called_once()
386 mock_disconnect_controller.assert_called_once()
387 mock_disconnect_model.assert_called_once()
388
389 self.assertEqual(status, {"status"})
390
391 def test_exception(
392 self,
393 mock_get_status,
394 mock_disconnect_controller,
395 mock_disconnect_model,
396 mock_get_model,
397 mock_get_controller,
398 ):
399 mock_get_model.return_value = juju.model.Model()
400 mock_get_status.side_effect = Exception()
401 status = None
402 with self.assertRaises(Exception):
403 status = self.loop.run_until_complete(
404 self.libjuju.get_model_status("model")
405 )
406
407 mock_disconnect_controller.assert_called_once()
408 mock_disconnect_model.assert_called_once()
409
410 self.assertIsNone(status)
411
412
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):
421 def setUp(self):
422 super(CreateMachineTest, self).setUp()
423
424 def test_existing_machine(
425 self,
426 mock_wait_for,
427 mock_add_machine,
428 mock_get_machines,
429 mock_disconnect_controller,
430 mock_disconnect_model,
431 mock_get_model,
432 mock_get_controller,
433 ):
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")
438 )
439
440 self.assertIsInstance(machine, FakeMachine)
441 self.assertFalse(bool_res)
442
443 mock_disconnect_controller.assert_called()
444 mock_disconnect_model.assert_called()
445
446 def test_non_existing_machine(
447 self,
448 mock_wait_for,
449 mock_add_machine,
450 mock_get_machines,
451 mock_disconnect_controller,
452 mock_disconnect_model,
453 mock_get_model,
454 mock_get_controller,
455 ):
456 machine = None
457 bool_res = None
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")
462 )
463 self.assertIsNone(machine)
464 self.assertIsNone(bool_res)
465
466 mock_disconnect_controller.assert_called()
467 mock_disconnect_model.assert_called()
468
469 def test_no_machine(
470 self,
471 mock_wait_for,
472 mock_add_machine,
473 mock_get_machines,
474 mock_disconnect_controller,
475 mock_disconnect_model,
476 mock_get_model,
477 mock_get_controller,
478 ):
479 mock_get_model.return_value = juju.model.Model()
480 mock_add_machine.return_value = FakeMachine()
481
482 machine, bool_res = self.loop.run_until_complete(
483 self.libjuju.create_machine("model")
484 )
485
486 self.assertIsInstance(machine, FakeMachine)
487 self.assertTrue(bool_res)
488
489 mock_wait_for.assert_called_once()
490 mock_add_machine.assert_called_once()
491
492 mock_disconnect_controller.assert_called()
493 mock_disconnect_model.assert_called()
494
495
496 # TODO test provision machine
497
498
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):
506 def setUp(self):
507 super(DeployTest, self).setUp()
508
509 def test_deploy(
510 self,
511 mock_deploy,
512 mock_wait_for_model,
513 mock_disconnect_controller,
514 mock_disconnect_model,
515 mock_get_model,
516 mock_get_controller,
517 ):
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)
521 )
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()
526
527 def test_deploy_no_wait(
528 self,
529 mock_deploy,
530 mock_wait_for_model,
531 mock_disconnect_controller,
532 mock_disconnect_model,
533 mock_get_model,
534 mock_get_controller,
535 ):
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)
539 )
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()
544
545 def test_deploy_exception(
546 self,
547 mock_deploy,
548 mock_wait_for_model,
549 mock_disconnect_controller,
550 mock_disconnect_model,
551 mock_get_model,
552 mock_get_controller,
553 ):
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()
562
563
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
570 )
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):
576 def setUp(self):
577 super(DeployCharmTest, self).setUp()
578
579 def test_existing_app(
580 self,
581 mock_create_machine,
582 mock_wait_for,
583 mock_deploy,
584 mock_machines,
585 mock_applications,
586 mock_disconnect_controller,
587 mock_disconnect_model,
588 mock_get_model,
589 mock_get_controller,
590 ):
591 mock_get_model.return_value = juju.model.Model()
592 mock_applications.return_value = {"existing_app"}
593
594 application = None
595 with self.assertRaises(JujuApplicationExists):
596 application = self.loop.run_until_complete(
597 self.libjuju.deploy_charm(
598 "existing_app",
599 "path",
600 "model",
601 "machine",
602 )
603 )
604 self.assertIsNone(application)
605
606 mock_disconnect_controller.assert_called()
607 mock_disconnect_model.assert_called()
608
609 def test_non_existing_machine(
610 self,
611 mock_create_machine,
612 mock_wait_for,
613 mock_deploy,
614 mock_machines,
615 mock_applications,
616 mock_disconnect_controller,
617 mock_disconnect_model,
618 mock_get_model,
619 mock_get_controller,
620 ):
621 mock_get_model.return_value = juju.model.Model()
622 mock_machines.return_value = {"existing_machine": FakeMachine()}
623 application = None
624 with self.assertRaises(JujuMachineNotFound):
625 application = self.loop.run_until_complete(
626 self.libjuju.deploy_charm(
627 "app",
628 "path",
629 "model",
630 "machine",
631 )
632 )
633
634 self.assertIsNone(application)
635
636 mock_disconnect_controller.assert_called()
637 mock_disconnect_model.assert_called()
638
639 def test_2_units(
640 self,
641 mock_create_machine,
642 mock_wait_for,
643 mock_deploy,
644 mock_machines,
645 mock_applications,
646 mock_disconnect_controller,
647 mock_disconnect_model,
648 mock_get_model,
649 mock_get_controller,
650 ):
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(
657 "app",
658 "path",
659 "model",
660 "existing_machine",
661 num_units=2,
662 )
663 )
664
665 self.assertIsInstance(application, FakeApplication)
666
667 mock_deploy.assert_called_once()
668 mock_wait_for.assert_called_once()
669
670 mock_create_machine.assert_called_once()
671
672 mock_disconnect_controller.assert_called()
673 mock_disconnect_model.assert_called()
674
675 def test_1_unit(
676 self,
677 mock_create_machine,
678 mock_wait_for,
679 mock_deploy,
680 mock_machines,
681 mock_applications,
682 mock_disconnect_controller,
683 mock_disconnect_model,
684 mock_get_model,
685 mock_get_controller,
686 ):
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")
692 )
693
694 self.assertIsInstance(application, FakeApplication)
695
696 mock_deploy.assert_called_once()
697 mock_wait_for.assert_called_once()
698
699 mock_disconnect_controller.assert_called()
700 mock_disconnect_model.assert_called()
701
702
703 @asynctest.mock.patch(
704 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
705 )
706 class GetApplicationTest(LibjujuTestCase):
707 def setUp(self):
708 super(GetApplicationTest, self).setUp()
709
710 def test_existing_application(
711 self,
712 mock_applications,
713 ):
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")
718
719 def test_non_existing_application(
720 self,
721 mock_applications,
722 ):
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)
727
728
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):
738 def setUp(self):
739 super(ExecuteActionTest, self).setUp()
740
741 def test_no_application(
742 self,
743 mock_get_action_status,
744 mock_get_action_output,
745 mock_wait_for,
746 mock__get_application,
747 mock_disconnect_controller,
748 mock_disconnect_model,
749 mock_get_model,
750 mock_get_controller,
751 ):
752 mock__get_application.return_value = None
753 mock_get_model.return_value = juju.model.Model()
754 output = None
755 status = None
756 with self.assertRaises(JujuApplicationNotFound):
757 output, status = self.loop.run_until_complete(
758 self.libjuju.execute_action(
759 "app",
760 "model",
761 "action",
762 )
763 )
764 self.assertIsNone(output)
765 self.assertIsNone(status)
766
767 mock_disconnect_controller.assert_called()
768 mock_disconnect_model.assert_called()
769
770 def test_no_action(
771 self,
772 mock_get_action_status,
773 mock_get_action_output,
774 mock_wait_for,
775 mock__get_application,
776 mock_disconnect_controller,
777 mock_disconnect_model,
778 mock_get_model,
779 mock_get_controller,
780 ):
781
782 mock_get_model.return_value = juju.model.Model()
783 mock__get_application.return_value = FakeApplication()
784 output = None
785 status = None
786 with self.assertRaises(JujuActionNotFound):
787 output, status = self.loop.run_until_complete(
788 self.libjuju.execute_action(
789 "app",
790 "model",
791 "action",
792 )
793 )
794 self.assertIsNone(output)
795 self.assertIsNone(status)
796
797 mock_disconnect_controller.assert_called()
798 mock_disconnect_model.assert_called()
799
800 @asynctest.mock.patch("asyncio.sleep")
801 @asynctest.mock.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
802 def test_no_leader(
803 self,
804 mock_is_leader_from_status,
805 mock_sleep,
806 mock_get_action_status,
807 mock_get_action_output,
808 mock_wait_for,
809 mock__get_application,
810 mock_disconnect_controller,
811 mock_disconnect_model,
812 mock_get_model,
813 mock_get_controller,
814 ):
815 mock_get_model.return_value = juju.model.Model()
816 mock__get_application.return_value = FakeApplication()
817 mock_is_leader_from_status.return_value = False
818 output = None
819 status = None
820 with self.assertRaises(JujuLeaderUnitNotFound):
821 output, status = self.loop.run_until_complete(
822 self.libjuju.execute_action(
823 "app",
824 "model",
825 "action",
826 )
827 )
828 self.assertIsNone(output)
829 self.assertIsNone(status)
830
831 mock_disconnect_controller.assert_called()
832 mock_disconnect_model.assert_called()
833
834 def test_successful_exec(
835 self,
836 mock_get_action_status,
837 mock_get_action_output,
838 mock_wait_for,
839 mock__get_application,
840 mock_disconnect_controller,
841 mock_disconnect_model,
842 mock_get_model,
843 mock_get_controller,
844 ):
845 mock_get_model.return_value = juju.model.Model()
846 mock__get_application.return_value = FakeApplication()
847 mock_get_action_output.return_value = "output"
848 mock_get_action_status.return_value = {"id": "status"}
849 output, status = self.loop.run_until_complete(
850 self.libjuju.execute_action("app", "model", "existing_action")
851 )
852 self.assertEqual(output, "output")
853 self.assertEqual(status, "status")
854
855 mock_wait_for.assert_called_once()
856
857 mock_disconnect_controller.assert_called()
858 mock_disconnect_model.assert_called()
859
860
861 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
862 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
863 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
864 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
865 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
866 class GetActionTest(LibjujuTestCase):
867 def setUp(self):
868 super(GetActionTest, self).setUp()
869
870 def test_exception(
871 self,
872 mock_get_application,
873 mock_disconnect_controller,
874 mock_disconnect_model,
875 mock_get_model,
876 mock_get_controller,
877 ):
878 mock_get_application.side_effect = Exception()
879 actions = None
880 with self.assertRaises(Exception):
881 actions = self.loop.run_until_complete(
882 self.libjuju.get_actions("app", "model")
883 )
884
885 self.assertIsNone(actions)
886 mock_disconnect_controller.assert_called_once()
887 mock_disconnect_model.assert_called_once()
888
889 def test_success(
890 self,
891 mock_get_application,
892 mock_disconnect_controller,
893 mock_disconnect_model,
894 mock_get_model,
895 mock_get_controller,
896 ):
897 mock_get_application.return_value = FakeApplication()
898
899 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
900
901 self.assertEqual(actions, ["existing_action"])
902
903 mock_get_controller.assert_called_once()
904 mock_get_model.assert_called_once()
905 mock_disconnect_controller.assert_called_once()
906 mock_disconnect_model.assert_called_once()
907
908
909 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
910 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
911 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
912 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
913 @asynctest.mock.patch("juju.application.Application.get_metrics")
914 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
915 class GetMetricsTest(LibjujuTestCase):
916 def setUp(self):
917 super(GetMetricsTest, self).setUp()
918
919 def test_get_metrics_success(
920 self,
921 mock_get_application,
922 mock_get_metrics,
923 mock_disconnect_controller,
924 mock_disconnect_model,
925 mock_get_model,
926 mock_get_controller,
927 ):
928 mock_get_application.return_value = FakeApplication()
929 mock_get_model.return_value = juju.model.Model()
930
931 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
932
933 mock_disconnect_controller.assert_called_once()
934 mock_disconnect_model.assert_called_once()
935
936 def test_get_metrics_exception(
937 self,
938 mock_get_application,
939 mock_get_metrics,
940 mock_disconnect_controller,
941 mock_disconnect_model,
942 mock_get_model,
943 mock_get_controller,
944 ):
945 mock_get_model.return_value = juju.model.Model()
946 mock_get_metrics.side_effect = Exception()
947 with self.assertRaises(Exception):
948 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
949
950 mock_disconnect_controller.assert_called_once()
951 mock_disconnect_model.assert_called_once()
952
953 def test_missing_args_exception(
954 self,
955 mock_get_application,
956 mock_get_metrics,
957 mock_disconnect_controller,
958 mock_disconnect_model,
959 mock_get_model,
960 mock_get_controller,
961 ):
962 mock_get_model.return_value = juju.model.Model()
963
964 with self.assertRaises(Exception):
965 self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
966
967 mock_get_controller.assert_not_called()
968 mock_get_model.assert_not_called()
969 mock_disconnect_controller.assert_not_called()
970 mock_disconnect_model.assert_not_called()
971
972
973 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
974 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
975 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
976 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
977 @asynctest.mock.patch("juju.model.Model.add_relation")
978 class AddRelationTest(LibjujuTestCase):
979 def setUp(self):
980 super(AddRelationTest, self).setUp()
981
982 @asynctest.mock.patch("logging.Logger.warning")
983 def test_not_found(
984 self,
985 mock_warning,
986 mock_add_relation,
987 mock_disconnect_controller,
988 mock_disconnect_model,
989 mock_get_model,
990 mock_get_controller,
991 ):
992 # TODO in libjuju.py should this fail only with a log message?
993 result = {"error": "not found", "response": "response", "request-id": 1}
994
995 mock_get_model.return_value = juju.model.Model()
996 mock_add_relation.side_effect = JujuAPIError(result)
997
998 self.loop.run_until_complete(
999 self.libjuju.add_relation(
1000 "model",
1001 "app1:relation1",
1002 "app2:relation2",
1003 )
1004 )
1005
1006 mock_warning.assert_called_with("Relation not found: not found")
1007 mock_disconnect_controller.assert_called_once()
1008 mock_disconnect_model.assert_called_once()
1009
1010 @asynctest.mock.patch("logging.Logger.warning")
1011 def test_not_found_in_error_code(
1012 self,
1013 mock_warning,
1014 mock_add_relation,
1015 mock_disconnect_controller,
1016 mock_disconnect_model,
1017 mock_get_model,
1018 mock_get_controller,
1019 ):
1020 result = {
1021 "error": "relation cannot be added",
1022 "error-code": "not found",
1023 "response": "response",
1024 "request-id": 1,
1025 }
1026
1027 mock_get_model.return_value = juju.model.Model()
1028 mock_add_relation.side_effect = JujuAPIError(result)
1029
1030 self.loop.run_until_complete(
1031 self.libjuju.add_relation(
1032 "model",
1033 "app1:relation1",
1034 "app2:relation2",
1035 )
1036 )
1037
1038 mock_warning.assert_called_with("Relation not found: relation cannot be added")
1039 mock_disconnect_controller.assert_called_once()
1040 mock_disconnect_model.assert_called_once()
1041
1042 @asynctest.mock.patch("logging.Logger.warning")
1043 def test_already_exists(
1044 self,
1045 mock_warning,
1046 mock_add_relation,
1047 mock_disconnect_controller,
1048 mock_disconnect_model,
1049 mock_get_model,
1050 mock_get_controller,
1051 ):
1052 # TODO in libjuju.py should this fail silently?
1053 result = {"error": "already exists", "response": "response", "request-id": 1}
1054
1055 mock_get_model.return_value = juju.model.Model()
1056 mock_add_relation.side_effect = JujuAPIError(result)
1057
1058 self.loop.run_until_complete(
1059 self.libjuju.add_relation(
1060 "model",
1061 "app1:relation1",
1062 "app2:relation2",
1063 )
1064 )
1065
1066 mock_warning.assert_called_with("Relation already exists: already exists")
1067 mock_disconnect_controller.assert_called_once()
1068 mock_disconnect_model.assert_called_once()
1069
1070 @asynctest.mock.patch("logging.Logger.warning")
1071 def test_already_exists_error_code(
1072 self,
1073 mock_warning,
1074 mock_add_relation,
1075 mock_disconnect_controller,
1076 mock_disconnect_model,
1077 mock_get_model,
1078 mock_get_controller,
1079 ):
1080 result = {
1081 "error": "relation cannot be added",
1082 "error-code": "already exists",
1083 "response": "response",
1084 "request-id": 1,
1085 }
1086
1087 mock_get_model.return_value = juju.model.Model()
1088 mock_add_relation.side_effect = JujuAPIError(result)
1089
1090 self.loop.run_until_complete(
1091 self.libjuju.add_relation(
1092 "model",
1093 "app1:relation1",
1094 "app2:relation2",
1095 )
1096 )
1097
1098 mock_warning.assert_called_with(
1099 "Relation already exists: relation cannot be added"
1100 )
1101 mock_disconnect_controller.assert_called_once()
1102 mock_disconnect_model.assert_called_once()
1103
1104 def test_exception(
1105 self,
1106 mock_add_relation,
1107 mock_disconnect_controller,
1108 mock_disconnect_model,
1109 mock_get_model,
1110 mock_get_controller,
1111 ):
1112 mock_get_model.return_value = juju.model.Model()
1113 result = {"error": "", "response": "response", "request-id": 1}
1114 mock_add_relation.side_effect = JujuAPIError(result)
1115
1116 with self.assertRaises(JujuAPIError):
1117 self.loop.run_until_complete(
1118 self.libjuju.add_relation(
1119 "model",
1120 "app1:relation1",
1121 "app2:relation2",
1122 )
1123 )
1124
1125 mock_disconnect_controller.assert_called_once()
1126 mock_disconnect_model.assert_called_once()
1127
1128 def test_success(
1129 self,
1130 mock_add_relation,
1131 mock_disconnect_controller,
1132 mock_disconnect_model,
1133 mock_get_model,
1134 mock_get_controller,
1135 ):
1136 mock_get_model.return_value = juju.model.Model()
1137
1138 self.loop.run_until_complete(
1139 self.libjuju.add_relation(
1140 "model",
1141 "app1:relation1",
1142 "app2:relation2",
1143 )
1144 )
1145
1146 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
1147 mock_disconnect_controller.assert_called_once()
1148 mock_disconnect_model.assert_called_once()
1149
1150 def test_saas(
1151 self,
1152 mock_add_relation,
1153 mock_disconnect_controller,
1154 mock_disconnect_model,
1155 mock_get_model,
1156 mock_get_controller,
1157 ):
1158 mock_get_model.return_value = juju.model.Model()
1159
1160 self.loop.run_until_complete(
1161 self.libjuju.add_relation(
1162 "model",
1163 "app1:relation1",
1164 "saas_name",
1165 )
1166 )
1167
1168 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
1169 mock_disconnect_controller.assert_called_once()
1170 mock_disconnect_model.assert_called_once()
1171
1172
1173 # TODO destroy_model testcase
1174
1175
1176 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1177 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1178 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1179 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1180 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1181 class DestroyApplicationTest(LibjujuTestCase):
1182 def setUp(self):
1183 super(DestroyApplicationTest, self).setUp()
1184
1185 def test_success(
1186 self,
1187 mock_get_controller,
1188 mock_get_model,
1189 mock_disconnect_controller,
1190 mock_get_application,
1191 mock_disconnect_model,
1192 ):
1193 mock_get_application.return_value = FakeApplication()
1194 mock_get_model.return_value = None
1195 self.loop.run_until_complete(
1196 self.libjuju.destroy_application(
1197 "existing_model",
1198 "existing_app",
1199 3600,
1200 )
1201 )
1202 mock_get_application.assert_called()
1203 mock_disconnect_controller.assert_called_once()
1204 mock_disconnect_model.assert_called_once()
1205
1206 def test_no_application(
1207 self,
1208 mock_get_controller,
1209 mock_get_model,
1210 mock_disconnect_controller,
1211 mock_get_application,
1212 mock_disconnect_model,
1213 ):
1214 mock_get_model.return_value = None
1215 mock_get_application.return_value = None
1216
1217 self.loop.run_until_complete(
1218 self.libjuju.destroy_application(
1219 "existing_model",
1220 "existing_app",
1221 3600,
1222 )
1223 )
1224 mock_get_application.assert_called()
1225
1226 def test_exception(
1227 self,
1228 mock_get_controller,
1229 mock_get_model,
1230 mock_disconnect_controller,
1231 mock_get_application,
1232 mock_disconnect_model,
1233 ):
1234 mock_get_application.return_value = FakeApplication
1235 mock_get_model.return_value = None
1236
1237 with self.assertRaises(Exception):
1238 self.loop.run_until_complete(
1239 self.libjuju.destroy_application(
1240 "existing_model",
1241 "existing_app",
1242 0,
1243 )
1244 )
1245 mock_get_application.assert_called_once()
1246
1247
1248 # @asynctest.mock.patch("juju.model.Model.get_machines")
1249 # @asynctest.mock.patch("logging.Logger.debug")
1250 # class DestroyMachineTest(LibjujuTestCase):
1251 # def setUp(self):
1252 # super(DestroyMachineTest, self).setUp()
1253
1254 # def test_success_manual_machine(
1255 # self, mock_debug, mock_get_machines,
1256 # ):
1257 # mock_get_machines.side_effect = [
1258 # {"machine": FakeManualMachine()},
1259 # {"machine": FakeManualMachine()},
1260 # {},
1261 # ]
1262 # self.loop.run_until_complete(
1263 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
1264 # )
1265 # calls = [
1266 # asynctest.call("Waiting for machine machine is destroyed"),
1267 # asynctest.call("Machine destroyed: machine"),
1268 # ]
1269 # mock_debug.assert_has_calls(calls)
1270
1271 # def test_no_machine(
1272 # self, mock_debug, mock_get_machines,
1273 # ):
1274 # mock_get_machines.return_value = {}
1275 # self.loop.run_until_complete(
1276 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
1277 # )
1278 # mock_debug.assert_called_with("Machine not found: machine")
1279
1280
1281 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1282 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1283 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1284 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1285 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1286 class ConfigureApplicationTest(LibjujuTestCase):
1287 def setUp(self):
1288 super(ConfigureApplicationTest, self).setUp()
1289
1290 def test_success(
1291 self,
1292 mock_get_application,
1293 mock_disconnect_controller,
1294 mock_disconnect_model,
1295 mock_get_model,
1296 mock_get_controller,
1297 ):
1298
1299 mock_get_application.return_value = FakeApplication()
1300
1301 self.loop.run_until_complete(
1302 self.libjuju.configure_application(
1303 "model",
1304 "app",
1305 {"config"},
1306 )
1307 )
1308 mock_get_application.assert_called_once()
1309 mock_disconnect_controller.assert_called_once()
1310 mock_disconnect_model.assert_called_once()
1311
1312 def test_exception(
1313 self,
1314 mock_get_application,
1315 mock_disconnect_controller,
1316 mock_disconnect_model,
1317 mock_get_model,
1318 mock_get_controller,
1319 ):
1320
1321 mock_get_application.side_effect = Exception()
1322
1323 with self.assertRaises(Exception):
1324 self.loop.run_until_complete(
1325 self.libjuju.configure_application(
1326 "model",
1327 "app",
1328 {"config"},
1329 )
1330 )
1331 mock_disconnect_controller.assert_called_once()
1332 mock_disconnect_model.assert_called_once()
1333
1334 def test_controller_exception(
1335 self,
1336 mock_get_application,
1337 mock_disconnect_controller,
1338 mock_disconnect_model,
1339 mock_get_model,
1340 mock_get_controller,
1341 ):
1342
1343 result = {"error": "not found", "response": "response", "request-id": 1}
1344
1345 mock_get_controller.side_effect = JujuAPIError(result)
1346
1347 with self.assertRaises(JujuAPIError):
1348 self.loop.run_until_complete(
1349 self.libjuju.configure_application(
1350 "model",
1351 "app",
1352 {"config"},
1353 )
1354 )
1355 mock_get_model.assert_not_called()
1356 mock_disconnect_controller.assert_not_called()
1357 mock_disconnect_model.assert_not_called()
1358
1359 def test_get_model_exception(
1360 self,
1361 mock_get_application,
1362 mock_disconnect_controller,
1363 mock_disconnect_model,
1364 mock_get_model,
1365 mock_get_controller,
1366 ):
1367
1368 result = {"error": "not found", "response": "response", "request-id": 1}
1369 mock_get_model.side_effect = JujuAPIError(result)
1370
1371 with self.assertRaises(JujuAPIError):
1372 self.loop.run_until_complete(
1373 self.libjuju.configure_application(
1374 "model",
1375 "app",
1376 {"config"},
1377 )
1378 )
1379 mock_get_model.assert_called_once()
1380 mock_disconnect_controller.assert_called_once()
1381 mock_disconnect_model.assert_not_called()
1382
1383
1384 # TODO _get_api_endpoints_db test case
1385 # TODO _update_api_endpoints_db test case
1386 # TODO healthcheck test case
1387
1388
1389 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1390 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1391 @asynctest.mock.patch("juju.controller.Controller.list_models")
1392 class ListModelsTest(LibjujuTestCase):
1393 def setUp(self):
1394 super(ListModelsTest, self).setUp()
1395
1396 def test_containing(
1397 self,
1398 mock_list_models,
1399 mock_disconnect_controller,
1400 mock_get_controller,
1401 ):
1402 mock_get_controller.return_value = juju.controller.Controller()
1403 mock_list_models.return_value = ["existingmodel"]
1404 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
1405
1406 mock_disconnect_controller.assert_called_once()
1407 self.assertEquals(models, ["existingmodel"])
1408
1409 def test_not_containing(
1410 self,
1411 mock_list_models,
1412 mock_disconnect_controller,
1413 mock_get_controller,
1414 ):
1415 mock_get_controller.return_value = juju.controller.Controller()
1416 mock_list_models.return_value = ["existingmodel", "model"]
1417 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
1418
1419 mock_disconnect_controller.assert_called_once()
1420 self.assertEquals(models, [])
1421
1422 def test_no_contains_arg(
1423 self,
1424 mock_list_models,
1425 mock_disconnect_controller,
1426 mock_get_controller,
1427 ):
1428 mock_get_controller.return_value = juju.controller.Controller()
1429 mock_list_models.return_value = ["existingmodel", "model"]
1430 models = self.loop.run_until_complete(self.libjuju.list_models())
1431
1432 mock_disconnect_controller.assert_called_once()
1433 self.assertEquals(models, ["existingmodel", "model"])
1434
1435
1436 @asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
1437 class ModelsExistTest(LibjujuTestCase):
1438 def setUp(self):
1439 super(ModelsExistTest, self).setUp()
1440
1441 def test_model_names_none(self, mock_list_models):
1442 mock_list_models.return_value = []
1443 with self.assertRaises(Exception):
1444 self.loop.run_until_complete(self.libjuju.models_exist(None))
1445
1446 def test_model_names_empty(self, mock_list_models):
1447 mock_list_models.return_value = []
1448 with self.assertRaises(Exception):
1449 (exist, non_existing_models) = self.loop.run_until_complete(
1450 self.libjuju.models_exist([])
1451 )
1452
1453 def test_model_names_not_existing(self, mock_list_models):
1454 mock_list_models.return_value = ["prometheus", "grafana"]
1455 (exist, non_existing_models) = self.loop.run_until_complete(
1456 self.libjuju.models_exist(["prometheus2", "grafana"])
1457 )
1458 self.assertFalse(exist)
1459 self.assertEqual(non_existing_models, ["prometheus2"])
1460
1461 def test_model_names_exist(self, mock_list_models):
1462 mock_list_models.return_value = ["prometheus", "grafana"]
1463 (exist, non_existing_models) = self.loop.run_until_complete(
1464 self.libjuju.models_exist(["prometheus", "grafana"])
1465 )
1466 self.assertTrue(exist)
1467 self.assertEqual(non_existing_models, [])
1468
1469
1470 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1471 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1472 @asynctest.mock.patch("juju.controller.Controller.list_offers")
1473 class ListOffers(LibjujuTestCase):
1474 def setUp(self):
1475 super(ListOffers, self).setUp()
1476
1477 def test_disconnect_controller(
1478 self,
1479 mock_list_offers,
1480 mock_disconnect_controller,
1481 mock_get_controller,
1482 ):
1483 mock_get_controller.return_value = juju.controller.Controller()
1484 mock_list_offers.side_effect = Exception()
1485 with self.assertRaises(Exception):
1486 self.loop.run_until_complete(self.libjuju._list_offers("model"))
1487 mock_disconnect_controller.assert_called_once()
1488
1489 def test_empty_list(
1490 self,
1491 mock_list_offers,
1492 mock_disconnect_controller,
1493 mock_get_controller,
1494 ):
1495 mock_get_controller.return_value = juju.controller.Controller()
1496 offer_results = Mock()
1497 offer_results.results = []
1498 mock_list_offers.return_value = offer_results
1499 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
1500 self.assertEqual(offers, [])
1501 mock_disconnect_controller.assert_called_once()
1502
1503 def test_non_empty_list(
1504 self,
1505 mock_list_offers,
1506 mock_disconnect_controller,
1507 mock_get_controller,
1508 ):
1509 mock_get_controller.return_value = juju.controller.Controller()
1510 offer = Mock()
1511 offer_results = Mock()
1512 offer_results.results = [offer]
1513 mock_list_offers.return_value = offer_results
1514 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
1515 self.assertEqual(offers, [offer])
1516 mock_disconnect_controller.assert_called_once()
1517
1518 def test_matching_offer_name(
1519 self,
1520 mock_list_offers,
1521 mock_disconnect_controller,
1522 mock_get_controller,
1523 ):
1524 mock_get_controller.return_value = juju.controller.Controller()
1525 offer_1 = Mock()
1526 offer_1.offer_name = "offer1"
1527 offer_2 = Mock()
1528 offer_2.offer_name = "offer2"
1529 offer_results = Mock()
1530 offer_results.results = [offer_1, offer_2]
1531 mock_list_offers.return_value = offer_results
1532 offers = self.loop.run_until_complete(
1533 self.libjuju._list_offers("model", offer_name="offer2")
1534 )
1535 self.assertEqual(offers, [offer_2])
1536 mock_disconnect_controller.assert_called_once()
1537
1538 def test_not_matching_offer_name(
1539 self,
1540 mock_list_offers,
1541 mock_disconnect_controller,
1542 mock_get_controller,
1543 ):
1544 mock_get_controller.return_value = juju.controller.Controller()
1545 offer_1 = Mock()
1546 offer_1.offer_name = "offer1"
1547 offer_2 = Mock()
1548 offer_2.offer_name = "offer2"
1549 offer_results = Mock()
1550 offer_results.results = [offer_1, offer_2]
1551 mock_list_offers.return_value = offer_results
1552 offers = self.loop.run_until_complete(
1553 self.libjuju._list_offers("model", offer_name="offer3")
1554 )
1555 self.assertEqual(offers, [])
1556 mock_disconnect_controller.assert_called_once()
1557
1558
1559 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1560 @asynctest.mock.patch("juju.controller.Controller.get_model")
1561 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1562 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1563 @asynctest.mock.patch("n2vc.libjuju.Libjuju._list_offers")
1564 @asynctest.mock.patch("juju.model.Model.create_offer")
1565 class OfferTest(LibjujuTestCase):
1566 def setUp(self):
1567 super(OfferTest, self).setUp()
1568
1569 def test_offer(
1570 self,
1571 mock_create_offer,
1572 mock__list_offers,
1573 mock_disconnect_controller,
1574 mock_disconnect_model,
1575 mock_get_model,
1576 mock_get_controller,
1577 ):
1578 controller = juju.controller.Controller()
1579 model = juju.model.Model()
1580 mock_get_controller.return_value = controller
1581 mock_get_model.return_value = model
1582 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1583 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1584 mock_create_offer.assert_called_with(
1585 "app-name:endpoint", offer_name="app-name-endpoint"
1586 )
1587 mock_disconnect_model.assert_called_once_with(model)
1588 mock_disconnect_controller.assert_called_once_with(controller)
1589
1590 def test_offer_exception(
1591 self,
1592 mock_create_offer,
1593 mock__list_offers,
1594 mock_disconnect_controller,
1595 mock_disconnect_model,
1596 mock_get_model,
1597 mock_get_controller,
1598 ):
1599 controller = juju.controller.Controller()
1600 model = juju.model.Model()
1601 mock_get_controller.return_value = controller
1602 mock_get_model.return_value = model
1603 mock__list_offers.return_value = []
1604 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1605 with self.assertRaises(Exception):
1606 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1607 mock_create_offer.assert_called_with(
1608 "app-name:endpoint", offer_name="app-name-endpoint"
1609 )
1610 mock_disconnect_model.assert_called_once_with(model)
1611 mock_disconnect_controller.assert_called_once_with(controller)
1612
1613
1614 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1615 @asynctest.mock.patch("juju.controller.Controller.get_model")
1616 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1617 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1618 @asynctest.mock.patch("juju.model.Model.consume")
1619 class ConsumeTest(LibjujuTestCase):
1620 def setUp(self):
1621 self.offer_url = "admin/model.offer_name"
1622 super(ConsumeTest, self).setUp()
1623 self.provider_libjuju = self.libjuju
1624
1625 def test_consume(
1626 self,
1627 mock_consume,
1628 mock_disconnect_controller,
1629 mock_disconnect_model,
1630 mock_get_model,
1631 mock_get_controller,
1632 ):
1633 self_controller = juju.controller.Controller()
1634 provider_controller = juju.controller.Controller()
1635 mock_get_controller.side_effect = [self_controller, provider_controller]
1636 mock_get_model.return_value = juju.model.Model()
1637
1638 self.loop.run_until_complete(
1639 self.libjuju.consume(
1640 "model_name",
1641 Offer(self.offer_url, vca_id="vca-id"),
1642 self.provider_libjuju,
1643 )
1644 )
1645 mock_consume.assert_called_once_with(
1646 "admin/model.offer_name",
1647 application_alias="offer_name-model-vca-id",
1648 controller=provider_controller,
1649 )
1650 mock_disconnect_model.assert_called_once()
1651 self.assertEqual(mock_disconnect_controller.call_count, 2)
1652
1653 def test_parsing_error_exception(
1654 self,
1655 mock_consume,
1656 mock_disconnect_controller,
1657 mock_disconnect_model,
1658 mock_get_model,
1659 mock_get_controller,
1660 ):
1661 mock_get_controller.return_value = juju.controller.Controller()
1662 mock_get_model.return_value = juju.model.Model()
1663 mock_consume.side_effect = juju.offerendpoints.ParseError("")
1664
1665 with self.assertRaises(juju.offerendpoints.ParseError):
1666 self.loop.run_until_complete(
1667 self.libjuju.consume(
1668 "model_name", Offer(self.offer_url), self.provider_libjuju
1669 )
1670 )
1671 mock_consume.assert_called_once()
1672 mock_disconnect_model.assert_called_once()
1673 self.assertEqual(mock_disconnect_controller.call_count, 2)
1674
1675 def test_juju_error_exception(
1676 self,
1677 mock_consume,
1678 mock_disconnect_controller,
1679 mock_disconnect_model,
1680 mock_get_model,
1681 mock_get_controller,
1682 ):
1683 mock_get_controller.return_value = juju.controller.Controller()
1684 mock_get_model.return_value = juju.model.Model()
1685 mock_consume.side_effect = juju.errors.JujuError("")
1686
1687 with self.assertRaises(juju.errors.JujuError):
1688 self.loop.run_until_complete(
1689 self.libjuju.consume(
1690 "model_name", Offer(self.offer_url), self.provider_libjuju
1691 )
1692 )
1693 mock_consume.assert_called_once()
1694 mock_disconnect_model.assert_called_once()
1695 self.assertEqual(mock_disconnect_controller.call_count, 2)
1696
1697 def test_juju_api_error_exception(
1698 self,
1699 mock_consume,
1700 mock_disconnect_controller,
1701 mock_disconnect_model,
1702 mock_get_model,
1703 mock_get_controller,
1704 ):
1705 mock_get_controller.return_value = juju.controller.Controller()
1706 mock_get_model.return_value = juju.model.Model()
1707 mock_consume.side_effect = juju.errors.JujuAPIError(
1708 {"error": "", "response": "", "request-id": ""}
1709 )
1710
1711 with self.assertRaises(juju.errors.JujuAPIError):
1712 self.loop.run_until_complete(
1713 self.libjuju.consume(
1714 "model_name", Offer(self.offer_url), self.provider_libjuju
1715 )
1716 )
1717 mock_consume.assert_called_once()
1718 mock_disconnect_model.assert_called_once()
1719 self.assertEqual(mock_disconnect_controller.call_count, 2)
1720
1721
1722 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
1723 @asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
1724 class AddK8sTest(LibjujuTestCase):
1725 def setUp(self):
1726 super(AddK8sTest, self).setUp()
1727 name = "cloud"
1728 rbac_id = generate_rbac_id()
1729 token = "token"
1730 client_cert_data = "cert"
1731 configuration = kubernetes.client.configuration.Configuration()
1732 storage_class = "storage_class"
1733 credential_name = name
1734
1735 self._add_k8s_args = {
1736 "name": name,
1737 "rbac_id": rbac_id,
1738 "token": token,
1739 "client_cert_data": client_cert_data,
1740 "configuration": configuration,
1741 "storage_class": storage_class,
1742 "credential_name": credential_name,
1743 }
1744
1745 def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
1746 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1747 mock_add_cloud.assert_called_once()
1748 mock_get_k8s_cloud_credential.assert_called_once()
1749
1750 def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
1751 mock_add_cloud.side_effect = Exception()
1752 with self.assertRaises(Exception):
1753 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1754 mock_add_cloud.assert_called_once()
1755 mock_get_k8s_cloud_credential.assert_called_once()
1756
1757 def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
1758 self._add_k8s_args["name"] = ""
1759 with self.assertRaises(Exception):
1760 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1761 mock_add_cloud.assert_not_called()
1762
1763 def test_add_k8s_missing_storage_name(
1764 self, mock_add_cloud, mock_get_k8s_cloud_credential
1765 ):
1766 self._add_k8s_args["storage_class"] = ""
1767 with self.assertRaises(Exception):
1768 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1769 mock_add_cloud.assert_not_called()
1770
1771 def test_add_k8s_missing_configuration_keys(
1772 self, mock_add_cloud, mock_get_k8s_cloud_credential
1773 ):
1774 self._add_k8s_args["configuration"] = None
1775 with self.assertRaises(Exception):
1776 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1777 mock_add_cloud.assert_not_called()
1778
1779
1780 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1781 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1782 @asynctest.mock.patch("juju.controller.Controller.add_cloud")
1783 @asynctest.mock.patch("juju.controller.Controller.add_credential")
1784 class AddCloudTest(LibjujuTestCase):
1785 def setUp(self):
1786 super(AddCloudTest, self).setUp()
1787 self.cloud = juju.client.client.Cloud()
1788 self.credential = juju.client.client.CloudCredential()
1789
1790 def test_add_cloud_with_credential(
1791 self,
1792 mock_add_credential,
1793 mock_add_cloud,
1794 mock_disconnect_controller,
1795 mock_get_controller,
1796 ):
1797 mock_get_controller.return_value = juju.controller.Controller()
1798
1799 cloud = self.loop.run_until_complete(
1800 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1801 )
1802 self.assertEqual(cloud, self.cloud)
1803 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1804 mock_add_credential.assert_called_once_with(
1805 "cloud", credential=self.credential, cloud="cloud"
1806 )
1807 mock_disconnect_controller.assert_called_once()
1808
1809 def test_add_cloud_no_credential(
1810 self,
1811 mock_add_credential,
1812 mock_add_cloud,
1813 mock_disconnect_controller,
1814 mock_get_controller,
1815 ):
1816 mock_get_controller.return_value = juju.controller.Controller()
1817
1818 cloud = self.loop.run_until_complete(
1819 self.libjuju.add_cloud("cloud", self.cloud)
1820 )
1821 self.assertEqual(cloud, self.cloud)
1822 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1823 mock_add_credential.assert_not_called()
1824 mock_disconnect_controller.assert_called_once()
1825
1826 def test_add_cloud_exception(
1827 self,
1828 mock_add_credential,
1829 mock_add_cloud,
1830 mock_disconnect_controller,
1831 mock_get_controller,
1832 ):
1833 mock_get_controller.return_value = juju.controller.Controller()
1834 mock_add_cloud.side_effect = Exception()
1835 with self.assertRaises(Exception):
1836 self.loop.run_until_complete(
1837 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1838 )
1839
1840 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1841 mock_add_credential.assert_not_called()
1842 mock_disconnect_controller.assert_called_once()
1843
1844 def test_add_credential_exception(
1845 self,
1846 mock_add_credential,
1847 mock_add_cloud,
1848 mock_disconnect_controller,
1849 mock_get_controller,
1850 ):
1851 mock_get_controller.return_value = juju.controller.Controller()
1852 mock_add_credential.side_effect = Exception()
1853 with self.assertRaises(Exception):
1854 self.loop.run_until_complete(
1855 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1856 )
1857
1858 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1859 mock_add_credential.assert_called_once_with(
1860 "cloud", credential=self.credential, cloud="cloud"
1861 )
1862 mock_disconnect_controller.assert_called_once()
1863
1864
1865 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1866 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1867 @asynctest.mock.patch("juju.controller.Controller.remove_cloud")
1868 class RemoveCloudTest(LibjujuTestCase):
1869 def setUp(self):
1870 super(RemoveCloudTest, self).setUp()
1871
1872 def test_remove_cloud(
1873 self,
1874 mock_remove_cloud,
1875 mock_disconnect_controller,
1876 mock_get_controller,
1877 ):
1878 mock_get_controller.return_value = juju.controller.Controller()
1879
1880 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1881 mock_remove_cloud.assert_called_once_with("cloud")
1882 mock_disconnect_controller.assert_called_once()
1883
1884 def test_remove_cloud_exception(
1885 self,
1886 mock_remove_cloud,
1887 mock_disconnect_controller,
1888 mock_get_controller,
1889 ):
1890 mock_get_controller.return_value = juju.controller.Controller()
1891 mock_remove_cloud.side_effect = Exception()
1892
1893 with self.assertRaises(Exception):
1894 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1895 mock_remove_cloud.assert_called_once_with("cloud")
1896 mock_disconnect_controller.assert_called_once()
1897
1898
1899 @asynctest.mock.patch("kubernetes.client.configuration.Configuration")
1900 class GetK8sCloudCredentials(LibjujuTestCase):
1901 def setUp(self):
1902 super(GetK8sCloudCredentials, self).setUp()
1903 self.cert_data = "cert"
1904 self.token = "token"
1905
1906 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1907 def test_not_supported(self, mock_exception, mock_configuration):
1908 mock_configuration.username = ""
1909 mock_configuration.password = ""
1910 mock_configuration.ssl_ca_cert = None
1911 mock_configuration.cert_file = None
1912 mock_configuration.key_file = None
1913 exception_raised = False
1914 self.token = None
1915 self.cert_data = None
1916 try:
1917 _ = self.libjuju.get_k8s_cloud_credential(
1918 mock_configuration,
1919 self.cert_data,
1920 self.token,
1921 )
1922 except JujuInvalidK8sConfiguration as e:
1923 exception_raised = True
1924 self.assertEqual(
1925 e.message,
1926 "authentication method not supported",
1927 )
1928 self.assertTrue(exception_raised)
1929
1930 def test_user_pass(self, mock_configuration):
1931 mock_configuration.username = "admin"
1932 mock_configuration.password = "admin"
1933 mock_configuration.ssl_ca_cert = None
1934 mock_configuration.cert_file = None
1935 mock_configuration.key_file = None
1936 self.token = None
1937 self.cert_data = None
1938 credential = self.libjuju.get_k8s_cloud_credential(
1939 mock_configuration,
1940 self.cert_data,
1941 self.token,
1942 )
1943 self.assertEqual(
1944 credential,
1945 juju.client._definitions.CloudCredential(
1946 attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
1947 ),
1948 )
1949
1950 def test_user_pass_with_cert(self, mock_configuration):
1951 mock_configuration.username = "admin"
1952 mock_configuration.password = "admin"
1953 mock_configuration.ssl_ca_cert = None
1954 mock_configuration.cert_file = None
1955 mock_configuration.key_file = None
1956 self.token = None
1957 credential = self.libjuju.get_k8s_cloud_credential(
1958 mock_configuration,
1959 self.cert_data,
1960 self.token,
1961 )
1962 self.assertEqual(
1963 credential,
1964 juju.client._definitions.CloudCredential(
1965 attrs={
1966 "ClientCertificateData": self.cert_data,
1967 "username": "admin",
1968 "password": "admin",
1969 },
1970 auth_type="userpasswithcert",
1971 ),
1972 )
1973
1974 def test_user_no_pass(self, mock_configuration):
1975 mock_configuration.username = "admin"
1976 mock_configuration.password = ""
1977 mock_configuration.ssl_ca_cert = None
1978 mock_configuration.cert_file = None
1979 mock_configuration.key_file = None
1980 self.token = None
1981 self.cert_data = None
1982 with patch.object(self.libjuju.log, "debug") as mock_debug:
1983 credential = self.libjuju.get_k8s_cloud_credential(
1984 mock_configuration,
1985 self.cert_data,
1986 self.token,
1987 )
1988 self.assertEqual(
1989 credential,
1990 juju.client._definitions.CloudCredential(
1991 attrs={"username": "admin", "password": ""}, auth_type="userpass"
1992 ),
1993 )
1994 mock_debug.assert_called_once_with(
1995 "credential for user admin has empty password"
1996 )
1997
1998 def test_cert(self, mock_configuration):
1999 mock_configuration.username = ""
2000 mock_configuration.password = ""
2001 mock_configuration.api_key = {"authorization": "Bearer Token"}
2002 ssl_ca_cert = tempfile.NamedTemporaryFile()
2003 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
2004 ssl_ca_cert_file.write("cacert")
2005 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
2006 mock_configuration.cert_file = None
2007 mock_configuration.key_file = None
2008 credential = self.libjuju.get_k8s_cloud_credential(
2009 mock_configuration,
2010 self.cert_data,
2011 self.token,
2012 )
2013 self.assertEqual(
2014 credential,
2015 juju.client._definitions.CloudCredential(
2016 attrs={"ClientCertificateData": self.cert_data, "Token": self.token},
2017 auth_type="certificate",
2018 ),
2019 )
2020
2021 # TODO: Fix this test when oauth authentication is supported
2022 # def test_oauth2(self, mock_configuration):
2023 # mock_configuration.username = ""
2024 # mock_configuration.password = ""
2025 # mock_configuration.api_key = {"authorization": "Bearer Token"}
2026 # key = tempfile.NamedTemporaryFile()
2027 # with open(key.name, "w") as key_file:
2028 # key_file.write("key")
2029 # mock_configuration.ssl_ca_cert = None
2030 # mock_configuration.cert_file = None
2031 # mock_configuration.key_file = key.name
2032 # credential = self.libjuju.get_k8s_cloud_credential(
2033 # mock_configuration,
2034 # self.cert_data,
2035 # self.token,
2036 # )
2037 # self.assertEqual(
2038 # credential,
2039 # juju.client._definitions.CloudCredential(
2040 # attrs={"ClientKeyData": "key", "Token": "Token"},
2041 # auth_type="oauth2",
2042 # ),
2043 # )
2044
2045 # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
2046 # def test_oauth2_missing_token(self, mock_exception, mock_configuration):
2047 # mock_configuration.username = ""
2048 # mock_configuration.password = ""
2049 # key = tempfile.NamedTemporaryFile()
2050 # with open(key.name, "w") as key_file:
2051 # key_file.write("key")
2052 # mock_configuration.ssl_ca_cert = None
2053 # mock_configuration.cert_file = None
2054 # mock_configuration.key_file = key.name
2055 # exception_raised = False
2056 # try:
2057 # _ = self.libjuju.get_k8s_cloud_credential(
2058 # mock_configuration,
2059 # self.cert_data,
2060 # self.token,
2061 # )
2062 # except JujuInvalidK8sConfiguration as e:
2063 # exception_raised = True
2064 # self.assertEqual(
2065 # e.message,
2066 # "missing token for auth type oauth2",
2067 # )
2068 # self.assertTrue(exception_raised)
2069
2070 def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
2071 mock_configuration.username = "admin"
2072 mock_configuration.password = "pass"
2073 mock_configuration.api_key = {"authorization": "No_bearer_token"}
2074 mock_configuration.ssl_ca_cert = None
2075 mock_configuration.cert_file = None
2076 mock_configuration.key_file = None
2077 exception_raised = False
2078 try:
2079 _ = self.libjuju.get_k8s_cloud_credential(
2080 mock_configuration,
2081 self.cert_data,
2082 self.token,
2083 )
2084 except JujuInvalidK8sConfiguration as e:
2085 exception_raised = True
2086 self.assertEqual(
2087 e.message,
2088 "Cannot set both token and user/pass",
2089 )
2090 self.assertTrue(exception_raised)
2091
2092
2093 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2094 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2095 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2096 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2097 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2098 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
2099 class ScaleApplicationTest(LibjujuTestCase):
2100 def setUp(self):
2101 super(ScaleApplicationTest, self).setUp()
2102
2103 @asynctest.mock.patch("asyncio.sleep")
2104 def test_scale_application(
2105 self,
2106 mock_sleep,
2107 mock_wait_for_model,
2108 mock_disconnect_controller,
2109 mock_disconnect_model,
2110 mock_get_application,
2111 mock_get_model,
2112 mock_get_controller,
2113 ):
2114 mock_get_model.return_value = juju.model.Model()
2115 mock_get_application.return_value = FakeApplication()
2116 self.loop.run_until_complete(self.libjuju.scale_application("model", "app", 2))
2117 mock_wait_for_model.assert_called_once()
2118 mock_disconnect_controller.assert_called_once()
2119 mock_disconnect_model.assert_called_once()
2120
2121 def test_no_application(
2122 self,
2123 mock_wait_for,
2124 mock_disconnect_controller,
2125 mock_disconnect_model,
2126 mock_get_application,
2127 mock_get_model,
2128 mock_get_controller,
2129 ):
2130 mock_get_application.return_value = None
2131 mock_get_model.return_value = juju.model.Model()
2132 with self.assertRaises(JujuApplicationNotFound):
2133 self.loop.run_until_complete(
2134 self.libjuju.scale_application("model", "app", 2)
2135 )
2136 mock_disconnect_controller.assert_called()
2137 mock_disconnect_model.assert_called()
2138
2139 def test_exception(
2140 self,
2141 mock_wait_for,
2142 mock_disconnect_controller,
2143 mock_disconnect_model,
2144 mock_get_application,
2145 mock_get_model,
2146 mock_get_controller,
2147 ):
2148 mock_get_model.return_value = None
2149 mock_get_application.return_value = FakeApplication()
2150 with self.assertRaises(Exception):
2151 self.loop.run_until_complete(
2152 self.libjuju.scale_application("model", "app", 2, total_timeout=0)
2153 )
2154 mock_disconnect_controller.assert_called_once()
2155
2156
2157 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2158 class GetUnitNumberTest(LibjujuTestCase):
2159 def setUp(self):
2160 super(GetUnitNumberTest, self).setUp()
2161
2162 def test_successful_get_unit_number(
2163 self,
2164 mock_get_applications,
2165 ):
2166 mock_get_applications.return_value = FakeApplication()
2167 model = juju.model.Model()
2168 result = self.libjuju._get_application_count(model, "app")
2169 self.assertEqual(result, 2)
2170
2171 def test_non_existing_application(
2172 self,
2173 mock_get_applications,
2174 ):
2175 mock_get_applications.return_value = None
2176 model = juju.model.Model()
2177 result = self.libjuju._get_application_count(model, "app")
2178 self.assertEqual(result, None)
2179
2180
2181 @asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
2182 class GetMachineInfoTest(LibjujuTestCase):
2183 def setUp(self):
2184 super(GetMachineInfoTest, self).setUp()
2185
2186 def test_successful(
2187 self,
2188 mock_machines,
2189 ):
2190 machine_id = "existing_machine"
2191 model = juju.model.Model()
2192 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2193 machine, series = self.libjuju._get_machine_info(
2194 machine_id=machine_id,
2195 model=model,
2196 )
2197 self.assertIsNotNone(machine, series)
2198
2199 def test_exception(
2200 self,
2201 mock_machines,
2202 ):
2203 machine_id = "not_existing_machine"
2204 machine = series = None
2205 model = juju.model.Model()
2206 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2207 with self.assertRaises(JujuMachineNotFound):
2208 machine, series = self.libjuju._get_machine_info(
2209 machine_id=machine_id,
2210 model=model,
2211 )
2212 self.assertIsNone(machine, series)
2213
2214
2215 class GetUnitTest(LibjujuTestCase):
2216 def setUp(self):
2217 super(GetUnitTest, self).setUp()
2218
2219 def test_successful(self):
2220 result = self.libjuju._get_unit(FakeApplication(), "existing_machine_id")
2221 self.assertIsInstance(result, FakeUnit)
2222
2223 def test_return_none(self):
2224 result = self.libjuju._get_unit(FakeApplication(), "not_existing_machine_id")
2225 self.assertIsNone(result)
2226
2227
2228 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2229 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2230 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2231 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2232 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2233 class CheckApplicationExists(LibjujuTestCase):
2234 def setUp(self):
2235 super(CheckApplicationExists, self).setUp()
2236
2237 def test_successful(
2238 self,
2239 mock_get_application,
2240 mock_disconnect_controller,
2241 mock_disconnect_model,
2242 mock_get_model,
2243 mock_get_controller,
2244 ):
2245 mock_get_model.return_value = juju.model.Model()
2246 mock_get_application.return_value = FakeApplication()
2247 result = self.loop.run_until_complete(
2248 self.libjuju.check_application_exists(
2249 "model",
2250 "app",
2251 )
2252 )
2253 self.assertEqual(result, True)
2254
2255 mock_get_application.assert_called_once()
2256 mock_get_controller.assert_called_once()
2257 mock_get_model.assert_called_once()
2258 mock_disconnect_controller.assert_called_once()
2259 mock_disconnect_model.assert_called_once()
2260
2261 def test_no_application(
2262 self,
2263 mock_get_application,
2264 mock_disconnect_controller,
2265 mock_disconnect_model,
2266 mock_get_model,
2267 mock_get_controller,
2268 ):
2269 mock_get_model.return_value = juju.model.Model()
2270 mock_get_application.return_value = None
2271 result = self.loop.run_until_complete(
2272 self.libjuju.check_application_exists(
2273 "model",
2274 "app",
2275 )
2276 )
2277 self.assertEqual(result, False)
2278
2279 mock_get_application.assert_called_once()
2280 mock_get_controller.assert_called_once()
2281 mock_get_model.assert_called_once()
2282 mock_disconnect_controller.assert_called_once()
2283 mock_disconnect_model.assert_called_once()
2284
2285
2286 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2287 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2288 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2289 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2290 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2291 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_machine_info")
2292 class AddUnitTest(LibjujuTestCase):
2293 def setUp(self):
2294 super(AddUnitTest, self).setUp()
2295
2296 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
2297 @asynctest.mock.patch("asyncio.sleep")
2298 def test_successful(
2299 self,
2300 mock_sleep,
2301 mock_wait_for,
2302 mock_get_machine_info,
2303 mock_get_application,
2304 mock_disconnect_controller,
2305 mock_disconnect_model,
2306 mock_get_model,
2307 mock_get_controller,
2308 ):
2309 mock_get_model.return_value = juju.model.Model()
2310 mock_get_application.return_value = FakeApplication()
2311 mock_get_machine_info.return_value = FakeMachine(), "series"
2312 self.loop.run_until_complete(
2313 self.libjuju.add_unit(
2314 "existing_app",
2315 "model",
2316 "machine",
2317 )
2318 )
2319
2320 mock_wait_for.assert_called_once()
2321 mock_get_application.assert_called_once()
2322 mock_get_controller.assert_called_once()
2323 mock_get_model.assert_called_once()
2324 mock_disconnect_controller.assert_called_once()
2325 mock_disconnect_model.assert_called_once()
2326
2327 def test_no_app(
2328 self,
2329 mock_get_machine_info,
2330 mock_get_application,
2331 mock_disconnect_controller,
2332 mock_disconnect_model,
2333 mock_get_model,
2334 mock_get_controller,
2335 ):
2336 mock_get_model.return_value = juju.model.Model()
2337 mock_get_application.return_value = None
2338 with self.assertRaises(JujuApplicationNotFound):
2339 self.loop.run_until_complete(
2340 self.libjuju.add_unit(
2341 "existing_app",
2342 "model",
2343 "machine",
2344 )
2345 )
2346
2347 mock_get_application.assert_called_once()
2348 mock_get_controller.assert_called_once()
2349 mock_get_model.assert_called_once()
2350 mock_disconnect_controller.assert_called_once()
2351 mock_disconnect_model.assert_called_once()
2352
2353 def test_no_machine(
2354 self,
2355 mock_get_machine_info,
2356 mock_get_application,
2357 mock_disconnect_controller,
2358 mock_disconnect_model,
2359 mock_get_model,
2360 mock_get_controller,
2361 ):
2362 mock_get_model.return_value = juju.model.Model()
2363 mock_get_application.return_value = FakeApplication()
2364 mock_get_machine_info.side_effect = JujuMachineNotFound()
2365 with self.assertRaises(JujuMachineNotFound):
2366 self.loop.run_until_complete(
2367 self.libjuju.add_unit(
2368 "existing_app",
2369 "model",
2370 "machine",
2371 )
2372 )
2373
2374 mock_get_application.assert_called_once()
2375 mock_get_controller.assert_called_once()
2376 mock_get_model.assert_called_once()
2377 mock_disconnect_controller.assert_called_once()
2378 mock_disconnect_model.assert_called_once()
2379
2380
2381 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2382 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2383 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2384 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2385 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2386 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_unit")
2387 class DestroyUnitTest(LibjujuTestCase):
2388 def setUp(self):
2389 super(DestroyUnitTest, self).setUp()
2390
2391 @asynctest.mock.patch("asyncio.sleep")
2392 def test_successful(
2393 self,
2394 mock_sleep,
2395 mock_get_unit,
2396 mock_get_application,
2397 mock_disconnect_controller,
2398 mock_disconnect_model,
2399 mock_get_model,
2400 mock_get_controller,
2401 ):
2402 mock_get_model.return_value = juju.model.Model()
2403 mock_get_application.return_value = FakeApplication()
2404
2405 self.loop.run_until_complete(
2406 self.libjuju.destroy_unit("app", "model", "machine", 0)
2407 )
2408
2409 mock_get_unit.assert_called()
2410 mock_get_application.assert_called_once()
2411 mock_get_controller.assert_called_once()
2412 mock_get_model.assert_called_once()
2413 mock_disconnect_controller.assert_called_once()
2414 mock_disconnect_model.assert_called_once()
2415
2416 def test_no_app(
2417 self,
2418 mock_get_unit,
2419 mock_get_application,
2420 mock_disconnect_controller,
2421 mock_disconnect_model,
2422 mock_get_model,
2423 mock_get_controller,
2424 ):
2425 mock_get_model.return_value = juju.model.Model()
2426 mock_get_application.return_value = None
2427
2428 with self.assertRaises(JujuApplicationNotFound):
2429 self.loop.run_until_complete(
2430 self.libjuju.destroy_unit("app", "model", "machine")
2431 )
2432
2433 mock_get_application.assert_called_once()
2434 mock_get_controller.assert_called_once()
2435 mock_get_model.assert_called_once()
2436 mock_disconnect_controller.assert_called_once()
2437 mock_disconnect_model.assert_called_once()
2438
2439 def test_no_unit(
2440 self,
2441 mock_get_unit,
2442 mock_get_application,
2443 mock_disconnect_controller,
2444 mock_disconnect_model,
2445 mock_get_model,
2446 mock_get_controller,
2447 ):
2448 mock_get_model.return_value = juju.model.Model()
2449 mock_get_application.return_value = FakeApplication()
2450 mock_get_unit.return_value = None
2451
2452 with self.assertRaises(JujuError):
2453 self.loop.run_until_complete(
2454 self.libjuju.destroy_unit("app", "model", "machine")
2455 )
2456
2457 mock_get_unit.assert_called_once()
2458 mock_get_application.assert_called_once()
2459 mock_get_controller.assert_called_once()
2460 mock_get_model.assert_called_once()
2461 mock_disconnect_controller.assert_called_once()
2462 mock_disconnect_model.assert_called_once()