blob: 36110f69597a7bf6255f0f218f94cd8d1cfe3ef1 [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,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020027 JujuMachineNotFound,
28 JujuApplicationNotFound,
29 JujuActionNotFound,
30 JujuApplicationExists,
David Garcia475a7222020-09-21 16:19:15 +020031 JujuInvalidK8sConfiguration,
David Garcia59f520d2020-10-15 13:16:45 +020032 JujuLeaderUnitNotFound,
ksaikiranrb84e4a72021-03-17 12:53:20 +053033 JujuError,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020034)
David Garciaf6e9b002020-11-27 15:32:02 +010035from n2vc.k8s_juju_conn import generate_rbac_id
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020036
37
38class LibjujuTestCase(asynctest.TestCase):
39 @asynctest.mock.patch("juju.controller.Controller.update_endpoints")
40 @asynctest.mock.patch("juju.client.connector.Connector.connect")
41 @asynctest.mock.patch("juju.controller.Controller.connection")
42 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_api_endpoints_db")
43 def setUp(
44 self,
45 mock__get_api_endpoints_db=None,
46 mock_connection=None,
47 mock_connect=None,
48 mock_update_endpoints=None,
49 ):
50 loop = asyncio.get_event_loop()
51 n2vc = FakeN2VC()
52 mock__get_api_endpoints_db.return_value = ["127.0.0.1:17070"]
53 endpoints = "127.0.0.1:17070"
54 username = "admin"
55 password = "secret"
56 cacert = """
57 -----BEGIN CERTIFICATE-----
58 SOMECERT
59 -----END CERTIFICATE-----"""
60 self.libjuju = Libjuju(
61 endpoints,
62 "192.168.0.155:17070",
63 username,
64 password,
65 cacert,
66 loop,
67 log=None,
68 db={"get_one": []},
69 n2vc=n2vc,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020070 )
71 logging.disable(logging.CRITICAL)
72 loop.run_until_complete(self.libjuju.disconnect())
73
74
David Garciaa4f57d62020-10-22 10:50:56 +020075@asynctest.mock.patch("n2vc.libjuju.Libjuju._create_health_check_task")
76@asynctest.mock.patch("n2vc.libjuju.Libjuju._update_api_endpoints_db")
77@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_api_endpoints_db")
78class LibjujuInitTestCase(asynctest.TestCase):
79 def setUp(self):
80 self.loop = asyncio.get_event_loop()
81 self.n2vc = FakeN2VC()
82 self.endpoint = "192.168.100.100:17070"
83 self.username = "admin"
84 self.password = "secret"
85 self.cacert = """
86 -----BEGIN CERTIFICATE-----
87 SOMECERT
88 -----END CERTIFICATE-----"""
89
90 def test_endpoint_not_in_db(
91 self,
92 mock__get_api_endpoints_db,
93 mock_update_endpoints,
94 mock_create_health_check_task,
95 ):
96 mock__get_api_endpoints_db.return_value = ["another_ip"]
97 Libjuju(
98 self.endpoint,
99 "192.168.0.155:17070",
100 self.username,
101 self.password,
102 self.cacert,
103 self.loop,
104 log=None,
105 db={"get_one": []},
106 n2vc=self.n2vc,
David Garciaa4f57d62020-10-22 10:50:56 +0200107 )
108 mock_update_endpoints.assert_called_once_with([self.endpoint])
109 mock__get_api_endpoints_db.assert_called_once()
110
111 def test_endpoint_in_db(
112 self,
113 mock__get_api_endpoints_db,
114 mock_update_endpoints,
115 mock_create_health_check_task,
116 ):
117 mock__get_api_endpoints_db.return_value = [self.endpoint, "another_ip"]
118 Libjuju(
119 self.endpoint,
120 "192.168.0.155:17070",
121 self.username,
122 self.password,
123 self.cacert,
124 self.loop,
125 log=None,
126 db={"get_one": []},
127 n2vc=self.n2vc,
David Garciaa4f57d62020-10-22 10:50:56 +0200128 )
129 mock_update_endpoints.assert_not_called()
130 mock__get_api_endpoints_db.assert_called_once()
131
132 def test_no_db_endpoints(
133 self,
134 mock__get_api_endpoints_db,
135 mock_update_endpoints,
136 mock_create_health_check_task,
137 ):
138 mock__get_api_endpoints_db.return_value = None
139 Libjuju(
140 self.endpoint,
141 "192.168.0.155:17070",
142 self.username,
143 self.password,
144 self.cacert,
145 self.loop,
146 log=None,
147 db={"get_one": []},
148 n2vc=self.n2vc,
David Garciaa4f57d62020-10-22 10:50:56 +0200149 )
150 mock_update_endpoints.assert_called_once_with([self.endpoint])
151 mock__get_api_endpoints_db.assert_called_once()
152
153
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200154@asynctest.mock.patch("juju.controller.Controller.connect")
155@asynctest.mock.patch(
156 "juju.controller.Controller.api_endpoints",
157 new_callable=asynctest.CoroutineMock(return_value=["127.0.0.1:17070"]),
158)
159@asynctest.mock.patch("n2vc.libjuju.Libjuju._update_api_endpoints_db")
160class GetControllerTest(LibjujuTestCase):
161 def setUp(self):
162 super(GetControllerTest, self).setUp()
163
164 def test_diff_endpoint(
165 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
166 ):
167 self.libjuju.endpoints = []
168 controller = self.loop.run_until_complete(self.libjuju.get_controller())
169 mock__update_api_endpoints_db.assert_called_once_with(["127.0.0.1:17070"])
170 self.assertIsInstance(controller, juju.controller.Controller)
171
172 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
173 def test_exception(
174 self,
175 mock_disconnect_controller,
176 mock__update_api_endpoints_db,
177 mock_api_endpoints,
178 mock_connect,
179 ):
180 self.libjuju.endpoints = []
181 mock__update_api_endpoints_db.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200182 controller = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200183 with self.assertRaises(JujuControllerFailedConnecting):
184 controller = self.loop.run_until_complete(self.libjuju.get_controller())
David Garcia12b29242020-09-17 16:01:48 +0200185 self.assertIsNone(controller)
186 mock_disconnect_controller.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200187
188 def test_same_endpoint_get_controller(
189 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
190 ):
191 self.libjuju.endpoints = ["127.0.0.1:17070"]
192 controller = self.loop.run_until_complete(self.libjuju.get_controller())
193 mock__update_api_endpoints_db.assert_not_called()
194 self.assertIsInstance(controller, juju.controller.Controller)
195
196
197class DisconnectTest(LibjujuTestCase):
198 def setUp(self):
199 super(DisconnectTest, self).setUp()
200
201 @asynctest.mock.patch("juju.model.Model.disconnect")
202 def test_disconnect_model(self, mock_disconnect):
203 self.loop.run_until_complete(self.libjuju.disconnect_model(juju.model.Model()))
204 mock_disconnect.assert_called_once()
205
206 @asynctest.mock.patch("juju.controller.Controller.disconnect")
207 def test_disconnect_controller(self, mock_disconnect):
208 self.loop.run_until_complete(
209 self.libjuju.disconnect_controller(juju.controller.Controller())
210 )
211 mock_disconnect.assert_called_once()
212
213
214@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
215@asynctest.mock.patch("n2vc.libjuju.Libjuju.model_exists")
216@asynctest.mock.patch("juju.controller.Controller.add_model")
217@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
218@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
219class AddModelTest(LibjujuTestCase):
220 def setUp(self):
221 super(AddModelTest, self).setUp()
222
223 def test_existing_model(
224 self,
225 mock_disconnect_model,
226 mock_disconnect_controller,
227 mock_add_model,
228 mock_model_exists,
229 mock_get_controller,
230 ):
231 mock_model_exists.return_value = True
232
David Garciab0a8f402021-03-15 18:41:34 +0100233 # This should not raise an exception
234 self.loop.run_until_complete(
235 self.libjuju.add_model("existing_model", "cloud")
236 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200237
David Garcia12b29242020-09-17 16:01:48 +0200238 mock_disconnect_controller.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200239
240 # TODO Check two job executing at the same time and one returning without doing anything.
241
242 def test_non_existing_model(
243 self,
244 mock_disconnect_model,
245 mock_disconnect_controller,
246 mock_add_model,
247 mock_model_exists,
248 mock_get_controller,
249 ):
250 mock_model_exists.return_value = False
251 mock_get_controller.return_value = juju.controller.Controller()
252
253 self.loop.run_until_complete(
254 self.libjuju.add_model("nonexisting_model", "cloud")
255 )
256
257 mock_add_model.assert_called_once()
258 mock_disconnect_controller.assert_called()
259 mock_disconnect_model.assert_called()
260
261
ksaikiranrb84e4a72021-03-17 12:53:20 +0530262@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
263@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
264@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
265@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
266@asynctest.mock.patch(
267 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
268)
269@asynctest.mock.patch("juju.model.Model.get_action_status")
270@asynctest.mock.patch("juju.model.Model.get_action_output")
271@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_actions")
272class GetExecutedActionsTest(LibjujuTestCase):
273 def setUp(self):
274 super(GetExecutedActionsTest, self).setUp()
275
276 def test_exception(
277 self,
278 mock_get_actions,
279 mock_get_action_output,
280 mock_get_action_status,
281 mock_applications,
282 mock_disconnect_controller,
283 mock_disconnect_model,
284 mock_get_model,
285 mock_get_controller,
286 ):
287 mock_get_model.return_value = None
288 with self.assertRaises(JujuError):
289 self.loop.run_until_complete(self.libjuju.get_executed_actions("model"))
290
291 mock_get_controller.assert_called_once()
292 mock_disconnect_controller.assert_called_once()
293 mock_get_model.assert_called_once()
294 mock_disconnect_model.assert_not_called()
295
296 def test_success(
297 self,
298 mock_get_actions,
299 mock_get_action_output,
300 mock_get_action_status,
301 mock_applications,
302 mock_disconnect_controller,
303 mock_disconnect_model,
304 mock_get_model,
305 mock_get_controller,
306 ):
307 mock_get_model.return_value = juju.model.Model()
308 mock_applications.return_value = {"existing_app"}
309 mock_get_actions.return_value = {"action_name": "description"}
310 mock_get_action_status.return_value = {"id": "status"}
311 mock_get_action_output.return_value = {"output": "completed"}
312
313 executed_actions = self.loop.run_until_complete(
314 self.libjuju.get_executed_actions("model")
315 )
316 expected_result = [{'id': 'id', 'action': 'action_name',
317 'status': 'status', 'output': 'completed'}]
318 self.assertListEqual(expected_result, executed_actions)
319 self.assertIsInstance(executed_actions, list)
320
321 mock_get_controller.assert_called_once()
322 mock_get_model.assert_called_once()
323 mock_disconnect_controller.assert_called_once()
324 mock_disconnect_model.assert_called_once()
325
326
327@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
328@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
329@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
330@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
331@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
332class GetApplicationConfigsTest(LibjujuTestCase):
333 def setUp(self):
334 super(GetApplicationConfigsTest, self).setUp()
335
336 def test_exception(
337 self,
338 mock_get_application,
339 mock_disconnect_controller,
340 mock_disconnect_model,
341 mock_get_model,
342 mock_get_controller,
343 ):
344 mock_get_model.return_value = None
345 with self.assertRaises(JujuError):
346 self.loop.run_until_complete(
347 self.libjuju.get_application_configs("model", "app"))
348
349 mock_get_controller.assert_called_once()
350 mock_disconnect_controller.assert_called_once()
351 mock_get_model.assert_called_once()
352 mock_disconnect_model.assert_not_called()
353
354 def test_success(
355 self,
356 mock_get_application,
357 mock_disconnect_controller,
358 mock_disconnect_model,
359 mock_get_model,
360 mock_get_controller,
361 ):
362 mock_get_application.return_value = FakeApplication()
363 application_configs = self.loop.run_until_complete(self.libjuju
364 .get_application_configs("model", "app"))
365
366 self.assertEqual(application_configs, ["app_config"])
367
368 mock_get_controller.assert_called_once()
369 mock_get_model.assert_called_once()
370 mock_disconnect_controller.assert_called_once()
371 mock_disconnect_model.assert_called_once()
372
373
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200374@asynctest.mock.patch("juju.controller.Controller.get_model")
375class GetModelTest(LibjujuTestCase):
376 def setUp(self):
377 super(GetModelTest, self).setUp()
378
379 def test_get_model(
David Garcia5b802c92020-11-11 16:56:06 +0100380 self,
381 mock_get_model,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200382 ):
383 mock_get_model.return_value = juju.model.Model()
384 model = self.loop.run_until_complete(
385 self.libjuju.get_model(juju.controller.Controller(), "model")
386 )
387 self.assertIsInstance(model, juju.model.Model)
388
389
390@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
391@asynctest.mock.patch("juju.controller.Controller.list_models")
392class ModelExistsTest(LibjujuTestCase):
393 def setUp(self):
394 super(ModelExistsTest, self).setUp()
395
396 async def test_existing_model(
David Garcia5b802c92020-11-11 16:56:06 +0100397 self,
398 mock_list_models,
399 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200400 ):
401 mock_list_models.return_value = ["existing_model"]
402 self.assertTrue(
403 await self.libjuju.model_exists(
404 "existing_model", juju.controller.Controller()
405 )
406 )
407
408 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
409 async def test_no_controller(
David Garcia5b802c92020-11-11 16:56:06 +0100410 self,
411 mock_disconnect_controller,
412 mock_list_models,
413 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200414 ):
415 mock_list_models.return_value = ["existing_model"]
416 mock_get_controller.return_value = juju.controller.Controller()
417 self.assertTrue(await self.libjuju.model_exists("existing_model"))
418 mock_disconnect_controller.assert_called_once()
419
420 async def test_non_existing_model(
David Garcia5b802c92020-11-11 16:56:06 +0100421 self,
422 mock_list_models,
423 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200424 ):
425 mock_list_models.return_value = ["existing_model"]
426 self.assertFalse(
427 await self.libjuju.model_exists(
428 "not_existing_model", juju.controller.Controller()
429 )
430 )
431
432
433@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
434@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
435@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
436@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
437@asynctest.mock.patch("juju.model.Model.get_status")
438class GetModelStatusTest(LibjujuTestCase):
439 def setUp(self):
440 super(GetModelStatusTest, self).setUp()
441
442 def test_success(
443 self,
444 mock_get_status,
445 mock_disconnect_controller,
446 mock_disconnect_model,
447 mock_get_model,
448 mock_get_controller,
449 ):
450 mock_get_model.return_value = juju.model.Model()
451 mock_get_status.return_value = {"status"}
452
453 status = self.loop.run_until_complete(self.libjuju.get_model_status("model"))
454
455 mock_get_status.assert_called_once()
456 mock_disconnect_controller.assert_called_once()
457 mock_disconnect_model.assert_called_once()
458
459 self.assertEqual(status, {"status"})
460
David Garcia12b29242020-09-17 16:01:48 +0200461 def test_exception(
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200462 self,
463 mock_get_status,
464 mock_disconnect_controller,
465 mock_disconnect_model,
466 mock_get_model,
467 mock_get_controller,
468 ):
469 mock_get_model.return_value = juju.model.Model()
470 mock_get_status.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200471 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200472 with self.assertRaises(Exception):
473 status = self.loop.run_until_complete(
474 self.libjuju.get_model_status("model")
475 )
476
David Garcia12b29242020-09-17 16:01:48 +0200477 mock_disconnect_controller.assert_called_once()
478 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200479
David Garcia12b29242020-09-17 16:01:48 +0200480 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200481
482
483@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
484@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
485@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
486@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
487@asynctest.mock.patch("juju.model.Model.get_machines")
488@asynctest.mock.patch("juju.model.Model.add_machine")
489@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
490class CreateMachineTest(LibjujuTestCase):
491 def setUp(self):
492 super(CreateMachineTest, self).setUp()
493
494 def test_existing_machine(
495 self,
496 mock_wait_for,
497 mock_add_machine,
498 mock_get_machines,
499 mock_disconnect_controller,
500 mock_disconnect_model,
501 mock_get_model,
502 mock_get_controller,
503 ):
504 mock_get_model.return_value = juju.model.Model()
505 mock_get_machines.return_value = {"existing_machine": FakeMachine()}
506 machine, bool_res = self.loop.run_until_complete(
507 self.libjuju.create_machine("model", "existing_machine")
508 )
509
510 self.assertIsInstance(machine, FakeMachine)
511 self.assertFalse(bool_res)
512
513 mock_disconnect_controller.assert_called()
514 mock_disconnect_model.assert_called()
515
516 def test_non_existing_machine(
517 self,
518 mock_wait_for,
519 mock_add_machine,
520 mock_get_machines,
521 mock_disconnect_controller,
522 mock_disconnect_model,
523 mock_get_model,
524 mock_get_controller,
525 ):
David Garcia12b29242020-09-17 16:01:48 +0200526 machine = None
527 bool_res = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200528 mock_get_model.return_value = juju.model.Model()
529 with self.assertRaises(JujuMachineNotFound):
530 machine, bool_res = self.loop.run_until_complete(
531 self.libjuju.create_machine("model", "non_existing_machine")
532 )
David Garcia12b29242020-09-17 16:01:48 +0200533 self.assertIsNone(machine)
534 self.assertIsNone(bool_res)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200535
David Garcia12b29242020-09-17 16:01:48 +0200536 mock_disconnect_controller.assert_called()
537 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200538
539 def test_no_machine(
540 self,
541 mock_wait_for,
542 mock_add_machine,
543 mock_get_machines,
544 mock_disconnect_controller,
545 mock_disconnect_model,
546 mock_get_model,
547 mock_get_controller,
548 ):
549 mock_get_model.return_value = juju.model.Model()
550 mock_add_machine.return_value = FakeMachine()
551
552 machine, bool_res = self.loop.run_until_complete(
553 self.libjuju.create_machine("model")
554 )
555
556 self.assertIsInstance(machine, FakeMachine)
557 self.assertTrue(bool_res)
558
559 mock_wait_for.assert_called_once()
560 mock_add_machine.assert_called_once()
561
562 mock_disconnect_controller.assert_called()
563 mock_disconnect_model.assert_called()
564
565
566# TODO test provision machine
567
568
569@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
570@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
571@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
572@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
David Garcia667696e2020-09-22 14:52:32 +0200573@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
574@asynctest.mock.patch("juju.model.Model.deploy")
575class DeployTest(LibjujuTestCase):
576 def setUp(self):
577 super(DeployTest, self).setUp()
578
579 def test_deploy(
580 self,
581 mock_deploy,
582 mock_wait_for_model,
583 mock_disconnect_controller,
584 mock_disconnect_model,
585 mock_get_model,
586 mock_get_controller,
587 ):
588 mock_get_model.return_value = juju.model.Model()
589 self.loop.run_until_complete(
590 self.libjuju.deploy("cs:osm", "model", wait=True, timeout=0)
591 )
592 mock_deploy.assert_called_once()
593 mock_wait_for_model.assert_called_once()
594 mock_disconnect_controller.assert_called_once()
595 mock_disconnect_model.assert_called_once()
596
597 def test_deploy_no_wait(
598 self,
599 mock_deploy,
600 mock_wait_for_model,
601 mock_disconnect_controller,
602 mock_disconnect_model,
603 mock_get_model,
604 mock_get_controller,
605 ):
606 mock_get_model.return_value = juju.model.Model()
607 self.loop.run_until_complete(
608 self.libjuju.deploy("cs:osm", "model", wait=False, timeout=0)
609 )
610 mock_deploy.assert_called_once()
611 mock_wait_for_model.assert_not_called()
612 mock_disconnect_controller.assert_called_once()
613 mock_disconnect_model.assert_called_once()
614
615 def test_deploy_exception(
616 self,
617 mock_deploy,
618 mock_wait_for_model,
619 mock_disconnect_controller,
620 mock_disconnect_model,
621 mock_get_model,
622 mock_get_controller,
623 ):
624 mock_deploy.side_effect = Exception()
625 mock_get_model.return_value = juju.model.Model()
626 with self.assertRaises(Exception):
627 self.loop.run_until_complete(self.libjuju.deploy("cs:osm", "model"))
628 mock_deploy.assert_called_once()
629 mock_wait_for_model.assert_not_called()
630 mock_disconnect_controller.assert_called_once()
631 mock_disconnect_model.assert_called_once()
632
633
634@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
635@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
636@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
637@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200638@asynctest.mock.patch(
639 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
640)
641@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
642@asynctest.mock.patch("juju.model.Model.deploy")
643@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
644@asynctest.mock.patch("n2vc.libjuju.Libjuju.create_machine")
645class DeployCharmTest(LibjujuTestCase):
646 def setUp(self):
647 super(DeployCharmTest, self).setUp()
648
649 def test_existing_app(
650 self,
651 mock_create_machine,
652 mock_wait_for,
653 mock_deploy,
654 mock_machines,
655 mock_applications,
656 mock_disconnect_controller,
657 mock_disconnect_model,
658 mock_get_model,
659 mock_get_controller,
660 ):
661 mock_get_model.return_value = juju.model.Model()
662 mock_applications.return_value = {"existing_app"}
663
David Garcia12b29242020-09-17 16:01:48 +0200664 application = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200665 with self.assertRaises(JujuApplicationExists):
666 application = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100667 self.libjuju.deploy_charm(
668 "existing_app",
669 "path",
670 "model",
671 "machine",
672 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200673 )
David Garcia12b29242020-09-17 16:01:48 +0200674 self.assertIsNone(application)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200675
David Garcia12b29242020-09-17 16:01:48 +0200676 mock_disconnect_controller.assert_called()
677 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200678
679 def test_non_existing_machine(
680 self,
681 mock_create_machine,
682 mock_wait_for,
683 mock_deploy,
684 mock_machines,
685 mock_applications,
686 mock_disconnect_controller,
687 mock_disconnect_model,
688 mock_get_model,
689 mock_get_controller,
690 ):
691 mock_get_model.return_value = juju.model.Model()
692 mock_machines.return_value = {"existing_machine": FakeMachine()}
David Garcia12b29242020-09-17 16:01:48 +0200693 application = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200694 with self.assertRaises(JujuMachineNotFound):
695 application = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100696 self.libjuju.deploy_charm(
697 "app",
698 "path",
699 "model",
700 "machine",
701 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200702 )
703
David Garcia12b29242020-09-17 16:01:48 +0200704 self.assertIsNone(application)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200705
David Garcia12b29242020-09-17 16:01:48 +0200706 mock_disconnect_controller.assert_called()
707 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200708
709 def test_2_units(
710 self,
711 mock_create_machine,
712 mock_wait_for,
713 mock_deploy,
714 mock_machines,
715 mock_applications,
716 mock_disconnect_controller,
717 mock_disconnect_model,
718 mock_get_model,
719 mock_get_controller,
720 ):
721 mock_get_model.return_value = juju.model.Model()
722 mock_machines.return_value = {"existing_machine": FakeMachine()}
723 mock_create_machine.return_value = (FakeMachine(), "other")
724 mock_deploy.return_value = FakeApplication()
725 application = self.loop.run_until_complete(
726 self.libjuju.deploy_charm(
David Garcia5b802c92020-11-11 16:56:06 +0100727 "app",
728 "path",
729 "model",
730 "existing_machine",
731 num_units=2,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200732 )
733 )
734
735 self.assertIsInstance(application, FakeApplication)
736
737 mock_deploy.assert_called_once()
738 mock_wait_for.assert_called_once()
739
740 mock_create_machine.assert_called_once()
741
742 mock_disconnect_controller.assert_called()
743 mock_disconnect_model.assert_called()
744
745 def test_1_unit(
746 self,
747 mock_create_machine,
748 mock_wait_for,
749 mock_deploy,
750 mock_machines,
751 mock_applications,
752 mock_disconnect_controller,
753 mock_disconnect_model,
754 mock_get_model,
755 mock_get_controller,
756 ):
757 mock_get_model.return_value = juju.model.Model()
758 mock_machines.return_value = {"existing_machine": FakeMachine()}
759 mock_deploy.return_value = FakeApplication()
760 application = self.loop.run_until_complete(
761 self.libjuju.deploy_charm("app", "path", "model", "existing_machine")
762 )
763
764 self.assertIsInstance(application, FakeApplication)
765
766 mock_deploy.assert_called_once()
767 mock_wait_for.assert_called_once()
768
769 mock_disconnect_controller.assert_called()
770 mock_disconnect_model.assert_called()
771
772
773@asynctest.mock.patch(
774 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
775)
776class GetApplicationTest(LibjujuTestCase):
777 def setUp(self):
778 super(GetApplicationTest, self).setUp()
779
780 def test_existing_application(
David Garcia5b802c92020-11-11 16:56:06 +0100781 self,
782 mock_applications,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200783 ):
784 mock_applications.return_value = {"existing_app": "exists"}
785 model = juju.model.Model()
786 result = self.libjuju._get_application(model, "existing_app")
787 self.assertEqual(result, "exists")
788
789 def test_non_existing_application(
David Garcia5b802c92020-11-11 16:56:06 +0100790 self,
791 mock_applications,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200792 ):
793 mock_applications.return_value = {"existing_app": "exists"}
794 model = juju.model.Model()
795 result = self.libjuju._get_application(model, "nonexisting_app")
796 self.assertIsNone(result)
797
798
799@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
800@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
801@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
802@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
803@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
804@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
805@asynctest.mock.patch("juju.model.Model.get_action_output")
806@asynctest.mock.patch("juju.model.Model.get_action_status")
807class ExecuteActionTest(LibjujuTestCase):
808 def setUp(self):
809 super(ExecuteActionTest, self).setUp()
810
811 def test_no_application(
812 self,
813 mock_get_action_status,
814 mock_get_action_output,
815 mock_wait_for,
816 mock__get_application,
817 mock_disconnect_controller,
818 mock_disconnect_model,
819 mock_get_model,
820 mock_get_controller,
821 ):
822 mock__get_application.return_value = None
823 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +0200824 output = None
825 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200826 with self.assertRaises(JujuApplicationNotFound):
827 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100828 self.libjuju.execute_action(
829 "app",
830 "model",
831 "action",
832 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200833 )
David Garcia12b29242020-09-17 16:01:48 +0200834 self.assertIsNone(output)
835 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200836
David Garcia12b29242020-09-17 16:01:48 +0200837 mock_disconnect_controller.assert_called()
838 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200839
840 def test_no_action(
841 self,
842 mock_get_action_status,
843 mock_get_action_output,
844 mock_wait_for,
845 mock__get_application,
846 mock_disconnect_controller,
847 mock_disconnect_model,
848 mock_get_model,
849 mock_get_controller,
850 ):
851
852 mock_get_model.return_value = juju.model.Model()
853 mock__get_application.return_value = FakeApplication()
David Garcia12b29242020-09-17 16:01:48 +0200854 output = None
855 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200856 with self.assertRaises(JujuActionNotFound):
857 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100858 self.libjuju.execute_action(
859 "app",
860 "model",
861 "action",
862 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200863 )
David Garcia12b29242020-09-17 16:01:48 +0200864 self.assertIsNone(output)
865 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200866
David Garcia12b29242020-09-17 16:01:48 +0200867 mock_disconnect_controller.assert_called()
868 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200869
David Garcia59f520d2020-10-15 13:16:45 +0200870 @asynctest.mock.patch("asyncio.sleep")
871 @asynctest.mock.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
872 def test_no_leader(
873 self,
874 mock_is_leader_from_status,
875 mock_sleep,
876 mock_get_action_status,
877 mock_get_action_output,
878 mock_wait_for,
879 mock__get_application,
880 mock_disconnect_controller,
881 mock_disconnect_model,
882 mock_get_model,
883 mock_get_controller,
884 ):
885 mock_get_model.return_value = juju.model.Model()
886 mock__get_application.return_value = FakeApplication()
887 mock_is_leader_from_status.return_value = False
888 output = None
889 status = None
890 with self.assertRaises(JujuLeaderUnitNotFound):
891 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100892 self.libjuju.execute_action(
893 "app",
894 "model",
895 "action",
896 )
David Garcia59f520d2020-10-15 13:16:45 +0200897 )
898 self.assertIsNone(output)
899 self.assertIsNone(status)
900
901 mock_disconnect_controller.assert_called()
902 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200903
904 def test_succesful_exec(
905 self,
906 mock_get_action_status,
907 mock_get_action_output,
908 mock_wait_for,
909 mock__get_application,
910 mock_disconnect_controller,
911 mock_disconnect_model,
912 mock_get_model,
913 mock_get_controller,
914 ):
915 mock_get_model.return_value = juju.model.Model()
916 mock__get_application.return_value = FakeApplication()
917 mock_get_action_output.return_value = "output"
918 mock_get_action_status.return_value = {"id": "status"}
919 output, status = self.loop.run_until_complete(
920 self.libjuju.execute_action("app", "model", "existing_action")
921 )
922 self.assertEqual(output, "output")
923 self.assertEqual(status, "status")
924
925 mock_wait_for.assert_called_once()
926
927 mock_disconnect_controller.assert_called()
928 mock_disconnect_model.assert_called()
929
930
931@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
932@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
933@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
934@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
935@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
936class GetActionTest(LibjujuTestCase):
937 def setUp(self):
938 super(GetActionTest, self).setUp()
939
940 def test_exception(
941 self,
942 mock_get_application,
943 mock_disconnect_controller,
944 mock_disconnect_model,
945 mock_get_model,
946 mock_get_controller,
947 ):
948 mock_get_application.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200949 actions = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200950 with self.assertRaises(Exception):
951 actions = self.loop.run_until_complete(
952 self.libjuju.get_actions("app", "model")
953 )
954
David Garcia12b29242020-09-17 16:01:48 +0200955 self.assertIsNone(actions)
956 mock_disconnect_controller.assert_called_once()
957 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200958
959 def test_success(
960 self,
961 mock_get_application,
962 mock_disconnect_controller,
963 mock_disconnect_model,
964 mock_get_model,
965 mock_get_controller,
966 ):
967 mock_get_application.return_value = FakeApplication()
968
969 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
970
971 self.assertEqual(actions, ["existing_action"])
972
973 mock_get_controller.assert_called_once()
974 mock_get_model.assert_called_once()
975 mock_disconnect_controller.assert_called_once()
976 mock_disconnect_model.assert_called_once()
977
978
979@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
980@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
981@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
982@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
David Garcia85755d12020-09-21 19:51:23 +0200983@asynctest.mock.patch("juju.application.Application.get_metrics")
984@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
985class GetMetricsTest(LibjujuTestCase):
986 def setUp(self):
987 super(GetMetricsTest, self).setUp()
988
989 def test_get_metrics_success(
990 self,
991 mock_get_application,
992 mock_get_metrics,
993 mock_disconnect_controller,
994 mock_disconnect_model,
995 mock_get_model,
996 mock_get_controller,
997 ):
998 mock_get_application.return_value = FakeApplication()
999 mock_get_model.return_value = juju.model.Model()
1000
1001 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
1002
1003 mock_disconnect_controller.assert_called_once()
1004 mock_disconnect_model.assert_called_once()
1005
1006 def test_get_metrics_exception(
1007 self,
1008 mock_get_application,
1009 mock_get_metrics,
1010 mock_disconnect_controller,
1011 mock_disconnect_model,
1012 mock_get_model,
1013 mock_get_controller,
1014 ):
1015 mock_get_model.return_value = juju.model.Model()
1016 mock_get_metrics.side_effect = Exception()
1017 with self.assertRaises(Exception):
1018 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
1019
1020 mock_disconnect_controller.assert_called_once()
1021 mock_disconnect_model.assert_called_once()
1022
1023 def test_missing_args_exception(
1024 self,
1025 mock_get_application,
1026 mock_get_metrics,
1027 mock_disconnect_controller,
1028 mock_disconnect_model,
1029 mock_get_model,
1030 mock_get_controller,
1031 ):
1032 mock_get_model.return_value = juju.model.Model()
1033
1034 with self.assertRaises(Exception):
1035 self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
1036
1037 mock_get_controller.assert_not_called()
1038 mock_get_model.assert_not_called()
1039 mock_disconnect_controller.assert_not_called()
1040 mock_disconnect_model.assert_not_called()
1041
1042
1043@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1044@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1045@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1046@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001047@asynctest.mock.patch("juju.model.Model.add_relation")
1048class AddRelationTest(LibjujuTestCase):
1049 def setUp(self):
1050 super(AddRelationTest, self).setUp()
1051
1052 @asynctest.mock.patch("logging.Logger.warning")
1053 def test_not_found(
1054 self,
1055 mock_warning,
1056 mock_add_relation,
1057 mock_disconnect_controller,
1058 mock_disconnect_model,
1059 mock_get_model,
1060 mock_get_controller,
1061 ):
1062 # TODO in libjuju.py should this fail only with a log message?
1063 result = {"error": "not found", "response": "response", "request-id": 1}
1064
1065 mock_get_model.return_value = juju.model.Model()
1066 mock_add_relation.side_effect = JujuAPIError(result)
1067
1068 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001069 self.libjuju.add_relation(
1070 "model",
1071 "app1:relation1",
1072 "app2:relation2",
1073 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001074 )
1075
1076 mock_warning.assert_called_with("Relation not found: not found")
1077 mock_disconnect_controller.assert_called_once()
1078 mock_disconnect_model.assert_called_once()
1079
1080 @asynctest.mock.patch("logging.Logger.warning")
1081 def test_already_exists(
1082 self,
1083 mock_warning,
1084 mock_add_relation,
1085 mock_disconnect_controller,
1086 mock_disconnect_model,
1087 mock_get_model,
1088 mock_get_controller,
1089 ):
1090 # TODO in libjuju.py should this fail silently?
1091 result = {"error": "already exists", "response": "response", "request-id": 1}
1092
1093 mock_get_model.return_value = juju.model.Model()
1094 mock_add_relation.side_effect = JujuAPIError(result)
1095
1096 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001097 self.libjuju.add_relation(
1098 "model",
1099 "app1:relation1",
1100 "app2:relation2",
1101 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001102 )
1103
1104 mock_warning.assert_called_with("Relation already exists: already exists")
1105 mock_disconnect_controller.assert_called_once()
1106 mock_disconnect_model.assert_called_once()
1107
1108 def test_exception(
1109 self,
1110 mock_add_relation,
1111 mock_disconnect_controller,
1112 mock_disconnect_model,
1113 mock_get_model,
1114 mock_get_controller,
1115 ):
1116 mock_get_model.return_value = juju.model.Model()
1117 result = {"error": "", "response": "response", "request-id": 1}
1118 mock_add_relation.side_effect = JujuAPIError(result)
1119
1120 with self.assertRaises(JujuAPIError):
1121 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001122 self.libjuju.add_relation(
1123 "model",
1124 "app1:relation1",
1125 "app2:relation2",
1126 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001127 )
1128
David Garcia12b29242020-09-17 16:01:48 +02001129 mock_disconnect_controller.assert_called_once()
1130 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001131
1132 def test_success(
1133 self,
1134 mock_add_relation,
1135 mock_disconnect_controller,
1136 mock_disconnect_model,
1137 mock_get_model,
1138 mock_get_controller,
1139 ):
1140 mock_get_model.return_value = juju.model.Model()
1141
1142 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001143 self.libjuju.add_relation(
1144 "model",
1145 "app1:relation1",
1146 "app2:relation2",
1147 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001148 )
1149
David Garcia12b29242020-09-17 16:01:48 +02001150 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
David Garcia8331f7c2020-08-25 16:10:07 +02001151 mock_disconnect_controller.assert_called_once()
1152 mock_disconnect_model.assert_called_once()
1153
1154 def test_saas(
1155 self,
1156 mock_add_relation,
1157 mock_disconnect_controller,
1158 mock_disconnect_model,
1159 mock_get_model,
1160 mock_get_controller,
1161 ):
1162 mock_get_model.return_value = juju.model.Model()
1163
1164 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001165 self.libjuju.add_relation(
1166 "model",
1167 "app1:relation1",
1168 "saas_name",
1169 )
David Garcia8331f7c2020-08-25 16:10:07 +02001170 )
1171
David Garcia12b29242020-09-17 16:01:48 +02001172 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001173 mock_disconnect_controller.assert_called_once()
1174 mock_disconnect_model.assert_called_once()
1175
1176
1177# TODO destroy_model testcase
1178
1179
David Garcia5ef42a12020-09-29 19:48:13 +02001180# @asynctest.mock.patch("juju.model.Model.get_machines")
1181# @asynctest.mock.patch("logging.Logger.debug")
1182# class DestroyMachineTest(LibjujuTestCase):
1183# def setUp(self):
1184# super(DestroyMachineTest, self).setUp()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001185
David Garcia5ef42a12020-09-29 19:48:13 +02001186# def test_success_manual_machine(
1187# self, mock_debug, mock_get_machines,
1188# ):
1189# mock_get_machines.side_effect = [
1190# {"machine": FakeManualMachine()},
1191# {"machine": FakeManualMachine()},
1192# {},
1193# ]
1194# self.loop.run_until_complete(
1195# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
1196# )
1197# calls = [
1198# asynctest.call("Waiting for machine machine is destroyed"),
1199# asynctest.call("Machine destroyed: machine"),
1200# ]
1201# mock_debug.assert_has_calls(calls)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001202
David Garcia5ef42a12020-09-29 19:48:13 +02001203# def test_no_machine(
1204# self, mock_debug, mock_get_machines,
1205# ):
1206# mock_get_machines.return_value = {}
1207# self.loop.run_until_complete(
1208# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
1209# )
1210# mock_debug.assert_called_with("Machine not found: machine")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001211
1212
1213@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1214@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1215@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1216@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1217@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1218class ConfigureApplicationTest(LibjujuTestCase):
1219 def setUp(self):
1220 super(ConfigureApplicationTest, self).setUp()
1221
1222 def test_success(
1223 self,
1224 mock_get_application,
1225 mock_disconnect_controller,
1226 mock_disconnect_model,
1227 mock_get_model,
1228 mock_get_controller,
1229 ):
1230
1231 mock_get_application.return_value = FakeApplication()
1232
1233 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001234 self.libjuju.configure_application(
1235 "model",
1236 "app",
1237 {"config"},
1238 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001239 )
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
1253 mock_get_application.side_effect = Exception()
1254
1255 with self.assertRaises(Exception):
1256 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001257 self.libjuju.configure_application(
1258 "model",
1259 "app",
1260 {"config"},
1261 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001262 )
David Garcia12b29242020-09-17 16:01:48 +02001263 mock_disconnect_controller.assert_called_once()
1264 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001265
David Garcia5b802c92020-11-11 16:56:06 +01001266 def test_controller_exception(
1267 self,
1268 mock_get_application,
1269 mock_disconnect_controller,
1270 mock_disconnect_model,
1271 mock_get_model,
1272 mock_get_controller,
1273 ):
1274
1275 result = {"error": "not found", "response": "response", "request-id": 1}
1276
1277 mock_get_controller.side_effect = JujuAPIError(result)
1278
1279 with self.assertRaises(JujuAPIError):
1280 self.loop.run_until_complete(
1281 self.libjuju.configure_application(
1282 "model",
1283 "app",
1284 {"config"},
1285 )
1286 )
1287 mock_get_model.assert_not_called()
1288 mock_disconnect_controller.assert_not_called()
1289 mock_disconnect_model.assert_not_called()
1290
1291 def test_get_model_exception(
1292 self,
1293 mock_get_application,
1294 mock_disconnect_controller,
1295 mock_disconnect_model,
1296 mock_get_model,
1297 mock_get_controller,
1298 ):
1299
1300 result = {"error": "not found", "response": "response", "request-id": 1}
1301 mock_get_model.side_effect = JujuAPIError(result)
1302
1303 with self.assertRaises(JujuAPIError):
1304 self.loop.run_until_complete(
1305 self.libjuju.configure_application(
1306 "model",
1307 "app",
1308 {"config"},
1309 )
1310 )
1311 mock_get_model.assert_called_once()
1312 mock_disconnect_controller.assert_called_once()
1313 mock_disconnect_model.assert_not_called()
1314
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001315
1316# TODO _get_api_endpoints_db test case
1317# TODO _update_api_endpoints_db test case
1318# TODO healthcheck test case
1319
1320
1321@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1322@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1323@asynctest.mock.patch("juju.controller.Controller.list_models")
1324class ListModelsTest(LibjujuTestCase):
1325 def setUp(self):
1326 super(ListModelsTest, self).setUp()
1327
1328 def test_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001329 self,
1330 mock_list_models,
1331 mock_disconnect_controller,
1332 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001333 ):
1334 mock_get_controller.return_value = juju.controller.Controller()
1335 mock_list_models.return_value = ["existingmodel"]
1336 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
1337
1338 mock_disconnect_controller.assert_called_once()
1339 self.assertEquals(models, ["existingmodel"])
1340
1341 def test_not_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001342 self,
1343 mock_list_models,
1344 mock_disconnect_controller,
1345 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001346 ):
1347 mock_get_controller.return_value = juju.controller.Controller()
1348 mock_list_models.return_value = ["existingmodel", "model"]
1349 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
1350
1351 mock_disconnect_controller.assert_called_once()
1352 self.assertEquals(models, [])
1353
1354 def test_no_contains_arg(
David Garcia5b802c92020-11-11 16:56:06 +01001355 self,
1356 mock_list_models,
1357 mock_disconnect_controller,
1358 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001359 ):
1360 mock_get_controller.return_value = juju.controller.Controller()
1361 mock_list_models.return_value = ["existingmodel", "model"]
1362 models = self.loop.run_until_complete(self.libjuju.list_models())
1363
1364 mock_disconnect_controller.assert_called_once()
1365 self.assertEquals(models, ["existingmodel", "model"])
David Garcia42f328a2020-08-25 15:03:01 +02001366
1367
1368@asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
1369class ModelsExistTest(LibjujuTestCase):
1370 def setUp(self):
1371 super(ModelsExistTest, self).setUp()
1372
1373 def test_model_names_none(self, mock_list_models):
1374 mock_list_models.return_value = []
1375 with self.assertRaises(Exception):
1376 self.loop.run_until_complete(self.libjuju.models_exist(None))
1377
1378 def test_model_names_empty(self, mock_list_models):
1379 mock_list_models.return_value = []
1380 with self.assertRaises(Exception):
1381 (exist, non_existing_models) = self.loop.run_until_complete(
1382 self.libjuju.models_exist([])
1383 )
1384
1385 def test_model_names_not_existing(self, mock_list_models):
1386 mock_list_models.return_value = ["prometheus", "grafana"]
1387 (exist, non_existing_models) = self.loop.run_until_complete(
1388 self.libjuju.models_exist(["prometheus2", "grafana"])
1389 )
1390 self.assertFalse(exist)
1391 self.assertEqual(non_existing_models, ["prometheus2"])
1392
1393 def test_model_names_exist(self, mock_list_models):
1394 mock_list_models.return_value = ["prometheus", "grafana"]
1395 (exist, non_existing_models) = self.loop.run_until_complete(
1396 self.libjuju.models_exist(["prometheus", "grafana"])
1397 )
1398 self.assertTrue(exist)
1399 self.assertEqual(non_existing_models, [])
David Garciabc538e42020-08-25 15:22:30 +02001400
1401
1402@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1403@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1404@asynctest.mock.patch("juju.controller.Controller.list_offers")
1405class ListOffers(LibjujuTestCase):
1406 def setUp(self):
1407 super(ListOffers, self).setUp()
1408
1409 def test_disconnect_controller(
David Garcia5b802c92020-11-11 16:56:06 +01001410 self,
1411 mock_list_offers,
1412 mock_disconnect_controller,
1413 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001414 ):
1415 mock_get_controller.return_value = juju.controller.Controller()
1416 mock_list_offers.side_effect = Exception()
1417 with self.assertRaises(Exception):
1418 self.loop.run_until_complete(self.libjuju.list_offers("model"))
1419 mock_disconnect_controller.assert_called_once()
1420
1421 def test_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001422 self,
1423 mock_list_offers,
1424 mock_disconnect_controller,
1425 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001426 ):
1427 mock_get_controller.return_value = juju.controller.Controller()
1428 mock_list_offers.return_value = []
1429 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
1430 self.assertEqual(offers, [])
1431 mock_disconnect_controller.assert_called_once()
1432
1433 def test_non_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001434 self,
1435 mock_list_offers,
1436 mock_disconnect_controller,
1437 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001438 ):
1439 mock_get_controller.return_value = juju.controller.Controller()
1440 mock_list_offers.return_value = ["offer"]
1441 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
1442 self.assertEqual(offers, ["offer"])
1443 mock_disconnect_controller.assert_called_once()
David Garcia68b00722020-09-11 15:05:00 +02001444
1445
1446@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1447@asynctest.mock.patch("juju.controller.Controller.get_model")
1448@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1449@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1450@asynctest.mock.patch("juju.model.Model.consume")
1451class ConsumeTest(LibjujuTestCase):
1452 def setUp(self):
1453 super(ConsumeTest, self).setUp()
1454
1455 def test_consume(
1456 self,
1457 mock_consume,
1458 mock_disconnect_controller,
1459 mock_disconnect_model,
1460 mock_get_model,
1461 mock_get_controller,
1462 ):
1463 mock_get_controller.return_value = juju.controller.Controller()
1464 mock_get_model.return_value = juju.model.Model()
1465
David Garcia12b29242020-09-17 16:01:48 +02001466 self.loop.run_until_complete(self.libjuju.consume("offer_url", "model_name"))
David Garcia68b00722020-09-11 15:05:00 +02001467 mock_consume.assert_called_once()
1468 mock_disconnect_model.assert_called_once()
1469 mock_disconnect_controller.assert_called_once()
1470
1471 def test_parsing_error_exception(
1472 self,
1473 mock_consume,
1474 mock_disconnect_controller,
1475 mock_disconnect_model,
1476 mock_get_model,
1477 mock_get_controller,
1478 ):
1479 mock_get_controller.return_value = juju.controller.Controller()
1480 mock_get_model.return_value = juju.model.Model()
1481 mock_consume.side_effect = juju.offerendpoints.ParseError("")
1482
1483 with self.assertRaises(juju.offerendpoints.ParseError):
1484 self.loop.run_until_complete(
1485 self.libjuju.consume("offer_url", "model_name")
1486 )
1487 mock_consume.assert_called_once()
1488 mock_disconnect_model.assert_called_once()
1489 mock_disconnect_controller.assert_called_once()
1490
1491 def test_juju_error_exception(
1492 self,
1493 mock_consume,
1494 mock_disconnect_controller,
1495 mock_disconnect_model,
1496 mock_get_model,
1497 mock_get_controller,
1498 ):
1499 mock_get_controller.return_value = juju.controller.Controller()
1500 mock_get_model.return_value = juju.model.Model()
1501 mock_consume.side_effect = juju.errors.JujuError("")
1502
1503 with self.assertRaises(juju.errors.JujuError):
1504 self.loop.run_until_complete(
1505 self.libjuju.consume("offer_url", "model_name")
1506 )
1507 mock_consume.assert_called_once()
1508 mock_disconnect_model.assert_called_once()
1509 mock_disconnect_controller.assert_called_once()
1510
1511 def test_juju_api_error_exception(
1512 self,
1513 mock_consume,
1514 mock_disconnect_controller,
1515 mock_disconnect_model,
1516 mock_get_model,
1517 mock_get_controller,
1518 ):
1519 mock_get_controller.return_value = juju.controller.Controller()
1520 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +02001521 mock_consume.side_effect = juju.errors.JujuAPIError(
1522 {"error": "", "response": "", "request-id": ""}
1523 )
David Garcia68b00722020-09-11 15:05:00 +02001524
1525 with self.assertRaises(juju.errors.JujuAPIError):
1526 self.loop.run_until_complete(
1527 self.libjuju.consume("offer_url", "model_name")
1528 )
1529 mock_consume.assert_called_once()
1530 mock_disconnect_model.assert_called_once()
1531 mock_disconnect_controller.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001532
1533
David Garcia475a7222020-09-21 16:19:15 +02001534@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
David Garcia12b29242020-09-17 16:01:48 +02001535@asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
1536class AddK8sTest(LibjujuTestCase):
1537 def setUp(self):
1538 super(AddK8sTest, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001539 name = "cloud"
1540 rbac_id = generate_rbac_id()
1541 token = "token"
1542 client_cert_data = "cert"
1543 configuration = kubernetes.client.configuration.Configuration()
1544 storage_class = "storage_class"
1545 credential_name = name
1546
1547 self._add_k8s_args = {
1548 "name": name,
1549 "rbac_id": rbac_id,
1550 "token": token,
1551 "client_cert_data": client_cert_data,
1552 "configuration": configuration,
1553 "storage_class": storage_class,
1554 "credential_name": credential_name,
1555 }
David Garcia12b29242020-09-17 16:01:48 +02001556
David Garcia475a7222020-09-21 16:19:15 +02001557 def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001558 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001559 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001560 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001561
David Garcia475a7222020-09-21 16:19:15 +02001562 def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garcia12b29242020-09-17 16:01:48 +02001563 mock_add_cloud.side_effect = Exception()
1564 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001565 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001566 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001567 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001568
David Garcia475a7222020-09-21 16:19:15 +02001569 def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001570 self._add_k8s_args["name"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001571 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001572 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001573 mock_add_cloud.assert_not_called()
1574
David Garcia475a7222020-09-21 16:19:15 +02001575 def test_add_k8s_missing_storage_name(
1576 self, mock_add_cloud, mock_get_k8s_cloud_credential
1577 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001578 self._add_k8s_args["storage_class"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001579 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001580 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001581 mock_add_cloud.assert_not_called()
1582
David Garcia475a7222020-09-21 16:19:15 +02001583 def test_add_k8s_missing_configuration_keys(
1584 self, mock_add_cloud, mock_get_k8s_cloud_credential
1585 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001586 self._add_k8s_args["configuration"] = None
David Garcia12b29242020-09-17 16:01:48 +02001587 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001588 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001589 mock_add_cloud.assert_not_called()
1590
1591
1592@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1593@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1594@asynctest.mock.patch("juju.controller.Controller.add_cloud")
1595@asynctest.mock.patch("juju.controller.Controller.add_credential")
1596class AddCloudTest(LibjujuTestCase):
1597 def setUp(self):
1598 super(AddCloudTest, self).setUp()
1599 self.cloud = juju.client.client.Cloud()
1600 self.credential = juju.client.client.CloudCredential()
1601
1602 def test_add_cloud_with_credential(
1603 self,
1604 mock_add_credential,
1605 mock_add_cloud,
1606 mock_disconnect_controller,
1607 mock_get_controller,
1608 ):
1609 mock_get_controller.return_value = juju.controller.Controller()
1610
1611 cloud = self.loop.run_until_complete(
1612 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1613 )
1614 self.assertEqual(cloud, self.cloud)
1615 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1616 mock_add_credential.assert_called_once_with(
1617 "cloud", credential=self.credential, cloud="cloud"
1618 )
1619 mock_disconnect_controller.assert_called_once()
1620
1621 def test_add_cloud_no_credential(
1622 self,
1623 mock_add_credential,
1624 mock_add_cloud,
1625 mock_disconnect_controller,
1626 mock_get_controller,
1627 ):
1628 mock_get_controller.return_value = juju.controller.Controller()
1629
1630 cloud = self.loop.run_until_complete(
1631 self.libjuju.add_cloud("cloud", self.cloud)
1632 )
1633 self.assertEqual(cloud, self.cloud)
1634 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1635 mock_add_credential.assert_not_called()
1636 mock_disconnect_controller.assert_called_once()
1637
1638 def test_add_cloud_exception(
1639 self,
1640 mock_add_credential,
1641 mock_add_cloud,
1642 mock_disconnect_controller,
1643 mock_get_controller,
1644 ):
1645 mock_get_controller.return_value = juju.controller.Controller()
1646 mock_add_cloud.side_effect = Exception()
1647 with self.assertRaises(Exception):
1648 self.loop.run_until_complete(
1649 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1650 )
1651
1652 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1653 mock_add_credential.assert_not_called()
1654 mock_disconnect_controller.assert_called_once()
1655
1656 def test_add_credential_exception(
1657 self,
1658 mock_add_credential,
1659 mock_add_cloud,
1660 mock_disconnect_controller,
1661 mock_get_controller,
1662 ):
1663 mock_get_controller.return_value = juju.controller.Controller()
1664 mock_add_credential.side_effect = Exception()
1665 with self.assertRaises(Exception):
1666 self.loop.run_until_complete(
1667 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1668 )
1669
1670 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1671 mock_add_credential.assert_called_once_with(
1672 "cloud", credential=self.credential, cloud="cloud"
1673 )
1674 mock_disconnect_controller.assert_called_once()
1675
1676
1677@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1678@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1679@asynctest.mock.patch("juju.controller.Controller.remove_cloud")
1680class RemoveCloudTest(LibjujuTestCase):
1681 def setUp(self):
1682 super(RemoveCloudTest, self).setUp()
1683
1684 def test_remove_cloud(
David Garcia5b802c92020-11-11 16:56:06 +01001685 self,
1686 mock_remove_cloud,
1687 mock_disconnect_controller,
1688 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001689 ):
1690 mock_get_controller.return_value = juju.controller.Controller()
1691
1692 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1693 mock_remove_cloud.assert_called_once_with("cloud")
1694 mock_disconnect_controller.assert_called_once()
1695
1696 def test_remove_cloud_exception(
David Garcia5b802c92020-11-11 16:56:06 +01001697 self,
1698 mock_remove_cloud,
1699 mock_disconnect_controller,
1700 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001701 ):
1702 mock_get_controller.return_value = juju.controller.Controller()
1703 mock_remove_cloud.side_effect = Exception()
1704
1705 with self.assertRaises(Exception):
1706 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1707 mock_remove_cloud.assert_called_once_with("cloud")
1708 mock_disconnect_controller.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001709
1710
1711@asynctest.mock.patch("kubernetes.client.configuration.Configuration")
1712class GetK8sCloudCredentials(LibjujuTestCase):
1713 def setUp(self):
1714 super(GetK8sCloudCredentials, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001715 self.cert_data = "cert"
1716 self.token = "token"
David Garcia475a7222020-09-21 16:19:15 +02001717
1718 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1719 def test_not_supported(self, mock_exception, mock_configuration):
1720 mock_configuration.username = ""
1721 mock_configuration.password = ""
1722 mock_configuration.ssl_ca_cert = None
1723 mock_configuration.cert_file = None
1724 mock_configuration.key_file = None
1725 exception_raised = False
David Garciaf6e9b002020-11-27 15:32:02 +01001726 self.token = None
1727 self.cert_data = None
David Garcia475a7222020-09-21 16:19:15 +02001728 try:
David Garciaf6e9b002020-11-27 15:32:02 +01001729 _ = self.libjuju.get_k8s_cloud_credential(
1730 mock_configuration,
1731 self.cert_data,
1732 self.token,
1733 )
David Garcia475a7222020-09-21 16:19:15 +02001734 except JujuInvalidK8sConfiguration as e:
1735 exception_raised = True
1736 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01001737 e.message,
1738 "authentication method not supported",
David Garcia475a7222020-09-21 16:19:15 +02001739 )
1740 self.assertTrue(exception_raised)
1741
1742 def test_user_pass(self, mock_configuration):
1743 mock_configuration.username = "admin"
1744 mock_configuration.password = "admin"
1745 mock_configuration.ssl_ca_cert = None
1746 mock_configuration.cert_file = None
1747 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001748 self.token = None
1749 self.cert_data = None
1750 credential = self.libjuju.get_k8s_cloud_credential(
1751 mock_configuration,
1752 self.cert_data,
1753 self.token,
1754 )
David Garcia475a7222020-09-21 16:19:15 +02001755 self.assertEqual(
1756 credential,
1757 juju.client._definitions.CloudCredential(
1758 attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
1759 ),
1760 )
1761
David Garciaf6e9b002020-11-27 15:32:02 +01001762 def test_user_pass_with_cert(self, mock_configuration):
1763 mock_configuration.username = "admin"
1764 mock_configuration.password = "admin"
1765 mock_configuration.ssl_ca_cert = None
1766 mock_configuration.cert_file = None
1767 mock_configuration.key_file = None
1768 self.token = None
1769 credential = self.libjuju.get_k8s_cloud_credential(
1770 mock_configuration,
1771 self.cert_data,
1772 self.token,
1773 )
1774 self.assertEqual(
1775 credential,
1776 juju.client._definitions.CloudCredential(
1777 attrs={
1778 "ClientCertificateData": self.cert_data,
1779 "username": "admin",
1780 "password": "admin",
1781 },
1782 auth_type="userpasswithcert",
1783 ),
1784 )
1785
David Garcia475a7222020-09-21 16:19:15 +02001786 def test_user_no_pass(self, mock_configuration):
1787 mock_configuration.username = "admin"
1788 mock_configuration.password = ""
1789 mock_configuration.ssl_ca_cert = None
1790 mock_configuration.cert_file = None
1791 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001792 self.token = None
1793 self.cert_data = None
David Garcia475a7222020-09-21 16:19:15 +02001794 with mock.patch.object(self.libjuju.log, "debug") as mock_debug:
David Garciaf6e9b002020-11-27 15:32:02 +01001795 credential = self.libjuju.get_k8s_cloud_credential(
1796 mock_configuration,
1797 self.cert_data,
1798 self.token,
1799 )
David Garcia475a7222020-09-21 16:19:15 +02001800 self.assertEqual(
1801 credential,
1802 juju.client._definitions.CloudCredential(
1803 attrs={"username": "admin", "password": ""}, auth_type="userpass"
1804 ),
1805 )
1806 mock_debug.assert_called_once_with(
1807 "credential for user admin has empty password"
1808 )
1809
David Garcia475a7222020-09-21 16:19:15 +02001810 def test_cert(self, mock_configuration):
1811 mock_configuration.username = ""
1812 mock_configuration.password = ""
1813 mock_configuration.api_key = {"authorization": "Bearer Token"}
1814 ssl_ca_cert = tempfile.NamedTemporaryFile()
1815 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
1816 ssl_ca_cert_file.write("cacert")
1817 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
1818 mock_configuration.cert_file = None
1819 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001820 credential = self.libjuju.get_k8s_cloud_credential(
1821 mock_configuration,
1822 self.cert_data,
1823 self.token,
1824 )
David Garcia475a7222020-09-21 16:19:15 +02001825 self.assertEqual(
1826 credential,
1827 juju.client._definitions.CloudCredential(
David Garciaf6e9b002020-11-27 15:32:02 +01001828 attrs={"ClientCertificateData": self.cert_data, "Token": self.token},
David Garcia475a7222020-09-21 16:19:15 +02001829 auth_type="certificate",
1830 ),
1831 )
1832
David Garciaf6e9b002020-11-27 15:32:02 +01001833 # TODO: Fix this test when oauth authentication is supported
1834 # def test_oauth2(self, mock_configuration):
1835 # mock_configuration.username = ""
1836 # mock_configuration.password = ""
1837 # mock_configuration.api_key = {"authorization": "Bearer Token"}
1838 # key = tempfile.NamedTemporaryFile()
1839 # with open(key.name, "w") as key_file:
1840 # key_file.write("key")
1841 # mock_configuration.ssl_ca_cert = None
1842 # mock_configuration.cert_file = None
1843 # mock_configuration.key_file = key.name
1844 # credential = self.libjuju.get_k8s_cloud_credential(
1845 # mock_configuration,
1846 # self.cert_data,
1847 # self.token,
1848 # )
1849 # self.assertEqual(
1850 # credential,
1851 # juju.client._definitions.CloudCredential(
1852 # attrs={"ClientKeyData": "key", "Token": "Token"},
1853 # auth_type="oauth2",
1854 # ),
1855 # )
David Garcia475a7222020-09-21 16:19:15 +02001856
David Garciaf6e9b002020-11-27 15:32:02 +01001857 # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1858 # def test_oauth2_missing_token(self, mock_exception, mock_configuration):
1859 # mock_configuration.username = ""
1860 # mock_configuration.password = ""
1861 # key = tempfile.NamedTemporaryFile()
1862 # with open(key.name, "w") as key_file:
1863 # key_file.write("key")
1864 # mock_configuration.ssl_ca_cert = None
1865 # mock_configuration.cert_file = None
1866 # mock_configuration.key_file = key.name
1867 # exception_raised = False
1868 # try:
1869 # _ = self.libjuju.get_k8s_cloud_credential(
1870 # mock_configuration,
1871 # self.cert_data,
1872 # self.token,
1873 # )
1874 # except JujuInvalidK8sConfiguration as e:
1875 # exception_raised = True
1876 # self.assertEqual(
1877 # e.message,
1878 # "missing token for auth type oauth2",
1879 # )
1880 # self.assertTrue(exception_raised)
David Garcia475a7222020-09-21 16:19:15 +02001881
1882 def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
1883 mock_configuration.username = "admin"
1884 mock_configuration.password = "pass"
1885 mock_configuration.api_key = {"authorization": "No_bearer_token"}
1886 mock_configuration.ssl_ca_cert = None
1887 mock_configuration.cert_file = None
1888 mock_configuration.key_file = None
1889 exception_raised = False
1890 try:
David Garciaf6e9b002020-11-27 15:32:02 +01001891 _ = self.libjuju.get_k8s_cloud_credential(
1892 mock_configuration,
1893 self.cert_data,
1894 self.token,
1895 )
David Garcia475a7222020-09-21 16:19:15 +02001896 except JujuInvalidK8sConfiguration as e:
1897 exception_raised = True
1898 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01001899 e.message,
1900 "Cannot set both token and user/pass",
David Garcia475a7222020-09-21 16:19:15 +02001901 )
1902 self.assertTrue(exception_raised)