blob: 2f9ea1ea7b3d470c2c12423ab4b6f51111fbecac [file] [log] [blame]
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +02001# 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
15import asyncio
16import asynctest
17import juju
18from juju.errors import JujuAPIError
19import logging
20from .utils import FakeN2VC, FakeMachine, FakeApplication
21from n2vc.libjuju import Libjuju
22from n2vc.exceptions import (
23 JujuControllerFailedConnecting,
24 JujuModelAlreadyExists,
25 JujuMachineNotFound,
26 JujuApplicationNotFound,
27 JujuActionNotFound,
28 JujuApplicationExists,
gsprib7620562021-02-24 05:03:17 +000029 JujuError,
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +020030)
31
32
33class LibjujuTestCase(asynctest.TestCase):
34 @asynctest.mock.patch("juju.controller.Controller.update_endpoints")
35 @asynctest.mock.patch("juju.client.connector.Connector.connect")
36 @asynctest.mock.patch("juju.controller.Controller.connection")
37 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_api_endpoints_db")
38 def setUp(
39 self,
40 mock__get_api_endpoints_db=None,
41 mock_connection=None,
42 mock_connect=None,
43 mock_update_endpoints=None,
44 ):
45 loop = asyncio.get_event_loop()
46 n2vc = FakeN2VC()
47 mock__get_api_endpoints_db.return_value = ["127.0.0.1:17070"]
48 endpoints = "127.0.0.1:17070"
49 username = "admin"
50 password = "secret"
51 cacert = """
52 -----BEGIN CERTIFICATE-----
53 SOMECERT
54 -----END CERTIFICATE-----"""
55 self.libjuju = Libjuju(
56 endpoints,
57 "192.168.0.155:17070",
58 username,
59 password,
60 cacert,
61 loop,
62 log=None,
63 db={"get_one": []},
64 n2vc=n2vc,
65 apt_mirror="192.168.0.100",
66 enable_os_upgrade=True,
67 )
68 logging.disable(logging.CRITICAL)
69 loop.run_until_complete(self.libjuju.disconnect())
70
71
72@asynctest.mock.patch("juju.controller.Controller.connect")
73@asynctest.mock.patch(
74 "juju.controller.Controller.api_endpoints",
75 new_callable=asynctest.CoroutineMock(return_value=["127.0.0.1:17070"]),
76)
77@asynctest.mock.patch("n2vc.libjuju.Libjuju._update_api_endpoints_db")
78class GetControllerTest(LibjujuTestCase):
79 def setUp(self):
80 super(GetControllerTest, self).setUp()
81
82 def test_diff_endpoint(
83 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
84 ):
85 self.libjuju.endpoints = []
86 controller = self.loop.run_until_complete(self.libjuju.get_controller())
87 mock__update_api_endpoints_db.assert_called_once_with(["127.0.0.1:17070"])
88 self.assertIsInstance(controller, juju.controller.Controller)
89
90 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
91 def test_exception(
92 self,
93 mock_disconnect_controller,
94 mock__update_api_endpoints_db,
95 mock_api_endpoints,
96 mock_connect,
97 ):
98 self.libjuju.endpoints = []
99 mock__update_api_endpoints_db.side_effect = Exception()
100 with self.assertRaises(JujuControllerFailedConnecting):
101 controller = self.loop.run_until_complete(self.libjuju.get_controller())
102 self.assertIsNone(controller)
103 mock_disconnect_controller.assert_called_once()
104
105 def test_same_endpoint_get_controller(
106 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
107 ):
108 self.libjuju.endpoints = ["127.0.0.1:17070"]
109 controller = self.loop.run_until_complete(self.libjuju.get_controller())
110 mock__update_api_endpoints_db.assert_not_called()
111 self.assertIsInstance(controller, juju.controller.Controller)
112
113
114class DisconnectTest(LibjujuTestCase):
115 def setUp(self):
116 super(DisconnectTest, self).setUp()
117
118 @asynctest.mock.patch("juju.model.Model.disconnect")
119 def test_disconnect_model(self, mock_disconnect):
120 self.loop.run_until_complete(self.libjuju.disconnect_model(juju.model.Model()))
121 mock_disconnect.assert_called_once()
122
123 @asynctest.mock.patch("juju.controller.Controller.disconnect")
124 def test_disconnect_controller(self, mock_disconnect):
125 self.loop.run_until_complete(
126 self.libjuju.disconnect_controller(juju.controller.Controller())
127 )
128 mock_disconnect.assert_called_once()
129
130
131@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
132@asynctest.mock.patch("n2vc.libjuju.Libjuju.model_exists")
133@asynctest.mock.patch("juju.controller.Controller.add_model")
134@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
135@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
136class AddModelTest(LibjujuTestCase):
137 def setUp(self):
138 super(AddModelTest, self).setUp()
139
140 def test_existing_model(
141 self,
142 mock_disconnect_model,
143 mock_disconnect_controller,
144 mock_add_model,
145 mock_model_exists,
146 mock_get_controller,
147 ):
148 mock_model_exists.return_value = True
149
150 with self.assertRaises(JujuModelAlreadyExists):
151 self.loop.run_until_complete(
152 self.libjuju.add_model("existing_model", "cloud")
153 )
154
155 mock_disconnect_controller.assert_called()
156
157 # TODO Check two job executing at the same time and one returning without doing anything.
158
159 def test_non_existing_model(
160 self,
161 mock_disconnect_model,
162 mock_disconnect_controller,
163 mock_add_model,
164 mock_model_exists,
165 mock_get_controller,
166 ):
167 mock_model_exists.return_value = False
168 mock_get_controller.return_value = juju.controller.Controller()
169
170 self.loop.run_until_complete(
171 self.libjuju.add_model("nonexisting_model", "cloud")
172 )
173
174 mock_add_model.assert_called_once()
175 mock_disconnect_controller.assert_called()
176 mock_disconnect_model.assert_called()
177
178
gsprib7620562021-02-24 05:03:17 +0000179@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
180@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
181@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
182@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
183@asynctest.mock.patch(
184 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
185)
186@asynctest.mock.patch("juju.model.Model.get_action_status")
187@asynctest.mock.patch("juju.model.Model.get_action_output")
188@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_actions")
189class GetExecutedActionsTest(LibjujuTestCase):
190 def setUp(self):
191 super(GetExecutedActionsTest, self).setUp()
192
193 def test_exception(
194 self,
195 mock_get_actions,
196 mock_get_action_output,
197 mock_get_action_status,
198 mock_applications,
199 mock_disconnect_controller,
200 mock_disconnect_model,
201 mock_get_model,
202 mock_get_controller,
203 ):
204 mock_get_model.return_value = None
205 with self.assertRaises(JujuError):
206 self.loop.run_until_complete(self.libjuju.get_executed_actions("model"))
207
208 mock_get_controller.assert_called_once()
209 mock_disconnect_controller.assert_called_once()
210 mock_get_model.assert_called_once()
211 mock_disconnect_model.assert_not_called()
212
213 def test_success(
214 self,
215 mock_get_actions,
216 mock_get_action_output,
217 mock_get_action_status,
218 mock_applications,
219 mock_disconnect_controller,
220 mock_disconnect_model,
221 mock_get_model,
222 mock_get_controller,
223 ):
224 mock_get_model.return_value = juju.model.Model()
225 mock_applications.return_value = {"existing_app"}
226 mock_get_actions.return_value = {"action_name": "description"}
227 mock_get_action_status.return_value = {"id": "status"}
228 mock_get_action_output.return_value = {"output": "completed"}
229
230 executed_actions = self.loop.run_until_complete(
231 self.libjuju.get_executed_actions("model")
232 )
233 expected_result = [{'id': 'id', 'action': 'action_name',
234 'status': 'status', 'output': 'completed'}]
235 self.assertListEqual(expected_result, executed_actions)
236 self.assertIsInstance(executed_actions, list)
237
238 mock_get_controller.assert_called_once()
239 mock_get_model.assert_called_once()
240 mock_disconnect_controller.assert_called_once()
241 mock_disconnect_model.assert_called_once()
242
243
244@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
245@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
246@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
247@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
248@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
249class GetApplicationConfigsTest(LibjujuTestCase):
250 def setUp(self):
251 super(GetApplicationConfigsTest, self).setUp()
252
253 def test_exception(
254 self,
255 mock_get_application,
256 mock_disconnect_controller,
257 mock_disconnect_model,
258 mock_get_model,
259 mock_get_controller,
260 ):
261 mock_get_model.return_value = None
262 with self.assertRaises(JujuError):
263 self.loop.run_until_complete(
264 self.libjuju.get_application_configs("model", "app"))
265
266 mock_get_controller.assert_called_once()
267 mock_disconnect_controller.assert_called_once()
268 mock_get_model.assert_called_once()
269 mock_disconnect_model.assert_not_called()
270
271 def test_success(
272 self,
273 mock_get_application,
274 mock_disconnect_controller,
275 mock_disconnect_model,
276 mock_get_model,
277 mock_get_controller,
278 ):
279 mock_get_application.return_value = FakeApplication()
280 application_configs = self.loop.run_until_complete(self.libjuju
281 .get_application_configs("model", "app"))
282
283 self.assertEqual(application_configs, ["app_config"])
284
285 mock_get_controller.assert_called_once()
286 mock_get_model.assert_called_once()
287 mock_disconnect_controller.assert_called_once()
288 mock_disconnect_model.assert_called_once()
289
290
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +0200291@asynctest.mock.patch("juju.controller.Controller.get_model")
292class GetModelTest(LibjujuTestCase):
293 def setUp(self):
294 super(GetModelTest, self).setUp()
295
296 def test_get_model(
297 self, mock_get_model,
298 ):
299 mock_get_model.return_value = juju.model.Model()
300 model = self.loop.run_until_complete(
301 self.libjuju.get_model(juju.controller.Controller(), "model")
302 )
303 self.assertIsInstance(model, juju.model.Model)
304
305
306@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
307@asynctest.mock.patch("juju.controller.Controller.list_models")
308class ModelExistsTest(LibjujuTestCase):
309 def setUp(self):
310 super(ModelExistsTest, self).setUp()
311
312 async def test_existing_model(
313 self, mock_list_models, mock_get_controller,
314 ):
315 mock_list_models.return_value = ["existing_model"]
316 self.assertTrue(
317 await self.libjuju.model_exists(
318 "existing_model", juju.controller.Controller()
319 )
320 )
321
322 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
323 async def test_no_controller(
324 self, mock_disconnect_controller, mock_list_models, mock_get_controller,
325 ):
326 mock_list_models.return_value = ["existing_model"]
327 mock_get_controller.return_value = juju.controller.Controller()
328 self.assertTrue(await self.libjuju.model_exists("existing_model"))
329 mock_disconnect_controller.assert_called_once()
330
331 async def test_non_existing_model(
332 self, mock_list_models, mock_get_controller,
333 ):
334 mock_list_models.return_value = ["existing_model"]
335 self.assertFalse(
336 await self.libjuju.model_exists(
337 "not_existing_model", juju.controller.Controller()
338 )
339 )
340
341
342@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
343@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
344@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
345@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
346@asynctest.mock.patch("juju.model.Model.get_status")
347class GetModelStatusTest(LibjujuTestCase):
348 def setUp(self):
349 super(GetModelStatusTest, self).setUp()
350
351 def test_success(
352 self,
353 mock_get_status,
354 mock_disconnect_controller,
355 mock_disconnect_model,
356 mock_get_model,
357 mock_get_controller,
358 ):
359 mock_get_model.return_value = juju.model.Model()
360 mock_get_status.return_value = {"status"}
361
362 status = self.loop.run_until_complete(self.libjuju.get_model_status("model"))
363
364 mock_get_status.assert_called_once()
365 mock_disconnect_controller.assert_called_once()
366 mock_disconnect_model.assert_called_once()
367
368 self.assertEqual(status, {"status"})
369
370 def test_excpetion(
371 self,
372 mock_get_status,
373 mock_disconnect_controller,
374 mock_disconnect_model,
375 mock_get_model,
376 mock_get_controller,
377 ):
378 mock_get_model.return_value = juju.model.Model()
379 mock_get_status.side_effect = Exception()
380
381 with self.assertRaises(Exception):
382 status = self.loop.run_until_complete(
383 self.libjuju.get_model_status("model")
384 )
385
386 mock_disconnect_controller.assert_called_once()
387 mock_disconnect_model.assert_called_once()
388
389 self.assertIsNone(status)
390
391
392@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
393@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
394@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
395@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
396@asynctest.mock.patch("juju.model.Model.get_machines")
397@asynctest.mock.patch("juju.model.Model.add_machine")
398@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
399class CreateMachineTest(LibjujuTestCase):
400 def setUp(self):
401 super(CreateMachineTest, self).setUp()
402
403 def test_existing_machine(
404 self,
405 mock_wait_for,
406 mock_add_machine,
407 mock_get_machines,
408 mock_disconnect_controller,
409 mock_disconnect_model,
410 mock_get_model,
411 mock_get_controller,
412 ):
413 mock_get_model.return_value = juju.model.Model()
414 mock_get_machines.return_value = {"existing_machine": FakeMachine()}
415 machine, bool_res = self.loop.run_until_complete(
416 self.libjuju.create_machine("model", "existing_machine")
417 )
418
419 self.assertIsInstance(machine, FakeMachine)
420 self.assertFalse(bool_res)
421
422 mock_disconnect_controller.assert_called()
423 mock_disconnect_model.assert_called()
424
425 def test_non_existing_machine(
426 self,
427 mock_wait_for,
428 mock_add_machine,
429 mock_get_machines,
430 mock_disconnect_controller,
431 mock_disconnect_model,
432 mock_get_model,
433 mock_get_controller,
434 ):
435 mock_get_model.return_value = juju.model.Model()
436 with self.assertRaises(JujuMachineNotFound):
437 machine, bool_res = self.loop.run_until_complete(
438 self.libjuju.create_machine("model", "non_existing_machine")
439 )
440 self.assertIsNone(machine)
441 self.assertIsNone(bool_res)
442
443 mock_disconnect_controller.assert_called()
444 mock_disconnect_model.assert_called()
445
446 def test_no_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 mock_get_model.return_value = juju.model.Model()
457 mock_add_machine.return_value = FakeMachine()
458
459 machine, bool_res = self.loop.run_until_complete(
460 self.libjuju.create_machine("model")
461 )
462
463 self.assertIsInstance(machine, FakeMachine)
464 self.assertTrue(bool_res)
465
466 mock_wait_for.assert_called_once()
467 mock_add_machine.assert_called_once()
468
469 mock_disconnect_controller.assert_called()
470 mock_disconnect_model.assert_called()
471
472
473# TODO test provision machine
474
475
476@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
477@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
478@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
479@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
480@asynctest.mock.patch(
481 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
482)
483@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
484@asynctest.mock.patch("juju.model.Model.deploy")
485@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
486@asynctest.mock.patch("n2vc.libjuju.Libjuju.create_machine")
487class DeployCharmTest(LibjujuTestCase):
488 def setUp(self):
489 super(DeployCharmTest, self).setUp()
490
491 def test_existing_app(
492 self,
493 mock_create_machine,
494 mock_wait_for,
495 mock_deploy,
496 mock_machines,
497 mock_applications,
498 mock_disconnect_controller,
499 mock_disconnect_model,
500 mock_get_model,
501 mock_get_controller,
502 ):
503 mock_get_model.return_value = juju.model.Model()
504 mock_applications.return_value = {"existing_app"}
505
506 with self.assertRaises(JujuApplicationExists):
507 application = self.loop.run_until_complete(
508 self.libjuju.deploy_charm("existing_app", "path", "model", "machine",)
509 )
510 self.assertIsNone(application)
511
512 mock_disconnect_controller.assert_called()
513 mock_disconnect_model.assert_called()
514
515 def test_non_existing_machine(
516 self,
517 mock_create_machine,
518 mock_wait_for,
519 mock_deploy,
520 mock_machines,
521 mock_applications,
522 mock_disconnect_controller,
523 mock_disconnect_model,
524 mock_get_model,
525 mock_get_controller,
526 ):
527 mock_get_model.return_value = juju.model.Model()
528 mock_machines.return_value = {"existing_machine": FakeMachine()}
529 with self.assertRaises(JujuMachineNotFound):
530 application = self.loop.run_until_complete(
531 self.libjuju.deploy_charm("app", "path", "model", "machine",)
532 )
533
534 self.assertIsNone(application)
535
536 mock_disconnect_controller.assert_called()
537 mock_disconnect_model.assert_called()
538
539 def test_2_units(
540 self,
541 mock_create_machine,
542 mock_wait_for,
543 mock_deploy,
544 mock_machines,
545 mock_applications,
546 mock_disconnect_controller,
547 mock_disconnect_model,
548 mock_get_model,
549 mock_get_controller,
550 ):
551 mock_get_model.return_value = juju.model.Model()
552 mock_machines.return_value = {"existing_machine": FakeMachine()}
553 mock_create_machine.return_value = (FakeMachine(), "other")
554 mock_deploy.return_value = FakeApplication()
555 application = self.loop.run_until_complete(
556 self.libjuju.deploy_charm(
557 "app", "path", "model", "existing_machine", num_units=2,
558 )
559 )
560
561 self.assertIsInstance(application, FakeApplication)
562
563 mock_deploy.assert_called_once()
564 mock_wait_for.assert_called_once()
565
566 mock_create_machine.assert_called_once()
567
568 mock_disconnect_controller.assert_called()
569 mock_disconnect_model.assert_called()
570
571 def test_1_unit(
572 self,
573 mock_create_machine,
574 mock_wait_for,
575 mock_deploy,
576 mock_machines,
577 mock_applications,
578 mock_disconnect_controller,
579 mock_disconnect_model,
580 mock_get_model,
581 mock_get_controller,
582 ):
583 mock_get_model.return_value = juju.model.Model()
584 mock_machines.return_value = {"existing_machine": FakeMachine()}
585 mock_deploy.return_value = FakeApplication()
586 application = self.loop.run_until_complete(
587 self.libjuju.deploy_charm("app", "path", "model", "existing_machine")
588 )
589
590 self.assertIsInstance(application, FakeApplication)
591
592 mock_deploy.assert_called_once()
593 mock_wait_for.assert_called_once()
594
595 mock_disconnect_controller.assert_called()
596 mock_disconnect_model.assert_called()
597
598
599@asynctest.mock.patch(
600 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
601)
602class GetApplicationTest(LibjujuTestCase):
603 def setUp(self):
604 super(GetApplicationTest, self).setUp()
605
606 def test_existing_application(
607 self, mock_applications,
608 ):
609 mock_applications.return_value = {"existing_app": "exists"}
610 model = juju.model.Model()
611 result = self.libjuju._get_application(model, "existing_app")
612 self.assertEqual(result, "exists")
613
614 def test_non_existing_application(
615 self, mock_applications,
616 ):
617 mock_applications.return_value = {"existing_app": "exists"}
618 model = juju.model.Model()
619 result = self.libjuju._get_application(model, "nonexisting_app")
620 self.assertIsNone(result)
621
622
623@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
624@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
625@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
626@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
627@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
628@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
629@asynctest.mock.patch("juju.model.Model.get_action_output")
630@asynctest.mock.patch("juju.model.Model.get_action_status")
631class ExecuteActionTest(LibjujuTestCase):
632 def setUp(self):
633 super(ExecuteActionTest, self).setUp()
634
635 def test_no_application(
636 self,
637 mock_get_action_status,
638 mock_get_action_output,
639 mock_wait_for,
640 mock__get_application,
641 mock_disconnect_controller,
642 mock_disconnect_model,
643 mock_get_model,
644 mock_get_controller,
645 ):
646 mock__get_application.return_value = None
647 mock_get_model.return_value = juju.model.Model()
648
649 with self.assertRaises(JujuApplicationNotFound):
650 output, status = self.loop.run_until_complete(
651 self.libjuju.execute_action("app", "model", "action",)
652 )
653 self.assertIsNone(output)
654 self.assertIsNone(status)
655
656 mock_disconnect_controller.assert_called()
657 mock_disconnect_model.assert_called()
658
659 def test_no_action(
660 self,
661 mock_get_action_status,
662 mock_get_action_output,
663 mock_wait_for,
664 mock__get_application,
665 mock_disconnect_controller,
666 mock_disconnect_model,
667 mock_get_model,
668 mock_get_controller,
669 ):
670
671 mock_get_model.return_value = juju.model.Model()
672 mock__get_application.return_value = FakeApplication()
673 with self.assertRaises(JujuActionNotFound):
674 output, status = self.loop.run_until_complete(
675 self.libjuju.execute_action("app", "model", "action",)
676 )
677 self.assertIsNone(output)
678 self.assertIsNone(status)
679
680 mock_disconnect_controller.assert_called()
681 mock_disconnect_model.assert_called()
682
683 # TODO no leader unit found exception
684
685 def test_succesful_exec(
686 self,
687 mock_get_action_status,
688 mock_get_action_output,
689 mock_wait_for,
690 mock__get_application,
691 mock_disconnect_controller,
692 mock_disconnect_model,
693 mock_get_model,
694 mock_get_controller,
695 ):
696 mock_get_model.return_value = juju.model.Model()
697 mock__get_application.return_value = FakeApplication()
698 mock_get_action_output.return_value = "output"
699 mock_get_action_status.return_value = {"id": "status"}
700 output, status = self.loop.run_until_complete(
701 self.libjuju.execute_action("app", "model", "existing_action")
702 )
703 self.assertEqual(output, "output")
704 self.assertEqual(status, "status")
705
706 mock_wait_for.assert_called_once()
707
708 mock_disconnect_controller.assert_called()
709 mock_disconnect_model.assert_called()
710
711
712@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
713@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
714@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
715@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
716@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
717class GetActionTest(LibjujuTestCase):
718 def setUp(self):
719 super(GetActionTest, self).setUp()
720
721 def test_exception(
722 self,
723 mock_get_application,
724 mock_disconnect_controller,
725 mock_disconnect_model,
726 mock_get_model,
727 mock_get_controller,
728 ):
729 mock_get_application.side_effect = Exception()
730
731 with self.assertRaises(Exception):
732 actions = self.loop.run_until_complete(
733 self.libjuju.get_actions("app", "model")
734 )
735
736 self.assertIsNone(actions)
737 mock_disconnect_controller.assert_called_once()
738 mock_disconnect_model.assert_called_once()
739
740 def test_success(
741 self,
742 mock_get_application,
743 mock_disconnect_controller,
744 mock_disconnect_model,
745 mock_get_model,
746 mock_get_controller,
747 ):
748 mock_get_application.return_value = FakeApplication()
749
750 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
751
752 self.assertEqual(actions, ["existing_action"])
753
754 mock_get_controller.assert_called_once()
755 mock_get_model.assert_called_once()
756 mock_disconnect_controller.assert_called_once()
757 mock_disconnect_model.assert_called_once()
758
759
760@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
761@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
762@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
763@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
764@asynctest.mock.patch("juju.model.Model.add_relation")
765class AddRelationTest(LibjujuTestCase):
766 def setUp(self):
767 super(AddRelationTest, self).setUp()
768
769 @asynctest.mock.patch("logging.Logger.warning")
770 def test_not_found(
771 self,
772 mock_warning,
773 mock_add_relation,
774 mock_disconnect_controller,
775 mock_disconnect_model,
776 mock_get_model,
777 mock_get_controller,
778 ):
779 # TODO in libjuju.py should this fail only with a log message?
780 result = {"error": "not found", "response": "response", "request-id": 1}
781
782 mock_get_model.return_value = juju.model.Model()
783 mock_add_relation.side_effect = JujuAPIError(result)
784
785 self.loop.run_until_complete(
786 self.libjuju.add_relation(
787 "model", "app1", "app2", "relation1", "relation2",
788 )
789 )
790
791 mock_warning.assert_called_with("Relation not found: not found")
792 mock_disconnect_controller.assert_called_once()
793 mock_disconnect_model.assert_called_once()
794
795 @asynctest.mock.patch("logging.Logger.warning")
796 def test_already_exists(
797 self,
798 mock_warning,
799 mock_add_relation,
800 mock_disconnect_controller,
801 mock_disconnect_model,
802 mock_get_model,
803 mock_get_controller,
804 ):
805 # TODO in libjuju.py should this fail silently?
806 result = {"error": "already exists", "response": "response", "request-id": 1}
807
808 mock_get_model.return_value = juju.model.Model()
809 mock_add_relation.side_effect = JujuAPIError(result)
810
811 self.loop.run_until_complete(
812 self.libjuju.add_relation(
813 "model", "app1", "app2", "relation1", "relation2",
814 )
815 )
816
817 mock_warning.assert_called_with("Relation already exists: already exists")
818 mock_disconnect_controller.assert_called_once()
819 mock_disconnect_model.assert_called_once()
820
821 def test_exception(
822 self,
823 mock_add_relation,
824 mock_disconnect_controller,
825 mock_disconnect_model,
826 mock_get_model,
827 mock_get_controller,
828 ):
829 mock_get_model.return_value = juju.model.Model()
830 result = {"error": "", "response": "response", "request-id": 1}
831 mock_add_relation.side_effect = JujuAPIError(result)
832
833 with self.assertRaises(JujuAPIError):
834 self.loop.run_until_complete(
835 self.libjuju.add_relation(
836 "model", "app1", "app2", "relation1", "relation2",
837 )
838 )
839
840 mock_disconnect_controller.assert_called_once()
841 mock_disconnect_model.assert_called_once()
842
843 def test_success(
844 self,
845 mock_add_relation,
846 mock_disconnect_controller,
847 mock_disconnect_model,
848 mock_get_model,
849 mock_get_controller,
850 ):
851 mock_get_model.return_value = juju.model.Model()
852
853 self.loop.run_until_complete(
854 self.libjuju.add_relation(
855 "model", "app1", "app2", "relation1", "relation2",
856 )
857 )
858
859 mock_add_relation.assert_called_with(
860 relation1="app1:relation1", relation2="app2:relation2"
861 )
862 mock_disconnect_controller.assert_called_once()
863 mock_disconnect_model.assert_called_once()
864
865
866# TODO destroy_model testcase
867
868
David Garcia4a8ed1c2020-09-29 19:48:13 +0200869# @asynctest.mock.patch("juju.model.Model.get_machines")
870# @asynctest.mock.patch("logging.Logger.debug")
871# class DestroyMachineTest(LibjujuTestCase):
872# def setUp(self):
873# super(DestroyMachineTest, self).setUp()
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +0200874
David Garcia4a8ed1c2020-09-29 19:48:13 +0200875# def test_success_manual_machine(
876# self, mock_debug, mock_get_machines,
877# ):
878# mock_get_machines.side_effect = [
879# {"machine": FakeManualMachine()},
880# {"machine": FakeManualMachine()},
881# {},
882# ]
883# self.loop.run_until_complete(
884# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
885# )
886# calls = [
887# asynctest.call("Waiting for machine machine is destroyed"),
888# asynctest.call("Machine destroyed: machine"),
889# ]
890# mock_debug.assert_has_calls(calls)
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +0200891
David Garcia4a8ed1c2020-09-29 19:48:13 +0200892# def test_no_machine(
893# self, mock_debug, mock_get_machines,
894# ):
895# mock_get_machines.return_value = {}
896# self.loop.run_until_complete(
897# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
898# )
899# mock_debug.assert_called_with("Machine not found: machine")
Dominik Fleischmannb78b3e02020-07-07 13:11:19 +0200900
901
902@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
903@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
904@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
905@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
906@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
907class ConfigureApplicationTest(LibjujuTestCase):
908 def setUp(self):
909 super(ConfigureApplicationTest, self).setUp()
910
911 def test_success(
912 self,
913 mock_get_application,
914 mock_disconnect_controller,
915 mock_disconnect_model,
916 mock_get_model,
917 mock_get_controller,
918 ):
919
920 mock_get_application.return_value = FakeApplication()
921
922 self.loop.run_until_complete(
923 self.libjuju.configure_application("model", "app", {"config"},)
924 )
925 mock_get_application.assert_called_once()
926 mock_disconnect_controller.assert_called_once()
927 mock_disconnect_model.assert_called_once()
928
929 def test_exception(
930 self,
931 mock_get_application,
932 mock_disconnect_controller,
933 mock_disconnect_model,
934 mock_get_model,
935 mock_get_controller,
936 ):
937
938 mock_get_application.side_effect = Exception()
939
940 with self.assertRaises(Exception):
941 self.loop.run_until_complete(
942 self.libjuju.configure_application("model", "app", {"config"},)
943 )
944 mock_disconnect_controller.assert_called_once()
945 mock_disconnect_model.assert_called_once()
946
947
948# TODO _get_api_endpoints_db test case
949# TODO _update_api_endpoints_db test case
950# TODO healthcheck test case
951
952
953@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
954@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
955@asynctest.mock.patch("juju.controller.Controller.list_models")
956class ListModelsTest(LibjujuTestCase):
957 def setUp(self):
958 super(ListModelsTest, self).setUp()
959
960 def test_containing(
961 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
962 ):
963 mock_get_controller.return_value = juju.controller.Controller()
964 mock_list_models.return_value = ["existingmodel"]
965 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
966
967 mock_disconnect_controller.assert_called_once()
968 self.assertEquals(models, ["existingmodel"])
969
970 def test_not_containing(
971 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
972 ):
973 mock_get_controller.return_value = juju.controller.Controller()
974 mock_list_models.return_value = ["existingmodel", "model"]
975 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
976
977 mock_disconnect_controller.assert_called_once()
978 self.assertEquals(models, [])
979
980 def test_no_contains_arg(
981 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
982 ):
983 mock_get_controller.return_value = juju.controller.Controller()
984 mock_list_models.return_value = ["existingmodel", "model"]
985 models = self.loop.run_until_complete(self.libjuju.list_models())
986
987 mock_disconnect_controller.assert_called_once()
988 self.assertEquals(models, ["existingmodel", "model"])