blob: 8c16c9d8b8b63a161c39e8f288dfcf982bf19f3e [file] [log] [blame]
Dominik Fleischmann7ff392f2020-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
David Garcia475a7222020-09-21 16:19:15 +020017import tempfile
18from unittest import mock
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020019import juju
David Garcia475a7222020-09-21 16:19:15 +020020import kubernetes
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020021from juju.errors import JujuAPIError
22import logging
23from .utils import FakeN2VC, FakeMachine, FakeApplication
24from n2vc.libjuju import Libjuju
25from n2vc.exceptions import (
26 JujuControllerFailedConnecting,
27 JujuModelAlreadyExists,
28 JujuMachineNotFound,
29 JujuApplicationNotFound,
30 JujuActionNotFound,
31 JujuApplicationExists,
David Garcia475a7222020-09-21 16:19:15 +020032 JujuInvalidK8sConfiguration,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020033)
34
35
36class LibjujuTestCase(asynctest.TestCase):
37 @asynctest.mock.patch("juju.controller.Controller.update_endpoints")
38 @asynctest.mock.patch("juju.client.connector.Connector.connect")
39 @asynctest.mock.patch("juju.controller.Controller.connection")
40 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_api_endpoints_db")
41 def setUp(
42 self,
43 mock__get_api_endpoints_db=None,
44 mock_connection=None,
45 mock_connect=None,
46 mock_update_endpoints=None,
47 ):
48 loop = asyncio.get_event_loop()
49 n2vc = FakeN2VC()
50 mock__get_api_endpoints_db.return_value = ["127.0.0.1:17070"]
51 endpoints = "127.0.0.1:17070"
52 username = "admin"
53 password = "secret"
54 cacert = """
55 -----BEGIN CERTIFICATE-----
56 SOMECERT
57 -----END CERTIFICATE-----"""
58 self.libjuju = Libjuju(
59 endpoints,
60 "192.168.0.155:17070",
61 username,
62 password,
63 cacert,
64 loop,
65 log=None,
66 db={"get_one": []},
67 n2vc=n2vc,
68 apt_mirror="192.168.0.100",
69 enable_os_upgrade=True,
70 )
71 logging.disable(logging.CRITICAL)
72 loop.run_until_complete(self.libjuju.disconnect())
73
74
75@asynctest.mock.patch("juju.controller.Controller.connect")
76@asynctest.mock.patch(
77 "juju.controller.Controller.api_endpoints",
78 new_callable=asynctest.CoroutineMock(return_value=["127.0.0.1:17070"]),
79)
80@asynctest.mock.patch("n2vc.libjuju.Libjuju._update_api_endpoints_db")
81class GetControllerTest(LibjujuTestCase):
82 def setUp(self):
83 super(GetControllerTest, self).setUp()
84
85 def test_diff_endpoint(
86 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
87 ):
88 self.libjuju.endpoints = []
89 controller = self.loop.run_until_complete(self.libjuju.get_controller())
90 mock__update_api_endpoints_db.assert_called_once_with(["127.0.0.1:17070"])
91 self.assertIsInstance(controller, juju.controller.Controller)
92
93 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
94 def test_exception(
95 self,
96 mock_disconnect_controller,
97 mock__update_api_endpoints_db,
98 mock_api_endpoints,
99 mock_connect,
100 ):
101 self.libjuju.endpoints = []
102 mock__update_api_endpoints_db.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200103 controller = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200104 with self.assertRaises(JujuControllerFailedConnecting):
105 controller = self.loop.run_until_complete(self.libjuju.get_controller())
David Garcia12b29242020-09-17 16:01:48 +0200106 self.assertIsNone(controller)
107 mock_disconnect_controller.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200108
109 def test_same_endpoint_get_controller(
110 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
111 ):
112 self.libjuju.endpoints = ["127.0.0.1:17070"]
113 controller = self.loop.run_until_complete(self.libjuju.get_controller())
114 mock__update_api_endpoints_db.assert_not_called()
115 self.assertIsInstance(controller, juju.controller.Controller)
116
117
118class DisconnectTest(LibjujuTestCase):
119 def setUp(self):
120 super(DisconnectTest, self).setUp()
121
122 @asynctest.mock.patch("juju.model.Model.disconnect")
123 def test_disconnect_model(self, mock_disconnect):
124 self.loop.run_until_complete(self.libjuju.disconnect_model(juju.model.Model()))
125 mock_disconnect.assert_called_once()
126
127 @asynctest.mock.patch("juju.controller.Controller.disconnect")
128 def test_disconnect_controller(self, mock_disconnect):
129 self.loop.run_until_complete(
130 self.libjuju.disconnect_controller(juju.controller.Controller())
131 )
132 mock_disconnect.assert_called_once()
133
134
135@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
136@asynctest.mock.patch("n2vc.libjuju.Libjuju.model_exists")
137@asynctest.mock.patch("juju.controller.Controller.add_model")
138@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
139@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
140class AddModelTest(LibjujuTestCase):
141 def setUp(self):
142 super(AddModelTest, self).setUp()
143
144 def test_existing_model(
145 self,
146 mock_disconnect_model,
147 mock_disconnect_controller,
148 mock_add_model,
149 mock_model_exists,
150 mock_get_controller,
151 ):
152 mock_model_exists.return_value = True
153
154 with self.assertRaises(JujuModelAlreadyExists):
155 self.loop.run_until_complete(
156 self.libjuju.add_model("existing_model", "cloud")
157 )
158
David Garcia12b29242020-09-17 16:01:48 +0200159 mock_disconnect_controller.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200160
161 # TODO Check two job executing at the same time and one returning without doing anything.
162
163 def test_non_existing_model(
164 self,
165 mock_disconnect_model,
166 mock_disconnect_controller,
167 mock_add_model,
168 mock_model_exists,
169 mock_get_controller,
170 ):
171 mock_model_exists.return_value = False
172 mock_get_controller.return_value = juju.controller.Controller()
173
174 self.loop.run_until_complete(
175 self.libjuju.add_model("nonexisting_model", "cloud")
176 )
177
178 mock_add_model.assert_called_once()
179 mock_disconnect_controller.assert_called()
180 mock_disconnect_model.assert_called()
181
182
183@asynctest.mock.patch("juju.controller.Controller.get_model")
184class GetModelTest(LibjujuTestCase):
185 def setUp(self):
186 super(GetModelTest, self).setUp()
187
188 def test_get_model(
189 self, mock_get_model,
190 ):
191 mock_get_model.return_value = juju.model.Model()
192 model = self.loop.run_until_complete(
193 self.libjuju.get_model(juju.controller.Controller(), "model")
194 )
195 self.assertIsInstance(model, juju.model.Model)
196
197
198@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
199@asynctest.mock.patch("juju.controller.Controller.list_models")
200class ModelExistsTest(LibjujuTestCase):
201 def setUp(self):
202 super(ModelExistsTest, self).setUp()
203
204 async def test_existing_model(
205 self, mock_list_models, mock_get_controller,
206 ):
207 mock_list_models.return_value = ["existing_model"]
208 self.assertTrue(
209 await self.libjuju.model_exists(
210 "existing_model", juju.controller.Controller()
211 )
212 )
213
214 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
215 async def test_no_controller(
216 self, mock_disconnect_controller, mock_list_models, mock_get_controller,
217 ):
218 mock_list_models.return_value = ["existing_model"]
219 mock_get_controller.return_value = juju.controller.Controller()
220 self.assertTrue(await self.libjuju.model_exists("existing_model"))
221 mock_disconnect_controller.assert_called_once()
222
223 async def test_non_existing_model(
224 self, mock_list_models, mock_get_controller,
225 ):
226 mock_list_models.return_value = ["existing_model"]
227 self.assertFalse(
228 await self.libjuju.model_exists(
229 "not_existing_model", juju.controller.Controller()
230 )
231 )
232
233
234@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
235@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
236@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
237@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
238@asynctest.mock.patch("juju.model.Model.get_status")
239class GetModelStatusTest(LibjujuTestCase):
240 def setUp(self):
241 super(GetModelStatusTest, self).setUp()
242
243 def test_success(
244 self,
245 mock_get_status,
246 mock_disconnect_controller,
247 mock_disconnect_model,
248 mock_get_model,
249 mock_get_controller,
250 ):
251 mock_get_model.return_value = juju.model.Model()
252 mock_get_status.return_value = {"status"}
253
254 status = self.loop.run_until_complete(self.libjuju.get_model_status("model"))
255
256 mock_get_status.assert_called_once()
257 mock_disconnect_controller.assert_called_once()
258 mock_disconnect_model.assert_called_once()
259
260 self.assertEqual(status, {"status"})
261
David Garcia12b29242020-09-17 16:01:48 +0200262 def test_exception(
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200263 self,
264 mock_get_status,
265 mock_disconnect_controller,
266 mock_disconnect_model,
267 mock_get_model,
268 mock_get_controller,
269 ):
270 mock_get_model.return_value = juju.model.Model()
271 mock_get_status.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200272 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200273 with self.assertRaises(Exception):
274 status = self.loop.run_until_complete(
275 self.libjuju.get_model_status("model")
276 )
277
David Garcia12b29242020-09-17 16:01:48 +0200278 mock_disconnect_controller.assert_called_once()
279 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200280
David Garcia12b29242020-09-17 16:01:48 +0200281 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200282
283
284@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
285@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
286@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
287@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
288@asynctest.mock.patch("juju.model.Model.get_machines")
289@asynctest.mock.patch("juju.model.Model.add_machine")
290@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
291class CreateMachineTest(LibjujuTestCase):
292 def setUp(self):
293 super(CreateMachineTest, self).setUp()
294
295 def test_existing_machine(
296 self,
297 mock_wait_for,
298 mock_add_machine,
299 mock_get_machines,
300 mock_disconnect_controller,
301 mock_disconnect_model,
302 mock_get_model,
303 mock_get_controller,
304 ):
305 mock_get_model.return_value = juju.model.Model()
306 mock_get_machines.return_value = {"existing_machine": FakeMachine()}
307 machine, bool_res = self.loop.run_until_complete(
308 self.libjuju.create_machine("model", "existing_machine")
309 )
310
311 self.assertIsInstance(machine, FakeMachine)
312 self.assertFalse(bool_res)
313
314 mock_disconnect_controller.assert_called()
315 mock_disconnect_model.assert_called()
316
317 def test_non_existing_machine(
318 self,
319 mock_wait_for,
320 mock_add_machine,
321 mock_get_machines,
322 mock_disconnect_controller,
323 mock_disconnect_model,
324 mock_get_model,
325 mock_get_controller,
326 ):
David Garcia12b29242020-09-17 16:01:48 +0200327 machine = None
328 bool_res = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200329 mock_get_model.return_value = juju.model.Model()
330 with self.assertRaises(JujuMachineNotFound):
331 machine, bool_res = self.loop.run_until_complete(
332 self.libjuju.create_machine("model", "non_existing_machine")
333 )
David Garcia12b29242020-09-17 16:01:48 +0200334 self.assertIsNone(machine)
335 self.assertIsNone(bool_res)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200336
David Garcia12b29242020-09-17 16:01:48 +0200337 mock_disconnect_controller.assert_called()
338 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200339
340 def test_no_machine(
341 self,
342 mock_wait_for,
343 mock_add_machine,
344 mock_get_machines,
345 mock_disconnect_controller,
346 mock_disconnect_model,
347 mock_get_model,
348 mock_get_controller,
349 ):
350 mock_get_model.return_value = juju.model.Model()
351 mock_add_machine.return_value = FakeMachine()
352
353 machine, bool_res = self.loop.run_until_complete(
354 self.libjuju.create_machine("model")
355 )
356
357 self.assertIsInstance(machine, FakeMachine)
358 self.assertTrue(bool_res)
359
360 mock_wait_for.assert_called_once()
361 mock_add_machine.assert_called_once()
362
363 mock_disconnect_controller.assert_called()
364 mock_disconnect_model.assert_called()
365
366
367# TODO test provision machine
368
369
370@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
371@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
372@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
373@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
374@asynctest.mock.patch(
375 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
376)
377@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
378@asynctest.mock.patch("juju.model.Model.deploy")
379@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
380@asynctest.mock.patch("n2vc.libjuju.Libjuju.create_machine")
381class DeployCharmTest(LibjujuTestCase):
382 def setUp(self):
383 super(DeployCharmTest, self).setUp()
384
385 def test_existing_app(
386 self,
387 mock_create_machine,
388 mock_wait_for,
389 mock_deploy,
390 mock_machines,
391 mock_applications,
392 mock_disconnect_controller,
393 mock_disconnect_model,
394 mock_get_model,
395 mock_get_controller,
396 ):
397 mock_get_model.return_value = juju.model.Model()
398 mock_applications.return_value = {"existing_app"}
399
David Garcia12b29242020-09-17 16:01:48 +0200400 application = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200401 with self.assertRaises(JujuApplicationExists):
402 application = self.loop.run_until_complete(
403 self.libjuju.deploy_charm("existing_app", "path", "model", "machine",)
404 )
David Garcia12b29242020-09-17 16:01:48 +0200405 self.assertIsNone(application)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200406
David Garcia12b29242020-09-17 16:01:48 +0200407 mock_disconnect_controller.assert_called()
408 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200409
410 def test_non_existing_machine(
411 self,
412 mock_create_machine,
413 mock_wait_for,
414 mock_deploy,
415 mock_machines,
416 mock_applications,
417 mock_disconnect_controller,
418 mock_disconnect_model,
419 mock_get_model,
420 mock_get_controller,
421 ):
422 mock_get_model.return_value = juju.model.Model()
423 mock_machines.return_value = {"existing_machine": FakeMachine()}
David Garcia12b29242020-09-17 16:01:48 +0200424 application = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200425 with self.assertRaises(JujuMachineNotFound):
426 application = self.loop.run_until_complete(
427 self.libjuju.deploy_charm("app", "path", "model", "machine",)
428 )
429
David Garcia12b29242020-09-17 16:01:48 +0200430 self.assertIsNone(application)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200431
David Garcia12b29242020-09-17 16:01:48 +0200432 mock_disconnect_controller.assert_called()
433 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200434
435 def test_2_units(
436 self,
437 mock_create_machine,
438 mock_wait_for,
439 mock_deploy,
440 mock_machines,
441 mock_applications,
442 mock_disconnect_controller,
443 mock_disconnect_model,
444 mock_get_model,
445 mock_get_controller,
446 ):
447 mock_get_model.return_value = juju.model.Model()
448 mock_machines.return_value = {"existing_machine": FakeMachine()}
449 mock_create_machine.return_value = (FakeMachine(), "other")
450 mock_deploy.return_value = FakeApplication()
451 application = self.loop.run_until_complete(
452 self.libjuju.deploy_charm(
453 "app", "path", "model", "existing_machine", num_units=2,
454 )
455 )
456
457 self.assertIsInstance(application, FakeApplication)
458
459 mock_deploy.assert_called_once()
460 mock_wait_for.assert_called_once()
461
462 mock_create_machine.assert_called_once()
463
464 mock_disconnect_controller.assert_called()
465 mock_disconnect_model.assert_called()
466
467 def test_1_unit(
468 self,
469 mock_create_machine,
470 mock_wait_for,
471 mock_deploy,
472 mock_machines,
473 mock_applications,
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_machines.return_value = {"existing_machine": FakeMachine()}
481 mock_deploy.return_value = FakeApplication()
482 application = self.loop.run_until_complete(
483 self.libjuju.deploy_charm("app", "path", "model", "existing_machine")
484 )
485
486 self.assertIsInstance(application, FakeApplication)
487
488 mock_deploy.assert_called_once()
489 mock_wait_for.assert_called_once()
490
491 mock_disconnect_controller.assert_called()
492 mock_disconnect_model.assert_called()
493
494
495@asynctest.mock.patch(
496 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
497)
498class GetApplicationTest(LibjujuTestCase):
499 def setUp(self):
500 super(GetApplicationTest, self).setUp()
501
502 def test_existing_application(
503 self, mock_applications,
504 ):
505 mock_applications.return_value = {"existing_app": "exists"}
506 model = juju.model.Model()
507 result = self.libjuju._get_application(model, "existing_app")
508 self.assertEqual(result, "exists")
509
510 def test_non_existing_application(
511 self, mock_applications,
512 ):
513 mock_applications.return_value = {"existing_app": "exists"}
514 model = juju.model.Model()
515 result = self.libjuju._get_application(model, "nonexisting_app")
516 self.assertIsNone(result)
517
518
519@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
520@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
521@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
522@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
523@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
524@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
525@asynctest.mock.patch("juju.model.Model.get_action_output")
526@asynctest.mock.patch("juju.model.Model.get_action_status")
527class ExecuteActionTest(LibjujuTestCase):
528 def setUp(self):
529 super(ExecuteActionTest, self).setUp()
530
531 def test_no_application(
532 self,
533 mock_get_action_status,
534 mock_get_action_output,
535 mock_wait_for,
536 mock__get_application,
537 mock_disconnect_controller,
538 mock_disconnect_model,
539 mock_get_model,
540 mock_get_controller,
541 ):
542 mock__get_application.return_value = None
543 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +0200544 output = None
545 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200546 with self.assertRaises(JujuApplicationNotFound):
547 output, status = self.loop.run_until_complete(
548 self.libjuju.execute_action("app", "model", "action",)
549 )
David Garcia12b29242020-09-17 16:01:48 +0200550 self.assertIsNone(output)
551 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200552
David Garcia12b29242020-09-17 16:01:48 +0200553 mock_disconnect_controller.assert_called()
554 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200555
556 def test_no_action(
557 self,
558 mock_get_action_status,
559 mock_get_action_output,
560 mock_wait_for,
561 mock__get_application,
562 mock_disconnect_controller,
563 mock_disconnect_model,
564 mock_get_model,
565 mock_get_controller,
566 ):
567
568 mock_get_model.return_value = juju.model.Model()
569 mock__get_application.return_value = FakeApplication()
David Garcia12b29242020-09-17 16:01:48 +0200570 output = None
571 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200572 with self.assertRaises(JujuActionNotFound):
573 output, status = self.loop.run_until_complete(
574 self.libjuju.execute_action("app", "model", "action",)
575 )
David Garcia12b29242020-09-17 16:01:48 +0200576 self.assertIsNone(output)
577 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200578
David Garcia12b29242020-09-17 16:01:48 +0200579 mock_disconnect_controller.assert_called()
580 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200581
582 # TODO no leader unit found exception
583
584 def test_succesful_exec(
585 self,
586 mock_get_action_status,
587 mock_get_action_output,
588 mock_wait_for,
589 mock__get_application,
590 mock_disconnect_controller,
591 mock_disconnect_model,
592 mock_get_model,
593 mock_get_controller,
594 ):
595 mock_get_model.return_value = juju.model.Model()
596 mock__get_application.return_value = FakeApplication()
597 mock_get_action_output.return_value = "output"
598 mock_get_action_status.return_value = {"id": "status"}
599 output, status = self.loop.run_until_complete(
600 self.libjuju.execute_action("app", "model", "existing_action")
601 )
602 self.assertEqual(output, "output")
603 self.assertEqual(status, "status")
604
605 mock_wait_for.assert_called_once()
606
607 mock_disconnect_controller.assert_called()
608 mock_disconnect_model.assert_called()
609
610
611@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
612@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
613@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
614@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
615@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
616class GetActionTest(LibjujuTestCase):
617 def setUp(self):
618 super(GetActionTest, self).setUp()
619
620 def test_exception(
621 self,
622 mock_get_application,
623 mock_disconnect_controller,
624 mock_disconnect_model,
625 mock_get_model,
626 mock_get_controller,
627 ):
628 mock_get_application.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200629 actions = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200630 with self.assertRaises(Exception):
631 actions = self.loop.run_until_complete(
632 self.libjuju.get_actions("app", "model")
633 )
634
David Garcia12b29242020-09-17 16:01:48 +0200635 self.assertIsNone(actions)
636 mock_disconnect_controller.assert_called_once()
637 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200638
639 def test_success(
640 self,
641 mock_get_application,
642 mock_disconnect_controller,
643 mock_disconnect_model,
644 mock_get_model,
645 mock_get_controller,
646 ):
647 mock_get_application.return_value = FakeApplication()
648
649 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
650
651 self.assertEqual(actions, ["existing_action"])
652
653 mock_get_controller.assert_called_once()
654 mock_get_model.assert_called_once()
655 mock_disconnect_controller.assert_called_once()
656 mock_disconnect_model.assert_called_once()
657
658
659@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
660@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
661@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
662@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
David Garcia85755d12020-09-21 19:51:23 +0200663@asynctest.mock.patch("juju.application.Application.get_metrics")
664@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
665class GetMetricsTest(LibjujuTestCase):
666 def setUp(self):
667 super(GetMetricsTest, self).setUp()
668
669 def test_get_metrics_success(
670 self,
671 mock_get_application,
672 mock_get_metrics,
673 mock_disconnect_controller,
674 mock_disconnect_model,
675 mock_get_model,
676 mock_get_controller,
677 ):
678 mock_get_application.return_value = FakeApplication()
679 mock_get_model.return_value = juju.model.Model()
680
681 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
682
683 mock_disconnect_controller.assert_called_once()
684 mock_disconnect_model.assert_called_once()
685
686 def test_get_metrics_exception(
687 self,
688 mock_get_application,
689 mock_get_metrics,
690 mock_disconnect_controller,
691 mock_disconnect_model,
692 mock_get_model,
693 mock_get_controller,
694 ):
695 mock_get_model.return_value = juju.model.Model()
696 mock_get_metrics.side_effect = Exception()
697 with self.assertRaises(Exception):
698 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
699
700 mock_disconnect_controller.assert_called_once()
701 mock_disconnect_model.assert_called_once()
702
703 def test_missing_args_exception(
704 self,
705 mock_get_application,
706 mock_get_metrics,
707 mock_disconnect_controller,
708 mock_disconnect_model,
709 mock_get_model,
710 mock_get_controller,
711 ):
712 mock_get_model.return_value = juju.model.Model()
713
714 with self.assertRaises(Exception):
715 self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
716
717 mock_get_controller.assert_not_called()
718 mock_get_model.assert_not_called()
719 mock_disconnect_controller.assert_not_called()
720 mock_disconnect_model.assert_not_called()
721
722
723@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
724@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
725@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
726@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200727@asynctest.mock.patch("juju.model.Model.add_relation")
728class AddRelationTest(LibjujuTestCase):
729 def setUp(self):
730 super(AddRelationTest, self).setUp()
731
732 @asynctest.mock.patch("logging.Logger.warning")
733 def test_not_found(
734 self,
735 mock_warning,
736 mock_add_relation,
737 mock_disconnect_controller,
738 mock_disconnect_model,
739 mock_get_model,
740 mock_get_controller,
741 ):
742 # TODO in libjuju.py should this fail only with a log message?
743 result = {"error": "not found", "response": "response", "request-id": 1}
744
745 mock_get_model.return_value = juju.model.Model()
746 mock_add_relation.side_effect = JujuAPIError(result)
747
748 self.loop.run_until_complete(
David Garcia8331f7c2020-08-25 16:10:07 +0200749 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200750 )
751
752 mock_warning.assert_called_with("Relation not found: not found")
753 mock_disconnect_controller.assert_called_once()
754 mock_disconnect_model.assert_called_once()
755
756 @asynctest.mock.patch("logging.Logger.warning")
757 def test_already_exists(
758 self,
759 mock_warning,
760 mock_add_relation,
761 mock_disconnect_controller,
762 mock_disconnect_model,
763 mock_get_model,
764 mock_get_controller,
765 ):
766 # TODO in libjuju.py should this fail silently?
767 result = {"error": "already exists", "response": "response", "request-id": 1}
768
769 mock_get_model.return_value = juju.model.Model()
770 mock_add_relation.side_effect = JujuAPIError(result)
771
772 self.loop.run_until_complete(
David Garcia8331f7c2020-08-25 16:10:07 +0200773 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200774 )
775
776 mock_warning.assert_called_with("Relation already exists: already exists")
777 mock_disconnect_controller.assert_called_once()
778 mock_disconnect_model.assert_called_once()
779
780 def test_exception(
781 self,
782 mock_add_relation,
783 mock_disconnect_controller,
784 mock_disconnect_model,
785 mock_get_model,
786 mock_get_controller,
787 ):
788 mock_get_model.return_value = juju.model.Model()
789 result = {"error": "", "response": "response", "request-id": 1}
790 mock_add_relation.side_effect = JujuAPIError(result)
791
792 with self.assertRaises(JujuAPIError):
793 self.loop.run_until_complete(
David Garcia8331f7c2020-08-25 16:10:07 +0200794 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200795 )
796
David Garcia12b29242020-09-17 16:01:48 +0200797 mock_disconnect_controller.assert_called_once()
798 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200799
800 def test_success(
801 self,
802 mock_add_relation,
803 mock_disconnect_controller,
804 mock_disconnect_model,
805 mock_get_model,
806 mock_get_controller,
807 ):
808 mock_get_model.return_value = juju.model.Model()
809
810 self.loop.run_until_complete(
David Garcia8331f7c2020-08-25 16:10:07 +0200811 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200812 )
813
David Garcia12b29242020-09-17 16:01:48 +0200814 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
David Garcia8331f7c2020-08-25 16:10:07 +0200815 mock_disconnect_controller.assert_called_once()
816 mock_disconnect_model.assert_called_once()
817
818 def test_saas(
819 self,
820 mock_add_relation,
821 mock_disconnect_controller,
822 mock_disconnect_model,
823 mock_get_model,
824 mock_get_controller,
825 ):
826 mock_get_model.return_value = juju.model.Model()
827
828 self.loop.run_until_complete(
829 self.libjuju.add_relation("model", "app1:relation1", "saas_name",)
830 )
831
David Garcia12b29242020-09-17 16:01:48 +0200832 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200833 mock_disconnect_controller.assert_called_once()
834 mock_disconnect_model.assert_called_once()
835
836
837# TODO destroy_model testcase
838
839
840@asynctest.mock.patch("juju.model.Model.get_machines")
841@asynctest.mock.patch("logging.Logger.debug")
842class DestroyMachineTest(LibjujuTestCase):
843 def setUp(self):
844 super(DestroyMachineTest, self).setUp()
845
846 def test_success(
847 self, mock_debug, mock_get_machines,
848 ):
849 mock_get_machines.side_effect = [
850 {"machine": FakeMachine()},
851 {"machine": FakeMachine()},
852 {},
853 ]
854 self.loop.run_until_complete(
855 self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
856 )
857 calls = [
858 asynctest.call("Waiting for machine machine is destroyed"),
859 asynctest.call("Machine destroyed: machine"),
860 ]
861 mock_debug.assert_has_calls(calls)
862
863 def test_no_machine(
864 self, mock_debug, mock_get_machines,
865 ):
866 mock_get_machines.return_value = {}
867 self.loop.run_until_complete(
868 self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
869 )
870 mock_debug.assert_called_with("Machine not found: machine")
871
872
873@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
874@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
875@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
876@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
877@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
878class ConfigureApplicationTest(LibjujuTestCase):
879 def setUp(self):
880 super(ConfigureApplicationTest, self).setUp()
881
882 def test_success(
883 self,
884 mock_get_application,
885 mock_disconnect_controller,
886 mock_disconnect_model,
887 mock_get_model,
888 mock_get_controller,
889 ):
890
891 mock_get_application.return_value = FakeApplication()
892
893 self.loop.run_until_complete(
894 self.libjuju.configure_application("model", "app", {"config"},)
895 )
896 mock_get_application.assert_called_once()
897 mock_disconnect_controller.assert_called_once()
898 mock_disconnect_model.assert_called_once()
899
900 def test_exception(
901 self,
902 mock_get_application,
903 mock_disconnect_controller,
904 mock_disconnect_model,
905 mock_get_model,
906 mock_get_controller,
907 ):
908
909 mock_get_application.side_effect = Exception()
910
911 with self.assertRaises(Exception):
912 self.loop.run_until_complete(
913 self.libjuju.configure_application("model", "app", {"config"},)
914 )
David Garcia12b29242020-09-17 16:01:48 +0200915 mock_disconnect_controller.assert_called_once()
916 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200917
918
919# TODO _get_api_endpoints_db test case
920# TODO _update_api_endpoints_db test case
921# TODO healthcheck test case
922
923
924@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
925@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
926@asynctest.mock.patch("juju.controller.Controller.list_models")
927class ListModelsTest(LibjujuTestCase):
928 def setUp(self):
929 super(ListModelsTest, self).setUp()
930
931 def test_containing(
932 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
933 ):
934 mock_get_controller.return_value = juju.controller.Controller()
935 mock_list_models.return_value = ["existingmodel"]
936 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
937
938 mock_disconnect_controller.assert_called_once()
939 self.assertEquals(models, ["existingmodel"])
940
941 def test_not_containing(
942 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
943 ):
944 mock_get_controller.return_value = juju.controller.Controller()
945 mock_list_models.return_value = ["existingmodel", "model"]
946 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
947
948 mock_disconnect_controller.assert_called_once()
949 self.assertEquals(models, [])
950
951 def test_no_contains_arg(
952 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
953 ):
954 mock_get_controller.return_value = juju.controller.Controller()
955 mock_list_models.return_value = ["existingmodel", "model"]
956 models = self.loop.run_until_complete(self.libjuju.list_models())
957
958 mock_disconnect_controller.assert_called_once()
959 self.assertEquals(models, ["existingmodel", "model"])
David Garcia42f328a2020-08-25 15:03:01 +0200960
961
962@asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
963class ModelsExistTest(LibjujuTestCase):
964 def setUp(self):
965 super(ModelsExistTest, self).setUp()
966
967 def test_model_names_none(self, mock_list_models):
968 mock_list_models.return_value = []
969 with self.assertRaises(Exception):
970 self.loop.run_until_complete(self.libjuju.models_exist(None))
971
972 def test_model_names_empty(self, mock_list_models):
973 mock_list_models.return_value = []
974 with self.assertRaises(Exception):
975 (exist, non_existing_models) = self.loop.run_until_complete(
976 self.libjuju.models_exist([])
977 )
978
979 def test_model_names_not_existing(self, mock_list_models):
980 mock_list_models.return_value = ["prometheus", "grafana"]
981 (exist, non_existing_models) = self.loop.run_until_complete(
982 self.libjuju.models_exist(["prometheus2", "grafana"])
983 )
984 self.assertFalse(exist)
985 self.assertEqual(non_existing_models, ["prometheus2"])
986
987 def test_model_names_exist(self, mock_list_models):
988 mock_list_models.return_value = ["prometheus", "grafana"]
989 (exist, non_existing_models) = self.loop.run_until_complete(
990 self.libjuju.models_exist(["prometheus", "grafana"])
991 )
992 self.assertTrue(exist)
993 self.assertEqual(non_existing_models, [])
David Garciabc538e42020-08-25 15:22:30 +0200994
995
996@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
997@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
998@asynctest.mock.patch("juju.controller.Controller.list_offers")
999class ListOffers(LibjujuTestCase):
1000 def setUp(self):
1001 super(ListOffers, self).setUp()
1002
1003 def test_disconnect_controller(
1004 self, mock_list_offers, mock_disconnect_controller, mock_get_controller,
1005 ):
1006 mock_get_controller.return_value = juju.controller.Controller()
1007 mock_list_offers.side_effect = Exception()
1008 with self.assertRaises(Exception):
1009 self.loop.run_until_complete(self.libjuju.list_offers("model"))
1010 mock_disconnect_controller.assert_called_once()
1011
1012 def test_empty_list(
1013 self, mock_list_offers, mock_disconnect_controller, mock_get_controller,
1014 ):
1015 mock_get_controller.return_value = juju.controller.Controller()
1016 mock_list_offers.return_value = []
1017 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
1018 self.assertEqual(offers, [])
1019 mock_disconnect_controller.assert_called_once()
1020
1021 def test_non_empty_list(
1022 self, mock_list_offers, mock_disconnect_controller, mock_get_controller,
1023 ):
1024 mock_get_controller.return_value = juju.controller.Controller()
1025 mock_list_offers.return_value = ["offer"]
1026 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
1027 self.assertEqual(offers, ["offer"])
1028 mock_disconnect_controller.assert_called_once()
David Garcia68b00722020-09-11 15:05:00 +02001029
1030
1031@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1032@asynctest.mock.patch("juju.controller.Controller.get_model")
1033@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1034@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1035@asynctest.mock.patch("juju.model.Model.consume")
1036class ConsumeTest(LibjujuTestCase):
1037 def setUp(self):
1038 super(ConsumeTest, self).setUp()
1039
1040 def test_consume(
1041 self,
1042 mock_consume,
1043 mock_disconnect_controller,
1044 mock_disconnect_model,
1045 mock_get_model,
1046 mock_get_controller,
1047 ):
1048 mock_get_controller.return_value = juju.controller.Controller()
1049 mock_get_model.return_value = juju.model.Model()
1050
David Garcia12b29242020-09-17 16:01:48 +02001051 self.loop.run_until_complete(self.libjuju.consume("offer_url", "model_name"))
David Garcia68b00722020-09-11 15:05:00 +02001052 mock_consume.assert_called_once()
1053 mock_disconnect_model.assert_called_once()
1054 mock_disconnect_controller.assert_called_once()
1055
1056 def test_parsing_error_exception(
1057 self,
1058 mock_consume,
1059 mock_disconnect_controller,
1060 mock_disconnect_model,
1061 mock_get_model,
1062 mock_get_controller,
1063 ):
1064 mock_get_controller.return_value = juju.controller.Controller()
1065 mock_get_model.return_value = juju.model.Model()
1066 mock_consume.side_effect = juju.offerendpoints.ParseError("")
1067
1068 with self.assertRaises(juju.offerendpoints.ParseError):
1069 self.loop.run_until_complete(
1070 self.libjuju.consume("offer_url", "model_name")
1071 )
1072 mock_consume.assert_called_once()
1073 mock_disconnect_model.assert_called_once()
1074 mock_disconnect_controller.assert_called_once()
1075
1076 def test_juju_error_exception(
1077 self,
1078 mock_consume,
1079 mock_disconnect_controller,
1080 mock_disconnect_model,
1081 mock_get_model,
1082 mock_get_controller,
1083 ):
1084 mock_get_controller.return_value = juju.controller.Controller()
1085 mock_get_model.return_value = juju.model.Model()
1086 mock_consume.side_effect = juju.errors.JujuError("")
1087
1088 with self.assertRaises(juju.errors.JujuError):
1089 self.loop.run_until_complete(
1090 self.libjuju.consume("offer_url", "model_name")
1091 )
1092 mock_consume.assert_called_once()
1093 mock_disconnect_model.assert_called_once()
1094 mock_disconnect_controller.assert_called_once()
1095
1096 def test_juju_api_error_exception(
1097 self,
1098 mock_consume,
1099 mock_disconnect_controller,
1100 mock_disconnect_model,
1101 mock_get_model,
1102 mock_get_controller,
1103 ):
1104 mock_get_controller.return_value = juju.controller.Controller()
1105 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +02001106 mock_consume.side_effect = juju.errors.JujuAPIError(
1107 {"error": "", "response": "", "request-id": ""}
1108 )
David Garcia68b00722020-09-11 15:05:00 +02001109
1110 with self.assertRaises(juju.errors.JujuAPIError):
1111 self.loop.run_until_complete(
1112 self.libjuju.consume("offer_url", "model_name")
1113 )
1114 mock_consume.assert_called_once()
1115 mock_disconnect_model.assert_called_once()
1116 mock_disconnect_controller.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001117
1118
David Garcia475a7222020-09-21 16:19:15 +02001119@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
David Garcia12b29242020-09-17 16:01:48 +02001120@asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
1121class AddK8sTest(LibjujuTestCase):
1122 def setUp(self):
1123 super(AddK8sTest, self).setUp()
David Garcia475a7222020-09-21 16:19:15 +02001124 self.configuration = kubernetes.client.configuration.Configuration()
David Garcia12b29242020-09-17 16:01:48 +02001125
David Garcia475a7222020-09-21 16:19:15 +02001126 def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garcia12b29242020-09-17 16:01:48 +02001127 self.loop.run_until_complete(
David Garcia475a7222020-09-21 16:19:15 +02001128 self.libjuju.add_k8s("cloud", self.configuration, "storage_class")
David Garcia12b29242020-09-17 16:01:48 +02001129 )
1130 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001131 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001132
David Garcia475a7222020-09-21 16:19:15 +02001133 def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garcia12b29242020-09-17 16:01:48 +02001134 mock_add_cloud.side_effect = Exception()
1135 with self.assertRaises(Exception):
1136 self.loop.run_until_complete(
David Garcia475a7222020-09-21 16:19:15 +02001137 self.libjuju.add_k8s("cloud", self.configuration, "storage_class")
David Garcia12b29242020-09-17 16:01:48 +02001138 )
1139 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001140 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001141
David Garcia475a7222020-09-21 16:19:15 +02001142 def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garcia12b29242020-09-17 16:01:48 +02001143 with self.assertRaises(Exception):
1144 self.loop.run_until_complete(
David Garcia475a7222020-09-21 16:19:15 +02001145 self.libjuju.add_k8s("", self.configuration, "storage_class")
David Garcia12b29242020-09-17 16:01:48 +02001146 )
1147 mock_add_cloud.assert_not_called()
1148
David Garcia475a7222020-09-21 16:19:15 +02001149 def test_add_k8s_missing_storage_name(
1150 self, mock_add_cloud, mock_get_k8s_cloud_credential
1151 ):
David Garcia12b29242020-09-17 16:01:48 +02001152 with self.assertRaises(Exception):
1153 self.loop.run_until_complete(
David Garcia475a7222020-09-21 16:19:15 +02001154 self.libjuju.add_k8s("cloud", self.configuration, "")
David Garcia12b29242020-09-17 16:01:48 +02001155 )
1156 mock_add_cloud.assert_not_called()
1157
David Garcia475a7222020-09-21 16:19:15 +02001158 def test_add_k8s_missing_configuration_keys(
1159 self, mock_add_cloud, mock_get_k8s_cloud_credential
1160 ):
David Garcia12b29242020-09-17 16:01:48 +02001161 with self.assertRaises(Exception):
David Garcia475a7222020-09-21 16:19:15 +02001162 self.loop.run_until_complete(self.libjuju.add_k8s("cloud", None, ""))
David Garcia12b29242020-09-17 16:01:48 +02001163 mock_add_cloud.assert_not_called()
1164
1165
1166@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1167@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1168@asynctest.mock.patch("juju.controller.Controller.add_cloud")
1169@asynctest.mock.patch("juju.controller.Controller.add_credential")
1170class AddCloudTest(LibjujuTestCase):
1171 def setUp(self):
1172 super(AddCloudTest, self).setUp()
1173 self.cloud = juju.client.client.Cloud()
1174 self.credential = juju.client.client.CloudCredential()
1175
1176 def test_add_cloud_with_credential(
1177 self,
1178 mock_add_credential,
1179 mock_add_cloud,
1180 mock_disconnect_controller,
1181 mock_get_controller,
1182 ):
1183 mock_get_controller.return_value = juju.controller.Controller()
1184
1185 cloud = self.loop.run_until_complete(
1186 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1187 )
1188 self.assertEqual(cloud, self.cloud)
1189 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1190 mock_add_credential.assert_called_once_with(
1191 "cloud", credential=self.credential, cloud="cloud"
1192 )
1193 mock_disconnect_controller.assert_called_once()
1194
1195 def test_add_cloud_no_credential(
1196 self,
1197 mock_add_credential,
1198 mock_add_cloud,
1199 mock_disconnect_controller,
1200 mock_get_controller,
1201 ):
1202 mock_get_controller.return_value = juju.controller.Controller()
1203
1204 cloud = self.loop.run_until_complete(
1205 self.libjuju.add_cloud("cloud", self.cloud)
1206 )
1207 self.assertEqual(cloud, self.cloud)
1208 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1209 mock_add_credential.assert_not_called()
1210 mock_disconnect_controller.assert_called_once()
1211
1212 def test_add_cloud_exception(
1213 self,
1214 mock_add_credential,
1215 mock_add_cloud,
1216 mock_disconnect_controller,
1217 mock_get_controller,
1218 ):
1219 mock_get_controller.return_value = juju.controller.Controller()
1220 mock_add_cloud.side_effect = Exception()
1221 with self.assertRaises(Exception):
1222 self.loop.run_until_complete(
1223 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1224 )
1225
1226 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1227 mock_add_credential.assert_not_called()
1228 mock_disconnect_controller.assert_called_once()
1229
1230 def test_add_credential_exception(
1231 self,
1232 mock_add_credential,
1233 mock_add_cloud,
1234 mock_disconnect_controller,
1235 mock_get_controller,
1236 ):
1237 mock_get_controller.return_value = juju.controller.Controller()
1238 mock_add_credential.side_effect = Exception()
1239 with self.assertRaises(Exception):
1240 self.loop.run_until_complete(
1241 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1242 )
1243
1244 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1245 mock_add_credential.assert_called_once_with(
1246 "cloud", credential=self.credential, cloud="cloud"
1247 )
1248 mock_disconnect_controller.assert_called_once()
1249
1250
1251@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1252@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1253@asynctest.mock.patch("juju.controller.Controller.remove_cloud")
1254class RemoveCloudTest(LibjujuTestCase):
1255 def setUp(self):
1256 super(RemoveCloudTest, self).setUp()
1257
1258 def test_remove_cloud(
1259 self, mock_remove_cloud, mock_disconnect_controller, mock_get_controller,
1260 ):
1261 mock_get_controller.return_value = juju.controller.Controller()
1262
1263 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1264 mock_remove_cloud.assert_called_once_with("cloud")
1265 mock_disconnect_controller.assert_called_once()
1266
1267 def test_remove_cloud_exception(
1268 self, mock_remove_cloud, mock_disconnect_controller, mock_get_controller,
1269 ):
1270 mock_get_controller.return_value = juju.controller.Controller()
1271 mock_remove_cloud.side_effect = Exception()
1272
1273 with self.assertRaises(Exception):
1274 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1275 mock_remove_cloud.assert_called_once_with("cloud")
1276 mock_disconnect_controller.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001277
1278
1279@asynctest.mock.patch("kubernetes.client.configuration.Configuration")
1280class GetK8sCloudCredentials(LibjujuTestCase):
1281 def setUp(self):
1282 super(GetK8sCloudCredentials, self).setUp()
1283
1284 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1285 def test_not_supported(self, mock_exception, mock_configuration):
1286 mock_configuration.username = ""
1287 mock_configuration.password = ""
1288 mock_configuration.ssl_ca_cert = None
1289 mock_configuration.cert_file = None
1290 mock_configuration.key_file = None
1291 exception_raised = False
1292 try:
1293 _ = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1294 except JujuInvalidK8sConfiguration as e:
1295 exception_raised = True
1296 self.assertEqual(
1297 e.message, "authentication method not supported",
1298 )
1299 self.assertTrue(exception_raised)
1300
1301 def test_user_pass(self, mock_configuration):
1302 mock_configuration.username = "admin"
1303 mock_configuration.password = "admin"
1304 mock_configuration.ssl_ca_cert = None
1305 mock_configuration.cert_file = None
1306 mock_configuration.key_file = None
1307 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1308 self.assertEqual(
1309 credential,
1310 juju.client._definitions.CloudCredential(
1311 attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
1312 ),
1313 )
1314
1315 def test_user_no_pass(self, mock_configuration):
1316 mock_configuration.username = "admin"
1317 mock_configuration.password = ""
1318 mock_configuration.ssl_ca_cert = None
1319 mock_configuration.cert_file = None
1320 mock_configuration.key_file = None
1321 with mock.patch.object(self.libjuju.log, "debug") as mock_debug:
1322 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1323 self.assertEqual(
1324 credential,
1325 juju.client._definitions.CloudCredential(
1326 attrs={"username": "admin", "password": ""}, auth_type="userpass"
1327 ),
1328 )
1329 mock_debug.assert_called_once_with(
1330 "credential for user admin has empty password"
1331 )
1332
1333 def test_user_pass_with_cert(self, mock_configuration):
1334 mock_configuration.username = "admin"
1335 mock_configuration.password = "admin"
1336 ssl_ca_cert = tempfile.NamedTemporaryFile()
1337 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
1338 ssl_ca_cert_file.write("cacert")
1339 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
1340 mock_configuration.cert_file = None
1341 mock_configuration.key_file = None
1342 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1343 self.assertEqual(
1344 credential,
1345 juju.client._definitions.CloudCredential(
1346 attrs={
1347 "username": "admin",
1348 "password": "admin",
1349 "ClientCertificateData": "cacert",
1350 },
1351 auth_type="userpasswithcert",
1352 ),
1353 )
1354
1355 def test_cert(self, mock_configuration):
1356 mock_configuration.username = ""
1357 mock_configuration.password = ""
1358 mock_configuration.api_key = {"authorization": "Bearer Token"}
1359 ssl_ca_cert = tempfile.NamedTemporaryFile()
1360 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
1361 ssl_ca_cert_file.write("cacert")
1362 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
1363 mock_configuration.cert_file = None
1364 mock_configuration.key_file = None
1365 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1366 self.assertEqual(
1367 credential,
1368 juju.client._definitions.CloudCredential(
1369 attrs={"ClientCertificateData": "cacert", "Token": "Token"},
1370 auth_type="certificate",
1371 ),
1372 )
1373
1374 def test_oauth2(self, mock_configuration):
1375 mock_configuration.username = ""
1376 mock_configuration.password = ""
1377 mock_configuration.api_key = {"authorization": "Bearer Token"}
1378 key = tempfile.NamedTemporaryFile()
1379 with open(key.name, "w") as key_file:
1380 key_file.write("key")
1381 mock_configuration.ssl_ca_cert = None
1382 mock_configuration.cert_file = None
1383 mock_configuration.key_file = key.name
1384 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1385 self.assertEqual(
1386 credential,
1387 juju.client._definitions.CloudCredential(
1388 attrs={"ClientKeyData": "key", "Token": "Token"}, auth_type="oauth2",
1389 ),
1390 )
1391
1392 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1393 def test_oauth2_missing_token(self, mock_exception, mock_configuration):
1394 mock_configuration.username = ""
1395 mock_configuration.password = ""
1396 key = tempfile.NamedTemporaryFile()
1397 with open(key.name, "w") as key_file:
1398 key_file.write("key")
1399 mock_configuration.ssl_ca_cert = None
1400 mock_configuration.cert_file = None
1401 mock_configuration.key_file = key.name
1402 exception_raised = False
1403 try:
1404 _ = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1405 except JujuInvalidK8sConfiguration as e:
1406 exception_raised = True
1407 self.assertEqual(
1408 e.message, "missing token for auth type oauth2",
1409 )
1410 self.assertTrue(exception_raised)
1411
1412 def test_unknown_api_key(self, mock_configuration):
1413 mock_configuration.username = ""
1414 mock_configuration.password = ""
1415 mock_configuration.api_key = {"authorization": "Bearer Token Wrong"}
1416 mock_configuration.ssl_ca_cert = None
1417 mock_configuration.cert_file = None
1418 mock_configuration.key_file = None
1419 exception_raised = False
1420 try:
1421 _ = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1422 except JujuInvalidK8sConfiguration as e:
1423 exception_raised = True
1424 self.assertEqual(
1425 e.message, "unknown format of api_key",
1426 )
1427 self.assertTrue(exception_raised)
1428
1429 def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
1430 mock_configuration.username = "admin"
1431 mock_configuration.password = "pass"
1432 mock_configuration.api_key = {"authorization": "No_bearer_token"}
1433 mock_configuration.ssl_ca_cert = None
1434 mock_configuration.cert_file = None
1435 mock_configuration.key_file = None
1436 exception_raised = False
1437 try:
1438 _ = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1439 except JujuInvalidK8sConfiguration as e:
1440 exception_raised = True
1441 self.assertEqual(
1442 e.message, "Cannot set both token and user/pass",
1443 )
1444 self.assertTrue(exception_raised)