blob: c5f80cf75b138b429ac7f6efc76e156ba9dc05ef [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
aktas3061bef2021-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
David Garcia6d670772022-06-21 11:26:57 +020061 # Connection._load_vca_connection_data = Mock()
David Garciaeb8943a2021-04-12 12:07:37 +020062 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)
beierlm9282b862022-01-31 15:26:29 -0500111 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 ):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200779 mock_get_model.return_value = juju.model.Model()
780 mock__get_application.return_value = FakeApplication()
David Garcia12b29242020-09-17 16:01:48 +0200781 output = None
782 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200783 with self.assertRaises(JujuActionNotFound):
784 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100785 self.libjuju.execute_action(
786 "app",
787 "model",
788 "action",
789 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200790 )
David Garcia12b29242020-09-17 16:01:48 +0200791 self.assertIsNone(output)
792 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200793
David Garcia12b29242020-09-17 16:01:48 +0200794 mock_disconnect_controller.assert_called()
795 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200796
David Garcia59f520d2020-10-15 13:16:45 +0200797 @asynctest.mock.patch("asyncio.sleep")
798 @asynctest.mock.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
799 def test_no_leader(
800 self,
801 mock_is_leader_from_status,
802 mock_sleep,
803 mock_get_action_status,
804 mock_get_action_output,
805 mock_wait_for,
806 mock__get_application,
807 mock_disconnect_controller,
808 mock_disconnect_model,
809 mock_get_model,
810 mock_get_controller,
811 ):
812 mock_get_model.return_value = juju.model.Model()
813 mock__get_application.return_value = FakeApplication()
814 mock_is_leader_from_status.return_value = False
815 output = None
816 status = None
817 with self.assertRaises(JujuLeaderUnitNotFound):
818 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100819 self.libjuju.execute_action(
820 "app",
821 "model",
822 "action",
823 )
David Garcia59f520d2020-10-15 13:16:45 +0200824 )
825 self.assertIsNone(output)
826 self.assertIsNone(status)
827
828 mock_disconnect_controller.assert_called()
829 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200830
aktas3061bef2021-07-29 17:41:40 +0300831 def test_successful_exec(
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200832 self,
833 mock_get_action_status,
834 mock_get_action_output,
835 mock_wait_for,
836 mock__get_application,
837 mock_disconnect_controller,
838 mock_disconnect_model,
839 mock_get_model,
840 mock_get_controller,
841 ):
842 mock_get_model.return_value = juju.model.Model()
843 mock__get_application.return_value = FakeApplication()
844 mock_get_action_output.return_value = "output"
845 mock_get_action_status.return_value = {"id": "status"}
846 output, status = self.loop.run_until_complete(
847 self.libjuju.execute_action("app", "model", "existing_action")
848 )
849 self.assertEqual(output, "output")
850 self.assertEqual(status, "status")
851
852 mock_wait_for.assert_called_once()
853
854 mock_disconnect_controller.assert_called()
855 mock_disconnect_model.assert_called()
856
857
858@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
859@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
860@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
861@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
862@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
863class GetActionTest(LibjujuTestCase):
864 def setUp(self):
865 super(GetActionTest, self).setUp()
866
867 def test_exception(
868 self,
869 mock_get_application,
870 mock_disconnect_controller,
871 mock_disconnect_model,
872 mock_get_model,
873 mock_get_controller,
874 ):
875 mock_get_application.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200876 actions = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200877 with self.assertRaises(Exception):
878 actions = self.loop.run_until_complete(
879 self.libjuju.get_actions("app", "model")
880 )
881
David Garcia12b29242020-09-17 16:01:48 +0200882 self.assertIsNone(actions)
883 mock_disconnect_controller.assert_called_once()
884 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200885
886 def test_success(
887 self,
888 mock_get_application,
889 mock_disconnect_controller,
890 mock_disconnect_model,
891 mock_get_model,
892 mock_get_controller,
893 ):
894 mock_get_application.return_value = FakeApplication()
895
896 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
897
898 self.assertEqual(actions, ["existing_action"])
899
900 mock_get_controller.assert_called_once()
901 mock_get_model.assert_called_once()
902 mock_disconnect_controller.assert_called_once()
903 mock_disconnect_model.assert_called_once()
904
905
906@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
907@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
908@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
909@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
David Garcia85755d12020-09-21 19:51:23 +0200910@asynctest.mock.patch("juju.application.Application.get_metrics")
911@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
912class GetMetricsTest(LibjujuTestCase):
913 def setUp(self):
914 super(GetMetricsTest, self).setUp()
915
916 def test_get_metrics_success(
917 self,
918 mock_get_application,
919 mock_get_metrics,
920 mock_disconnect_controller,
921 mock_disconnect_model,
922 mock_get_model,
923 mock_get_controller,
924 ):
925 mock_get_application.return_value = FakeApplication()
926 mock_get_model.return_value = juju.model.Model()
927
928 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
929
930 mock_disconnect_controller.assert_called_once()
931 mock_disconnect_model.assert_called_once()
932
933 def test_get_metrics_exception(
934 self,
935 mock_get_application,
936 mock_get_metrics,
937 mock_disconnect_controller,
938 mock_disconnect_model,
939 mock_get_model,
940 mock_get_controller,
941 ):
942 mock_get_model.return_value = juju.model.Model()
943 mock_get_metrics.side_effect = Exception()
944 with self.assertRaises(Exception):
945 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
946
947 mock_disconnect_controller.assert_called_once()
948 mock_disconnect_model.assert_called_once()
949
950 def test_missing_args_exception(
951 self,
952 mock_get_application,
953 mock_get_metrics,
954 mock_disconnect_controller,
955 mock_disconnect_model,
956 mock_get_model,
957 mock_get_controller,
958 ):
959 mock_get_model.return_value = juju.model.Model()
960
961 with self.assertRaises(Exception):
962 self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
963
964 mock_get_controller.assert_not_called()
965 mock_get_model.assert_not_called()
966 mock_disconnect_controller.assert_not_called()
967 mock_disconnect_model.assert_not_called()
968
969
970@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
971@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
972@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
973@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200974@asynctest.mock.patch("juju.model.Model.add_relation")
975class AddRelationTest(LibjujuTestCase):
976 def setUp(self):
977 super(AddRelationTest, self).setUp()
978
979 @asynctest.mock.patch("logging.Logger.warning")
980 def test_not_found(
981 self,
982 mock_warning,
983 mock_add_relation,
984 mock_disconnect_controller,
985 mock_disconnect_model,
986 mock_get_model,
987 mock_get_controller,
988 ):
989 # TODO in libjuju.py should this fail only with a log message?
990 result = {"error": "not found", "response": "response", "request-id": 1}
991
992 mock_get_model.return_value = juju.model.Model()
993 mock_add_relation.side_effect = JujuAPIError(result)
994
995 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100996 self.libjuju.add_relation(
997 "model",
998 "app1:relation1",
999 "app2:relation2",
1000 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001001 )
1002
1003 mock_warning.assert_called_with("Relation not found: not found")
1004 mock_disconnect_controller.assert_called_once()
1005 mock_disconnect_model.assert_called_once()
1006
1007 @asynctest.mock.patch("logging.Logger.warning")
1008 def test_already_exists(
1009 self,
1010 mock_warning,
1011 mock_add_relation,
1012 mock_disconnect_controller,
1013 mock_disconnect_model,
1014 mock_get_model,
1015 mock_get_controller,
1016 ):
1017 # TODO in libjuju.py should this fail silently?
1018 result = {"error": "already exists", "response": "response", "request-id": 1}
1019
1020 mock_get_model.return_value = juju.model.Model()
1021 mock_add_relation.side_effect = JujuAPIError(result)
1022
1023 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001024 self.libjuju.add_relation(
1025 "model",
1026 "app1:relation1",
1027 "app2:relation2",
1028 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001029 )
1030
1031 mock_warning.assert_called_with("Relation already exists: already exists")
1032 mock_disconnect_controller.assert_called_once()
1033 mock_disconnect_model.assert_called_once()
1034
1035 def test_exception(
1036 self,
1037 mock_add_relation,
1038 mock_disconnect_controller,
1039 mock_disconnect_model,
1040 mock_get_model,
1041 mock_get_controller,
1042 ):
1043 mock_get_model.return_value = juju.model.Model()
1044 result = {"error": "", "response": "response", "request-id": 1}
1045 mock_add_relation.side_effect = JujuAPIError(result)
1046
1047 with self.assertRaises(JujuAPIError):
1048 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001049 self.libjuju.add_relation(
1050 "model",
1051 "app1:relation1",
1052 "app2:relation2",
1053 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001054 )
1055
David Garcia12b29242020-09-17 16:01:48 +02001056 mock_disconnect_controller.assert_called_once()
1057 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001058
1059 def test_success(
1060 self,
1061 mock_add_relation,
1062 mock_disconnect_controller,
1063 mock_disconnect_model,
1064 mock_get_model,
1065 mock_get_controller,
1066 ):
1067 mock_get_model.return_value = juju.model.Model()
1068
1069 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001070 self.libjuju.add_relation(
1071 "model",
1072 "app1:relation1",
1073 "app2:relation2",
1074 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001075 )
1076
David Garcia12b29242020-09-17 16:01:48 +02001077 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
David Garcia8331f7c2020-08-25 16:10:07 +02001078 mock_disconnect_controller.assert_called_once()
1079 mock_disconnect_model.assert_called_once()
1080
1081 def test_saas(
1082 self,
1083 mock_add_relation,
1084 mock_disconnect_controller,
1085 mock_disconnect_model,
1086 mock_get_model,
1087 mock_get_controller,
1088 ):
1089 mock_get_model.return_value = juju.model.Model()
1090
1091 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001092 self.libjuju.add_relation(
1093 "model",
1094 "app1:relation1",
1095 "saas_name",
1096 )
David Garcia8331f7c2020-08-25 16:10:07 +02001097 )
1098
David Garcia12b29242020-09-17 16:01:48 +02001099 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001100 mock_disconnect_controller.assert_called_once()
1101 mock_disconnect_model.assert_called_once()
1102
1103
1104# TODO destroy_model testcase
1105
1106
aktas56120292021-02-26 15:32:39 +03001107@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1108@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1109@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1110@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1111@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1112class DestroyApplicationTest(LibjujuTestCase):
1113 def setUp(self):
1114 super(DestroyApplicationTest, self).setUp()
1115
1116 def test_success(
garciadeblas82b591c2021-03-24 09:22:13 +01001117 self,
1118 mock_get_controller,
1119 mock_get_model,
1120 mock_disconnect_controller,
1121 mock_get_application,
1122 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001123 ):
1124 mock_get_application.return_value = FakeApplication()
1125 mock_get_model.return_value = None
1126 self.loop.run_until_complete(
1127 self.libjuju.destroy_application(
1128 "existing_model",
1129 "existing_app",
1130 3600,
1131 )
1132 )
1133 mock_get_application.assert_called()
1134 mock_disconnect_controller.assert_called_once()
1135 mock_disconnect_model.assert_called_once()
1136
1137 def test_no_application(
garciadeblas82b591c2021-03-24 09:22:13 +01001138 self,
1139 mock_get_controller,
1140 mock_get_model,
1141 mock_disconnect_controller,
1142 mock_get_application,
1143 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001144 ):
1145 mock_get_model.return_value = None
1146 mock_get_application.return_value = None
1147
1148 self.loop.run_until_complete(
1149 self.libjuju.destroy_application(
1150 "existing_model",
1151 "existing_app",
1152 3600,
1153 )
1154 )
1155 mock_get_application.assert_called()
1156
1157 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01001158 self,
1159 mock_get_controller,
1160 mock_get_model,
1161 mock_disconnect_controller,
1162 mock_get_application,
1163 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001164 ):
1165 mock_get_application.return_value = FakeApplication
1166 mock_get_model.return_value = None
1167
1168 with self.assertRaises(Exception):
1169 self.loop.run_until_complete(
1170 self.libjuju.destroy_application(
1171 "existing_model",
1172 "existing_app",
1173 0,
1174 )
1175 )
1176 mock_get_application.assert_called_once()
1177
1178
David Garcia5ef42a12020-09-29 19:48:13 +02001179# @asynctest.mock.patch("juju.model.Model.get_machines")
1180# @asynctest.mock.patch("logging.Logger.debug")
1181# class DestroyMachineTest(LibjujuTestCase):
1182# def setUp(self):
1183# super(DestroyMachineTest, self).setUp()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001184
David Garcia5ef42a12020-09-29 19:48:13 +02001185# def test_success_manual_machine(
1186# self, mock_debug, mock_get_machines,
1187# ):
1188# mock_get_machines.side_effect = [
1189# {"machine": FakeManualMachine()},
1190# {"machine": FakeManualMachine()},
1191# {},
1192# ]
1193# self.loop.run_until_complete(
1194# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
1195# )
1196# calls = [
1197# asynctest.call("Waiting for machine machine is destroyed"),
1198# asynctest.call("Machine destroyed: machine"),
1199# ]
1200# mock_debug.assert_has_calls(calls)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001201
David Garcia5ef42a12020-09-29 19:48:13 +02001202# def test_no_machine(
1203# self, mock_debug, mock_get_machines,
1204# ):
1205# mock_get_machines.return_value = {}
1206# self.loop.run_until_complete(
1207# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
1208# )
1209# mock_debug.assert_called_with("Machine not found: machine")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001210
1211
1212@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1213@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1214@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1215@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1216@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1217class ConfigureApplicationTest(LibjujuTestCase):
1218 def setUp(self):
1219 super(ConfigureApplicationTest, self).setUp()
1220
1221 def test_success(
1222 self,
1223 mock_get_application,
1224 mock_disconnect_controller,
1225 mock_disconnect_model,
1226 mock_get_model,
1227 mock_get_controller,
1228 ):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001229 mock_get_application.return_value = FakeApplication()
1230
1231 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001232 self.libjuju.configure_application(
1233 "model",
1234 "app",
1235 {"config"},
1236 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001237 )
1238 mock_get_application.assert_called_once()
1239 mock_disconnect_controller.assert_called_once()
1240 mock_disconnect_model.assert_called_once()
1241
1242 def test_exception(
1243 self,
1244 mock_get_application,
1245 mock_disconnect_controller,
1246 mock_disconnect_model,
1247 mock_get_model,
1248 mock_get_controller,
1249 ):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001250 mock_get_application.side_effect = Exception()
1251
1252 with self.assertRaises(Exception):
1253 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001254 self.libjuju.configure_application(
1255 "model",
1256 "app",
1257 {"config"},
1258 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001259 )
David Garcia12b29242020-09-17 16:01:48 +02001260 mock_disconnect_controller.assert_called_once()
1261 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001262
David Garcia5b802c92020-11-11 16:56:06 +01001263 def test_controller_exception(
1264 self,
1265 mock_get_application,
1266 mock_disconnect_controller,
1267 mock_disconnect_model,
1268 mock_get_model,
1269 mock_get_controller,
1270 ):
David Garcia5b802c92020-11-11 16:56:06 +01001271 result = {"error": "not found", "response": "response", "request-id": 1}
1272
1273 mock_get_controller.side_effect = JujuAPIError(result)
1274
1275 with self.assertRaises(JujuAPIError):
1276 self.loop.run_until_complete(
1277 self.libjuju.configure_application(
1278 "model",
1279 "app",
1280 {"config"},
1281 )
1282 )
1283 mock_get_model.assert_not_called()
1284 mock_disconnect_controller.assert_not_called()
1285 mock_disconnect_model.assert_not_called()
1286
1287 def test_get_model_exception(
1288 self,
1289 mock_get_application,
1290 mock_disconnect_controller,
1291 mock_disconnect_model,
1292 mock_get_model,
1293 mock_get_controller,
1294 ):
David Garcia5b802c92020-11-11 16:56:06 +01001295 result = {"error": "not found", "response": "response", "request-id": 1}
1296 mock_get_model.side_effect = JujuAPIError(result)
1297
1298 with self.assertRaises(JujuAPIError):
1299 self.loop.run_until_complete(
1300 self.libjuju.configure_application(
1301 "model",
1302 "app",
1303 {"config"},
1304 )
1305 )
1306 mock_get_model.assert_called_once()
1307 mock_disconnect_controller.assert_called_once()
1308 mock_disconnect_model.assert_not_called()
1309
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001310
1311# TODO _get_api_endpoints_db test case
1312# TODO _update_api_endpoints_db test case
1313# TODO healthcheck test case
1314
1315
1316@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1317@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1318@asynctest.mock.patch("juju.controller.Controller.list_models")
1319class ListModelsTest(LibjujuTestCase):
1320 def setUp(self):
1321 super(ListModelsTest, self).setUp()
1322
1323 def test_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001324 self,
1325 mock_list_models,
1326 mock_disconnect_controller,
1327 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001328 ):
1329 mock_get_controller.return_value = juju.controller.Controller()
1330 mock_list_models.return_value = ["existingmodel"]
1331 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
1332
1333 mock_disconnect_controller.assert_called_once()
1334 self.assertEquals(models, ["existingmodel"])
1335
1336 def test_not_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001337 self,
1338 mock_list_models,
1339 mock_disconnect_controller,
1340 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001341 ):
1342 mock_get_controller.return_value = juju.controller.Controller()
1343 mock_list_models.return_value = ["existingmodel", "model"]
1344 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
1345
1346 mock_disconnect_controller.assert_called_once()
1347 self.assertEquals(models, [])
1348
1349 def test_no_contains_arg(
David Garcia5b802c92020-11-11 16:56:06 +01001350 self,
1351 mock_list_models,
1352 mock_disconnect_controller,
1353 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001354 ):
1355 mock_get_controller.return_value = juju.controller.Controller()
1356 mock_list_models.return_value = ["existingmodel", "model"]
1357 models = self.loop.run_until_complete(self.libjuju.list_models())
1358
1359 mock_disconnect_controller.assert_called_once()
1360 self.assertEquals(models, ["existingmodel", "model"])
David Garcia42f328a2020-08-25 15:03:01 +02001361
1362
1363@asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
1364class ModelsExistTest(LibjujuTestCase):
1365 def setUp(self):
1366 super(ModelsExistTest, self).setUp()
1367
1368 def test_model_names_none(self, mock_list_models):
1369 mock_list_models.return_value = []
1370 with self.assertRaises(Exception):
1371 self.loop.run_until_complete(self.libjuju.models_exist(None))
1372
1373 def test_model_names_empty(self, mock_list_models):
1374 mock_list_models.return_value = []
1375 with self.assertRaises(Exception):
1376 (exist, non_existing_models) = self.loop.run_until_complete(
1377 self.libjuju.models_exist([])
1378 )
1379
1380 def test_model_names_not_existing(self, mock_list_models):
1381 mock_list_models.return_value = ["prometheus", "grafana"]
1382 (exist, non_existing_models) = self.loop.run_until_complete(
1383 self.libjuju.models_exist(["prometheus2", "grafana"])
1384 )
1385 self.assertFalse(exist)
1386 self.assertEqual(non_existing_models, ["prometheus2"])
1387
1388 def test_model_names_exist(self, mock_list_models):
1389 mock_list_models.return_value = ["prometheus", "grafana"]
1390 (exist, non_existing_models) = self.loop.run_until_complete(
1391 self.libjuju.models_exist(["prometheus", "grafana"])
1392 )
1393 self.assertTrue(exist)
1394 self.assertEqual(non_existing_models, [])
David Garciabc538e42020-08-25 15:22:30 +02001395
1396
1397@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1398@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1399@asynctest.mock.patch("juju.controller.Controller.list_offers")
1400class ListOffers(LibjujuTestCase):
1401 def setUp(self):
1402 super(ListOffers, self).setUp()
1403
1404 def test_disconnect_controller(
David Garcia5b802c92020-11-11 16:56:06 +01001405 self,
1406 mock_list_offers,
1407 mock_disconnect_controller,
1408 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001409 ):
1410 mock_get_controller.return_value = juju.controller.Controller()
1411 mock_list_offers.side_effect = Exception()
1412 with self.assertRaises(Exception):
1413 self.loop.run_until_complete(self.libjuju.list_offers("model"))
1414 mock_disconnect_controller.assert_called_once()
1415
1416 def test_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001417 self,
1418 mock_list_offers,
1419 mock_disconnect_controller,
1420 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001421 ):
1422 mock_get_controller.return_value = juju.controller.Controller()
1423 mock_list_offers.return_value = []
1424 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
1425 self.assertEqual(offers, [])
1426 mock_disconnect_controller.assert_called_once()
1427
1428 def test_non_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001429 self,
1430 mock_list_offers,
1431 mock_disconnect_controller,
1432 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001433 ):
1434 mock_get_controller.return_value = juju.controller.Controller()
1435 mock_list_offers.return_value = ["offer"]
1436 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
1437 self.assertEqual(offers, ["offer"])
1438 mock_disconnect_controller.assert_called_once()
David Garcia68b00722020-09-11 15:05:00 +02001439
1440
1441@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1442@asynctest.mock.patch("juju.controller.Controller.get_model")
1443@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1444@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1445@asynctest.mock.patch("juju.model.Model.consume")
1446class ConsumeTest(LibjujuTestCase):
1447 def setUp(self):
1448 super(ConsumeTest, self).setUp()
1449
1450 def test_consume(
1451 self,
1452 mock_consume,
1453 mock_disconnect_controller,
1454 mock_disconnect_model,
1455 mock_get_model,
1456 mock_get_controller,
1457 ):
1458 mock_get_controller.return_value = juju.controller.Controller()
1459 mock_get_model.return_value = juju.model.Model()
1460
David Garcia12b29242020-09-17 16:01:48 +02001461 self.loop.run_until_complete(self.libjuju.consume("offer_url", "model_name"))
David Garcia68b00722020-09-11 15:05:00 +02001462 mock_consume.assert_called_once()
1463 mock_disconnect_model.assert_called_once()
1464 mock_disconnect_controller.assert_called_once()
1465
1466 def test_parsing_error_exception(
1467 self,
1468 mock_consume,
1469 mock_disconnect_controller,
1470 mock_disconnect_model,
1471 mock_get_model,
1472 mock_get_controller,
1473 ):
1474 mock_get_controller.return_value = juju.controller.Controller()
1475 mock_get_model.return_value = juju.model.Model()
1476 mock_consume.side_effect = juju.offerendpoints.ParseError("")
1477
1478 with self.assertRaises(juju.offerendpoints.ParseError):
1479 self.loop.run_until_complete(
1480 self.libjuju.consume("offer_url", "model_name")
1481 )
1482 mock_consume.assert_called_once()
1483 mock_disconnect_model.assert_called_once()
1484 mock_disconnect_controller.assert_called_once()
1485
1486 def test_juju_error_exception(
1487 self,
1488 mock_consume,
1489 mock_disconnect_controller,
1490 mock_disconnect_model,
1491 mock_get_model,
1492 mock_get_controller,
1493 ):
1494 mock_get_controller.return_value = juju.controller.Controller()
1495 mock_get_model.return_value = juju.model.Model()
1496 mock_consume.side_effect = juju.errors.JujuError("")
1497
1498 with self.assertRaises(juju.errors.JujuError):
1499 self.loop.run_until_complete(
1500 self.libjuju.consume("offer_url", "model_name")
1501 )
1502 mock_consume.assert_called_once()
1503 mock_disconnect_model.assert_called_once()
1504 mock_disconnect_controller.assert_called_once()
1505
1506 def test_juju_api_error_exception(
1507 self,
1508 mock_consume,
1509 mock_disconnect_controller,
1510 mock_disconnect_model,
1511 mock_get_model,
1512 mock_get_controller,
1513 ):
1514 mock_get_controller.return_value = juju.controller.Controller()
1515 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +02001516 mock_consume.side_effect = juju.errors.JujuAPIError(
1517 {"error": "", "response": "", "request-id": ""}
1518 )
David Garcia68b00722020-09-11 15:05:00 +02001519
1520 with self.assertRaises(juju.errors.JujuAPIError):
1521 self.loop.run_until_complete(
1522 self.libjuju.consume("offer_url", "model_name")
1523 )
1524 mock_consume.assert_called_once()
1525 mock_disconnect_model.assert_called_once()
1526 mock_disconnect_controller.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001527
1528
David Garcia475a7222020-09-21 16:19:15 +02001529@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
David Garcia12b29242020-09-17 16:01:48 +02001530@asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
1531class AddK8sTest(LibjujuTestCase):
1532 def setUp(self):
1533 super(AddK8sTest, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001534 name = "cloud"
1535 rbac_id = generate_rbac_id()
1536 token = "token"
1537 client_cert_data = "cert"
1538 configuration = kubernetes.client.configuration.Configuration()
1539 storage_class = "storage_class"
1540 credential_name = name
1541
1542 self._add_k8s_args = {
1543 "name": name,
1544 "rbac_id": rbac_id,
1545 "token": token,
1546 "client_cert_data": client_cert_data,
1547 "configuration": configuration,
1548 "storage_class": storage_class,
1549 "credential_name": credential_name,
1550 }
David Garcia12b29242020-09-17 16:01:48 +02001551
David Garcia475a7222020-09-21 16:19:15 +02001552 def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001553 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001554 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001555 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001556
David Garcia475a7222020-09-21 16:19:15 +02001557 def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garcia12b29242020-09-17 16:01:48 +02001558 mock_add_cloud.side_effect = Exception()
1559 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001560 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001561 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001562 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001563
David Garcia475a7222020-09-21 16:19:15 +02001564 def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001565 self._add_k8s_args["name"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001566 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001567 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001568 mock_add_cloud.assert_not_called()
1569
David Garcia475a7222020-09-21 16:19:15 +02001570 def test_add_k8s_missing_storage_name(
1571 self, mock_add_cloud, mock_get_k8s_cloud_credential
1572 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001573 self._add_k8s_args["storage_class"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001574 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001575 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001576 mock_add_cloud.assert_not_called()
1577
David Garcia475a7222020-09-21 16:19:15 +02001578 def test_add_k8s_missing_configuration_keys(
1579 self, mock_add_cloud, mock_get_k8s_cloud_credential
1580 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001581 self._add_k8s_args["configuration"] = None
David Garcia12b29242020-09-17 16:01:48 +02001582 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001583 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001584 mock_add_cloud.assert_not_called()
1585
1586
1587@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1588@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1589@asynctest.mock.patch("juju.controller.Controller.add_cloud")
1590@asynctest.mock.patch("juju.controller.Controller.add_credential")
1591class AddCloudTest(LibjujuTestCase):
1592 def setUp(self):
1593 super(AddCloudTest, self).setUp()
1594 self.cloud = juju.client.client.Cloud()
1595 self.credential = juju.client.client.CloudCredential()
1596
1597 def test_add_cloud_with_credential(
1598 self,
1599 mock_add_credential,
1600 mock_add_cloud,
1601 mock_disconnect_controller,
1602 mock_get_controller,
1603 ):
1604 mock_get_controller.return_value = juju.controller.Controller()
1605
1606 cloud = self.loop.run_until_complete(
1607 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1608 )
1609 self.assertEqual(cloud, self.cloud)
1610 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1611 mock_add_credential.assert_called_once_with(
1612 "cloud", credential=self.credential, cloud="cloud"
1613 )
1614 mock_disconnect_controller.assert_called_once()
1615
1616 def test_add_cloud_no_credential(
1617 self,
1618 mock_add_credential,
1619 mock_add_cloud,
1620 mock_disconnect_controller,
1621 mock_get_controller,
1622 ):
1623 mock_get_controller.return_value = juju.controller.Controller()
1624
1625 cloud = self.loop.run_until_complete(
1626 self.libjuju.add_cloud("cloud", self.cloud)
1627 )
1628 self.assertEqual(cloud, self.cloud)
1629 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1630 mock_add_credential.assert_not_called()
1631 mock_disconnect_controller.assert_called_once()
1632
1633 def test_add_cloud_exception(
1634 self,
1635 mock_add_credential,
1636 mock_add_cloud,
1637 mock_disconnect_controller,
1638 mock_get_controller,
1639 ):
1640 mock_get_controller.return_value = juju.controller.Controller()
1641 mock_add_cloud.side_effect = Exception()
1642 with self.assertRaises(Exception):
1643 self.loop.run_until_complete(
1644 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1645 )
1646
1647 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1648 mock_add_credential.assert_not_called()
1649 mock_disconnect_controller.assert_called_once()
1650
1651 def test_add_credential_exception(
1652 self,
1653 mock_add_credential,
1654 mock_add_cloud,
1655 mock_disconnect_controller,
1656 mock_get_controller,
1657 ):
1658 mock_get_controller.return_value = juju.controller.Controller()
1659 mock_add_credential.side_effect = Exception()
1660 with self.assertRaises(Exception):
1661 self.loop.run_until_complete(
1662 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1663 )
1664
1665 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1666 mock_add_credential.assert_called_once_with(
1667 "cloud", credential=self.credential, cloud="cloud"
1668 )
1669 mock_disconnect_controller.assert_called_once()
1670
1671
1672@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1673@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1674@asynctest.mock.patch("juju.controller.Controller.remove_cloud")
1675class RemoveCloudTest(LibjujuTestCase):
1676 def setUp(self):
1677 super(RemoveCloudTest, self).setUp()
1678
1679 def test_remove_cloud(
David Garcia5b802c92020-11-11 16:56:06 +01001680 self,
1681 mock_remove_cloud,
1682 mock_disconnect_controller,
1683 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001684 ):
1685 mock_get_controller.return_value = juju.controller.Controller()
1686
1687 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1688 mock_remove_cloud.assert_called_once_with("cloud")
1689 mock_disconnect_controller.assert_called_once()
1690
1691 def test_remove_cloud_exception(
David Garcia5b802c92020-11-11 16:56:06 +01001692 self,
1693 mock_remove_cloud,
1694 mock_disconnect_controller,
1695 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001696 ):
1697 mock_get_controller.return_value = juju.controller.Controller()
1698 mock_remove_cloud.side_effect = Exception()
1699
1700 with self.assertRaises(Exception):
1701 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1702 mock_remove_cloud.assert_called_once_with("cloud")
1703 mock_disconnect_controller.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001704
1705
1706@asynctest.mock.patch("kubernetes.client.configuration.Configuration")
1707class GetK8sCloudCredentials(LibjujuTestCase):
1708 def setUp(self):
1709 super(GetK8sCloudCredentials, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001710 self.cert_data = "cert"
1711 self.token = "token"
David Garcia475a7222020-09-21 16:19:15 +02001712
1713 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1714 def test_not_supported(self, mock_exception, mock_configuration):
1715 mock_configuration.username = ""
1716 mock_configuration.password = ""
1717 mock_configuration.ssl_ca_cert = None
1718 mock_configuration.cert_file = None
1719 mock_configuration.key_file = None
1720 exception_raised = False
David Garciaf6e9b002020-11-27 15:32:02 +01001721 self.token = None
1722 self.cert_data = None
David Garcia475a7222020-09-21 16:19:15 +02001723 try:
David Garciaf6e9b002020-11-27 15:32:02 +01001724 _ = self.libjuju.get_k8s_cloud_credential(
1725 mock_configuration,
1726 self.cert_data,
1727 self.token,
1728 )
David Garcia475a7222020-09-21 16:19:15 +02001729 except JujuInvalidK8sConfiguration as e:
1730 exception_raised = True
1731 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01001732 e.message,
1733 "authentication method not supported",
David Garcia475a7222020-09-21 16:19:15 +02001734 )
1735 self.assertTrue(exception_raised)
1736
1737 def test_user_pass(self, mock_configuration):
1738 mock_configuration.username = "admin"
1739 mock_configuration.password = "admin"
1740 mock_configuration.ssl_ca_cert = None
1741 mock_configuration.cert_file = None
1742 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001743 self.token = None
1744 self.cert_data = None
1745 credential = self.libjuju.get_k8s_cloud_credential(
1746 mock_configuration,
1747 self.cert_data,
1748 self.token,
1749 )
David Garcia475a7222020-09-21 16:19:15 +02001750 self.assertEqual(
1751 credential,
1752 juju.client._definitions.CloudCredential(
1753 attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
1754 ),
1755 )
1756
David Garciaf6e9b002020-11-27 15:32:02 +01001757 def test_user_pass_with_cert(self, mock_configuration):
1758 mock_configuration.username = "admin"
1759 mock_configuration.password = "admin"
1760 mock_configuration.ssl_ca_cert = None
1761 mock_configuration.cert_file = None
1762 mock_configuration.key_file = None
1763 self.token = None
1764 credential = self.libjuju.get_k8s_cloud_credential(
1765 mock_configuration,
1766 self.cert_data,
1767 self.token,
1768 )
1769 self.assertEqual(
1770 credential,
1771 juju.client._definitions.CloudCredential(
1772 attrs={
1773 "ClientCertificateData": self.cert_data,
1774 "username": "admin",
1775 "password": "admin",
1776 },
1777 auth_type="userpasswithcert",
1778 ),
1779 )
1780
David Garcia475a7222020-09-21 16:19:15 +02001781 def test_user_no_pass(self, mock_configuration):
1782 mock_configuration.username = "admin"
1783 mock_configuration.password = ""
1784 mock_configuration.ssl_ca_cert = None
1785 mock_configuration.cert_file = None
1786 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001787 self.token = None
1788 self.cert_data = None
David Garciaeb8943a2021-04-12 12:07:37 +02001789 with patch.object(self.libjuju.log, "debug") as mock_debug:
David Garciaf6e9b002020-11-27 15:32:02 +01001790 credential = self.libjuju.get_k8s_cloud_credential(
1791 mock_configuration,
1792 self.cert_data,
1793 self.token,
1794 )
David Garcia475a7222020-09-21 16:19:15 +02001795 self.assertEqual(
1796 credential,
1797 juju.client._definitions.CloudCredential(
1798 attrs={"username": "admin", "password": ""}, auth_type="userpass"
1799 ),
1800 )
1801 mock_debug.assert_called_once_with(
1802 "credential for user admin has empty password"
1803 )
1804
David Garcia475a7222020-09-21 16:19:15 +02001805 def test_cert(self, mock_configuration):
1806 mock_configuration.username = ""
1807 mock_configuration.password = ""
1808 mock_configuration.api_key = {"authorization": "Bearer Token"}
1809 ssl_ca_cert = tempfile.NamedTemporaryFile()
1810 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
1811 ssl_ca_cert_file.write("cacert")
1812 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
1813 mock_configuration.cert_file = None
1814 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001815 credential = self.libjuju.get_k8s_cloud_credential(
1816 mock_configuration,
1817 self.cert_data,
1818 self.token,
1819 )
David Garcia475a7222020-09-21 16:19:15 +02001820 self.assertEqual(
1821 credential,
1822 juju.client._definitions.CloudCredential(
David Garciaf6e9b002020-11-27 15:32:02 +01001823 attrs={"ClientCertificateData": self.cert_data, "Token": self.token},
David Garcia475a7222020-09-21 16:19:15 +02001824 auth_type="certificate",
1825 ),
1826 )
1827
David Garciaf6e9b002020-11-27 15:32:02 +01001828 # TODO: Fix this test when oauth authentication is supported
1829 # def test_oauth2(self, mock_configuration):
1830 # mock_configuration.username = ""
1831 # mock_configuration.password = ""
1832 # mock_configuration.api_key = {"authorization": "Bearer Token"}
1833 # key = tempfile.NamedTemporaryFile()
1834 # with open(key.name, "w") as key_file:
1835 # key_file.write("key")
1836 # mock_configuration.ssl_ca_cert = None
1837 # mock_configuration.cert_file = None
1838 # mock_configuration.key_file = key.name
1839 # credential = self.libjuju.get_k8s_cloud_credential(
1840 # mock_configuration,
1841 # self.cert_data,
1842 # self.token,
1843 # )
1844 # self.assertEqual(
1845 # credential,
1846 # juju.client._definitions.CloudCredential(
1847 # attrs={"ClientKeyData": "key", "Token": "Token"},
1848 # auth_type="oauth2",
1849 # ),
1850 # )
David Garcia475a7222020-09-21 16:19:15 +02001851
David Garciaf6e9b002020-11-27 15:32:02 +01001852 # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1853 # def test_oauth2_missing_token(self, mock_exception, mock_configuration):
1854 # mock_configuration.username = ""
1855 # mock_configuration.password = ""
1856 # key = tempfile.NamedTemporaryFile()
1857 # with open(key.name, "w") as key_file:
1858 # key_file.write("key")
1859 # mock_configuration.ssl_ca_cert = None
1860 # mock_configuration.cert_file = None
1861 # mock_configuration.key_file = key.name
1862 # exception_raised = False
1863 # try:
1864 # _ = self.libjuju.get_k8s_cloud_credential(
1865 # mock_configuration,
1866 # self.cert_data,
1867 # self.token,
1868 # )
1869 # except JujuInvalidK8sConfiguration as e:
1870 # exception_raised = True
1871 # self.assertEqual(
1872 # e.message,
1873 # "missing token for auth type oauth2",
1874 # )
1875 # self.assertTrue(exception_raised)
David Garcia475a7222020-09-21 16:19:15 +02001876
1877 def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
1878 mock_configuration.username = "admin"
1879 mock_configuration.password = "pass"
1880 mock_configuration.api_key = {"authorization": "No_bearer_token"}
1881 mock_configuration.ssl_ca_cert = None
1882 mock_configuration.cert_file = None
1883 mock_configuration.key_file = None
1884 exception_raised = False
1885 try:
David Garciaf6e9b002020-11-27 15:32:02 +01001886 _ = self.libjuju.get_k8s_cloud_credential(
1887 mock_configuration,
1888 self.cert_data,
1889 self.token,
1890 )
David Garcia475a7222020-09-21 16:19:15 +02001891 except JujuInvalidK8sConfiguration as e:
1892 exception_raised = True
1893 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01001894 e.message,
1895 "Cannot set both token and user/pass",
David Garcia475a7222020-09-21 16:19:15 +02001896 )
1897 self.assertTrue(exception_raised)
aktas2962f3e2021-03-15 11:05:35 +03001898
1899
1900@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1901@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1902@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1903@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1904@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1905@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
1906class ScaleApplicationTest(LibjujuTestCase):
1907 def setUp(self):
1908 super(ScaleApplicationTest, self).setUp()
1909
1910 @asynctest.mock.patch("asyncio.sleep")
1911 def test_scale_application(
1912 self,
1913 mock_sleep,
1914 mock_wait_for_model,
1915 mock_disconnect_controller,
1916 mock_disconnect_model,
1917 mock_get_application,
1918 mock_get_model,
1919 mock_get_controller,
1920 ):
1921 mock_get_model.return_value = juju.model.Model()
1922 mock_get_application.return_value = FakeApplication()
garciadeblas82b591c2021-03-24 09:22:13 +01001923 self.loop.run_until_complete(self.libjuju.scale_application("model", "app", 2))
aktas2962f3e2021-03-15 11:05:35 +03001924 mock_wait_for_model.assert_called_once()
1925 mock_disconnect_controller.assert_called_once()
1926 mock_disconnect_model.assert_called_once()
1927
1928 def test_no_application(
1929 self,
1930 mock_wait_for,
1931 mock_disconnect_controller,
1932 mock_disconnect_model,
1933 mock_get_application,
1934 mock_get_model,
1935 mock_get_controller,
1936 ):
1937 mock_get_application.return_value = None
1938 mock_get_model.return_value = juju.model.Model()
1939 with self.assertRaises(JujuApplicationNotFound):
1940 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01001941 self.libjuju.scale_application("model", "app", 2)
aktas2962f3e2021-03-15 11:05:35 +03001942 )
1943 mock_disconnect_controller.assert_called()
1944 mock_disconnect_model.assert_called()
1945
1946 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01001947 self,
1948 mock_wait_for,
1949 mock_disconnect_controller,
1950 mock_disconnect_model,
1951 mock_get_application,
1952 mock_get_model,
1953 mock_get_controller,
aktas2962f3e2021-03-15 11:05:35 +03001954 ):
1955 mock_get_model.return_value = None
1956 mock_get_application.return_value = FakeApplication()
1957 with self.assertRaises(Exception):
1958 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01001959 self.libjuju.scale_application("model", "app", 2, total_timeout=0)
aktas2962f3e2021-03-15 11:05:35 +03001960 )
1961 mock_disconnect_controller.assert_called_once()
1962
1963
1964@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1965class GetUnitNumberTest(LibjujuTestCase):
1966 def setUp(self):
1967 super(GetUnitNumberTest, self).setUp()
1968
aktas3061bef2021-07-29 17:41:40 +03001969 def test_successful_get_unit_number(
aktas2962f3e2021-03-15 11:05:35 +03001970 self,
1971 mock_get_applications,
1972 ):
1973 mock_get_applications.return_value = FakeApplication()
1974 model = juju.model.Model()
1975 result = self.libjuju._get_application_count(model, "app")
1976 self.assertEqual(result, 2)
1977
1978 def test_non_existing_application(
1979 self,
1980 mock_get_applications,
1981 ):
1982 mock_get_applications.return_value = None
1983 model = juju.model.Model()
1984 result = self.libjuju._get_application_count(model, "app")
1985 self.assertEqual(result, None)
aktas3061bef2021-07-29 17:41:40 +03001986
1987
1988@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
1989class GetMachineInfoTest(LibjujuTestCase):
1990 def setUp(self):
1991 super(GetMachineInfoTest, self).setUp()
1992
1993 def test_successful(
1994 self,
1995 mock_machines,
1996 ):
1997 machine_id = "existing_machine"
1998 model = juju.model.Model()
1999 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2000 machine, series = self.libjuju._get_machine_info(
2001 machine_id=machine_id,
2002 model=model,
2003 )
2004 self.assertIsNotNone(machine, series)
2005
2006 def test_exception(
2007 self,
2008 mock_machines,
2009 ):
2010 machine_id = "not_existing_machine"
2011 machine = series = None
2012 model = juju.model.Model()
2013 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2014 with self.assertRaises(JujuMachineNotFound):
2015 machine, series = self.libjuju._get_machine_info(
2016 machine_id=machine_id,
2017 model=model,
2018 )
2019 self.assertIsNone(machine, series)
2020
2021
2022class GetUnitTest(LibjujuTestCase):
2023 def setUp(self):
2024 super(GetUnitTest, self).setUp()
2025
2026 def test_successful(self):
2027 result = self.libjuju._get_unit(FakeApplication(), "existing_machine_id")
2028 self.assertIsInstance(result, FakeUnit)
2029
2030 def test_return_none(self):
2031 result = self.libjuju._get_unit(FakeApplication(), "not_existing_machine_id")
2032 self.assertIsNone(result)
2033
2034
2035@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2036@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2037@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2038@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2039@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2040class CheckApplicationExists(LibjujuTestCase):
2041 def setUp(self):
2042 super(CheckApplicationExists, self).setUp()
2043
2044 def test_successful(
2045 self,
2046 mock_get_application,
2047 mock_disconnect_controller,
2048 mock_disconnect_model,
2049 mock_get_model,
2050 mock_get_controller,
2051 ):
2052 mock_get_model.return_value = juju.model.Model()
2053 mock_get_application.return_value = FakeApplication()
2054 result = self.loop.run_until_complete(
2055 self.libjuju.check_application_exists(
2056 "model",
2057 "app",
2058 )
2059 )
2060 self.assertEqual(result, True)
2061
2062 mock_get_application.assert_called_once()
2063 mock_get_controller.assert_called_once()
2064 mock_get_model.assert_called_once()
2065 mock_disconnect_controller.assert_called_once()
2066 mock_disconnect_model.assert_called_once()
2067
2068 def test_no_application(
2069 self,
2070 mock_get_application,
2071 mock_disconnect_controller,
2072 mock_disconnect_model,
2073 mock_get_model,
2074 mock_get_controller,
2075 ):
2076 mock_get_model.return_value = juju.model.Model()
2077 mock_get_application.return_value = None
2078 result = self.loop.run_until_complete(
2079 self.libjuju.check_application_exists(
2080 "model",
2081 "app",
2082 )
2083 )
2084 self.assertEqual(result, False)
2085
2086 mock_get_application.assert_called_once()
2087 mock_get_controller.assert_called_once()
2088 mock_get_model.assert_called_once()
2089 mock_disconnect_controller.assert_called_once()
2090 mock_disconnect_model.assert_called_once()
2091
2092
2093@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2094@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2095@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2096@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2097@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2098@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_machine_info")
2099class AddUnitTest(LibjujuTestCase):
2100 def setUp(self):
2101 super(AddUnitTest, self).setUp()
2102
2103 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
2104 @asynctest.mock.patch("asyncio.sleep")
2105 def test_successful(
2106 self,
2107 mock_sleep,
2108 mock_wait_for,
2109 mock_get_machine_info,
2110 mock_get_application,
2111 mock_disconnect_controller,
2112 mock_disconnect_model,
2113 mock_get_model,
2114 mock_get_controller,
2115 ):
2116 mock_get_model.return_value = juju.model.Model()
2117 mock_get_application.return_value = FakeApplication()
2118 mock_get_machine_info.return_value = FakeMachine(), "series"
2119 self.loop.run_until_complete(
2120 self.libjuju.add_unit(
2121 "existing_app",
2122 "model",
2123 "machine",
2124 )
2125 )
2126
2127 mock_wait_for.assert_called_once()
2128 mock_get_application.assert_called_once()
2129 mock_get_controller.assert_called_once()
2130 mock_get_model.assert_called_once()
2131 mock_disconnect_controller.assert_called_once()
2132 mock_disconnect_model.assert_called_once()
2133
2134 def test_no_app(
2135 self,
2136 mock_get_machine_info,
2137 mock_get_application,
2138 mock_disconnect_controller,
2139 mock_disconnect_model,
2140 mock_get_model,
2141 mock_get_controller,
2142 ):
2143 mock_get_model.return_value = juju.model.Model()
2144 mock_get_application.return_value = None
2145 with self.assertRaises(JujuApplicationNotFound):
2146 self.loop.run_until_complete(
2147 self.libjuju.add_unit(
2148 "existing_app",
2149 "model",
2150 "machine",
2151 )
2152 )
2153
2154 mock_get_application.assert_called_once()
2155 mock_get_controller.assert_called_once()
2156 mock_get_model.assert_called_once()
2157 mock_disconnect_controller.assert_called_once()
2158 mock_disconnect_model.assert_called_once()
2159
2160 def test_no_machine(
2161 self,
2162 mock_get_machine_info,
2163 mock_get_application,
2164 mock_disconnect_controller,
2165 mock_disconnect_model,
2166 mock_get_model,
2167 mock_get_controller,
2168 ):
2169 mock_get_model.return_value = juju.model.Model()
2170 mock_get_application.return_value = FakeApplication()
2171 mock_get_machine_info.side_effect = JujuMachineNotFound()
2172 with self.assertRaises(JujuMachineNotFound):
2173 self.loop.run_until_complete(
2174 self.libjuju.add_unit(
2175 "existing_app",
2176 "model",
2177 "machine",
2178 )
2179 )
2180
2181 mock_get_application.assert_called_once()
2182 mock_get_controller.assert_called_once()
2183 mock_get_model.assert_called_once()
2184 mock_disconnect_controller.assert_called_once()
2185 mock_disconnect_model.assert_called_once()
2186
2187
2188@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2189@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2190@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2191@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2192@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2193@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_unit")
2194class DestroyUnitTest(LibjujuTestCase):
2195 def setUp(self):
2196 super(DestroyUnitTest, self).setUp()
2197
2198 @asynctest.mock.patch("asyncio.sleep")
2199 def test_successful(
2200 self,
2201 mock_sleep,
2202 mock_get_unit,
2203 mock_get_application,
2204 mock_disconnect_controller,
2205 mock_disconnect_model,
2206 mock_get_model,
2207 mock_get_controller,
2208 ):
2209 mock_get_model.return_value = juju.model.Model()
2210 mock_get_application.return_value = FakeApplication()
2211
2212 self.loop.run_until_complete(
2213 self.libjuju.destroy_unit("app", "model", "machine", 0)
2214 )
2215
2216 mock_get_unit.assert_called()
2217 mock_get_application.assert_called_once()
2218 mock_get_controller.assert_called_once()
2219 mock_get_model.assert_called_once()
2220 mock_disconnect_controller.assert_called_once()
2221 mock_disconnect_model.assert_called_once()
2222
2223 def test_no_app(
2224 self,
2225 mock_get_unit,
2226 mock_get_application,
2227 mock_disconnect_controller,
2228 mock_disconnect_model,
2229 mock_get_model,
2230 mock_get_controller,
2231 ):
2232 mock_get_model.return_value = juju.model.Model()
2233 mock_get_application.return_value = None
2234
2235 with self.assertRaises(JujuApplicationNotFound):
2236 self.loop.run_until_complete(
2237 self.libjuju.destroy_unit("app", "model", "machine")
2238 )
2239
2240 mock_get_application.assert_called_once()
2241 mock_get_controller.assert_called_once()
2242 mock_get_model.assert_called_once()
2243 mock_disconnect_controller.assert_called_once()
2244 mock_disconnect_model.assert_called_once()
2245
2246 def test_no_unit(
2247 self,
2248 mock_get_unit,
2249 mock_get_application,
2250 mock_disconnect_controller,
2251 mock_disconnect_model,
2252 mock_get_model,
2253 mock_get_controller,
2254 ):
2255 mock_get_model.return_value = juju.model.Model()
2256 mock_get_application.return_value = FakeApplication()
2257 mock_get_unit.return_value = None
2258
2259 with self.assertRaises(JujuError):
2260 self.loop.run_until_complete(
2261 self.libjuju.destroy_unit("app", "model", "machine")
2262 )
2263
2264 mock_get_unit.assert_called_once()
2265 mock_get_application.assert_called_once()
2266 mock_get_controller.assert_called_once()
2267 mock_get_model.assert_called_once()
2268 mock_disconnect_controller.assert_called_once()
2269 mock_disconnect_model.assert_called_once()