Fix black errors
[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 mock_get_model.return_value = juju.model.Model()
782 mock__get_application.return_value = FakeApplication()
783 output = None
784 status = None
785 with self.assertRaises(JujuActionNotFound):
786 output, status = self.loop.run_until_complete(
787 self.libjuju.execute_action(
788 "app",
789 "model",
790 "action",
791 )
792 )
793 self.assertIsNone(output)
794 self.assertIsNone(status)
795
796 mock_disconnect_controller.assert_called()
797 mock_disconnect_model.assert_called()
798
799 @asynctest.mock.patch("asyncio.sleep")
800 @asynctest.mock.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
801 def test_no_leader(
802 self,
803 mock_is_leader_from_status,
804 mock_sleep,
805 mock_get_action_status,
806 mock_get_action_output,
807 mock_wait_for,
808 mock__get_application,
809 mock_disconnect_controller,
810 mock_disconnect_model,
811 mock_get_model,
812 mock_get_controller,
813 ):
814 mock_get_model.return_value = juju.model.Model()
815 mock__get_application.return_value = FakeApplication()
816 mock_is_leader_from_status.return_value = False
817 output = None
818 status = None
819 with self.assertRaises(JujuLeaderUnitNotFound):
820 output, status = self.loop.run_until_complete(
821 self.libjuju.execute_action(
822 "app",
823 "model",
824 "action",
825 )
826 )
827 self.assertIsNone(output)
828 self.assertIsNone(status)
829
830 mock_disconnect_controller.assert_called()
831 mock_disconnect_model.assert_called()
832
833 def test_successful_exec(
834 self,
835 mock_get_action_status,
836 mock_get_action_output,
837 mock_wait_for,
838 mock__get_application,
839 mock_disconnect_controller,
840 mock_disconnect_model,
841 mock_get_model,
842 mock_get_controller,
843 ):
844 mock_get_model.return_value = juju.model.Model()
845 mock__get_application.return_value = FakeApplication()
846 mock_get_action_output.return_value = "output"
847 mock_get_action_status.return_value = {"id": "status"}
848 output, status = self.loop.run_until_complete(
849 self.libjuju.execute_action("app", "model", "existing_action")
850 )
851 self.assertEqual(output, "output")
852 self.assertEqual(status, "status")
853
854 mock_wait_for.assert_called_once()
855
856 mock_disconnect_controller.assert_called()
857 mock_disconnect_model.assert_called()
858
859
860 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
861 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
862 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
863 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
864 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
865 class GetActionTest(LibjujuTestCase):
866 def setUp(self):
867 super(GetActionTest, self).setUp()
868
869 def test_exception(
870 self,
871 mock_get_application,
872 mock_disconnect_controller,
873 mock_disconnect_model,
874 mock_get_model,
875 mock_get_controller,
876 ):
877 mock_get_application.side_effect = Exception()
878 actions = None
879 with self.assertRaises(Exception):
880 actions = self.loop.run_until_complete(
881 self.libjuju.get_actions("app", "model")
882 )
883
884 self.assertIsNone(actions)
885 mock_disconnect_controller.assert_called_once()
886 mock_disconnect_model.assert_called_once()
887
888 def test_success(
889 self,
890 mock_get_application,
891 mock_disconnect_controller,
892 mock_disconnect_model,
893 mock_get_model,
894 mock_get_controller,
895 ):
896 mock_get_application.return_value = FakeApplication()
897
898 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
899
900 self.assertEqual(actions, ["existing_action"])
901
902 mock_get_controller.assert_called_once()
903 mock_get_model.assert_called_once()
904 mock_disconnect_controller.assert_called_once()
905 mock_disconnect_model.assert_called_once()
906
907
908 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
909 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
910 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
911 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
912 @asynctest.mock.patch("juju.application.Application.get_metrics")
913 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
914 class GetMetricsTest(LibjujuTestCase):
915 def setUp(self):
916 super(GetMetricsTest, self).setUp()
917
918 def test_get_metrics_success(
919 self,
920 mock_get_application,
921 mock_get_metrics,
922 mock_disconnect_controller,
923 mock_disconnect_model,
924 mock_get_model,
925 mock_get_controller,
926 ):
927 mock_get_application.return_value = FakeApplication()
928 mock_get_model.return_value = juju.model.Model()
929
930 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
931
932 mock_disconnect_controller.assert_called_once()
933 mock_disconnect_model.assert_called_once()
934
935 def test_get_metrics_exception(
936 self,
937 mock_get_application,
938 mock_get_metrics,
939 mock_disconnect_controller,
940 mock_disconnect_model,
941 mock_get_model,
942 mock_get_controller,
943 ):
944 mock_get_model.return_value = juju.model.Model()
945 mock_get_metrics.side_effect = Exception()
946 with self.assertRaises(Exception):
947 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
948
949 mock_disconnect_controller.assert_called_once()
950 mock_disconnect_model.assert_called_once()
951
952 def test_missing_args_exception(
953 self,
954 mock_get_application,
955 mock_get_metrics,
956 mock_disconnect_controller,
957 mock_disconnect_model,
958 mock_get_model,
959 mock_get_controller,
960 ):
961 mock_get_model.return_value = juju.model.Model()
962
963 with self.assertRaises(Exception):
964 self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
965
966 mock_get_controller.assert_not_called()
967 mock_get_model.assert_not_called()
968 mock_disconnect_controller.assert_not_called()
969 mock_disconnect_model.assert_not_called()
970
971
972 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
973 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
974 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
975 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
976 @asynctest.mock.patch("juju.model.Model.add_relation")
977 class AddRelationTest(LibjujuTestCase):
978 def setUp(self):
979 super(AddRelationTest, self).setUp()
980
981 @asynctest.mock.patch("logging.Logger.warning")
982 def test_not_found(
983 self,
984 mock_warning,
985 mock_add_relation,
986 mock_disconnect_controller,
987 mock_disconnect_model,
988 mock_get_model,
989 mock_get_controller,
990 ):
991 # TODO in libjuju.py should this fail only with a log message?
992 result = {"error": "not found", "response": "response", "request-id": 1}
993
994 mock_get_model.return_value = juju.model.Model()
995 mock_add_relation.side_effect = JujuAPIError(result)
996
997 self.loop.run_until_complete(
998 self.libjuju.add_relation(
999 "model",
1000 "app1:relation1",
1001 "app2:relation2",
1002 )
1003 )
1004
1005 mock_warning.assert_called_with("Relation not found: not found")
1006 mock_disconnect_controller.assert_called_once()
1007 mock_disconnect_model.assert_called_once()
1008
1009 @asynctest.mock.patch("logging.Logger.warning")
1010 def test_already_exists(
1011 self,
1012 mock_warning,
1013 mock_add_relation,
1014 mock_disconnect_controller,
1015 mock_disconnect_model,
1016 mock_get_model,
1017 mock_get_controller,
1018 ):
1019 # TODO in libjuju.py should this fail silently?
1020 result = {"error": "already exists", "response": "response", "request-id": 1}
1021
1022 mock_get_model.return_value = juju.model.Model()
1023 mock_add_relation.side_effect = JujuAPIError(result)
1024
1025 self.loop.run_until_complete(
1026 self.libjuju.add_relation(
1027 "model",
1028 "app1:relation1",
1029 "app2:relation2",
1030 )
1031 )
1032
1033 mock_warning.assert_called_with("Relation already exists: already exists")
1034 mock_disconnect_controller.assert_called_once()
1035 mock_disconnect_model.assert_called_once()
1036
1037 def test_exception(
1038 self,
1039 mock_add_relation,
1040 mock_disconnect_controller,
1041 mock_disconnect_model,
1042 mock_get_model,
1043 mock_get_controller,
1044 ):
1045 mock_get_model.return_value = juju.model.Model()
1046 result = {"error": "", "response": "response", "request-id": 1}
1047 mock_add_relation.side_effect = JujuAPIError(result)
1048
1049 with self.assertRaises(JujuAPIError):
1050 self.loop.run_until_complete(
1051 self.libjuju.add_relation(
1052 "model",
1053 "app1:relation1",
1054 "app2:relation2",
1055 )
1056 )
1057
1058 mock_disconnect_controller.assert_called_once()
1059 mock_disconnect_model.assert_called_once()
1060
1061 def test_success(
1062 self,
1063 mock_add_relation,
1064 mock_disconnect_controller,
1065 mock_disconnect_model,
1066 mock_get_model,
1067 mock_get_controller,
1068 ):
1069 mock_get_model.return_value = juju.model.Model()
1070
1071 self.loop.run_until_complete(
1072 self.libjuju.add_relation(
1073 "model",
1074 "app1:relation1",
1075 "app2:relation2",
1076 )
1077 )
1078
1079 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
1080 mock_disconnect_controller.assert_called_once()
1081 mock_disconnect_model.assert_called_once()
1082
1083 def test_saas(
1084 self,
1085 mock_add_relation,
1086 mock_disconnect_controller,
1087 mock_disconnect_model,
1088 mock_get_model,
1089 mock_get_controller,
1090 ):
1091 mock_get_model.return_value = juju.model.Model()
1092
1093 self.loop.run_until_complete(
1094 self.libjuju.add_relation(
1095 "model",
1096 "app1:relation1",
1097 "saas_name",
1098 )
1099 )
1100
1101 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
1102 mock_disconnect_controller.assert_called_once()
1103 mock_disconnect_model.assert_called_once()
1104
1105
1106 # TODO destroy_model testcase
1107
1108
1109 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1110 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1111 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1112 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1113 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1114 class DestroyApplicationTest(LibjujuTestCase):
1115 def setUp(self):
1116 super(DestroyApplicationTest, self).setUp()
1117
1118 def test_success(
1119 self,
1120 mock_get_controller,
1121 mock_get_model,
1122 mock_disconnect_controller,
1123 mock_get_application,
1124 mock_disconnect_model,
1125 ):
1126 mock_get_application.return_value = FakeApplication()
1127 mock_get_model.return_value = None
1128 self.loop.run_until_complete(
1129 self.libjuju.destroy_application(
1130 "existing_model",
1131 "existing_app",
1132 3600,
1133 )
1134 )
1135 mock_get_application.assert_called()
1136 mock_disconnect_controller.assert_called_once()
1137 mock_disconnect_model.assert_called_once()
1138
1139 def test_no_application(
1140 self,
1141 mock_get_controller,
1142 mock_get_model,
1143 mock_disconnect_controller,
1144 mock_get_application,
1145 mock_disconnect_model,
1146 ):
1147 mock_get_model.return_value = None
1148 mock_get_application.return_value = None
1149
1150 self.loop.run_until_complete(
1151 self.libjuju.destroy_application(
1152 "existing_model",
1153 "existing_app",
1154 3600,
1155 )
1156 )
1157 mock_get_application.assert_called()
1158
1159 def test_exception(
1160 self,
1161 mock_get_controller,
1162 mock_get_model,
1163 mock_disconnect_controller,
1164 mock_get_application,
1165 mock_disconnect_model,
1166 ):
1167 mock_get_application.return_value = FakeApplication
1168 mock_get_model.return_value = None
1169
1170 with self.assertRaises(Exception):
1171 self.loop.run_until_complete(
1172 self.libjuju.destroy_application(
1173 "existing_model",
1174 "existing_app",
1175 0,
1176 )
1177 )
1178 mock_get_application.assert_called_once()
1179
1180
1181 # @asynctest.mock.patch("juju.model.Model.get_machines")
1182 # @asynctest.mock.patch("logging.Logger.debug")
1183 # class DestroyMachineTest(LibjujuTestCase):
1184 # def setUp(self):
1185 # super(DestroyMachineTest, self).setUp()
1186
1187 # def test_success_manual_machine(
1188 # self, mock_debug, mock_get_machines,
1189 # ):
1190 # mock_get_machines.side_effect = [
1191 # {"machine": FakeManualMachine()},
1192 # {"machine": FakeManualMachine()},
1193 # {},
1194 # ]
1195 # self.loop.run_until_complete(
1196 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
1197 # )
1198 # calls = [
1199 # asynctest.call("Waiting for machine machine is destroyed"),
1200 # asynctest.call("Machine destroyed: machine"),
1201 # ]
1202 # mock_debug.assert_has_calls(calls)
1203
1204 # def test_no_machine(
1205 # self, mock_debug, mock_get_machines,
1206 # ):
1207 # mock_get_machines.return_value = {}
1208 # self.loop.run_until_complete(
1209 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
1210 # )
1211 # mock_debug.assert_called_with("Machine not found: machine")
1212
1213
1214 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1215 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1216 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1217 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1218 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1219 class ConfigureApplicationTest(LibjujuTestCase):
1220 def setUp(self):
1221 super(ConfigureApplicationTest, self).setUp()
1222
1223 def test_success(
1224 self,
1225 mock_get_application,
1226 mock_disconnect_controller,
1227 mock_disconnect_model,
1228 mock_get_model,
1229 mock_get_controller,
1230 ):
1231 mock_get_application.return_value = FakeApplication()
1232
1233 self.loop.run_until_complete(
1234 self.libjuju.configure_application(
1235 "model",
1236 "app",
1237 {"config"},
1238 )
1239 )
1240 mock_get_application.assert_called_once()
1241 mock_disconnect_controller.assert_called_once()
1242 mock_disconnect_model.assert_called_once()
1243
1244 def test_exception(
1245 self,
1246 mock_get_application,
1247 mock_disconnect_controller,
1248 mock_disconnect_model,
1249 mock_get_model,
1250 mock_get_controller,
1251 ):
1252 mock_get_application.side_effect = Exception()
1253
1254 with self.assertRaises(Exception):
1255 self.loop.run_until_complete(
1256 self.libjuju.configure_application(
1257 "model",
1258 "app",
1259 {"config"},
1260 )
1261 )
1262 mock_disconnect_controller.assert_called_once()
1263 mock_disconnect_model.assert_called_once()
1264
1265 def test_controller_exception(
1266 self,
1267 mock_get_application,
1268 mock_disconnect_controller,
1269 mock_disconnect_model,
1270 mock_get_model,
1271 mock_get_controller,
1272 ):
1273 result = {"error": "not found", "response": "response", "request-id": 1}
1274
1275 mock_get_controller.side_effect = JujuAPIError(result)
1276
1277 with self.assertRaises(JujuAPIError):
1278 self.loop.run_until_complete(
1279 self.libjuju.configure_application(
1280 "model",
1281 "app",
1282 {"config"},
1283 )
1284 )
1285 mock_get_model.assert_not_called()
1286 mock_disconnect_controller.assert_not_called()
1287 mock_disconnect_model.assert_not_called()
1288
1289 def test_get_model_exception(
1290 self,
1291 mock_get_application,
1292 mock_disconnect_controller,
1293 mock_disconnect_model,
1294 mock_get_model,
1295 mock_get_controller,
1296 ):
1297 result = {"error": "not found", "response": "response", "request-id": 1}
1298 mock_get_model.side_effect = JujuAPIError(result)
1299
1300 with self.assertRaises(JujuAPIError):
1301 self.loop.run_until_complete(
1302 self.libjuju.configure_application(
1303 "model",
1304 "app",
1305 {"config"},
1306 )
1307 )
1308 mock_get_model.assert_called_once()
1309 mock_disconnect_controller.assert_called_once()
1310 mock_disconnect_model.assert_not_called()
1311
1312
1313 # TODO _get_api_endpoints_db test case
1314 # TODO _update_api_endpoints_db test case
1315 # TODO healthcheck test case
1316
1317
1318 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1319 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1320 @asynctest.mock.patch("juju.controller.Controller.list_models")
1321 class ListModelsTest(LibjujuTestCase):
1322 def setUp(self):
1323 super(ListModelsTest, self).setUp()
1324
1325 def test_containing(
1326 self,
1327 mock_list_models,
1328 mock_disconnect_controller,
1329 mock_get_controller,
1330 ):
1331 mock_get_controller.return_value = juju.controller.Controller()
1332 mock_list_models.return_value = ["existingmodel"]
1333 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
1334
1335 mock_disconnect_controller.assert_called_once()
1336 self.assertEquals(models, ["existingmodel"])
1337
1338 def test_not_containing(
1339 self,
1340 mock_list_models,
1341 mock_disconnect_controller,
1342 mock_get_controller,
1343 ):
1344 mock_get_controller.return_value = juju.controller.Controller()
1345 mock_list_models.return_value = ["existingmodel", "model"]
1346 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
1347
1348 mock_disconnect_controller.assert_called_once()
1349 self.assertEquals(models, [])
1350
1351 def test_no_contains_arg(
1352 self,
1353 mock_list_models,
1354 mock_disconnect_controller,
1355 mock_get_controller,
1356 ):
1357 mock_get_controller.return_value = juju.controller.Controller()
1358 mock_list_models.return_value = ["existingmodel", "model"]
1359 models = self.loop.run_until_complete(self.libjuju.list_models())
1360
1361 mock_disconnect_controller.assert_called_once()
1362 self.assertEquals(models, ["existingmodel", "model"])
1363
1364
1365 @asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
1366 class ModelsExistTest(LibjujuTestCase):
1367 def setUp(self):
1368 super(ModelsExistTest, self).setUp()
1369
1370 def test_model_names_none(self, mock_list_models):
1371 mock_list_models.return_value = []
1372 with self.assertRaises(Exception):
1373 self.loop.run_until_complete(self.libjuju.models_exist(None))
1374
1375 def test_model_names_empty(self, mock_list_models):
1376 mock_list_models.return_value = []
1377 with self.assertRaises(Exception):
1378 (exist, non_existing_models) = self.loop.run_until_complete(
1379 self.libjuju.models_exist([])
1380 )
1381
1382 def test_model_names_not_existing(self, mock_list_models):
1383 mock_list_models.return_value = ["prometheus", "grafana"]
1384 (exist, non_existing_models) = self.loop.run_until_complete(
1385 self.libjuju.models_exist(["prometheus2", "grafana"])
1386 )
1387 self.assertFalse(exist)
1388 self.assertEqual(non_existing_models, ["prometheus2"])
1389
1390 def test_model_names_exist(self, mock_list_models):
1391 mock_list_models.return_value = ["prometheus", "grafana"]
1392 (exist, non_existing_models) = self.loop.run_until_complete(
1393 self.libjuju.models_exist(["prometheus", "grafana"])
1394 )
1395 self.assertTrue(exist)
1396 self.assertEqual(non_existing_models, [])
1397
1398
1399 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1400 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1401 @asynctest.mock.patch("juju.controller.Controller.list_offers")
1402 class ListOffers(LibjujuTestCase):
1403 def setUp(self):
1404 super(ListOffers, self).setUp()
1405
1406 def test_disconnect_controller(
1407 self,
1408 mock_list_offers,
1409 mock_disconnect_controller,
1410 mock_get_controller,
1411 ):
1412 mock_get_controller.return_value = juju.controller.Controller()
1413 mock_list_offers.side_effect = Exception()
1414 with self.assertRaises(Exception):
1415 self.loop.run_until_complete(self.libjuju._list_offers("model"))
1416 mock_disconnect_controller.assert_called_once()
1417
1418 def test_empty_list(
1419 self,
1420 mock_list_offers,
1421 mock_disconnect_controller,
1422 mock_get_controller,
1423 ):
1424 mock_get_controller.return_value = juju.controller.Controller()
1425 offer_results = Mock()
1426 offer_results.results = []
1427 mock_list_offers.return_value = offer_results
1428 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
1429 self.assertEqual(offers, [])
1430 mock_disconnect_controller.assert_called_once()
1431
1432 def test_non_empty_list(
1433 self,
1434 mock_list_offers,
1435 mock_disconnect_controller,
1436 mock_get_controller,
1437 ):
1438 mock_get_controller.return_value = juju.controller.Controller()
1439 offer = Mock()
1440 offer_results = Mock()
1441 offer_results.results = [offer]
1442 mock_list_offers.return_value = offer_results
1443 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
1444 self.assertEqual(offers, [offer])
1445 mock_disconnect_controller.assert_called_once()
1446
1447 def test_matching_offer_name(
1448 self,
1449 mock_list_offers,
1450 mock_disconnect_controller,
1451 mock_get_controller,
1452 ):
1453 mock_get_controller.return_value = juju.controller.Controller()
1454 offer_1 = Mock()
1455 offer_1.offer_name = "offer1"
1456 offer_2 = Mock()
1457 offer_2.offer_name = "offer2"
1458 offer_results = Mock()
1459 offer_results.results = [offer_1, offer_2]
1460 mock_list_offers.return_value = offer_results
1461 offers = self.loop.run_until_complete(
1462 self.libjuju._list_offers("model", offer_name="offer2")
1463 )
1464 self.assertEqual(offers, [offer_2])
1465 mock_disconnect_controller.assert_called_once()
1466
1467 def test_not_matching_offer_name(
1468 self,
1469 mock_list_offers,
1470 mock_disconnect_controller,
1471 mock_get_controller,
1472 ):
1473 mock_get_controller.return_value = juju.controller.Controller()
1474 offer_1 = Mock()
1475 offer_1.offer_name = "offer1"
1476 offer_2 = Mock()
1477 offer_2.offer_name = "offer2"
1478 offer_results = Mock()
1479 offer_results.results = [offer_1, offer_2]
1480 mock_list_offers.return_value = offer_results
1481 offers = self.loop.run_until_complete(
1482 self.libjuju._list_offers("model", offer_name="offer3")
1483 )
1484 self.assertEqual(offers, [])
1485 mock_disconnect_controller.assert_called_once()
1486
1487
1488 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1489 @asynctest.mock.patch("juju.controller.Controller.get_model")
1490 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1491 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1492 @asynctest.mock.patch("n2vc.libjuju.Libjuju._list_offers")
1493 @asynctest.mock.patch("juju.model.Model.create_offer")
1494 class OfferTest(LibjujuTestCase):
1495 def setUp(self):
1496 super(OfferTest, self).setUp()
1497
1498 def test_offer(
1499 self,
1500 mock_create_offer,
1501 mock__list_offers,
1502 mock_disconnect_controller,
1503 mock_disconnect_model,
1504 mock_get_model,
1505 mock_get_controller,
1506 ):
1507 controller = juju.controller.Controller()
1508 model = juju.model.Model()
1509 mock_get_controller.return_value = controller
1510 mock_get_model.return_value = model
1511 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1512 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1513 mock_create_offer.assert_called_with(
1514 "app-name:endpoint", offer_name="app-name-endpoint"
1515 )
1516 mock_disconnect_model.assert_called_once_with(model)
1517 mock_disconnect_controller.assert_called_once_with(controller)
1518
1519 def test_offer_exception(
1520 self,
1521 mock_create_offer,
1522 mock__list_offers,
1523 mock_disconnect_controller,
1524 mock_disconnect_model,
1525 mock_get_model,
1526 mock_get_controller,
1527 ):
1528 controller = juju.controller.Controller()
1529 model = juju.model.Model()
1530 mock_get_controller.return_value = controller
1531 mock_get_model.return_value = model
1532 mock__list_offers.return_value = []
1533 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1534 with self.assertRaises(Exception):
1535 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1536 mock_create_offer.assert_called_with(
1537 "app-name:endpoint", offer_name="app-name-endpoint"
1538 )
1539 mock_disconnect_model.assert_called_once_with(model)
1540 mock_disconnect_controller.assert_called_once_with(controller)
1541
1542
1543 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1544 @asynctest.mock.patch("juju.controller.Controller.get_model")
1545 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1546 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1547 @asynctest.mock.patch("juju.model.Model.consume")
1548 class ConsumeTest(LibjujuTestCase):
1549 def setUp(self):
1550 self.offer_url = "admin/model.offer_name"
1551 super(ConsumeTest, self).setUp()
1552 self.provider_libjuju = self.libjuju
1553
1554 def test_consume(
1555 self,
1556 mock_consume,
1557 mock_disconnect_controller,
1558 mock_disconnect_model,
1559 mock_get_model,
1560 mock_get_controller,
1561 ):
1562 self_controller = juju.controller.Controller()
1563 provider_controller = juju.controller.Controller()
1564 mock_get_controller.side_effect = [self_controller, provider_controller]
1565 mock_get_model.return_value = juju.model.Model()
1566
1567 self.loop.run_until_complete(
1568 self.libjuju.consume(
1569 "model_name",
1570 Offer(self.offer_url, vca_id="vca-id"),
1571 self.provider_libjuju,
1572 )
1573 )
1574 mock_consume.assert_called_once_with(
1575 "admin/model.offer_name",
1576 application_alias="offer_name-model-vca-id",
1577 controller=provider_controller,
1578 )
1579 mock_disconnect_model.assert_called_once()
1580 self.assertEqual(mock_disconnect_controller.call_count, 2)
1581
1582 def test_parsing_error_exception(
1583 self,
1584 mock_consume,
1585 mock_disconnect_controller,
1586 mock_disconnect_model,
1587 mock_get_model,
1588 mock_get_controller,
1589 ):
1590 mock_get_controller.return_value = juju.controller.Controller()
1591 mock_get_model.return_value = juju.model.Model()
1592 mock_consume.side_effect = juju.offerendpoints.ParseError("")
1593
1594 with self.assertRaises(juju.offerendpoints.ParseError):
1595 self.loop.run_until_complete(
1596 self.libjuju.consume(
1597 "model_name", Offer(self.offer_url), self.provider_libjuju
1598 )
1599 )
1600 mock_consume.assert_called_once()
1601 mock_disconnect_model.assert_called_once()
1602 self.assertEqual(mock_disconnect_controller.call_count, 2)
1603
1604 def test_juju_error_exception(
1605 self,
1606 mock_consume,
1607 mock_disconnect_controller,
1608 mock_disconnect_model,
1609 mock_get_model,
1610 mock_get_controller,
1611 ):
1612 mock_get_controller.return_value = juju.controller.Controller()
1613 mock_get_model.return_value = juju.model.Model()
1614 mock_consume.side_effect = juju.errors.JujuError("")
1615
1616 with self.assertRaises(juju.errors.JujuError):
1617 self.loop.run_until_complete(
1618 self.libjuju.consume(
1619 "model_name", Offer(self.offer_url), self.provider_libjuju
1620 )
1621 )
1622 mock_consume.assert_called_once()
1623 mock_disconnect_model.assert_called_once()
1624 self.assertEqual(mock_disconnect_controller.call_count, 2)
1625
1626 def test_juju_api_error_exception(
1627 self,
1628 mock_consume,
1629 mock_disconnect_controller,
1630 mock_disconnect_model,
1631 mock_get_model,
1632 mock_get_controller,
1633 ):
1634 mock_get_controller.return_value = juju.controller.Controller()
1635 mock_get_model.return_value = juju.model.Model()
1636 mock_consume.side_effect = juju.errors.JujuAPIError(
1637 {"error": "", "response": "", "request-id": ""}
1638 )
1639
1640 with self.assertRaises(juju.errors.JujuAPIError):
1641 self.loop.run_until_complete(
1642 self.libjuju.consume(
1643 "model_name", Offer(self.offer_url), self.provider_libjuju
1644 )
1645 )
1646 mock_consume.assert_called_once()
1647 mock_disconnect_model.assert_called_once()
1648 self.assertEqual(mock_disconnect_controller.call_count, 2)
1649
1650
1651 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
1652 @asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
1653 class AddK8sTest(LibjujuTestCase):
1654 def setUp(self):
1655 super(AddK8sTest, self).setUp()
1656 name = "cloud"
1657 rbac_id = generate_rbac_id()
1658 token = "token"
1659 client_cert_data = "cert"
1660 configuration = kubernetes.client.configuration.Configuration()
1661 storage_class = "storage_class"
1662 credential_name = name
1663
1664 self._add_k8s_args = {
1665 "name": name,
1666 "rbac_id": rbac_id,
1667 "token": token,
1668 "client_cert_data": client_cert_data,
1669 "configuration": configuration,
1670 "storage_class": storage_class,
1671 "credential_name": credential_name,
1672 }
1673
1674 def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
1675 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1676 mock_add_cloud.assert_called_once()
1677 mock_get_k8s_cloud_credential.assert_called_once()
1678
1679 def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
1680 mock_add_cloud.side_effect = Exception()
1681 with self.assertRaises(Exception):
1682 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1683 mock_add_cloud.assert_called_once()
1684 mock_get_k8s_cloud_credential.assert_called_once()
1685
1686 def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
1687 self._add_k8s_args["name"] = ""
1688 with self.assertRaises(Exception):
1689 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1690 mock_add_cloud.assert_not_called()
1691
1692 def test_add_k8s_missing_storage_name(
1693 self, mock_add_cloud, mock_get_k8s_cloud_credential
1694 ):
1695 self._add_k8s_args["storage_class"] = ""
1696 with self.assertRaises(Exception):
1697 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1698 mock_add_cloud.assert_not_called()
1699
1700 def test_add_k8s_missing_configuration_keys(
1701 self, mock_add_cloud, mock_get_k8s_cloud_credential
1702 ):
1703 self._add_k8s_args["configuration"] = None
1704 with self.assertRaises(Exception):
1705 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
1706 mock_add_cloud.assert_not_called()
1707
1708
1709 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1710 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1711 @asynctest.mock.patch("juju.controller.Controller.add_cloud")
1712 @asynctest.mock.patch("juju.controller.Controller.add_credential")
1713 class AddCloudTest(LibjujuTestCase):
1714 def setUp(self):
1715 super(AddCloudTest, self).setUp()
1716 self.cloud = juju.client.client.Cloud()
1717 self.credential = juju.client.client.CloudCredential()
1718
1719 def test_add_cloud_with_credential(
1720 self,
1721 mock_add_credential,
1722 mock_add_cloud,
1723 mock_disconnect_controller,
1724 mock_get_controller,
1725 ):
1726 mock_get_controller.return_value = juju.controller.Controller()
1727
1728 cloud = self.loop.run_until_complete(
1729 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1730 )
1731 self.assertEqual(cloud, self.cloud)
1732 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1733 mock_add_credential.assert_called_once_with(
1734 "cloud", credential=self.credential, cloud="cloud"
1735 )
1736 mock_disconnect_controller.assert_called_once()
1737
1738 def test_add_cloud_no_credential(
1739 self,
1740 mock_add_credential,
1741 mock_add_cloud,
1742 mock_disconnect_controller,
1743 mock_get_controller,
1744 ):
1745 mock_get_controller.return_value = juju.controller.Controller()
1746
1747 cloud = self.loop.run_until_complete(
1748 self.libjuju.add_cloud("cloud", self.cloud)
1749 )
1750 self.assertEqual(cloud, self.cloud)
1751 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1752 mock_add_credential.assert_not_called()
1753 mock_disconnect_controller.assert_called_once()
1754
1755 def test_add_cloud_exception(
1756 self,
1757 mock_add_credential,
1758 mock_add_cloud,
1759 mock_disconnect_controller,
1760 mock_get_controller,
1761 ):
1762 mock_get_controller.return_value = juju.controller.Controller()
1763 mock_add_cloud.side_effect = Exception()
1764 with self.assertRaises(Exception):
1765 self.loop.run_until_complete(
1766 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1767 )
1768
1769 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1770 mock_add_credential.assert_not_called()
1771 mock_disconnect_controller.assert_called_once()
1772
1773 def test_add_credential_exception(
1774 self,
1775 mock_add_credential,
1776 mock_add_cloud,
1777 mock_disconnect_controller,
1778 mock_get_controller,
1779 ):
1780 mock_get_controller.return_value = juju.controller.Controller()
1781 mock_add_credential.side_effect = Exception()
1782 with self.assertRaises(Exception):
1783 self.loop.run_until_complete(
1784 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1785 )
1786
1787 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1788 mock_add_credential.assert_called_once_with(
1789 "cloud", credential=self.credential, cloud="cloud"
1790 )
1791 mock_disconnect_controller.assert_called_once()
1792
1793
1794 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1795 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1796 @asynctest.mock.patch("juju.controller.Controller.remove_cloud")
1797 class RemoveCloudTest(LibjujuTestCase):
1798 def setUp(self):
1799 super(RemoveCloudTest, self).setUp()
1800
1801 def test_remove_cloud(
1802 self,
1803 mock_remove_cloud,
1804 mock_disconnect_controller,
1805 mock_get_controller,
1806 ):
1807 mock_get_controller.return_value = juju.controller.Controller()
1808
1809 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1810 mock_remove_cloud.assert_called_once_with("cloud")
1811 mock_disconnect_controller.assert_called_once()
1812
1813 def test_remove_cloud_exception(
1814 self,
1815 mock_remove_cloud,
1816 mock_disconnect_controller,
1817 mock_get_controller,
1818 ):
1819 mock_get_controller.return_value = juju.controller.Controller()
1820 mock_remove_cloud.side_effect = Exception()
1821
1822 with self.assertRaises(Exception):
1823 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1824 mock_remove_cloud.assert_called_once_with("cloud")
1825 mock_disconnect_controller.assert_called_once()
1826
1827
1828 @asynctest.mock.patch("kubernetes.client.configuration.Configuration")
1829 class GetK8sCloudCredentials(LibjujuTestCase):
1830 def setUp(self):
1831 super(GetK8sCloudCredentials, self).setUp()
1832 self.cert_data = "cert"
1833 self.token = "token"
1834
1835 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1836 def test_not_supported(self, mock_exception, mock_configuration):
1837 mock_configuration.username = ""
1838 mock_configuration.password = ""
1839 mock_configuration.ssl_ca_cert = None
1840 mock_configuration.cert_file = None
1841 mock_configuration.key_file = None
1842 exception_raised = False
1843 self.token = None
1844 self.cert_data = None
1845 try:
1846 _ = self.libjuju.get_k8s_cloud_credential(
1847 mock_configuration,
1848 self.cert_data,
1849 self.token,
1850 )
1851 except JujuInvalidK8sConfiguration as e:
1852 exception_raised = True
1853 self.assertEqual(
1854 e.message,
1855 "authentication method not supported",
1856 )
1857 self.assertTrue(exception_raised)
1858
1859 def test_user_pass(self, mock_configuration):
1860 mock_configuration.username = "admin"
1861 mock_configuration.password = "admin"
1862 mock_configuration.ssl_ca_cert = None
1863 mock_configuration.cert_file = None
1864 mock_configuration.key_file = None
1865 self.token = None
1866 self.cert_data = None
1867 credential = self.libjuju.get_k8s_cloud_credential(
1868 mock_configuration,
1869 self.cert_data,
1870 self.token,
1871 )
1872 self.assertEqual(
1873 credential,
1874 juju.client._definitions.CloudCredential(
1875 attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
1876 ),
1877 )
1878
1879 def test_user_pass_with_cert(self, mock_configuration):
1880 mock_configuration.username = "admin"
1881 mock_configuration.password = "admin"
1882 mock_configuration.ssl_ca_cert = None
1883 mock_configuration.cert_file = None
1884 mock_configuration.key_file = None
1885 self.token = None
1886 credential = self.libjuju.get_k8s_cloud_credential(
1887 mock_configuration,
1888 self.cert_data,
1889 self.token,
1890 )
1891 self.assertEqual(
1892 credential,
1893 juju.client._definitions.CloudCredential(
1894 attrs={
1895 "ClientCertificateData": self.cert_data,
1896 "username": "admin",
1897 "password": "admin",
1898 },
1899 auth_type="userpasswithcert",
1900 ),
1901 )
1902
1903 def test_user_no_pass(self, mock_configuration):
1904 mock_configuration.username = "admin"
1905 mock_configuration.password = ""
1906 mock_configuration.ssl_ca_cert = None
1907 mock_configuration.cert_file = None
1908 mock_configuration.key_file = None
1909 self.token = None
1910 self.cert_data = None
1911 with patch.object(self.libjuju.log, "debug") as mock_debug:
1912 credential = self.libjuju.get_k8s_cloud_credential(
1913 mock_configuration,
1914 self.cert_data,
1915 self.token,
1916 )
1917 self.assertEqual(
1918 credential,
1919 juju.client._definitions.CloudCredential(
1920 attrs={"username": "admin", "password": ""}, auth_type="userpass"
1921 ),
1922 )
1923 mock_debug.assert_called_once_with(
1924 "credential for user admin has empty password"
1925 )
1926
1927 def test_cert(self, mock_configuration):
1928 mock_configuration.username = ""
1929 mock_configuration.password = ""
1930 mock_configuration.api_key = {"authorization": "Bearer Token"}
1931 ssl_ca_cert = tempfile.NamedTemporaryFile()
1932 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
1933 ssl_ca_cert_file.write("cacert")
1934 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
1935 mock_configuration.cert_file = None
1936 mock_configuration.key_file = None
1937 credential = self.libjuju.get_k8s_cloud_credential(
1938 mock_configuration,
1939 self.cert_data,
1940 self.token,
1941 )
1942 self.assertEqual(
1943 credential,
1944 juju.client._definitions.CloudCredential(
1945 attrs={"ClientCertificateData": self.cert_data, "Token": self.token},
1946 auth_type="certificate",
1947 ),
1948 )
1949
1950 # TODO: Fix this test when oauth authentication is supported
1951 # def test_oauth2(self, mock_configuration):
1952 # mock_configuration.username = ""
1953 # mock_configuration.password = ""
1954 # mock_configuration.api_key = {"authorization": "Bearer Token"}
1955 # key = tempfile.NamedTemporaryFile()
1956 # with open(key.name, "w") as key_file:
1957 # key_file.write("key")
1958 # mock_configuration.ssl_ca_cert = None
1959 # mock_configuration.cert_file = None
1960 # mock_configuration.key_file = key.name
1961 # credential = self.libjuju.get_k8s_cloud_credential(
1962 # mock_configuration,
1963 # self.cert_data,
1964 # self.token,
1965 # )
1966 # self.assertEqual(
1967 # credential,
1968 # juju.client._definitions.CloudCredential(
1969 # attrs={"ClientKeyData": "key", "Token": "Token"},
1970 # auth_type="oauth2",
1971 # ),
1972 # )
1973
1974 # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1975 # def test_oauth2_missing_token(self, mock_exception, mock_configuration):
1976 # mock_configuration.username = ""
1977 # mock_configuration.password = ""
1978 # key = tempfile.NamedTemporaryFile()
1979 # with open(key.name, "w") as key_file:
1980 # key_file.write("key")
1981 # mock_configuration.ssl_ca_cert = None
1982 # mock_configuration.cert_file = None
1983 # mock_configuration.key_file = key.name
1984 # exception_raised = False
1985 # try:
1986 # _ = self.libjuju.get_k8s_cloud_credential(
1987 # mock_configuration,
1988 # self.cert_data,
1989 # self.token,
1990 # )
1991 # except JujuInvalidK8sConfiguration as e:
1992 # exception_raised = True
1993 # self.assertEqual(
1994 # e.message,
1995 # "missing token for auth type oauth2",
1996 # )
1997 # self.assertTrue(exception_raised)
1998
1999 def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
2000 mock_configuration.username = "admin"
2001 mock_configuration.password = "pass"
2002 mock_configuration.api_key = {"authorization": "No_bearer_token"}
2003 mock_configuration.ssl_ca_cert = None
2004 mock_configuration.cert_file = None
2005 mock_configuration.key_file = None
2006 exception_raised = False
2007 try:
2008 _ = self.libjuju.get_k8s_cloud_credential(
2009 mock_configuration,
2010 self.cert_data,
2011 self.token,
2012 )
2013 except JujuInvalidK8sConfiguration as e:
2014 exception_raised = True
2015 self.assertEqual(
2016 e.message,
2017 "Cannot set both token and user/pass",
2018 )
2019 self.assertTrue(exception_raised)
2020
2021
2022 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2023 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2024 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2025 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2026 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2027 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
2028 class ScaleApplicationTest(LibjujuTestCase):
2029 def setUp(self):
2030 super(ScaleApplicationTest, self).setUp()
2031
2032 @asynctest.mock.patch("asyncio.sleep")
2033 def test_scale_application(
2034 self,
2035 mock_sleep,
2036 mock_wait_for_model,
2037 mock_disconnect_controller,
2038 mock_disconnect_model,
2039 mock_get_application,
2040 mock_get_model,
2041 mock_get_controller,
2042 ):
2043 mock_get_model.return_value = juju.model.Model()
2044 mock_get_application.return_value = FakeApplication()
2045 self.loop.run_until_complete(self.libjuju.scale_application("model", "app", 2))
2046 mock_wait_for_model.assert_called_once()
2047 mock_disconnect_controller.assert_called_once()
2048 mock_disconnect_model.assert_called_once()
2049
2050 def test_no_application(
2051 self,
2052 mock_wait_for,
2053 mock_disconnect_controller,
2054 mock_disconnect_model,
2055 mock_get_application,
2056 mock_get_model,
2057 mock_get_controller,
2058 ):
2059 mock_get_application.return_value = None
2060 mock_get_model.return_value = juju.model.Model()
2061 with self.assertRaises(JujuApplicationNotFound):
2062 self.loop.run_until_complete(
2063 self.libjuju.scale_application("model", "app", 2)
2064 )
2065 mock_disconnect_controller.assert_called()
2066 mock_disconnect_model.assert_called()
2067
2068 def test_exception(
2069 self,
2070 mock_wait_for,
2071 mock_disconnect_controller,
2072 mock_disconnect_model,
2073 mock_get_application,
2074 mock_get_model,
2075 mock_get_controller,
2076 ):
2077 mock_get_model.return_value = None
2078 mock_get_application.return_value = FakeApplication()
2079 with self.assertRaises(Exception):
2080 self.loop.run_until_complete(
2081 self.libjuju.scale_application("model", "app", 2, total_timeout=0)
2082 )
2083 mock_disconnect_controller.assert_called_once()
2084
2085
2086 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2087 class GetUnitNumberTest(LibjujuTestCase):
2088 def setUp(self):
2089 super(GetUnitNumberTest, self).setUp()
2090
2091 def test_successful_get_unit_number(
2092 self,
2093 mock_get_applications,
2094 ):
2095 mock_get_applications.return_value = FakeApplication()
2096 model = juju.model.Model()
2097 result = self.libjuju._get_application_count(model, "app")
2098 self.assertEqual(result, 2)
2099
2100 def test_non_existing_application(
2101 self,
2102 mock_get_applications,
2103 ):
2104 mock_get_applications.return_value = None
2105 model = juju.model.Model()
2106 result = self.libjuju._get_application_count(model, "app")
2107 self.assertEqual(result, None)
2108
2109
2110 @asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
2111 class GetMachineInfoTest(LibjujuTestCase):
2112 def setUp(self):
2113 super(GetMachineInfoTest, self).setUp()
2114
2115 def test_successful(
2116 self,
2117 mock_machines,
2118 ):
2119 machine_id = "existing_machine"
2120 model = juju.model.Model()
2121 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2122 machine, series = self.libjuju._get_machine_info(
2123 machine_id=machine_id,
2124 model=model,
2125 )
2126 self.assertIsNotNone(machine, series)
2127
2128 def test_exception(
2129 self,
2130 mock_machines,
2131 ):
2132 machine_id = "not_existing_machine"
2133 machine = series = None
2134 model = juju.model.Model()
2135 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2136 with self.assertRaises(JujuMachineNotFound):
2137 machine, series = self.libjuju._get_machine_info(
2138 machine_id=machine_id,
2139 model=model,
2140 )
2141 self.assertIsNone(machine, series)
2142
2143
2144 class GetUnitTest(LibjujuTestCase):
2145 def setUp(self):
2146 super(GetUnitTest, self).setUp()
2147
2148 def test_successful(self):
2149 result = self.libjuju._get_unit(FakeApplication(), "existing_machine_id")
2150 self.assertIsInstance(result, FakeUnit)
2151
2152 def test_return_none(self):
2153 result = self.libjuju._get_unit(FakeApplication(), "not_existing_machine_id")
2154 self.assertIsNone(result)
2155
2156
2157 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2158 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2159 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2160 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2161 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2162 class CheckApplicationExists(LibjujuTestCase):
2163 def setUp(self):
2164 super(CheckApplicationExists, self).setUp()
2165
2166 def test_successful(
2167 self,
2168 mock_get_application,
2169 mock_disconnect_controller,
2170 mock_disconnect_model,
2171 mock_get_model,
2172 mock_get_controller,
2173 ):
2174 mock_get_model.return_value = juju.model.Model()
2175 mock_get_application.return_value = FakeApplication()
2176 result = self.loop.run_until_complete(
2177 self.libjuju.check_application_exists(
2178 "model",
2179 "app",
2180 )
2181 )
2182 self.assertEqual(result, True)
2183
2184 mock_get_application.assert_called_once()
2185 mock_get_controller.assert_called_once()
2186 mock_get_model.assert_called_once()
2187 mock_disconnect_controller.assert_called_once()
2188 mock_disconnect_model.assert_called_once()
2189
2190 def test_no_application(
2191 self,
2192 mock_get_application,
2193 mock_disconnect_controller,
2194 mock_disconnect_model,
2195 mock_get_model,
2196 mock_get_controller,
2197 ):
2198 mock_get_model.return_value = juju.model.Model()
2199 mock_get_application.return_value = None
2200 result = self.loop.run_until_complete(
2201 self.libjuju.check_application_exists(
2202 "model",
2203 "app",
2204 )
2205 )
2206 self.assertEqual(result, False)
2207
2208 mock_get_application.assert_called_once()
2209 mock_get_controller.assert_called_once()
2210 mock_get_model.assert_called_once()
2211 mock_disconnect_controller.assert_called_once()
2212 mock_disconnect_model.assert_called_once()
2213
2214
2215 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2216 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2217 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2218 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2219 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2220 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_machine_info")
2221 class AddUnitTest(LibjujuTestCase):
2222 def setUp(self):
2223 super(AddUnitTest, self).setUp()
2224
2225 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
2226 @asynctest.mock.patch("asyncio.sleep")
2227 def test_successful(
2228 self,
2229 mock_sleep,
2230 mock_wait_for,
2231 mock_get_machine_info,
2232 mock_get_application,
2233 mock_disconnect_controller,
2234 mock_disconnect_model,
2235 mock_get_model,
2236 mock_get_controller,
2237 ):
2238 mock_get_model.return_value = juju.model.Model()
2239 mock_get_application.return_value = FakeApplication()
2240 mock_get_machine_info.return_value = FakeMachine(), "series"
2241 self.loop.run_until_complete(
2242 self.libjuju.add_unit(
2243 "existing_app",
2244 "model",
2245 "machine",
2246 )
2247 )
2248
2249 mock_wait_for.assert_called_once()
2250 mock_get_application.assert_called_once()
2251 mock_get_controller.assert_called_once()
2252 mock_get_model.assert_called_once()
2253 mock_disconnect_controller.assert_called_once()
2254 mock_disconnect_model.assert_called_once()
2255
2256 def test_no_app(
2257 self,
2258 mock_get_machine_info,
2259 mock_get_application,
2260 mock_disconnect_controller,
2261 mock_disconnect_model,
2262 mock_get_model,
2263 mock_get_controller,
2264 ):
2265 mock_get_model.return_value = juju.model.Model()
2266 mock_get_application.return_value = None
2267 with self.assertRaises(JujuApplicationNotFound):
2268 self.loop.run_until_complete(
2269 self.libjuju.add_unit(
2270 "existing_app",
2271 "model",
2272 "machine",
2273 )
2274 )
2275
2276 mock_get_application.assert_called_once()
2277 mock_get_controller.assert_called_once()
2278 mock_get_model.assert_called_once()
2279 mock_disconnect_controller.assert_called_once()
2280 mock_disconnect_model.assert_called_once()
2281
2282 def test_no_machine(
2283 self,
2284 mock_get_machine_info,
2285 mock_get_application,
2286 mock_disconnect_controller,
2287 mock_disconnect_model,
2288 mock_get_model,
2289 mock_get_controller,
2290 ):
2291 mock_get_model.return_value = juju.model.Model()
2292 mock_get_application.return_value = FakeApplication()
2293 mock_get_machine_info.side_effect = JujuMachineNotFound()
2294 with self.assertRaises(JujuMachineNotFound):
2295 self.loop.run_until_complete(
2296 self.libjuju.add_unit(
2297 "existing_app",
2298 "model",
2299 "machine",
2300 )
2301 )
2302
2303 mock_get_application.assert_called_once()
2304 mock_get_controller.assert_called_once()
2305 mock_get_model.assert_called_once()
2306 mock_disconnect_controller.assert_called_once()
2307 mock_disconnect_model.assert_called_once()
2308
2309
2310 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2311 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2312 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2313 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2314 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2315 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_unit")
2316 class DestroyUnitTest(LibjujuTestCase):
2317 def setUp(self):
2318 super(DestroyUnitTest, self).setUp()
2319
2320 @asynctest.mock.patch("asyncio.sleep")
2321 def test_successful(
2322 self,
2323 mock_sleep,
2324 mock_get_unit,
2325 mock_get_application,
2326 mock_disconnect_controller,
2327 mock_disconnect_model,
2328 mock_get_model,
2329 mock_get_controller,
2330 ):
2331 mock_get_model.return_value = juju.model.Model()
2332 mock_get_application.return_value = FakeApplication()
2333
2334 self.loop.run_until_complete(
2335 self.libjuju.destroy_unit("app", "model", "machine", 0)
2336 )
2337
2338 mock_get_unit.assert_called()
2339 mock_get_application.assert_called_once()
2340 mock_get_controller.assert_called_once()
2341 mock_get_model.assert_called_once()
2342 mock_disconnect_controller.assert_called_once()
2343 mock_disconnect_model.assert_called_once()
2344
2345 def test_no_app(
2346 self,
2347 mock_get_unit,
2348 mock_get_application,
2349 mock_disconnect_controller,
2350 mock_disconnect_model,
2351 mock_get_model,
2352 mock_get_controller,
2353 ):
2354 mock_get_model.return_value = juju.model.Model()
2355 mock_get_application.return_value = None
2356
2357 with self.assertRaises(JujuApplicationNotFound):
2358 self.loop.run_until_complete(
2359 self.libjuju.destroy_unit("app", "model", "machine")
2360 )
2361
2362 mock_get_application.assert_called_once()
2363 mock_get_controller.assert_called_once()
2364 mock_get_model.assert_called_once()
2365 mock_disconnect_controller.assert_called_once()
2366 mock_disconnect_model.assert_called_once()
2367
2368 def test_no_unit(
2369 self,
2370 mock_get_unit,
2371 mock_get_application,
2372 mock_disconnect_controller,
2373 mock_disconnect_model,
2374 mock_get_model,
2375 mock_get_controller,
2376 ):
2377 mock_get_model.return_value = juju.model.Model()
2378 mock_get_application.return_value = FakeApplication()
2379 mock_get_unit.return_value = None
2380
2381 with self.assertRaises(JujuError):
2382 self.loop.run_until_complete(
2383 self.libjuju.destroy_unit("app", "model", "machine")
2384 )
2385
2386 mock_get_unit.assert_called_once()
2387 mock_get_application.assert_called_once()
2388 mock_get_controller.assert_called_once()
2389 mock_get_model.assert_called_once()
2390 mock_disconnect_controller.assert_called_once()
2391 mock_disconnect_model.assert_called_once()