blob: 918a2fb87b2fc39decf78181d10e535a40bf7194 [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
David Garciaeb8943a2021-04-12 12:07:37 +020018from unittest.mock import Mock, patch
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
aktasfa02f8a2021-07-29 17:41:40 +030023from .utils import (
24 FakeApplication,
25 FakeMachine,
26 FakeManualMachine,
27 FakeUnit,
28)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020029from n2vc.libjuju import Libjuju
30from n2vc.exceptions import (
31 JujuControllerFailedConnecting,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020032 JujuMachineNotFound,
33 JujuApplicationNotFound,
34 JujuActionNotFound,
35 JujuApplicationExists,
David Garcia475a7222020-09-21 16:19:15 +020036 JujuInvalidK8sConfiguration,
David Garcia59f520d2020-10-15 13:16:45 +020037 JujuLeaderUnitNotFound,
ksaikiranrb84e4a72021-03-17 12:53:20 +053038 JujuError,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020039)
David Garciaf6e9b002020-11-27 15:32:02 +010040from n2vc.k8s_juju_conn import generate_rbac_id
David Garciaeb8943a2021-04-12 12:07:37 +020041from n2vc.tests.unit.utils import AsyncMock
42from n2vc.vca.connection import Connection
43from n2vc.vca.connection_data import ConnectionData
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020044
45
David Garciaeb8943a2021-04-12 12:07:37 +020046cacert = """-----BEGIN CERTIFICATE-----
47SOMECERT
48-----END CERTIFICATE-----"""
49
50
51@asynctest.mock.patch("n2vc.libjuju.Controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020052class LibjujuTestCase(asynctest.TestCase):
David Garciaeb8943a2021-04-12 12:07:37 +020053 @asynctest.mock.patch("n2vc.vca.connection_data.base64_to_cacert")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020054 def setUp(
55 self,
David Garciaeb8943a2021-04-12 12:07:37 +020056 mock_base64_to_cacert=None,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020057 ):
David Garciaeb8943a2021-04-12 12:07:37 +020058 self.loop = asyncio.get_event_loop()
59 self.db = Mock()
60 mock_base64_to_cacert.return_value = cacert
61 Connection._load_vca_connection_data = Mock()
62 vca_connection = Connection(AsyncMock())
63 vca_connection._data = ConnectionData(
64 **{
65 "endpoints": ["1.2.3.4:17070"],
66 "user": "user",
67 "secret": "secret",
68 "cacert": "cacert",
69 "pubkey": "pubkey",
70 "lxd-cloud": "cloud",
71 "lxd-credentials": "credentials",
72 "k8s-cloud": "k8s_cloud",
73 "k8s-credentials": "k8s_credentials",
74 "model-config": {},
75 "api-proxy": "api_proxy",
76 }
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020077 )
78 logging.disable(logging.CRITICAL)
David Garciaeb8943a2021-04-12 12:07:37 +020079 self.libjuju = Libjuju(vca_connection, self.loop)
80 self.loop.run_until_complete(self.libjuju.disconnect())
David Garciaa4f57d62020-10-22 10:50:56 +020081
82
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020083@asynctest.mock.patch("juju.controller.Controller.connect")
84@asynctest.mock.patch(
85 "juju.controller.Controller.api_endpoints",
86 new_callable=asynctest.CoroutineMock(return_value=["127.0.0.1:17070"]),
87)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020088class GetControllerTest(LibjujuTestCase):
89 def setUp(self):
90 super(GetControllerTest, self).setUp()
91
David Garciaeb8943a2021-04-12 12:07:37 +020092 def test_diff_endpoint(self, mock_api_endpoints, mock_connect):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020093 self.libjuju.endpoints = []
94 controller = self.loop.run_until_complete(self.libjuju.get_controller())
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020095 self.assertIsInstance(controller, juju.controller.Controller)
96
97 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
98 def test_exception(
99 self,
100 mock_disconnect_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200101 mock_api_endpoints,
102 mock_connect,
103 ):
104 self.libjuju.endpoints = []
David Garciaeb8943a2021-04-12 12:07:37 +0200105
106 mock_connect.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200107 controller = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200108 with self.assertRaises(JujuControllerFailedConnecting):
109 controller = self.loop.run_until_complete(self.libjuju.get_controller())
David Garcia12b29242020-09-17 16:01:48 +0200110 self.assertIsNone(controller)
David Garcia4ae527e2021-07-26 16:04:59 +0200111 mock_disconnect_controller.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200112
David Garciaeb8943a2021-04-12 12:07:37 +0200113 def test_same_endpoint_get_controller(self, mock_api_endpoints, mock_connect):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200114 self.libjuju.endpoints = ["127.0.0.1:17070"]
115 controller = self.loop.run_until_complete(self.libjuju.get_controller())
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200116 self.assertIsInstance(controller, juju.controller.Controller)
117
118
119class DisconnectTest(LibjujuTestCase):
120 def setUp(self):
121 super(DisconnectTest, self).setUp()
122
123 @asynctest.mock.patch("juju.model.Model.disconnect")
124 def test_disconnect_model(self, mock_disconnect):
125 self.loop.run_until_complete(self.libjuju.disconnect_model(juju.model.Model()))
126 mock_disconnect.assert_called_once()
127
128 @asynctest.mock.patch("juju.controller.Controller.disconnect")
129 def test_disconnect_controller(self, mock_disconnect):
130 self.loop.run_until_complete(
131 self.libjuju.disconnect_controller(juju.controller.Controller())
132 )
133 mock_disconnect.assert_called_once()
134
135
136@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
137@asynctest.mock.patch("n2vc.libjuju.Libjuju.model_exists")
138@asynctest.mock.patch("juju.controller.Controller.add_model")
139@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
140@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
141class AddModelTest(LibjujuTestCase):
142 def setUp(self):
143 super(AddModelTest, self).setUp()
144
145 def test_existing_model(
146 self,
147 mock_disconnect_model,
148 mock_disconnect_controller,
149 mock_add_model,
150 mock_model_exists,
151 mock_get_controller,
152 ):
153 mock_model_exists.return_value = True
154
David Garciab0a8f402021-03-15 18:41:34 +0100155 # This should not raise an exception
David Garciaeb8943a2021-04-12 12:07:37 +0200156 self.loop.run_until_complete(self.libjuju.add_model("existing_model", "cloud"))
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200157
David Garcia12b29242020-09-17 16:01:48 +0200158 mock_disconnect_controller.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200159
160 # TODO Check two job executing at the same time and one returning without doing anything.
161
162 def test_non_existing_model(
163 self,
164 mock_disconnect_model,
165 mock_disconnect_controller,
166 mock_add_model,
167 mock_model_exists,
168 mock_get_controller,
169 ):
170 mock_model_exists.return_value = False
171 mock_get_controller.return_value = juju.controller.Controller()
172
173 self.loop.run_until_complete(
David Garciaeb8943a2021-04-12 12:07:37 +0200174 self.libjuju.add_model("nonexisting_model", Mock())
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200175 )
176
177 mock_add_model.assert_called_once()
178 mock_disconnect_controller.assert_called()
179 mock_disconnect_model.assert_called()
180
181
ksaikiranrb84e4a72021-03-17 12:53:20 +0530182@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
183@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
184@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
185@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
186@asynctest.mock.patch(
187 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
188)
189@asynctest.mock.patch("juju.model.Model.get_action_status")
190@asynctest.mock.patch("juju.model.Model.get_action_output")
191@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_actions")
192class GetExecutedActionsTest(LibjujuTestCase):
193 def setUp(self):
194 super(GetExecutedActionsTest, self).setUp()
195
196 def test_exception(
197 self,
198 mock_get_actions,
199 mock_get_action_output,
200 mock_get_action_status,
201 mock_applications,
202 mock_disconnect_controller,
203 mock_disconnect_model,
204 mock_get_model,
205 mock_get_controller,
206 ):
207 mock_get_model.return_value = None
208 with self.assertRaises(JujuError):
209 self.loop.run_until_complete(self.libjuju.get_executed_actions("model"))
210
211 mock_get_controller.assert_called_once()
212 mock_disconnect_controller.assert_called_once()
213 mock_get_model.assert_called_once()
214 mock_disconnect_model.assert_not_called()
215
216 def test_success(
217 self,
218 mock_get_actions,
219 mock_get_action_output,
220 mock_get_action_status,
221 mock_applications,
222 mock_disconnect_controller,
223 mock_disconnect_model,
224 mock_get_model,
225 mock_get_controller,
226 ):
227 mock_get_model.return_value = juju.model.Model()
228 mock_applications.return_value = {"existing_app"}
229 mock_get_actions.return_value = {"action_name": "description"}
230 mock_get_action_status.return_value = {"id": "status"}
231 mock_get_action_output.return_value = {"output": "completed"}
232
233 executed_actions = self.loop.run_until_complete(
234 self.libjuju.get_executed_actions("model")
235 )
garciadeblas82b591c2021-03-24 09:22:13 +0100236 expected_result = [
237 {
238 "id": "id",
239 "action": "action_name",
240 "status": "status",
241 "output": "completed",
242 }
243 ]
ksaikiranrb84e4a72021-03-17 12:53:20 +0530244 self.assertListEqual(expected_result, executed_actions)
245 self.assertIsInstance(executed_actions, list)
246
247 mock_get_controller.assert_called_once()
248 mock_get_model.assert_called_once()
249 mock_disconnect_controller.assert_called_once()
250 mock_disconnect_model.assert_called_once()
251
252
253@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
254@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
255@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
256@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
257@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
258class GetApplicationConfigsTest(LibjujuTestCase):
259 def setUp(self):
260 super(GetApplicationConfigsTest, self).setUp()
261
262 def test_exception(
263 self,
264 mock_get_application,
265 mock_disconnect_controller,
266 mock_disconnect_model,
267 mock_get_model,
268 mock_get_controller,
269 ):
270 mock_get_model.return_value = None
271 with self.assertRaises(JujuError):
272 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +0100273 self.libjuju.get_application_configs("model", "app")
274 )
ksaikiranrb84e4a72021-03-17 12:53:20 +0530275
276 mock_get_controller.assert_called_once()
277 mock_disconnect_controller.assert_called_once()
278 mock_get_model.assert_called_once()
279 mock_disconnect_model.assert_not_called()
280
281 def test_success(
282 self,
283 mock_get_application,
284 mock_disconnect_controller,
285 mock_disconnect_model,
286 mock_get_model,
287 mock_get_controller,
288 ):
289 mock_get_application.return_value = FakeApplication()
garciadeblas82b591c2021-03-24 09:22:13 +0100290 application_configs = self.loop.run_until_complete(
291 self.libjuju.get_application_configs("model", "app")
292 )
ksaikiranrb84e4a72021-03-17 12:53:20 +0530293
294 self.assertEqual(application_configs, ["app_config"])
295
296 mock_get_controller.assert_called_once()
297 mock_get_model.assert_called_once()
298 mock_disconnect_controller.assert_called_once()
299 mock_disconnect_model.assert_called_once()
300
301
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200302@asynctest.mock.patch("juju.controller.Controller.get_model")
303class GetModelTest(LibjujuTestCase):
304 def setUp(self):
305 super(GetModelTest, self).setUp()
306
307 def test_get_model(
David Garcia5b802c92020-11-11 16:56:06 +0100308 self,
309 mock_get_model,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200310 ):
311 mock_get_model.return_value = juju.model.Model()
312 model = self.loop.run_until_complete(
313 self.libjuju.get_model(juju.controller.Controller(), "model")
314 )
315 self.assertIsInstance(model, juju.model.Model)
316
317
318@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
319@asynctest.mock.patch("juju.controller.Controller.list_models")
320class ModelExistsTest(LibjujuTestCase):
321 def setUp(self):
322 super(ModelExistsTest, self).setUp()
323
324 async def test_existing_model(
David Garcia5b802c92020-11-11 16:56:06 +0100325 self,
326 mock_list_models,
327 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200328 ):
329 mock_list_models.return_value = ["existing_model"]
330 self.assertTrue(
331 await self.libjuju.model_exists(
332 "existing_model", juju.controller.Controller()
333 )
334 )
335
336 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
337 async def test_no_controller(
David Garcia5b802c92020-11-11 16:56:06 +0100338 self,
339 mock_disconnect_controller,
340 mock_list_models,
341 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200342 ):
343 mock_list_models.return_value = ["existing_model"]
344 mock_get_controller.return_value = juju.controller.Controller()
345 self.assertTrue(await self.libjuju.model_exists("existing_model"))
346 mock_disconnect_controller.assert_called_once()
347
348 async def test_non_existing_model(
David Garcia5b802c92020-11-11 16:56:06 +0100349 self,
350 mock_list_models,
351 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200352 ):
353 mock_list_models.return_value = ["existing_model"]
354 self.assertFalse(
355 await self.libjuju.model_exists(
356 "not_existing_model", juju.controller.Controller()
357 )
358 )
359
360
361@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
362@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
363@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
364@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
365@asynctest.mock.patch("juju.model.Model.get_status")
366class GetModelStatusTest(LibjujuTestCase):
367 def setUp(self):
368 super(GetModelStatusTest, self).setUp()
369
370 def test_success(
371 self,
372 mock_get_status,
373 mock_disconnect_controller,
374 mock_disconnect_model,
375 mock_get_model,
376 mock_get_controller,
377 ):
378 mock_get_model.return_value = juju.model.Model()
379 mock_get_status.return_value = {"status"}
380
381 status = self.loop.run_until_complete(self.libjuju.get_model_status("model"))
382
383 mock_get_status.assert_called_once()
384 mock_disconnect_controller.assert_called_once()
385 mock_disconnect_model.assert_called_once()
386
387 self.assertEqual(status, {"status"})
388
David Garcia12b29242020-09-17 16:01:48 +0200389 def test_exception(
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200390 self,
391 mock_get_status,
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_get_status.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200399 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200400 with self.assertRaises(Exception):
401 status = self.loop.run_until_complete(
402 self.libjuju.get_model_status("model")
403 )
404
David Garcia12b29242020-09-17 16:01:48 +0200405 mock_disconnect_controller.assert_called_once()
406 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200407
David Garcia12b29242020-09-17 16:01:48 +0200408 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200409
410
411@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
412@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
413@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
414@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
415@asynctest.mock.patch("juju.model.Model.get_machines")
416@asynctest.mock.patch("juju.model.Model.add_machine")
417@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
418class CreateMachineTest(LibjujuTestCase):
419 def setUp(self):
420 super(CreateMachineTest, self).setUp()
421
422 def test_existing_machine(
423 self,
424 mock_wait_for,
425 mock_add_machine,
426 mock_get_machines,
427 mock_disconnect_controller,
428 mock_disconnect_model,
429 mock_get_model,
430 mock_get_controller,
431 ):
432 mock_get_model.return_value = juju.model.Model()
433 mock_get_machines.return_value = {"existing_machine": FakeMachine()}
434 machine, bool_res = self.loop.run_until_complete(
435 self.libjuju.create_machine("model", "existing_machine")
436 )
437
438 self.assertIsInstance(machine, FakeMachine)
439 self.assertFalse(bool_res)
440
441 mock_disconnect_controller.assert_called()
442 mock_disconnect_model.assert_called()
443
444 def test_non_existing_machine(
445 self,
446 mock_wait_for,
447 mock_add_machine,
448 mock_get_machines,
449 mock_disconnect_controller,
450 mock_disconnect_model,
451 mock_get_model,
452 mock_get_controller,
453 ):
David Garcia12b29242020-09-17 16:01:48 +0200454 machine = None
455 bool_res = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200456 mock_get_model.return_value = juju.model.Model()
457 with self.assertRaises(JujuMachineNotFound):
458 machine, bool_res = self.loop.run_until_complete(
459 self.libjuju.create_machine("model", "non_existing_machine")
460 )
David Garcia12b29242020-09-17 16:01:48 +0200461 self.assertIsNone(machine)
462 self.assertIsNone(bool_res)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200463
David Garcia12b29242020-09-17 16:01:48 +0200464 mock_disconnect_controller.assert_called()
465 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200466
467 def test_no_machine(
468 self,
469 mock_wait_for,
470 mock_add_machine,
471 mock_get_machines,
472 mock_disconnect_controller,
473 mock_disconnect_model,
474 mock_get_model,
475 mock_get_controller,
476 ):
477 mock_get_model.return_value = juju.model.Model()
478 mock_add_machine.return_value = FakeMachine()
479
480 machine, bool_res = self.loop.run_until_complete(
481 self.libjuju.create_machine("model")
482 )
483
484 self.assertIsInstance(machine, FakeMachine)
485 self.assertTrue(bool_res)
486
487 mock_wait_for.assert_called_once()
488 mock_add_machine.assert_called_once()
489
490 mock_disconnect_controller.assert_called()
491 mock_disconnect_model.assert_called()
492
493
494# TODO test provision machine
495
496
497@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
498@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
499@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
500@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
David Garcia667696e2020-09-22 14:52:32 +0200501@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
502@asynctest.mock.patch("juju.model.Model.deploy")
503class DeployTest(LibjujuTestCase):
504 def setUp(self):
505 super(DeployTest, self).setUp()
506
507 def test_deploy(
508 self,
509 mock_deploy,
510 mock_wait_for_model,
511 mock_disconnect_controller,
512 mock_disconnect_model,
513 mock_get_model,
514 mock_get_controller,
515 ):
516 mock_get_model.return_value = juju.model.Model()
517 self.loop.run_until_complete(
518 self.libjuju.deploy("cs:osm", "model", wait=True, timeout=0)
519 )
520 mock_deploy.assert_called_once()
521 mock_wait_for_model.assert_called_once()
522 mock_disconnect_controller.assert_called_once()
523 mock_disconnect_model.assert_called_once()
524
525 def test_deploy_no_wait(
526 self,
527 mock_deploy,
528 mock_wait_for_model,
529 mock_disconnect_controller,
530 mock_disconnect_model,
531 mock_get_model,
532 mock_get_controller,
533 ):
534 mock_get_model.return_value = juju.model.Model()
535 self.loop.run_until_complete(
536 self.libjuju.deploy("cs:osm", "model", wait=False, timeout=0)
537 )
538 mock_deploy.assert_called_once()
539 mock_wait_for_model.assert_not_called()
540 mock_disconnect_controller.assert_called_once()
541 mock_disconnect_model.assert_called_once()
542
543 def test_deploy_exception(
544 self,
545 mock_deploy,
546 mock_wait_for_model,
547 mock_disconnect_controller,
548 mock_disconnect_model,
549 mock_get_model,
550 mock_get_controller,
551 ):
552 mock_deploy.side_effect = Exception()
553 mock_get_model.return_value = juju.model.Model()
554 with self.assertRaises(Exception):
555 self.loop.run_until_complete(self.libjuju.deploy("cs:osm", "model"))
556 mock_deploy.assert_called_once()
557 mock_wait_for_model.assert_not_called()
558 mock_disconnect_controller.assert_called_once()
559 mock_disconnect_model.assert_called_once()
560
561
562@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
563@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
564@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
565@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200566@asynctest.mock.patch(
567 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
568)
569@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
570@asynctest.mock.patch("juju.model.Model.deploy")
571@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
572@asynctest.mock.patch("n2vc.libjuju.Libjuju.create_machine")
573class DeployCharmTest(LibjujuTestCase):
574 def setUp(self):
575 super(DeployCharmTest, self).setUp()
576
577 def test_existing_app(
578 self,
579 mock_create_machine,
580 mock_wait_for,
581 mock_deploy,
582 mock_machines,
583 mock_applications,
584 mock_disconnect_controller,
585 mock_disconnect_model,
586 mock_get_model,
587 mock_get_controller,
588 ):
589 mock_get_model.return_value = juju.model.Model()
590 mock_applications.return_value = {"existing_app"}
591
David Garcia12b29242020-09-17 16:01:48 +0200592 application = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200593 with self.assertRaises(JujuApplicationExists):
594 application = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100595 self.libjuju.deploy_charm(
596 "existing_app",
597 "path",
598 "model",
599 "machine",
600 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200601 )
David Garcia12b29242020-09-17 16:01:48 +0200602 self.assertIsNone(application)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200603
David Garcia12b29242020-09-17 16:01:48 +0200604 mock_disconnect_controller.assert_called()
605 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200606
607 def test_non_existing_machine(
608 self,
609 mock_create_machine,
610 mock_wait_for,
611 mock_deploy,
612 mock_machines,
613 mock_applications,
614 mock_disconnect_controller,
615 mock_disconnect_model,
616 mock_get_model,
617 mock_get_controller,
618 ):
619 mock_get_model.return_value = juju.model.Model()
620 mock_machines.return_value = {"existing_machine": FakeMachine()}
David Garcia12b29242020-09-17 16:01:48 +0200621 application = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200622 with self.assertRaises(JujuMachineNotFound):
623 application = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100624 self.libjuju.deploy_charm(
625 "app",
626 "path",
627 "model",
628 "machine",
629 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200630 )
631
David Garcia12b29242020-09-17 16:01:48 +0200632 self.assertIsNone(application)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200633
David Garcia12b29242020-09-17 16:01:48 +0200634 mock_disconnect_controller.assert_called()
635 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200636
637 def test_2_units(
638 self,
639 mock_create_machine,
640 mock_wait_for,
641 mock_deploy,
642 mock_machines,
643 mock_applications,
644 mock_disconnect_controller,
645 mock_disconnect_model,
646 mock_get_model,
647 mock_get_controller,
648 ):
649 mock_get_model.return_value = juju.model.Model()
650 mock_machines.return_value = {"existing_machine": FakeMachine()}
651 mock_create_machine.return_value = (FakeMachine(), "other")
652 mock_deploy.return_value = FakeApplication()
653 application = self.loop.run_until_complete(
654 self.libjuju.deploy_charm(
David Garcia5b802c92020-11-11 16:56:06 +0100655 "app",
656 "path",
657 "model",
658 "existing_machine",
659 num_units=2,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200660 )
661 )
662
663 self.assertIsInstance(application, FakeApplication)
664
665 mock_deploy.assert_called_once()
666 mock_wait_for.assert_called_once()
667
668 mock_create_machine.assert_called_once()
669
670 mock_disconnect_controller.assert_called()
671 mock_disconnect_model.assert_called()
672
673 def test_1_unit(
674 self,
675 mock_create_machine,
676 mock_wait_for,
677 mock_deploy,
678 mock_machines,
679 mock_applications,
680 mock_disconnect_controller,
681 mock_disconnect_model,
682 mock_get_model,
683 mock_get_controller,
684 ):
685 mock_get_model.return_value = juju.model.Model()
686 mock_machines.return_value = {"existing_machine": FakeMachine()}
687 mock_deploy.return_value = FakeApplication()
688 application = self.loop.run_until_complete(
689 self.libjuju.deploy_charm("app", "path", "model", "existing_machine")
690 )
691
692 self.assertIsInstance(application, FakeApplication)
693
694 mock_deploy.assert_called_once()
695 mock_wait_for.assert_called_once()
696
697 mock_disconnect_controller.assert_called()
698 mock_disconnect_model.assert_called()
699
700
701@asynctest.mock.patch(
702 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
703)
704class GetApplicationTest(LibjujuTestCase):
705 def setUp(self):
706 super(GetApplicationTest, self).setUp()
707
708 def test_existing_application(
David Garcia5b802c92020-11-11 16:56:06 +0100709 self,
710 mock_applications,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200711 ):
712 mock_applications.return_value = {"existing_app": "exists"}
713 model = juju.model.Model()
714 result = self.libjuju._get_application(model, "existing_app")
715 self.assertEqual(result, "exists")
716
717 def test_non_existing_application(
David Garcia5b802c92020-11-11 16:56:06 +0100718 self,
719 mock_applications,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200720 ):
721 mock_applications.return_value = {"existing_app": "exists"}
722 model = juju.model.Model()
723 result = self.libjuju._get_application(model, "nonexisting_app")
724 self.assertIsNone(result)
725
726
727@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
728@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
729@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
730@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
731@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
732@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
733@asynctest.mock.patch("juju.model.Model.get_action_output")
734@asynctest.mock.patch("juju.model.Model.get_action_status")
735class ExecuteActionTest(LibjujuTestCase):
736 def setUp(self):
737 super(ExecuteActionTest, self).setUp()
738
739 def test_no_application(
740 self,
741 mock_get_action_status,
742 mock_get_action_output,
743 mock_wait_for,
744 mock__get_application,
745 mock_disconnect_controller,
746 mock_disconnect_model,
747 mock_get_model,
748 mock_get_controller,
749 ):
750 mock__get_application.return_value = None
751 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +0200752 output = None
753 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200754 with self.assertRaises(JujuApplicationNotFound):
755 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100756 self.libjuju.execute_action(
757 "app",
758 "model",
759 "action",
760 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200761 )
David Garcia12b29242020-09-17 16:01:48 +0200762 self.assertIsNone(output)
763 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200764
David Garcia12b29242020-09-17 16:01:48 +0200765 mock_disconnect_controller.assert_called()
766 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200767
768 def test_no_action(
769 self,
770 mock_get_action_status,
771 mock_get_action_output,
772 mock_wait_for,
773 mock__get_application,
774 mock_disconnect_controller,
775 mock_disconnect_model,
776 mock_get_model,
777 mock_get_controller,
778 ):
779
780 mock_get_model.return_value = juju.model.Model()
781 mock__get_application.return_value = FakeApplication()
David Garcia12b29242020-09-17 16:01:48 +0200782 output = None
783 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200784 with self.assertRaises(JujuActionNotFound):
785 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100786 self.libjuju.execute_action(
787 "app",
788 "model",
789 "action",
790 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200791 )
David Garcia12b29242020-09-17 16:01:48 +0200792 self.assertIsNone(output)
793 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200794
David Garcia12b29242020-09-17 16:01:48 +0200795 mock_disconnect_controller.assert_called()
796 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200797
David Garcia59f520d2020-10-15 13:16:45 +0200798 @asynctest.mock.patch("asyncio.sleep")
799 @asynctest.mock.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
800 def test_no_leader(
801 self,
802 mock_is_leader_from_status,
803 mock_sleep,
804 mock_get_action_status,
805 mock_get_action_output,
806 mock_wait_for,
807 mock__get_application,
808 mock_disconnect_controller,
809 mock_disconnect_model,
810 mock_get_model,
811 mock_get_controller,
812 ):
813 mock_get_model.return_value = juju.model.Model()
814 mock__get_application.return_value = FakeApplication()
815 mock_is_leader_from_status.return_value = False
816 output = None
817 status = None
818 with self.assertRaises(JujuLeaderUnitNotFound):
819 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100820 self.libjuju.execute_action(
821 "app",
822 "model",
823 "action",
824 )
David Garcia59f520d2020-10-15 13:16:45 +0200825 )
826 self.assertIsNone(output)
827 self.assertIsNone(status)
828
829 mock_disconnect_controller.assert_called()
830 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200831
aktasfa02f8a2021-07-29 17:41:40 +0300832 def test_successful_exec(
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200833 self,
834 mock_get_action_status,
835 mock_get_action_output,
836 mock_wait_for,
837 mock__get_application,
838 mock_disconnect_controller,
839 mock_disconnect_model,
840 mock_get_model,
841 mock_get_controller,
842 ):
843 mock_get_model.return_value = juju.model.Model()
844 mock__get_application.return_value = FakeApplication()
845 mock_get_action_output.return_value = "output"
846 mock_get_action_status.return_value = {"id": "status"}
847 output, status = self.loop.run_until_complete(
848 self.libjuju.execute_action("app", "model", "existing_action")
849 )
850 self.assertEqual(output, "output")
851 self.assertEqual(status, "status")
852
853 mock_wait_for.assert_called_once()
854
855 mock_disconnect_controller.assert_called()
856 mock_disconnect_model.assert_called()
857
858
859@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
860@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
861@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
862@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
863@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
864class GetActionTest(LibjujuTestCase):
865 def setUp(self):
866 super(GetActionTest, self).setUp()
867
868 def test_exception(
869 self,
870 mock_get_application,
871 mock_disconnect_controller,
872 mock_disconnect_model,
873 mock_get_model,
874 mock_get_controller,
875 ):
876 mock_get_application.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200877 actions = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200878 with self.assertRaises(Exception):
879 actions = self.loop.run_until_complete(
880 self.libjuju.get_actions("app", "model")
881 )
882
David Garcia12b29242020-09-17 16:01:48 +0200883 self.assertIsNone(actions)
884 mock_disconnect_controller.assert_called_once()
885 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200886
887 def test_success(
888 self,
889 mock_get_application,
890 mock_disconnect_controller,
891 mock_disconnect_model,
892 mock_get_model,
893 mock_get_controller,
894 ):
895 mock_get_application.return_value = FakeApplication()
896
897 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
898
899 self.assertEqual(actions, ["existing_action"])
900
901 mock_get_controller.assert_called_once()
902 mock_get_model.assert_called_once()
903 mock_disconnect_controller.assert_called_once()
904 mock_disconnect_model.assert_called_once()
905
906
907@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
908@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
909@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
910@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
David Garcia85755d12020-09-21 19:51:23 +0200911@asynctest.mock.patch("juju.application.Application.get_metrics")
912@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
913class GetMetricsTest(LibjujuTestCase):
914 def setUp(self):
915 super(GetMetricsTest, self).setUp()
916
917 def test_get_metrics_success(
918 self,
919 mock_get_application,
920 mock_get_metrics,
921 mock_disconnect_controller,
922 mock_disconnect_model,
923 mock_get_model,
924 mock_get_controller,
925 ):
926 mock_get_application.return_value = FakeApplication()
927 mock_get_model.return_value = juju.model.Model()
928
929 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
930
931 mock_disconnect_controller.assert_called_once()
932 mock_disconnect_model.assert_called_once()
933
934 def test_get_metrics_exception(
935 self,
936 mock_get_application,
937 mock_get_metrics,
938 mock_disconnect_controller,
939 mock_disconnect_model,
940 mock_get_model,
941 mock_get_controller,
942 ):
943 mock_get_model.return_value = juju.model.Model()
944 mock_get_metrics.side_effect = Exception()
945 with self.assertRaises(Exception):
946 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
947
948 mock_disconnect_controller.assert_called_once()
949 mock_disconnect_model.assert_called_once()
950
951 def test_missing_args_exception(
952 self,
953 mock_get_application,
954 mock_get_metrics,
955 mock_disconnect_controller,
956 mock_disconnect_model,
957 mock_get_model,
958 mock_get_controller,
959 ):
960 mock_get_model.return_value = juju.model.Model()
961
962 with self.assertRaises(Exception):
963 self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
964
965 mock_get_controller.assert_not_called()
966 mock_get_model.assert_not_called()
967 mock_disconnect_controller.assert_not_called()
968 mock_disconnect_model.assert_not_called()
969
970
971@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
972@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
973@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
974@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200975@asynctest.mock.patch("juju.model.Model.add_relation")
976class AddRelationTest(LibjujuTestCase):
977 def setUp(self):
978 super(AddRelationTest, self).setUp()
979
980 @asynctest.mock.patch("logging.Logger.warning")
981 def test_not_found(
982 self,
983 mock_warning,
984 mock_add_relation,
985 mock_disconnect_controller,
986 mock_disconnect_model,
987 mock_get_model,
988 mock_get_controller,
989 ):
990 # TODO in libjuju.py should this fail only with a log message?
991 result = {"error": "not found", "response": "response", "request-id": 1}
992
993 mock_get_model.return_value = juju.model.Model()
994 mock_add_relation.side_effect = JujuAPIError(result)
995
996 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100997 self.libjuju.add_relation(
998 "model",
999 "app1:relation1",
1000 "app2:relation2",
1001 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001002 )
1003
1004 mock_warning.assert_called_with("Relation not found: not found")
1005 mock_disconnect_controller.assert_called_once()
1006 mock_disconnect_model.assert_called_once()
1007
1008 @asynctest.mock.patch("logging.Logger.warning")
1009 def test_already_exists(
1010 self,
1011 mock_warning,
1012 mock_add_relation,
1013 mock_disconnect_controller,
1014 mock_disconnect_model,
1015 mock_get_model,
1016 mock_get_controller,
1017 ):
1018 # TODO in libjuju.py should this fail silently?
1019 result = {"error": "already exists", "response": "response", "request-id": 1}
1020
1021 mock_get_model.return_value = juju.model.Model()
1022 mock_add_relation.side_effect = JujuAPIError(result)
1023
1024 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001025 self.libjuju.add_relation(
1026 "model",
1027 "app1:relation1",
1028 "app2:relation2",
1029 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001030 )
1031
1032 mock_warning.assert_called_with("Relation already exists: already exists")
1033 mock_disconnect_controller.assert_called_once()
1034 mock_disconnect_model.assert_called_once()
1035
1036 def test_exception(
1037 self,
1038 mock_add_relation,
1039 mock_disconnect_controller,
1040 mock_disconnect_model,
1041 mock_get_model,
1042 mock_get_controller,
1043 ):
1044 mock_get_model.return_value = juju.model.Model()
1045 result = {"error": "", "response": "response", "request-id": 1}
1046 mock_add_relation.side_effect = JujuAPIError(result)
1047
1048 with self.assertRaises(JujuAPIError):
1049 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001050 self.libjuju.add_relation(
1051 "model",
1052 "app1:relation1",
1053 "app2:relation2",
1054 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001055 )
1056
David Garcia12b29242020-09-17 16:01:48 +02001057 mock_disconnect_controller.assert_called_once()
1058 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001059
1060 def test_success(
1061 self,
1062 mock_add_relation,
1063 mock_disconnect_controller,
1064 mock_disconnect_model,
1065 mock_get_model,
1066 mock_get_controller,
1067 ):
1068 mock_get_model.return_value = juju.model.Model()
1069
1070 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001071 self.libjuju.add_relation(
1072 "model",
1073 "app1:relation1",
1074 "app2:relation2",
1075 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001076 )
1077
David Garcia12b29242020-09-17 16:01:48 +02001078 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
David Garcia8331f7c2020-08-25 16:10:07 +02001079 mock_disconnect_controller.assert_called_once()
1080 mock_disconnect_model.assert_called_once()
1081
1082 def test_saas(
1083 self,
1084 mock_add_relation,
1085 mock_disconnect_controller,
1086 mock_disconnect_model,
1087 mock_get_model,
1088 mock_get_controller,
1089 ):
1090 mock_get_model.return_value = juju.model.Model()
1091
1092 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001093 self.libjuju.add_relation(
1094 "model",
1095 "app1:relation1",
1096 "saas_name",
1097 )
David Garcia8331f7c2020-08-25 16:10:07 +02001098 )
1099
David Garcia12b29242020-09-17 16:01:48 +02001100 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001101 mock_disconnect_controller.assert_called_once()
1102 mock_disconnect_model.assert_called_once()
1103
1104
1105# TODO destroy_model testcase
1106
1107
aktas56120292021-02-26 15:32:39 +03001108@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1109@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1110@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1111@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1112@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1113class DestroyApplicationTest(LibjujuTestCase):
1114 def setUp(self):
1115 super(DestroyApplicationTest, self).setUp()
1116
1117 def test_success(
garciadeblas82b591c2021-03-24 09:22:13 +01001118 self,
1119 mock_get_controller,
1120 mock_get_model,
1121 mock_disconnect_controller,
1122 mock_get_application,
1123 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001124 ):
1125 mock_get_application.return_value = FakeApplication()
1126 mock_get_model.return_value = None
1127 self.loop.run_until_complete(
1128 self.libjuju.destroy_application(
1129 "existing_model",
1130 "existing_app",
1131 3600,
1132 )
1133 )
1134 mock_get_application.assert_called()
1135 mock_disconnect_controller.assert_called_once()
1136 mock_disconnect_model.assert_called_once()
1137
1138 def test_no_application(
garciadeblas82b591c2021-03-24 09:22:13 +01001139 self,
1140 mock_get_controller,
1141 mock_get_model,
1142 mock_disconnect_controller,
1143 mock_get_application,
1144 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001145 ):
1146 mock_get_model.return_value = None
1147 mock_get_application.return_value = None
1148
1149 self.loop.run_until_complete(
1150 self.libjuju.destroy_application(
1151 "existing_model",
1152 "existing_app",
1153 3600,
1154 )
1155 )
1156 mock_get_application.assert_called()
1157
1158 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01001159 self,
1160 mock_get_controller,
1161 mock_get_model,
1162 mock_disconnect_controller,
1163 mock_get_application,
1164 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001165 ):
1166 mock_get_application.return_value = FakeApplication
1167 mock_get_model.return_value = None
1168
1169 with self.assertRaises(Exception):
1170 self.loop.run_until_complete(
1171 self.libjuju.destroy_application(
1172 "existing_model",
1173 "existing_app",
1174 0,
1175 )
1176 )
1177 mock_get_application.assert_called_once()
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 Garciaeb8943a2021-04-12 12:07:37 +02001794 with 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)
aktas2962f3e2021-03-15 11:05:35 +03001903
1904
1905@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1906@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1907@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1908@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1909@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1910@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
1911class ScaleApplicationTest(LibjujuTestCase):
1912 def setUp(self):
1913 super(ScaleApplicationTest, self).setUp()
1914
1915 @asynctest.mock.patch("asyncio.sleep")
1916 def test_scale_application(
1917 self,
1918 mock_sleep,
1919 mock_wait_for_model,
1920 mock_disconnect_controller,
1921 mock_disconnect_model,
1922 mock_get_application,
1923 mock_get_model,
1924 mock_get_controller,
1925 ):
1926 mock_get_model.return_value = juju.model.Model()
1927 mock_get_application.return_value = FakeApplication()
garciadeblas82b591c2021-03-24 09:22:13 +01001928 self.loop.run_until_complete(self.libjuju.scale_application("model", "app", 2))
aktas2962f3e2021-03-15 11:05:35 +03001929 mock_wait_for_model.assert_called_once()
1930 mock_disconnect_controller.assert_called_once()
1931 mock_disconnect_model.assert_called_once()
1932
1933 def test_no_application(
1934 self,
1935 mock_wait_for,
1936 mock_disconnect_controller,
1937 mock_disconnect_model,
1938 mock_get_application,
1939 mock_get_model,
1940 mock_get_controller,
1941 ):
1942 mock_get_application.return_value = None
1943 mock_get_model.return_value = juju.model.Model()
1944 with self.assertRaises(JujuApplicationNotFound):
1945 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01001946 self.libjuju.scale_application("model", "app", 2)
aktas2962f3e2021-03-15 11:05:35 +03001947 )
1948 mock_disconnect_controller.assert_called()
1949 mock_disconnect_model.assert_called()
1950
1951 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01001952 self,
1953 mock_wait_for,
1954 mock_disconnect_controller,
1955 mock_disconnect_model,
1956 mock_get_application,
1957 mock_get_model,
1958 mock_get_controller,
aktas2962f3e2021-03-15 11:05:35 +03001959 ):
1960 mock_get_model.return_value = None
1961 mock_get_application.return_value = FakeApplication()
1962 with self.assertRaises(Exception):
1963 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01001964 self.libjuju.scale_application("model", "app", 2, total_timeout=0)
aktas2962f3e2021-03-15 11:05:35 +03001965 )
1966 mock_disconnect_controller.assert_called_once()
1967
1968
1969@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1970class GetUnitNumberTest(LibjujuTestCase):
1971 def setUp(self):
1972 super(GetUnitNumberTest, self).setUp()
1973
aktasfa02f8a2021-07-29 17:41:40 +03001974 def test_successful_get_unit_number(
aktas2962f3e2021-03-15 11:05:35 +03001975 self,
1976 mock_get_applications,
1977 ):
1978 mock_get_applications.return_value = FakeApplication()
1979 model = juju.model.Model()
1980 result = self.libjuju._get_application_count(model, "app")
1981 self.assertEqual(result, 2)
1982
1983 def test_non_existing_application(
1984 self,
1985 mock_get_applications,
1986 ):
1987 mock_get_applications.return_value = None
1988 model = juju.model.Model()
1989 result = self.libjuju._get_application_count(model, "app")
1990 self.assertEqual(result, None)
aktasfa02f8a2021-07-29 17:41:40 +03001991
1992
1993@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
1994class GetMachineInfoTest(LibjujuTestCase):
1995 def setUp(self):
1996 super(GetMachineInfoTest, self).setUp()
1997
1998 def test_successful(
1999 self,
2000 mock_machines,
2001 ):
2002 machine_id = "existing_machine"
2003 model = juju.model.Model()
2004 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2005 machine, series = self.libjuju._get_machine_info(
2006 machine_id=machine_id,
2007 model=model,
2008 )
2009 self.assertIsNotNone(machine, series)
2010
2011 def test_exception(
2012 self,
2013 mock_machines,
2014 ):
2015 machine_id = "not_existing_machine"
2016 machine = series = None
2017 model = juju.model.Model()
2018 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2019 with self.assertRaises(JujuMachineNotFound):
2020 machine, series = self.libjuju._get_machine_info(
2021 machine_id=machine_id,
2022 model=model,
2023 )
2024 self.assertIsNone(machine, series)
2025
2026
2027class GetUnitTest(LibjujuTestCase):
2028 def setUp(self):
2029 super(GetUnitTest, self).setUp()
2030
2031 def test_successful(self):
2032 result = self.libjuju._get_unit(FakeApplication(), "existing_machine_id")
2033 self.assertIsInstance(result, FakeUnit)
2034
2035 def test_return_none(self):
2036 result = self.libjuju._get_unit(FakeApplication(), "not_existing_machine_id")
2037 self.assertIsNone(result)
2038
2039
2040@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2041@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2042@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2043@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2044@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2045class CheckApplicationExists(LibjujuTestCase):
2046 def setUp(self):
2047 super(CheckApplicationExists, self).setUp()
2048
2049 def test_successful(
2050 self,
2051 mock_get_application,
2052 mock_disconnect_controller,
2053 mock_disconnect_model,
2054 mock_get_model,
2055 mock_get_controller,
2056 ):
2057 mock_get_model.return_value = juju.model.Model()
2058 mock_get_application.return_value = FakeApplication()
2059 result = self.loop.run_until_complete(
2060 self.libjuju.check_application_exists(
2061 "model",
2062 "app",
2063 )
2064 )
2065 self.assertEqual(result, True)
2066
2067 mock_get_application.assert_called_once()
2068 mock_get_controller.assert_called_once()
2069 mock_get_model.assert_called_once()
2070 mock_disconnect_controller.assert_called_once()
2071 mock_disconnect_model.assert_called_once()
2072
2073 def test_no_application(
2074 self,
2075 mock_get_application,
2076 mock_disconnect_controller,
2077 mock_disconnect_model,
2078 mock_get_model,
2079 mock_get_controller,
2080 ):
2081 mock_get_model.return_value = juju.model.Model()
2082 mock_get_application.return_value = None
2083 result = self.loop.run_until_complete(
2084 self.libjuju.check_application_exists(
2085 "model",
2086 "app",
2087 )
2088 )
2089 self.assertEqual(result, False)
2090
2091 mock_get_application.assert_called_once()
2092 mock_get_controller.assert_called_once()
2093 mock_get_model.assert_called_once()
2094 mock_disconnect_controller.assert_called_once()
2095 mock_disconnect_model.assert_called_once()
2096
2097
2098@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2099@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2100@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2101@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2102@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2103@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_machine_info")
2104class AddUnitTest(LibjujuTestCase):
2105 def setUp(self):
2106 super(AddUnitTest, self).setUp()
2107
2108 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
2109 @asynctest.mock.patch("asyncio.sleep")
2110 def test_successful(
2111 self,
2112 mock_sleep,
2113 mock_wait_for,
2114 mock_get_machine_info,
2115 mock_get_application,
2116 mock_disconnect_controller,
2117 mock_disconnect_model,
2118 mock_get_model,
2119 mock_get_controller,
2120 ):
2121 mock_get_model.return_value = juju.model.Model()
2122 mock_get_application.return_value = FakeApplication()
2123 mock_get_machine_info.return_value = FakeMachine(), "series"
2124 self.loop.run_until_complete(
2125 self.libjuju.add_unit(
2126 "existing_app",
2127 "model",
2128 "machine",
2129 )
2130 )
2131
2132 mock_wait_for.assert_called_once()
2133 mock_get_application.assert_called_once()
2134 mock_get_controller.assert_called_once()
2135 mock_get_model.assert_called_once()
2136 mock_disconnect_controller.assert_called_once()
2137 mock_disconnect_model.assert_called_once()
2138
2139 def test_no_app(
2140 self,
2141 mock_get_machine_info,
2142 mock_get_application,
2143 mock_disconnect_controller,
2144 mock_disconnect_model,
2145 mock_get_model,
2146 mock_get_controller,
2147 ):
2148 mock_get_model.return_value = juju.model.Model()
2149 mock_get_application.return_value = None
2150 with self.assertRaises(JujuApplicationNotFound):
2151 self.loop.run_until_complete(
2152 self.libjuju.add_unit(
2153 "existing_app",
2154 "model",
2155 "machine",
2156 )
2157 )
2158
2159 mock_get_application.assert_called_once()
2160 mock_get_controller.assert_called_once()
2161 mock_get_model.assert_called_once()
2162 mock_disconnect_controller.assert_called_once()
2163 mock_disconnect_model.assert_called_once()
2164
2165 def test_no_machine(
2166 self,
2167 mock_get_machine_info,
2168 mock_get_application,
2169 mock_disconnect_controller,
2170 mock_disconnect_model,
2171 mock_get_model,
2172 mock_get_controller,
2173 ):
2174 mock_get_model.return_value = juju.model.Model()
2175 mock_get_application.return_value = FakeApplication()
2176 mock_get_machine_info.side_effect = JujuMachineNotFound()
2177 with self.assertRaises(JujuMachineNotFound):
2178 self.loop.run_until_complete(
2179 self.libjuju.add_unit(
2180 "existing_app",
2181 "model",
2182 "machine",
2183 )
2184 )
2185
2186 mock_get_application.assert_called_once()
2187 mock_get_controller.assert_called_once()
2188 mock_get_model.assert_called_once()
2189 mock_disconnect_controller.assert_called_once()
2190 mock_disconnect_model.assert_called_once()
2191
2192
2193@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2194@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2195@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2196@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2197@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2198@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_unit")
2199class DestroyUnitTest(LibjujuTestCase):
2200 def setUp(self):
2201 super(DestroyUnitTest, self).setUp()
2202
2203 @asynctest.mock.patch("asyncio.sleep")
2204 def test_successful(
2205 self,
2206 mock_sleep,
2207 mock_get_unit,
2208 mock_get_application,
2209 mock_disconnect_controller,
2210 mock_disconnect_model,
2211 mock_get_model,
2212 mock_get_controller,
2213 ):
2214 mock_get_model.return_value = juju.model.Model()
2215 mock_get_application.return_value = FakeApplication()
2216
2217 self.loop.run_until_complete(
2218 self.libjuju.destroy_unit("app", "model", "machine", 0)
2219 )
2220
2221 mock_get_unit.assert_called()
2222 mock_get_application.assert_called_once()
2223 mock_get_controller.assert_called_once()
2224 mock_get_model.assert_called_once()
2225 mock_disconnect_controller.assert_called_once()
2226 mock_disconnect_model.assert_called_once()
2227
2228 def test_no_app(
2229 self,
2230 mock_get_unit,
2231 mock_get_application,
2232 mock_disconnect_controller,
2233 mock_disconnect_model,
2234 mock_get_model,
2235 mock_get_controller,
2236 ):
2237 mock_get_model.return_value = juju.model.Model()
2238 mock_get_application.return_value = None
2239
2240 with self.assertRaises(JujuApplicationNotFound):
2241 self.loop.run_until_complete(
2242 self.libjuju.destroy_unit("app", "model", "machine")
2243 )
2244
2245 mock_get_application.assert_called_once()
2246 mock_get_controller.assert_called_once()
2247 mock_get_model.assert_called_once()
2248 mock_disconnect_controller.assert_called_once()
2249 mock_disconnect_model.assert_called_once()
2250
2251 def test_no_unit(
2252 self,
2253 mock_get_unit,
2254 mock_get_application,
2255 mock_disconnect_controller,
2256 mock_disconnect_model,
2257 mock_get_model,
2258 mock_get_controller,
2259 ):
2260 mock_get_model.return_value = juju.model.Model()
2261 mock_get_application.return_value = FakeApplication()
2262 mock_get_unit.return_value = None
2263
2264 with self.assertRaises(JujuError):
2265 self.loop.run_until_complete(
2266 self.libjuju.destroy_unit("app", "model", "machine")
2267 )
2268
2269 mock_get_unit.assert_called_once()
2270 mock_get_application.assert_called_once()
2271 mock_get_controller.assert_called_once()
2272 mock_get_model.assert_called_once()
2273 mock_disconnect_controller.assert_called_once()
2274 mock_disconnect_model.assert_called_once()