blob: 3de4aee43e06ece9210a21e1832157670bfca29f [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
David Garcia582b9232021-10-26 12:30:44 +020023
24from n2vc.definitions import Offer, RelationEndpoint
aktasfa02f8a2021-07-29 17:41:40 +030025from .utils import (
26 FakeApplication,
27 FakeMachine,
28 FakeManualMachine,
29 FakeUnit,
30)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020031from n2vc.libjuju import Libjuju
32from n2vc.exceptions import (
33 JujuControllerFailedConnecting,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020034 JujuMachineNotFound,
35 JujuApplicationNotFound,
36 JujuActionNotFound,
37 JujuApplicationExists,
David Garcia475a7222020-09-21 16:19:15 +020038 JujuInvalidK8sConfiguration,
David Garcia59f520d2020-10-15 13:16:45 +020039 JujuLeaderUnitNotFound,
ksaikiranrb84e4a72021-03-17 12:53:20 +053040 JujuError,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020041)
David Garciaf6e9b002020-11-27 15:32:02 +010042from n2vc.k8s_juju_conn import generate_rbac_id
David Garciaeb8943a2021-04-12 12:07:37 +020043from n2vc.tests.unit.utils import AsyncMock
44from n2vc.vca.connection import Connection
45from n2vc.vca.connection_data import ConnectionData
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020046
47
David Garciaeb8943a2021-04-12 12:07:37 +020048cacert = """-----BEGIN CERTIFICATE-----
49SOMECERT
50-----END CERTIFICATE-----"""
51
52
53@asynctest.mock.patch("n2vc.libjuju.Controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020054class LibjujuTestCase(asynctest.TestCase):
David Garciaeb8943a2021-04-12 12:07:37 +020055 @asynctest.mock.patch("n2vc.vca.connection_data.base64_to_cacert")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020056 def setUp(
57 self,
David Garciaeb8943a2021-04-12 12:07:37 +020058 mock_base64_to_cacert=None,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020059 ):
David Garciaeb8943a2021-04-12 12:07:37 +020060 self.loop = asyncio.get_event_loop()
61 self.db = Mock()
62 mock_base64_to_cacert.return_value = cacert
David Garcia553d1b72022-06-21 11:26:57 +020063 # Connection._load_vca_connection_data = Mock()
David Garciaeb8943a2021-04-12 12:07:37 +020064 vca_connection = Connection(AsyncMock())
65 vca_connection._data = ConnectionData(
66 **{
67 "endpoints": ["1.2.3.4:17070"],
68 "user": "user",
69 "secret": "secret",
70 "cacert": "cacert",
71 "pubkey": "pubkey",
72 "lxd-cloud": "cloud",
73 "lxd-credentials": "credentials",
74 "k8s-cloud": "k8s_cloud",
75 "k8s-credentials": "k8s_credentials",
76 "model-config": {},
77 "api-proxy": "api_proxy",
78 }
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020079 )
80 logging.disable(logging.CRITICAL)
David Garciaeb8943a2021-04-12 12:07:37 +020081 self.libjuju = Libjuju(vca_connection, self.loop)
82 self.loop.run_until_complete(self.libjuju.disconnect())
David Garciaa4f57d62020-10-22 10:50:56 +020083
84
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020085@asynctest.mock.patch("juju.controller.Controller.connect")
86@asynctest.mock.patch(
87 "juju.controller.Controller.api_endpoints",
88 new_callable=asynctest.CoroutineMock(return_value=["127.0.0.1:17070"]),
89)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020090class GetControllerTest(LibjujuTestCase):
91 def setUp(self):
92 super(GetControllerTest, self).setUp()
93
David Garciaeb8943a2021-04-12 12:07:37 +020094 def test_diff_endpoint(self, mock_api_endpoints, mock_connect):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020095 self.libjuju.endpoints = []
96 controller = self.loop.run_until_complete(self.libjuju.get_controller())
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +020097 self.assertIsInstance(controller, juju.controller.Controller)
98
99 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
100 def test_exception(
101 self,
102 mock_disconnect_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200103 mock_api_endpoints,
104 mock_connect,
105 ):
106 self.libjuju.endpoints = []
David Garciaeb8943a2021-04-12 12:07:37 +0200107
108 mock_connect.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200109 controller = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200110 with self.assertRaises(JujuControllerFailedConnecting):
111 controller = self.loop.run_until_complete(self.libjuju.get_controller())
David Garcia12b29242020-09-17 16:01:48 +0200112 self.assertIsNone(controller)
David Garcia4ae527e2021-07-26 16:04:59 +0200113 mock_disconnect_controller.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200114
David Garciaeb8943a2021-04-12 12:07:37 +0200115 def test_same_endpoint_get_controller(self, mock_api_endpoints, mock_connect):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200116 self.libjuju.endpoints = ["127.0.0.1:17070"]
117 controller = self.loop.run_until_complete(self.libjuju.get_controller())
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200118 self.assertIsInstance(controller, juju.controller.Controller)
119
120
121class DisconnectTest(LibjujuTestCase):
122 def setUp(self):
123 super(DisconnectTest, self).setUp()
124
125 @asynctest.mock.patch("juju.model.Model.disconnect")
126 def test_disconnect_model(self, mock_disconnect):
127 self.loop.run_until_complete(self.libjuju.disconnect_model(juju.model.Model()))
128 mock_disconnect.assert_called_once()
129
130 @asynctest.mock.patch("juju.controller.Controller.disconnect")
131 def test_disconnect_controller(self, mock_disconnect):
132 self.loop.run_until_complete(
133 self.libjuju.disconnect_controller(juju.controller.Controller())
134 )
135 mock_disconnect.assert_called_once()
136
137
138@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
139@asynctest.mock.patch("n2vc.libjuju.Libjuju.model_exists")
140@asynctest.mock.patch("juju.controller.Controller.add_model")
141@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
142@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
143class AddModelTest(LibjujuTestCase):
144 def setUp(self):
145 super(AddModelTest, self).setUp()
146
147 def test_existing_model(
148 self,
149 mock_disconnect_model,
150 mock_disconnect_controller,
151 mock_add_model,
152 mock_model_exists,
153 mock_get_controller,
154 ):
155 mock_model_exists.return_value = True
156
David Garciab0a8f402021-03-15 18:41:34 +0100157 # This should not raise an exception
David Garciaeb8943a2021-04-12 12:07:37 +0200158 self.loop.run_until_complete(self.libjuju.add_model("existing_model", "cloud"))
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200159
David Garcia12b29242020-09-17 16:01:48 +0200160 mock_disconnect_controller.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200161
162 # TODO Check two job executing at the same time and one returning without doing anything.
163
164 def test_non_existing_model(
165 self,
166 mock_disconnect_model,
167 mock_disconnect_controller,
168 mock_add_model,
169 mock_model_exists,
170 mock_get_controller,
171 ):
172 mock_model_exists.return_value = False
173 mock_get_controller.return_value = juju.controller.Controller()
174
175 self.loop.run_until_complete(
David Garciaeb8943a2021-04-12 12:07:37 +0200176 self.libjuju.add_model("nonexisting_model", Mock())
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200177 )
178
179 mock_add_model.assert_called_once()
180 mock_disconnect_controller.assert_called()
181 mock_disconnect_model.assert_called()
182
183
ksaikiranrb84e4a72021-03-17 12:53:20 +0530184@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
185@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
186@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
187@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
188@asynctest.mock.patch(
189 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
190)
191@asynctest.mock.patch("juju.model.Model.get_action_status")
192@asynctest.mock.patch("juju.model.Model.get_action_output")
193@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_actions")
194class GetExecutedActionsTest(LibjujuTestCase):
195 def setUp(self):
196 super(GetExecutedActionsTest, self).setUp()
197
198 def test_exception(
199 self,
200 mock_get_actions,
201 mock_get_action_output,
202 mock_get_action_status,
203 mock_applications,
204 mock_disconnect_controller,
205 mock_disconnect_model,
206 mock_get_model,
207 mock_get_controller,
208 ):
209 mock_get_model.return_value = None
210 with self.assertRaises(JujuError):
211 self.loop.run_until_complete(self.libjuju.get_executed_actions("model"))
212
213 mock_get_controller.assert_called_once()
214 mock_disconnect_controller.assert_called_once()
215 mock_get_model.assert_called_once()
216 mock_disconnect_model.assert_not_called()
217
218 def test_success(
219 self,
220 mock_get_actions,
221 mock_get_action_output,
222 mock_get_action_status,
223 mock_applications,
224 mock_disconnect_controller,
225 mock_disconnect_model,
226 mock_get_model,
227 mock_get_controller,
228 ):
229 mock_get_model.return_value = juju.model.Model()
230 mock_applications.return_value = {"existing_app"}
231 mock_get_actions.return_value = {"action_name": "description"}
232 mock_get_action_status.return_value = {"id": "status"}
233 mock_get_action_output.return_value = {"output": "completed"}
234
235 executed_actions = self.loop.run_until_complete(
236 self.libjuju.get_executed_actions("model")
237 )
garciadeblas82b591c2021-03-24 09:22:13 +0100238 expected_result = [
239 {
240 "id": "id",
241 "action": "action_name",
242 "status": "status",
243 "output": "completed",
244 }
245 ]
ksaikiranrb84e4a72021-03-17 12:53:20 +0530246 self.assertListEqual(expected_result, executed_actions)
247 self.assertIsInstance(executed_actions, list)
248
249 mock_get_controller.assert_called_once()
250 mock_get_model.assert_called_once()
251 mock_disconnect_controller.assert_called_once()
252 mock_disconnect_model.assert_called_once()
253
254
255@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
256@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
257@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
258@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
259@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
260class GetApplicationConfigsTest(LibjujuTestCase):
261 def setUp(self):
262 super(GetApplicationConfigsTest, self).setUp()
263
264 def test_exception(
265 self,
266 mock_get_application,
267 mock_disconnect_controller,
268 mock_disconnect_model,
269 mock_get_model,
270 mock_get_controller,
271 ):
272 mock_get_model.return_value = None
273 with self.assertRaises(JujuError):
274 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +0100275 self.libjuju.get_application_configs("model", "app")
276 )
ksaikiranrb84e4a72021-03-17 12:53:20 +0530277
278 mock_get_controller.assert_called_once()
279 mock_disconnect_controller.assert_called_once()
280 mock_get_model.assert_called_once()
281 mock_disconnect_model.assert_not_called()
282
283 def test_success(
284 self,
285 mock_get_application,
286 mock_disconnect_controller,
287 mock_disconnect_model,
288 mock_get_model,
289 mock_get_controller,
290 ):
291 mock_get_application.return_value = FakeApplication()
garciadeblas82b591c2021-03-24 09:22:13 +0100292 application_configs = self.loop.run_until_complete(
293 self.libjuju.get_application_configs("model", "app")
294 )
ksaikiranrb84e4a72021-03-17 12:53:20 +0530295
296 self.assertEqual(application_configs, ["app_config"])
297
298 mock_get_controller.assert_called_once()
299 mock_get_model.assert_called_once()
300 mock_disconnect_controller.assert_called_once()
301 mock_disconnect_model.assert_called_once()
302
303
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200304@asynctest.mock.patch("juju.controller.Controller.get_model")
305class GetModelTest(LibjujuTestCase):
306 def setUp(self):
307 super(GetModelTest, self).setUp()
308
309 def test_get_model(
David Garcia5b802c92020-11-11 16:56:06 +0100310 self,
311 mock_get_model,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200312 ):
313 mock_get_model.return_value = juju.model.Model()
314 model = self.loop.run_until_complete(
315 self.libjuju.get_model(juju.controller.Controller(), "model")
316 )
317 self.assertIsInstance(model, juju.model.Model)
318
319
320@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
321@asynctest.mock.patch("juju.controller.Controller.list_models")
322class ModelExistsTest(LibjujuTestCase):
323 def setUp(self):
324 super(ModelExistsTest, self).setUp()
325
326 async def test_existing_model(
David Garcia5b802c92020-11-11 16:56:06 +0100327 self,
328 mock_list_models,
329 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200330 ):
331 mock_list_models.return_value = ["existing_model"]
332 self.assertTrue(
333 await self.libjuju.model_exists(
334 "existing_model", juju.controller.Controller()
335 )
336 )
337
338 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
339 async def test_no_controller(
David Garcia5b802c92020-11-11 16:56:06 +0100340 self,
341 mock_disconnect_controller,
342 mock_list_models,
343 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200344 ):
345 mock_list_models.return_value = ["existing_model"]
346 mock_get_controller.return_value = juju.controller.Controller()
347 self.assertTrue(await self.libjuju.model_exists("existing_model"))
348 mock_disconnect_controller.assert_called_once()
349
350 async def test_non_existing_model(
David Garcia5b802c92020-11-11 16:56:06 +0100351 self,
352 mock_list_models,
353 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200354 ):
355 mock_list_models.return_value = ["existing_model"]
356 self.assertFalse(
357 await self.libjuju.model_exists(
358 "not_existing_model", juju.controller.Controller()
359 )
360 )
361
362
363@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
364@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
365@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
366@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
367@asynctest.mock.patch("juju.model.Model.get_status")
368class GetModelStatusTest(LibjujuTestCase):
369 def setUp(self):
370 super(GetModelStatusTest, self).setUp()
371
372 def test_success(
373 self,
374 mock_get_status,
375 mock_disconnect_controller,
376 mock_disconnect_model,
377 mock_get_model,
378 mock_get_controller,
379 ):
380 mock_get_model.return_value = juju.model.Model()
381 mock_get_status.return_value = {"status"}
382
383 status = self.loop.run_until_complete(self.libjuju.get_model_status("model"))
384
385 mock_get_status.assert_called_once()
386 mock_disconnect_controller.assert_called_once()
387 mock_disconnect_model.assert_called_once()
388
389 self.assertEqual(status, {"status"})
390
David Garcia12b29242020-09-17 16:01:48 +0200391 def test_exception(
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200392 self,
393 mock_get_status,
394 mock_disconnect_controller,
395 mock_disconnect_model,
396 mock_get_model,
397 mock_get_controller,
398 ):
399 mock_get_model.return_value = juju.model.Model()
400 mock_get_status.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200401 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200402 with self.assertRaises(Exception):
403 status = self.loop.run_until_complete(
404 self.libjuju.get_model_status("model")
405 )
406
David Garcia12b29242020-09-17 16:01:48 +0200407 mock_disconnect_controller.assert_called_once()
408 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200409
David Garcia12b29242020-09-17 16:01:48 +0200410 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200411
412
413@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
414@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
415@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
416@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
417@asynctest.mock.patch("juju.model.Model.get_machines")
418@asynctest.mock.patch("juju.model.Model.add_machine")
419@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
420class CreateMachineTest(LibjujuTestCase):
421 def setUp(self):
422 super(CreateMachineTest, self).setUp()
423
424 def test_existing_machine(
425 self,
426 mock_wait_for,
427 mock_add_machine,
428 mock_get_machines,
429 mock_disconnect_controller,
430 mock_disconnect_model,
431 mock_get_model,
432 mock_get_controller,
433 ):
434 mock_get_model.return_value = juju.model.Model()
435 mock_get_machines.return_value = {"existing_machine": FakeMachine()}
436 machine, bool_res = self.loop.run_until_complete(
437 self.libjuju.create_machine("model", "existing_machine")
438 )
439
440 self.assertIsInstance(machine, FakeMachine)
441 self.assertFalse(bool_res)
442
443 mock_disconnect_controller.assert_called()
444 mock_disconnect_model.assert_called()
445
446 def test_non_existing_machine(
447 self,
448 mock_wait_for,
449 mock_add_machine,
450 mock_get_machines,
451 mock_disconnect_controller,
452 mock_disconnect_model,
453 mock_get_model,
454 mock_get_controller,
455 ):
David Garcia12b29242020-09-17 16:01:48 +0200456 machine = None
457 bool_res = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200458 mock_get_model.return_value = juju.model.Model()
459 with self.assertRaises(JujuMachineNotFound):
460 machine, bool_res = self.loop.run_until_complete(
461 self.libjuju.create_machine("model", "non_existing_machine")
462 )
David Garcia12b29242020-09-17 16:01:48 +0200463 self.assertIsNone(machine)
464 self.assertIsNone(bool_res)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200465
David Garcia12b29242020-09-17 16:01:48 +0200466 mock_disconnect_controller.assert_called()
467 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200468
469 def test_no_machine(
470 self,
471 mock_wait_for,
472 mock_add_machine,
473 mock_get_machines,
474 mock_disconnect_controller,
475 mock_disconnect_model,
476 mock_get_model,
477 mock_get_controller,
478 ):
479 mock_get_model.return_value = juju.model.Model()
480 mock_add_machine.return_value = FakeMachine()
481
482 machine, bool_res = self.loop.run_until_complete(
483 self.libjuju.create_machine("model")
484 )
485
486 self.assertIsInstance(machine, FakeMachine)
487 self.assertTrue(bool_res)
488
489 mock_wait_for.assert_called_once()
490 mock_add_machine.assert_called_once()
491
492 mock_disconnect_controller.assert_called()
493 mock_disconnect_model.assert_called()
494
495
496# TODO test provision machine
497
498
499@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
500@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
501@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
502@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
David Garcia667696e2020-09-22 14:52:32 +0200503@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
504@asynctest.mock.patch("juju.model.Model.deploy")
505class DeployTest(LibjujuTestCase):
506 def setUp(self):
507 super(DeployTest, self).setUp()
508
509 def test_deploy(
510 self,
511 mock_deploy,
512 mock_wait_for_model,
513 mock_disconnect_controller,
514 mock_disconnect_model,
515 mock_get_model,
516 mock_get_controller,
517 ):
518 mock_get_model.return_value = juju.model.Model()
519 self.loop.run_until_complete(
520 self.libjuju.deploy("cs:osm", "model", wait=True, timeout=0)
521 )
522 mock_deploy.assert_called_once()
523 mock_wait_for_model.assert_called_once()
524 mock_disconnect_controller.assert_called_once()
525 mock_disconnect_model.assert_called_once()
526
527 def test_deploy_no_wait(
528 self,
529 mock_deploy,
530 mock_wait_for_model,
531 mock_disconnect_controller,
532 mock_disconnect_model,
533 mock_get_model,
534 mock_get_controller,
535 ):
536 mock_get_model.return_value = juju.model.Model()
537 self.loop.run_until_complete(
538 self.libjuju.deploy("cs:osm", "model", wait=False, timeout=0)
539 )
540 mock_deploy.assert_called_once()
541 mock_wait_for_model.assert_not_called()
542 mock_disconnect_controller.assert_called_once()
543 mock_disconnect_model.assert_called_once()
544
545 def test_deploy_exception(
546 self,
547 mock_deploy,
548 mock_wait_for_model,
549 mock_disconnect_controller,
550 mock_disconnect_model,
551 mock_get_model,
552 mock_get_controller,
553 ):
554 mock_deploy.side_effect = Exception()
555 mock_get_model.return_value = juju.model.Model()
556 with self.assertRaises(Exception):
557 self.loop.run_until_complete(self.libjuju.deploy("cs:osm", "model"))
558 mock_deploy.assert_called_once()
559 mock_wait_for_model.assert_not_called()
560 mock_disconnect_controller.assert_called_once()
561 mock_disconnect_model.assert_called_once()
562
563
564@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
565@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
566@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
567@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200568@asynctest.mock.patch(
569 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
570)
571@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
572@asynctest.mock.patch("juju.model.Model.deploy")
573@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
574@asynctest.mock.patch("n2vc.libjuju.Libjuju.create_machine")
575class DeployCharmTest(LibjujuTestCase):
576 def setUp(self):
577 super(DeployCharmTest, self).setUp()
578
579 def test_existing_app(
580 self,
581 mock_create_machine,
582 mock_wait_for,
583 mock_deploy,
584 mock_machines,
585 mock_applications,
586 mock_disconnect_controller,
587 mock_disconnect_model,
588 mock_get_model,
589 mock_get_controller,
590 ):
591 mock_get_model.return_value = juju.model.Model()
592 mock_applications.return_value = {"existing_app"}
593
David Garcia12b29242020-09-17 16:01:48 +0200594 application = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200595 with self.assertRaises(JujuApplicationExists):
596 application = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100597 self.libjuju.deploy_charm(
598 "existing_app",
599 "path",
600 "model",
601 "machine",
602 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200603 )
David Garcia12b29242020-09-17 16:01:48 +0200604 self.assertIsNone(application)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200605
David Garcia12b29242020-09-17 16:01:48 +0200606 mock_disconnect_controller.assert_called()
607 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200608
609 def test_non_existing_machine(
610 self,
611 mock_create_machine,
612 mock_wait_for,
613 mock_deploy,
614 mock_machines,
615 mock_applications,
616 mock_disconnect_controller,
617 mock_disconnect_model,
618 mock_get_model,
619 mock_get_controller,
620 ):
621 mock_get_model.return_value = juju.model.Model()
622 mock_machines.return_value = {"existing_machine": FakeMachine()}
David Garcia12b29242020-09-17 16:01:48 +0200623 application = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200624 with self.assertRaises(JujuMachineNotFound):
625 application = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100626 self.libjuju.deploy_charm(
627 "app",
628 "path",
629 "model",
630 "machine",
631 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200632 )
633
David Garcia12b29242020-09-17 16:01:48 +0200634 self.assertIsNone(application)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200635
David Garcia12b29242020-09-17 16:01:48 +0200636 mock_disconnect_controller.assert_called()
637 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200638
639 def test_2_units(
640 self,
641 mock_create_machine,
642 mock_wait_for,
643 mock_deploy,
644 mock_machines,
645 mock_applications,
646 mock_disconnect_controller,
647 mock_disconnect_model,
648 mock_get_model,
649 mock_get_controller,
650 ):
651 mock_get_model.return_value = juju.model.Model()
652 mock_machines.return_value = {"existing_machine": FakeMachine()}
653 mock_create_machine.return_value = (FakeMachine(), "other")
654 mock_deploy.return_value = FakeApplication()
655 application = self.loop.run_until_complete(
656 self.libjuju.deploy_charm(
David Garcia5b802c92020-11-11 16:56:06 +0100657 "app",
658 "path",
659 "model",
660 "existing_machine",
661 num_units=2,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200662 )
663 )
664
665 self.assertIsInstance(application, FakeApplication)
666
667 mock_deploy.assert_called_once()
668 mock_wait_for.assert_called_once()
669
670 mock_create_machine.assert_called_once()
671
672 mock_disconnect_controller.assert_called()
673 mock_disconnect_model.assert_called()
674
675 def test_1_unit(
676 self,
677 mock_create_machine,
678 mock_wait_for,
679 mock_deploy,
680 mock_machines,
681 mock_applications,
682 mock_disconnect_controller,
683 mock_disconnect_model,
684 mock_get_model,
685 mock_get_controller,
686 ):
687 mock_get_model.return_value = juju.model.Model()
688 mock_machines.return_value = {"existing_machine": FakeMachine()}
689 mock_deploy.return_value = FakeApplication()
690 application = self.loop.run_until_complete(
691 self.libjuju.deploy_charm("app", "path", "model", "existing_machine")
692 )
693
694 self.assertIsInstance(application, FakeApplication)
695
696 mock_deploy.assert_called_once()
697 mock_wait_for.assert_called_once()
698
699 mock_disconnect_controller.assert_called()
700 mock_disconnect_model.assert_called()
701
702
703@asynctest.mock.patch(
704 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
705)
706class GetApplicationTest(LibjujuTestCase):
707 def setUp(self):
708 super(GetApplicationTest, self).setUp()
709
710 def test_existing_application(
David Garcia5b802c92020-11-11 16:56:06 +0100711 self,
712 mock_applications,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200713 ):
714 mock_applications.return_value = {"existing_app": "exists"}
715 model = juju.model.Model()
716 result = self.libjuju._get_application(model, "existing_app")
717 self.assertEqual(result, "exists")
718
719 def test_non_existing_application(
David Garcia5b802c92020-11-11 16:56:06 +0100720 self,
721 mock_applications,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200722 ):
723 mock_applications.return_value = {"existing_app": "exists"}
724 model = juju.model.Model()
725 result = self.libjuju._get_application(model, "nonexisting_app")
726 self.assertIsNone(result)
727
728
729@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
730@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
731@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
732@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
733@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
734@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
735@asynctest.mock.patch("juju.model.Model.get_action_output")
736@asynctest.mock.patch("juju.model.Model.get_action_status")
737class ExecuteActionTest(LibjujuTestCase):
738 def setUp(self):
739 super(ExecuteActionTest, self).setUp()
740
741 def test_no_application(
742 self,
743 mock_get_action_status,
744 mock_get_action_output,
745 mock_wait_for,
746 mock__get_application,
747 mock_disconnect_controller,
748 mock_disconnect_model,
749 mock_get_model,
750 mock_get_controller,
751 ):
752 mock__get_application.return_value = None
753 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +0200754 output = None
755 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200756 with self.assertRaises(JujuApplicationNotFound):
757 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100758 self.libjuju.execute_action(
759 "app",
760 "model",
761 "action",
762 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200763 )
David Garcia12b29242020-09-17 16:01:48 +0200764 self.assertIsNone(output)
765 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200766
David Garcia12b29242020-09-17 16:01:48 +0200767 mock_disconnect_controller.assert_called()
768 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200769
770 def test_no_action(
771 self,
772 mock_get_action_status,
773 mock_get_action_output,
774 mock_wait_for,
775 mock__get_application,
776 mock_disconnect_controller,
777 mock_disconnect_model,
778 mock_get_model,
779 mock_get_controller,
780 ):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200781 mock_get_model.return_value = juju.model.Model()
782 mock__get_application.return_value = FakeApplication()
David Garcia12b29242020-09-17 16:01:48 +0200783 output = None
784 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200785 with self.assertRaises(JujuActionNotFound):
786 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100787 self.libjuju.execute_action(
788 "app",
789 "model",
790 "action",
791 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200792 )
David Garcia12b29242020-09-17 16:01:48 +0200793 self.assertIsNone(output)
794 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200795
David Garcia12b29242020-09-17 16:01:48 +0200796 mock_disconnect_controller.assert_called()
797 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200798
David Garcia59f520d2020-10-15 13:16:45 +0200799 @asynctest.mock.patch("asyncio.sleep")
800 @asynctest.mock.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
801 def test_no_leader(
802 self,
803 mock_is_leader_from_status,
804 mock_sleep,
805 mock_get_action_status,
806 mock_get_action_output,
807 mock_wait_for,
808 mock__get_application,
809 mock_disconnect_controller,
810 mock_disconnect_model,
811 mock_get_model,
812 mock_get_controller,
813 ):
814 mock_get_model.return_value = juju.model.Model()
815 mock__get_application.return_value = FakeApplication()
816 mock_is_leader_from_status.return_value = False
817 output = None
818 status = None
819 with self.assertRaises(JujuLeaderUnitNotFound):
820 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100821 self.libjuju.execute_action(
822 "app",
823 "model",
824 "action",
825 )
David Garcia59f520d2020-10-15 13:16:45 +0200826 )
827 self.assertIsNone(output)
828 self.assertIsNone(status)
829
830 mock_disconnect_controller.assert_called()
831 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200832
aktasfa02f8a2021-07-29 17:41:40 +0300833 def test_successful_exec(
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200834 self,
835 mock_get_action_status,
836 mock_get_action_output,
837 mock_wait_for,
838 mock__get_application,
839 mock_disconnect_controller,
840 mock_disconnect_model,
841 mock_get_model,
842 mock_get_controller,
843 ):
844 mock_get_model.return_value = juju.model.Model()
845 mock__get_application.return_value = FakeApplication()
846 mock_get_action_output.return_value = "output"
847 mock_get_action_status.return_value = {"id": "status"}
848 output, status = self.loop.run_until_complete(
849 self.libjuju.execute_action("app", "model", "existing_action")
850 )
851 self.assertEqual(output, "output")
852 self.assertEqual(status, "status")
853
854 mock_wait_for.assert_called_once()
855
856 mock_disconnect_controller.assert_called()
857 mock_disconnect_model.assert_called()
858
859
860@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
861@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
862@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
863@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
864@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
865class GetActionTest(LibjujuTestCase):
866 def setUp(self):
867 super(GetActionTest, self).setUp()
868
869 def test_exception(
870 self,
871 mock_get_application,
872 mock_disconnect_controller,
873 mock_disconnect_model,
874 mock_get_model,
875 mock_get_controller,
876 ):
877 mock_get_application.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200878 actions = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200879 with self.assertRaises(Exception):
880 actions = self.loop.run_until_complete(
881 self.libjuju.get_actions("app", "model")
882 )
883
David Garcia12b29242020-09-17 16:01:48 +0200884 self.assertIsNone(actions)
885 mock_disconnect_controller.assert_called_once()
886 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200887
888 def test_success(
889 self,
890 mock_get_application,
891 mock_disconnect_controller,
892 mock_disconnect_model,
893 mock_get_model,
894 mock_get_controller,
895 ):
896 mock_get_application.return_value = FakeApplication()
897
898 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
899
900 self.assertEqual(actions, ["existing_action"])
901
902 mock_get_controller.assert_called_once()
903 mock_get_model.assert_called_once()
904 mock_disconnect_controller.assert_called_once()
905 mock_disconnect_model.assert_called_once()
906
907
908@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
909@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
910@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
911@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
David Garcia85755d12020-09-21 19:51:23 +0200912@asynctest.mock.patch("juju.application.Application.get_metrics")
913@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
914class GetMetricsTest(LibjujuTestCase):
915 def setUp(self):
916 super(GetMetricsTest, self).setUp()
917
918 def test_get_metrics_success(
919 self,
920 mock_get_application,
921 mock_get_metrics,
922 mock_disconnect_controller,
923 mock_disconnect_model,
924 mock_get_model,
925 mock_get_controller,
926 ):
927 mock_get_application.return_value = FakeApplication()
928 mock_get_model.return_value = juju.model.Model()
929
930 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
931
932 mock_disconnect_controller.assert_called_once()
933 mock_disconnect_model.assert_called_once()
934
935 def test_get_metrics_exception(
936 self,
937 mock_get_application,
938 mock_get_metrics,
939 mock_disconnect_controller,
940 mock_disconnect_model,
941 mock_get_model,
942 mock_get_controller,
943 ):
944 mock_get_model.return_value = juju.model.Model()
945 mock_get_metrics.side_effect = Exception()
946 with self.assertRaises(Exception):
947 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
948
949 mock_disconnect_controller.assert_called_once()
950 mock_disconnect_model.assert_called_once()
951
952 def test_missing_args_exception(
953 self,
954 mock_get_application,
955 mock_get_metrics,
956 mock_disconnect_controller,
957 mock_disconnect_model,
958 mock_get_model,
959 mock_get_controller,
960 ):
961 mock_get_model.return_value = juju.model.Model()
962
963 with self.assertRaises(Exception):
964 self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
965
966 mock_get_controller.assert_not_called()
967 mock_get_model.assert_not_called()
968 mock_disconnect_controller.assert_not_called()
969 mock_disconnect_model.assert_not_called()
970
971
972@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
973@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
974@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
975@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200976@asynctest.mock.patch("juju.model.Model.add_relation")
977class AddRelationTest(LibjujuTestCase):
978 def setUp(self):
979 super(AddRelationTest, self).setUp()
980
981 @asynctest.mock.patch("logging.Logger.warning")
982 def test_not_found(
983 self,
984 mock_warning,
985 mock_add_relation,
986 mock_disconnect_controller,
987 mock_disconnect_model,
988 mock_get_model,
989 mock_get_controller,
990 ):
991 # TODO in libjuju.py should this fail only with a log message?
992 result = {"error": "not found", "response": "response", "request-id": 1}
993
994 mock_get_model.return_value = juju.model.Model()
995 mock_add_relation.side_effect = JujuAPIError(result)
996
997 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100998 self.libjuju.add_relation(
999 "model",
1000 "app1:relation1",
1001 "app2:relation2",
1002 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001003 )
1004
1005 mock_warning.assert_called_with("Relation not found: not found")
1006 mock_disconnect_controller.assert_called_once()
1007 mock_disconnect_model.assert_called_once()
1008
1009 @asynctest.mock.patch("logging.Logger.warning")
Patricia Reinosoa07f6952023-01-04 10:40:10 +00001010 def test_not_found_in_error_code(
1011 self,
1012 mock_warning,
1013 mock_add_relation,
1014 mock_disconnect_controller,
1015 mock_disconnect_model,
1016 mock_get_model,
1017 mock_get_controller,
1018 ):
1019 result = {
1020 "error": "relation cannot be added",
1021 "error-code": "not found",
1022 "response": "response",
1023 "request-id": 1,
1024 }
1025
1026 mock_get_model.return_value = juju.model.Model()
1027 mock_add_relation.side_effect = JujuAPIError(result)
1028
1029 self.loop.run_until_complete(
1030 self.libjuju.add_relation(
1031 "model",
1032 "app1:relation1",
1033 "app2:relation2",
1034 )
1035 )
1036
1037 mock_warning.assert_called_with("Relation not found: relation cannot be added")
1038 mock_disconnect_controller.assert_called_once()
1039 mock_disconnect_model.assert_called_once()
1040
1041 @asynctest.mock.patch("logging.Logger.warning")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001042 def test_already_exists(
1043 self,
1044 mock_warning,
1045 mock_add_relation,
1046 mock_disconnect_controller,
1047 mock_disconnect_model,
1048 mock_get_model,
1049 mock_get_controller,
1050 ):
1051 # TODO in libjuju.py should this fail silently?
1052 result = {"error": "already exists", "response": "response", "request-id": 1}
1053
1054 mock_get_model.return_value = juju.model.Model()
1055 mock_add_relation.side_effect = JujuAPIError(result)
1056
1057 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001058 self.libjuju.add_relation(
1059 "model",
1060 "app1:relation1",
1061 "app2:relation2",
1062 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001063 )
1064
1065 mock_warning.assert_called_with("Relation already exists: already exists")
1066 mock_disconnect_controller.assert_called_once()
1067 mock_disconnect_model.assert_called_once()
1068
Patricia Reinosoa07f6952023-01-04 10:40:10 +00001069 @asynctest.mock.patch("logging.Logger.warning")
1070 def test_already_exists_error_code(
1071 self,
1072 mock_warning,
1073 mock_add_relation,
1074 mock_disconnect_controller,
1075 mock_disconnect_model,
1076 mock_get_model,
1077 mock_get_controller,
1078 ):
1079 result = {
1080 "error": "relation cannot be added",
1081 "error-code": "already exists",
1082 "response": "response",
1083 "request-id": 1,
1084 }
1085
1086 mock_get_model.return_value = juju.model.Model()
1087 mock_add_relation.side_effect = JujuAPIError(result)
1088
1089 self.loop.run_until_complete(
1090 self.libjuju.add_relation(
1091 "model",
1092 "app1:relation1",
1093 "app2:relation2",
1094 )
1095 )
1096
1097 mock_warning.assert_called_with(
1098 "Relation already exists: relation cannot be added"
1099 )
1100 mock_disconnect_controller.assert_called_once()
1101 mock_disconnect_model.assert_called_once()
1102
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001103 def test_exception(
1104 self,
1105 mock_add_relation,
1106 mock_disconnect_controller,
1107 mock_disconnect_model,
1108 mock_get_model,
1109 mock_get_controller,
1110 ):
1111 mock_get_model.return_value = juju.model.Model()
1112 result = {"error": "", "response": "response", "request-id": 1}
1113 mock_add_relation.side_effect = JujuAPIError(result)
1114
1115 with self.assertRaises(JujuAPIError):
1116 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001117 self.libjuju.add_relation(
1118 "model",
1119 "app1:relation1",
1120 "app2:relation2",
1121 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001122 )
1123
David Garcia12b29242020-09-17 16:01:48 +02001124 mock_disconnect_controller.assert_called_once()
1125 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001126
1127 def test_success(
1128 self,
1129 mock_add_relation,
1130 mock_disconnect_controller,
1131 mock_disconnect_model,
1132 mock_get_model,
1133 mock_get_controller,
1134 ):
1135 mock_get_model.return_value = juju.model.Model()
1136
1137 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001138 self.libjuju.add_relation(
1139 "model",
1140 "app1:relation1",
1141 "app2:relation2",
1142 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001143 )
1144
David Garcia12b29242020-09-17 16:01:48 +02001145 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
David Garcia8331f7c2020-08-25 16:10:07 +02001146 mock_disconnect_controller.assert_called_once()
1147 mock_disconnect_model.assert_called_once()
1148
1149 def test_saas(
1150 self,
1151 mock_add_relation,
1152 mock_disconnect_controller,
1153 mock_disconnect_model,
1154 mock_get_model,
1155 mock_get_controller,
1156 ):
1157 mock_get_model.return_value = juju.model.Model()
1158
1159 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001160 self.libjuju.add_relation(
1161 "model",
1162 "app1:relation1",
1163 "saas_name",
1164 )
David Garcia8331f7c2020-08-25 16:10:07 +02001165 )
1166
David Garcia12b29242020-09-17 16:01:48 +02001167 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001168 mock_disconnect_controller.assert_called_once()
1169 mock_disconnect_model.assert_called_once()
1170
1171
1172# TODO destroy_model testcase
1173
1174
aktas56120292021-02-26 15:32:39 +03001175@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1176@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1177@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1178@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1179@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1180class DestroyApplicationTest(LibjujuTestCase):
1181 def setUp(self):
1182 super(DestroyApplicationTest, self).setUp()
1183
1184 def test_success(
garciadeblas82b591c2021-03-24 09:22:13 +01001185 self,
1186 mock_get_controller,
1187 mock_get_model,
1188 mock_disconnect_controller,
1189 mock_get_application,
1190 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001191 ):
1192 mock_get_application.return_value = FakeApplication()
1193 mock_get_model.return_value = None
1194 self.loop.run_until_complete(
1195 self.libjuju.destroy_application(
1196 "existing_model",
1197 "existing_app",
1198 3600,
1199 )
1200 )
1201 mock_get_application.assert_called()
1202 mock_disconnect_controller.assert_called_once()
1203 mock_disconnect_model.assert_called_once()
1204
1205 def test_no_application(
garciadeblas82b591c2021-03-24 09:22:13 +01001206 self,
1207 mock_get_controller,
1208 mock_get_model,
1209 mock_disconnect_controller,
1210 mock_get_application,
1211 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001212 ):
1213 mock_get_model.return_value = None
1214 mock_get_application.return_value = None
1215
1216 self.loop.run_until_complete(
1217 self.libjuju.destroy_application(
1218 "existing_model",
1219 "existing_app",
1220 3600,
1221 )
1222 )
1223 mock_get_application.assert_called()
1224
1225 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01001226 self,
1227 mock_get_controller,
1228 mock_get_model,
1229 mock_disconnect_controller,
1230 mock_get_application,
1231 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001232 ):
1233 mock_get_application.return_value = FakeApplication
1234 mock_get_model.return_value = None
1235
1236 with self.assertRaises(Exception):
1237 self.loop.run_until_complete(
1238 self.libjuju.destroy_application(
1239 "existing_model",
1240 "existing_app",
1241 0,
1242 )
1243 )
1244 mock_get_application.assert_called_once()
1245
1246
David Garcia5ef42a12020-09-29 19:48:13 +02001247# @asynctest.mock.patch("juju.model.Model.get_machines")
1248# @asynctest.mock.patch("logging.Logger.debug")
1249# class DestroyMachineTest(LibjujuTestCase):
1250# def setUp(self):
1251# super(DestroyMachineTest, self).setUp()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001252
David Garcia5ef42a12020-09-29 19:48:13 +02001253# def test_success_manual_machine(
1254# self, mock_debug, mock_get_machines,
1255# ):
1256# mock_get_machines.side_effect = [
1257# {"machine": FakeManualMachine()},
1258# {"machine": FakeManualMachine()},
1259# {},
1260# ]
1261# self.loop.run_until_complete(
1262# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
1263# )
1264# calls = [
1265# asynctest.call("Waiting for machine machine is destroyed"),
1266# asynctest.call("Machine destroyed: machine"),
1267# ]
1268# mock_debug.assert_has_calls(calls)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001269
David Garcia5ef42a12020-09-29 19:48:13 +02001270# def test_no_machine(
1271# self, mock_debug, mock_get_machines,
1272# ):
1273# mock_get_machines.return_value = {}
1274# self.loop.run_until_complete(
1275# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
1276# )
1277# mock_debug.assert_called_with("Machine not found: machine")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001278
1279
1280@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1281@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1282@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1283@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1284@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1285class ConfigureApplicationTest(LibjujuTestCase):
1286 def setUp(self):
1287 super(ConfigureApplicationTest, self).setUp()
1288
1289 def test_success(
1290 self,
1291 mock_get_application,
1292 mock_disconnect_controller,
1293 mock_disconnect_model,
1294 mock_get_model,
1295 mock_get_controller,
1296 ):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001297 mock_get_application.return_value = FakeApplication()
1298
1299 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001300 self.libjuju.configure_application(
1301 "model",
1302 "app",
1303 {"config"},
1304 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001305 )
1306 mock_get_application.assert_called_once()
1307 mock_disconnect_controller.assert_called_once()
1308 mock_disconnect_model.assert_called_once()
1309
1310 def test_exception(
1311 self,
1312 mock_get_application,
1313 mock_disconnect_controller,
1314 mock_disconnect_model,
1315 mock_get_model,
1316 mock_get_controller,
1317 ):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001318 mock_get_application.side_effect = Exception()
1319
1320 with self.assertRaises(Exception):
1321 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001322 self.libjuju.configure_application(
1323 "model",
1324 "app",
1325 {"config"},
1326 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001327 )
David Garcia12b29242020-09-17 16:01:48 +02001328 mock_disconnect_controller.assert_called_once()
1329 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001330
David Garcia5b802c92020-11-11 16:56:06 +01001331 def test_controller_exception(
1332 self,
1333 mock_get_application,
1334 mock_disconnect_controller,
1335 mock_disconnect_model,
1336 mock_get_model,
1337 mock_get_controller,
1338 ):
David Garcia5b802c92020-11-11 16:56:06 +01001339 result = {"error": "not found", "response": "response", "request-id": 1}
1340
1341 mock_get_controller.side_effect = JujuAPIError(result)
1342
1343 with self.assertRaises(JujuAPIError):
1344 self.loop.run_until_complete(
1345 self.libjuju.configure_application(
1346 "model",
1347 "app",
1348 {"config"},
1349 )
1350 )
1351 mock_get_model.assert_not_called()
1352 mock_disconnect_controller.assert_not_called()
1353 mock_disconnect_model.assert_not_called()
1354
1355 def test_get_model_exception(
1356 self,
1357 mock_get_application,
1358 mock_disconnect_controller,
1359 mock_disconnect_model,
1360 mock_get_model,
1361 mock_get_controller,
1362 ):
David Garcia5b802c92020-11-11 16:56:06 +01001363 result = {"error": "not found", "response": "response", "request-id": 1}
1364 mock_get_model.side_effect = JujuAPIError(result)
1365
1366 with self.assertRaises(JujuAPIError):
1367 self.loop.run_until_complete(
1368 self.libjuju.configure_application(
1369 "model",
1370 "app",
1371 {"config"},
1372 )
1373 )
1374 mock_get_model.assert_called_once()
1375 mock_disconnect_controller.assert_called_once()
1376 mock_disconnect_model.assert_not_called()
1377
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001378
1379# TODO _get_api_endpoints_db test case
1380# TODO _update_api_endpoints_db test case
1381# TODO healthcheck test case
1382
1383
1384@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1385@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1386@asynctest.mock.patch("juju.controller.Controller.list_models")
1387class ListModelsTest(LibjujuTestCase):
1388 def setUp(self):
1389 super(ListModelsTest, self).setUp()
1390
1391 def test_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001392 self,
1393 mock_list_models,
1394 mock_disconnect_controller,
1395 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001396 ):
1397 mock_get_controller.return_value = juju.controller.Controller()
1398 mock_list_models.return_value = ["existingmodel"]
1399 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
1400
1401 mock_disconnect_controller.assert_called_once()
1402 self.assertEquals(models, ["existingmodel"])
1403
1404 def test_not_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001405 self,
1406 mock_list_models,
1407 mock_disconnect_controller,
1408 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001409 ):
1410 mock_get_controller.return_value = juju.controller.Controller()
1411 mock_list_models.return_value = ["existingmodel", "model"]
1412 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
1413
1414 mock_disconnect_controller.assert_called_once()
1415 self.assertEquals(models, [])
1416
1417 def test_no_contains_arg(
David Garcia5b802c92020-11-11 16:56:06 +01001418 self,
1419 mock_list_models,
1420 mock_disconnect_controller,
1421 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001422 ):
1423 mock_get_controller.return_value = juju.controller.Controller()
1424 mock_list_models.return_value = ["existingmodel", "model"]
1425 models = self.loop.run_until_complete(self.libjuju.list_models())
1426
1427 mock_disconnect_controller.assert_called_once()
1428 self.assertEquals(models, ["existingmodel", "model"])
David Garcia42f328a2020-08-25 15:03:01 +02001429
1430
1431@asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
1432class ModelsExistTest(LibjujuTestCase):
1433 def setUp(self):
1434 super(ModelsExistTest, self).setUp()
1435
1436 def test_model_names_none(self, mock_list_models):
1437 mock_list_models.return_value = []
1438 with self.assertRaises(Exception):
1439 self.loop.run_until_complete(self.libjuju.models_exist(None))
1440
1441 def test_model_names_empty(self, mock_list_models):
1442 mock_list_models.return_value = []
1443 with self.assertRaises(Exception):
1444 (exist, non_existing_models) = self.loop.run_until_complete(
1445 self.libjuju.models_exist([])
1446 )
1447
1448 def test_model_names_not_existing(self, mock_list_models):
1449 mock_list_models.return_value = ["prometheus", "grafana"]
1450 (exist, non_existing_models) = self.loop.run_until_complete(
1451 self.libjuju.models_exist(["prometheus2", "grafana"])
1452 )
1453 self.assertFalse(exist)
1454 self.assertEqual(non_existing_models, ["prometheus2"])
1455
1456 def test_model_names_exist(self, mock_list_models):
1457 mock_list_models.return_value = ["prometheus", "grafana"]
1458 (exist, non_existing_models) = self.loop.run_until_complete(
1459 self.libjuju.models_exist(["prometheus", "grafana"])
1460 )
1461 self.assertTrue(exist)
1462 self.assertEqual(non_existing_models, [])
David Garciabc538e42020-08-25 15:22:30 +02001463
1464
1465@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1466@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1467@asynctest.mock.patch("juju.controller.Controller.list_offers")
1468class ListOffers(LibjujuTestCase):
1469 def setUp(self):
1470 super(ListOffers, self).setUp()
1471
1472 def test_disconnect_controller(
David Garcia5b802c92020-11-11 16:56:06 +01001473 self,
1474 mock_list_offers,
1475 mock_disconnect_controller,
1476 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001477 ):
1478 mock_get_controller.return_value = juju.controller.Controller()
1479 mock_list_offers.side_effect = Exception()
1480 with self.assertRaises(Exception):
David Garcia582b9232021-10-26 12:30:44 +02001481 self.loop.run_until_complete(self.libjuju._list_offers("model"))
David Garciabc538e42020-08-25 15:22:30 +02001482 mock_disconnect_controller.assert_called_once()
1483
1484 def test_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001485 self,
1486 mock_list_offers,
1487 mock_disconnect_controller,
1488 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001489 ):
1490 mock_get_controller.return_value = juju.controller.Controller()
David Garcia582b9232021-10-26 12:30:44 +02001491 offer_results = Mock()
1492 offer_results.results = []
1493 mock_list_offers.return_value = offer_results
1494 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
David Garciabc538e42020-08-25 15:22:30 +02001495 self.assertEqual(offers, [])
1496 mock_disconnect_controller.assert_called_once()
1497
1498 def test_non_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001499 self,
1500 mock_list_offers,
1501 mock_disconnect_controller,
1502 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001503 ):
1504 mock_get_controller.return_value = juju.controller.Controller()
David Garcia582b9232021-10-26 12:30:44 +02001505 offer = Mock()
1506 offer_results = Mock()
1507 offer_results.results = [offer]
1508 mock_list_offers.return_value = offer_results
1509 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
1510 self.assertEqual(offers, [offer])
David Garciabc538e42020-08-25 15:22:30 +02001511 mock_disconnect_controller.assert_called_once()
David Garcia68b00722020-09-11 15:05:00 +02001512
David Garcia582b9232021-10-26 12:30:44 +02001513 def test_matching_offer_name(
1514 self,
1515 mock_list_offers,
1516 mock_disconnect_controller,
1517 mock_get_controller,
1518 ):
1519 mock_get_controller.return_value = juju.controller.Controller()
1520 offer_1 = Mock()
1521 offer_1.offer_name = "offer1"
1522 offer_2 = Mock()
1523 offer_2.offer_name = "offer2"
1524 offer_results = Mock()
1525 offer_results.results = [offer_1, offer_2]
1526 mock_list_offers.return_value = offer_results
1527 offers = self.loop.run_until_complete(
1528 self.libjuju._list_offers("model", offer_name="offer2")
1529 )
1530 self.assertEqual(offers, [offer_2])
1531 mock_disconnect_controller.assert_called_once()
1532
1533 def test_not_matching_offer_name(
1534 self,
1535 mock_list_offers,
1536 mock_disconnect_controller,
1537 mock_get_controller,
1538 ):
1539 mock_get_controller.return_value = juju.controller.Controller()
1540 offer_1 = Mock()
1541 offer_1.offer_name = "offer1"
1542 offer_2 = Mock()
1543 offer_2.offer_name = "offer2"
1544 offer_results = Mock()
1545 offer_results.results = [offer_1, offer_2]
1546 mock_list_offers.return_value = offer_results
1547 offers = self.loop.run_until_complete(
1548 self.libjuju._list_offers("model", offer_name="offer3")
1549 )
1550 self.assertEqual(offers, [])
1551 mock_disconnect_controller.assert_called_once()
1552
1553
1554@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1555@asynctest.mock.patch("juju.controller.Controller.get_model")
1556@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1557@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1558@asynctest.mock.patch("n2vc.libjuju.Libjuju._list_offers")
1559@asynctest.mock.patch("juju.model.Model.create_offer")
1560class OfferTest(LibjujuTestCase):
1561 def setUp(self):
1562 super(OfferTest, self).setUp()
1563
1564 def test_offer(
1565 self,
1566 mock_create_offer,
1567 mock__list_offers,
1568 mock_disconnect_controller,
1569 mock_disconnect_model,
1570 mock_get_model,
1571 mock_get_controller,
1572 ):
1573 controller = juju.controller.Controller()
1574 model = juju.model.Model()
1575 mock_get_controller.return_value = controller
1576 mock_get_model.return_value = model
1577 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1578 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1579 mock_create_offer.assert_called_with(
1580 "app-name:endpoint", offer_name="app-name-endpoint"
1581 )
1582 mock_disconnect_model.assert_called_once_with(model)
1583 mock_disconnect_controller.assert_called_once_with(controller)
1584
1585 def test_offer_exception(
1586 self,
1587 mock_create_offer,
1588 mock__list_offers,
1589 mock_disconnect_controller,
1590 mock_disconnect_model,
1591 mock_get_model,
1592 mock_get_controller,
1593 ):
1594 controller = juju.controller.Controller()
1595 model = juju.model.Model()
1596 mock_get_controller.return_value = controller
1597 mock_get_model.return_value = model
1598 mock__list_offers.return_value = []
1599 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1600 with self.assertRaises(Exception):
1601 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1602 mock_create_offer.assert_called_with(
1603 "app-name:endpoint", offer_name="app-name-endpoint"
1604 )
1605 mock_disconnect_model.assert_called_once_with(model)
1606 mock_disconnect_controller.assert_called_once_with(controller)
1607
David Garcia68b00722020-09-11 15:05:00 +02001608
1609@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1610@asynctest.mock.patch("juju.controller.Controller.get_model")
1611@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1612@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1613@asynctest.mock.patch("juju.model.Model.consume")
1614class ConsumeTest(LibjujuTestCase):
1615 def setUp(self):
David Garcia582b9232021-10-26 12:30:44 +02001616 self.offer_url = "admin/model.offer_name"
David Garcia68b00722020-09-11 15:05:00 +02001617 super(ConsumeTest, self).setUp()
David Garcia582b9232021-10-26 12:30:44 +02001618 self.provider_libjuju = self.libjuju
David Garcia68b00722020-09-11 15:05:00 +02001619
1620 def test_consume(
1621 self,
1622 mock_consume,
1623 mock_disconnect_controller,
1624 mock_disconnect_model,
1625 mock_get_model,
1626 mock_get_controller,
1627 ):
David Garcia582b9232021-10-26 12:30:44 +02001628 self_controller = juju.controller.Controller()
1629 provider_controller = juju.controller.Controller()
1630 mock_get_controller.side_effect = [self_controller, provider_controller]
David Garcia68b00722020-09-11 15:05:00 +02001631 mock_get_model.return_value = juju.model.Model()
1632
David Garcia582b9232021-10-26 12:30:44 +02001633 self.loop.run_until_complete(
1634 self.libjuju.consume(
1635 "model_name",
1636 Offer(self.offer_url, vca_id="vca-id"),
1637 self.provider_libjuju,
1638 )
1639 )
1640 mock_consume.assert_called_once_with(
1641 "admin/model.offer_name",
1642 application_alias="offer_name-model-vca-id",
1643 controller=provider_controller,
1644 )
David Garcia68b00722020-09-11 15:05:00 +02001645 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001646 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia68b00722020-09-11 15:05:00 +02001647
1648 def test_parsing_error_exception(
1649 self,
1650 mock_consume,
1651 mock_disconnect_controller,
1652 mock_disconnect_model,
1653 mock_get_model,
1654 mock_get_controller,
1655 ):
1656 mock_get_controller.return_value = juju.controller.Controller()
1657 mock_get_model.return_value = juju.model.Model()
1658 mock_consume.side_effect = juju.offerendpoints.ParseError("")
1659
1660 with self.assertRaises(juju.offerendpoints.ParseError):
1661 self.loop.run_until_complete(
David Garcia582b9232021-10-26 12:30:44 +02001662 self.libjuju.consume(
1663 "model_name", Offer(self.offer_url), self.provider_libjuju
1664 )
David Garcia68b00722020-09-11 15:05:00 +02001665 )
1666 mock_consume.assert_called_once()
1667 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001668 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia68b00722020-09-11 15:05:00 +02001669
1670 def test_juju_error_exception(
1671 self,
1672 mock_consume,
1673 mock_disconnect_controller,
1674 mock_disconnect_model,
1675 mock_get_model,
1676 mock_get_controller,
1677 ):
1678 mock_get_controller.return_value = juju.controller.Controller()
1679 mock_get_model.return_value = juju.model.Model()
1680 mock_consume.side_effect = juju.errors.JujuError("")
1681
1682 with self.assertRaises(juju.errors.JujuError):
1683 self.loop.run_until_complete(
David Garcia582b9232021-10-26 12:30:44 +02001684 self.libjuju.consume(
1685 "model_name", Offer(self.offer_url), self.provider_libjuju
1686 )
David Garcia68b00722020-09-11 15:05:00 +02001687 )
1688 mock_consume.assert_called_once()
1689 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001690 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia68b00722020-09-11 15:05:00 +02001691
1692 def test_juju_api_error_exception(
1693 self,
1694 mock_consume,
1695 mock_disconnect_controller,
1696 mock_disconnect_model,
1697 mock_get_model,
1698 mock_get_controller,
1699 ):
1700 mock_get_controller.return_value = juju.controller.Controller()
1701 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +02001702 mock_consume.side_effect = juju.errors.JujuAPIError(
1703 {"error": "", "response": "", "request-id": ""}
1704 )
David Garcia68b00722020-09-11 15:05:00 +02001705
1706 with self.assertRaises(juju.errors.JujuAPIError):
1707 self.loop.run_until_complete(
David Garcia582b9232021-10-26 12:30:44 +02001708 self.libjuju.consume(
1709 "model_name", Offer(self.offer_url), self.provider_libjuju
1710 )
David Garcia68b00722020-09-11 15:05:00 +02001711 )
1712 mock_consume.assert_called_once()
1713 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001714 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia12b29242020-09-17 16:01:48 +02001715
1716
David Garcia475a7222020-09-21 16:19:15 +02001717@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
David Garcia12b29242020-09-17 16:01:48 +02001718@asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
1719class AddK8sTest(LibjujuTestCase):
1720 def setUp(self):
1721 super(AddK8sTest, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001722 name = "cloud"
1723 rbac_id = generate_rbac_id()
1724 token = "token"
1725 client_cert_data = "cert"
1726 configuration = kubernetes.client.configuration.Configuration()
1727 storage_class = "storage_class"
1728 credential_name = name
1729
1730 self._add_k8s_args = {
1731 "name": name,
1732 "rbac_id": rbac_id,
1733 "token": token,
1734 "client_cert_data": client_cert_data,
1735 "configuration": configuration,
1736 "storage_class": storage_class,
1737 "credential_name": credential_name,
1738 }
David Garcia12b29242020-09-17 16:01:48 +02001739
David Garcia475a7222020-09-21 16:19:15 +02001740 def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001741 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001742 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001743 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001744
David Garcia475a7222020-09-21 16:19:15 +02001745 def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garcia12b29242020-09-17 16:01:48 +02001746 mock_add_cloud.side_effect = Exception()
1747 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001748 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001749 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001750 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001751
David Garcia475a7222020-09-21 16:19:15 +02001752 def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001753 self._add_k8s_args["name"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001754 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001755 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001756 mock_add_cloud.assert_not_called()
1757
David Garcia475a7222020-09-21 16:19:15 +02001758 def test_add_k8s_missing_storage_name(
1759 self, mock_add_cloud, mock_get_k8s_cloud_credential
1760 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001761 self._add_k8s_args["storage_class"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001762 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001763 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001764 mock_add_cloud.assert_not_called()
1765
David Garcia475a7222020-09-21 16:19:15 +02001766 def test_add_k8s_missing_configuration_keys(
1767 self, mock_add_cloud, mock_get_k8s_cloud_credential
1768 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001769 self._add_k8s_args["configuration"] = None
David Garcia12b29242020-09-17 16:01:48 +02001770 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001771 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001772 mock_add_cloud.assert_not_called()
1773
1774
1775@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1776@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1777@asynctest.mock.patch("juju.controller.Controller.add_cloud")
1778@asynctest.mock.patch("juju.controller.Controller.add_credential")
1779class AddCloudTest(LibjujuTestCase):
1780 def setUp(self):
1781 super(AddCloudTest, self).setUp()
1782 self.cloud = juju.client.client.Cloud()
1783 self.credential = juju.client.client.CloudCredential()
1784
1785 def test_add_cloud_with_credential(
1786 self,
1787 mock_add_credential,
1788 mock_add_cloud,
1789 mock_disconnect_controller,
1790 mock_get_controller,
1791 ):
1792 mock_get_controller.return_value = juju.controller.Controller()
1793
1794 cloud = self.loop.run_until_complete(
1795 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1796 )
1797 self.assertEqual(cloud, self.cloud)
1798 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1799 mock_add_credential.assert_called_once_with(
1800 "cloud", credential=self.credential, cloud="cloud"
1801 )
1802 mock_disconnect_controller.assert_called_once()
1803
1804 def test_add_cloud_no_credential(
1805 self,
1806 mock_add_credential,
1807 mock_add_cloud,
1808 mock_disconnect_controller,
1809 mock_get_controller,
1810 ):
1811 mock_get_controller.return_value = juju.controller.Controller()
1812
1813 cloud = self.loop.run_until_complete(
1814 self.libjuju.add_cloud("cloud", self.cloud)
1815 )
1816 self.assertEqual(cloud, self.cloud)
1817 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1818 mock_add_credential.assert_not_called()
1819 mock_disconnect_controller.assert_called_once()
1820
1821 def test_add_cloud_exception(
1822 self,
1823 mock_add_credential,
1824 mock_add_cloud,
1825 mock_disconnect_controller,
1826 mock_get_controller,
1827 ):
1828 mock_get_controller.return_value = juju.controller.Controller()
1829 mock_add_cloud.side_effect = Exception()
1830 with self.assertRaises(Exception):
1831 self.loop.run_until_complete(
1832 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1833 )
1834
1835 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1836 mock_add_credential.assert_not_called()
1837 mock_disconnect_controller.assert_called_once()
1838
1839 def test_add_credential_exception(
1840 self,
1841 mock_add_credential,
1842 mock_add_cloud,
1843 mock_disconnect_controller,
1844 mock_get_controller,
1845 ):
1846 mock_get_controller.return_value = juju.controller.Controller()
1847 mock_add_credential.side_effect = Exception()
1848 with self.assertRaises(Exception):
1849 self.loop.run_until_complete(
1850 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1851 )
1852
1853 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1854 mock_add_credential.assert_called_once_with(
1855 "cloud", credential=self.credential, cloud="cloud"
1856 )
1857 mock_disconnect_controller.assert_called_once()
1858
1859
1860@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1861@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1862@asynctest.mock.patch("juju.controller.Controller.remove_cloud")
1863class RemoveCloudTest(LibjujuTestCase):
1864 def setUp(self):
1865 super(RemoveCloudTest, self).setUp()
1866
1867 def test_remove_cloud(
David Garcia5b802c92020-11-11 16:56:06 +01001868 self,
1869 mock_remove_cloud,
1870 mock_disconnect_controller,
1871 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001872 ):
1873 mock_get_controller.return_value = juju.controller.Controller()
1874
1875 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1876 mock_remove_cloud.assert_called_once_with("cloud")
1877 mock_disconnect_controller.assert_called_once()
1878
1879 def test_remove_cloud_exception(
David Garcia5b802c92020-11-11 16:56:06 +01001880 self,
1881 mock_remove_cloud,
1882 mock_disconnect_controller,
1883 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001884 ):
1885 mock_get_controller.return_value = juju.controller.Controller()
1886 mock_remove_cloud.side_effect = Exception()
1887
1888 with self.assertRaises(Exception):
1889 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1890 mock_remove_cloud.assert_called_once_with("cloud")
1891 mock_disconnect_controller.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001892
1893
1894@asynctest.mock.patch("kubernetes.client.configuration.Configuration")
1895class GetK8sCloudCredentials(LibjujuTestCase):
1896 def setUp(self):
1897 super(GetK8sCloudCredentials, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001898 self.cert_data = "cert"
1899 self.token = "token"
David Garcia475a7222020-09-21 16:19:15 +02001900
1901 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1902 def test_not_supported(self, mock_exception, mock_configuration):
1903 mock_configuration.username = ""
1904 mock_configuration.password = ""
1905 mock_configuration.ssl_ca_cert = None
1906 mock_configuration.cert_file = None
1907 mock_configuration.key_file = None
1908 exception_raised = False
David Garciaf6e9b002020-11-27 15:32:02 +01001909 self.token = None
1910 self.cert_data = None
David Garcia475a7222020-09-21 16:19:15 +02001911 try:
David Garciaf6e9b002020-11-27 15:32:02 +01001912 _ = self.libjuju.get_k8s_cloud_credential(
1913 mock_configuration,
1914 self.cert_data,
1915 self.token,
1916 )
David Garcia475a7222020-09-21 16:19:15 +02001917 except JujuInvalidK8sConfiguration as e:
1918 exception_raised = True
1919 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01001920 e.message,
1921 "authentication method not supported",
David Garcia475a7222020-09-21 16:19:15 +02001922 )
1923 self.assertTrue(exception_raised)
1924
1925 def test_user_pass(self, mock_configuration):
1926 mock_configuration.username = "admin"
1927 mock_configuration.password = "admin"
1928 mock_configuration.ssl_ca_cert = None
1929 mock_configuration.cert_file = None
1930 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001931 self.token = None
1932 self.cert_data = None
1933 credential = self.libjuju.get_k8s_cloud_credential(
1934 mock_configuration,
1935 self.cert_data,
1936 self.token,
1937 )
David Garcia475a7222020-09-21 16:19:15 +02001938 self.assertEqual(
1939 credential,
1940 juju.client._definitions.CloudCredential(
1941 attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
1942 ),
1943 )
1944
David Garciaf6e9b002020-11-27 15:32:02 +01001945 def test_user_pass_with_cert(self, mock_configuration):
1946 mock_configuration.username = "admin"
1947 mock_configuration.password = "admin"
1948 mock_configuration.ssl_ca_cert = None
1949 mock_configuration.cert_file = None
1950 mock_configuration.key_file = None
1951 self.token = None
1952 credential = self.libjuju.get_k8s_cloud_credential(
1953 mock_configuration,
1954 self.cert_data,
1955 self.token,
1956 )
1957 self.assertEqual(
1958 credential,
1959 juju.client._definitions.CloudCredential(
1960 attrs={
1961 "ClientCertificateData": self.cert_data,
1962 "username": "admin",
1963 "password": "admin",
1964 },
1965 auth_type="userpasswithcert",
1966 ),
1967 )
1968
David Garcia475a7222020-09-21 16:19:15 +02001969 def test_user_no_pass(self, mock_configuration):
1970 mock_configuration.username = "admin"
1971 mock_configuration.password = ""
1972 mock_configuration.ssl_ca_cert = None
1973 mock_configuration.cert_file = None
1974 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001975 self.token = None
1976 self.cert_data = None
David Garciaeb8943a2021-04-12 12:07:37 +02001977 with patch.object(self.libjuju.log, "debug") as mock_debug:
David Garciaf6e9b002020-11-27 15:32:02 +01001978 credential = self.libjuju.get_k8s_cloud_credential(
1979 mock_configuration,
1980 self.cert_data,
1981 self.token,
1982 )
David Garcia475a7222020-09-21 16:19:15 +02001983 self.assertEqual(
1984 credential,
1985 juju.client._definitions.CloudCredential(
1986 attrs={"username": "admin", "password": ""}, auth_type="userpass"
1987 ),
1988 )
1989 mock_debug.assert_called_once_with(
1990 "credential for user admin has empty password"
1991 )
1992
David Garcia475a7222020-09-21 16:19:15 +02001993 def test_cert(self, mock_configuration):
1994 mock_configuration.username = ""
1995 mock_configuration.password = ""
1996 mock_configuration.api_key = {"authorization": "Bearer Token"}
1997 ssl_ca_cert = tempfile.NamedTemporaryFile()
1998 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
1999 ssl_ca_cert_file.write("cacert")
2000 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
2001 mock_configuration.cert_file = None
2002 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01002003 credential = self.libjuju.get_k8s_cloud_credential(
2004 mock_configuration,
2005 self.cert_data,
2006 self.token,
2007 )
David Garcia475a7222020-09-21 16:19:15 +02002008 self.assertEqual(
2009 credential,
2010 juju.client._definitions.CloudCredential(
David Garciaf6e9b002020-11-27 15:32:02 +01002011 attrs={"ClientCertificateData": self.cert_data, "Token": self.token},
David Garcia475a7222020-09-21 16:19:15 +02002012 auth_type="certificate",
2013 ),
2014 )
2015
David Garciaf6e9b002020-11-27 15:32:02 +01002016 # TODO: Fix this test when oauth authentication is supported
2017 # def test_oauth2(self, mock_configuration):
2018 # mock_configuration.username = ""
2019 # mock_configuration.password = ""
2020 # mock_configuration.api_key = {"authorization": "Bearer Token"}
2021 # key = tempfile.NamedTemporaryFile()
2022 # with open(key.name, "w") as key_file:
2023 # key_file.write("key")
2024 # mock_configuration.ssl_ca_cert = None
2025 # mock_configuration.cert_file = None
2026 # mock_configuration.key_file = key.name
2027 # credential = self.libjuju.get_k8s_cloud_credential(
2028 # mock_configuration,
2029 # self.cert_data,
2030 # self.token,
2031 # )
2032 # self.assertEqual(
2033 # credential,
2034 # juju.client._definitions.CloudCredential(
2035 # attrs={"ClientKeyData": "key", "Token": "Token"},
2036 # auth_type="oauth2",
2037 # ),
2038 # )
David Garcia475a7222020-09-21 16:19:15 +02002039
David Garciaf6e9b002020-11-27 15:32:02 +01002040 # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
2041 # def test_oauth2_missing_token(self, mock_exception, mock_configuration):
2042 # mock_configuration.username = ""
2043 # mock_configuration.password = ""
2044 # key = tempfile.NamedTemporaryFile()
2045 # with open(key.name, "w") as key_file:
2046 # key_file.write("key")
2047 # mock_configuration.ssl_ca_cert = None
2048 # mock_configuration.cert_file = None
2049 # mock_configuration.key_file = key.name
2050 # exception_raised = False
2051 # try:
2052 # _ = self.libjuju.get_k8s_cloud_credential(
2053 # mock_configuration,
2054 # self.cert_data,
2055 # self.token,
2056 # )
2057 # except JujuInvalidK8sConfiguration as e:
2058 # exception_raised = True
2059 # self.assertEqual(
2060 # e.message,
2061 # "missing token for auth type oauth2",
2062 # )
2063 # self.assertTrue(exception_raised)
David Garcia475a7222020-09-21 16:19:15 +02002064
2065 def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
2066 mock_configuration.username = "admin"
2067 mock_configuration.password = "pass"
2068 mock_configuration.api_key = {"authorization": "No_bearer_token"}
2069 mock_configuration.ssl_ca_cert = None
2070 mock_configuration.cert_file = None
2071 mock_configuration.key_file = None
2072 exception_raised = False
2073 try:
David Garciaf6e9b002020-11-27 15:32:02 +01002074 _ = self.libjuju.get_k8s_cloud_credential(
2075 mock_configuration,
2076 self.cert_data,
2077 self.token,
2078 )
David Garcia475a7222020-09-21 16:19:15 +02002079 except JujuInvalidK8sConfiguration as e:
2080 exception_raised = True
2081 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01002082 e.message,
2083 "Cannot set both token and user/pass",
David Garcia475a7222020-09-21 16:19:15 +02002084 )
2085 self.assertTrue(exception_raised)
aktas2962f3e2021-03-15 11:05:35 +03002086
2087
2088@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2089@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2090@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2091@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2092@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2093@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
2094class ScaleApplicationTest(LibjujuTestCase):
2095 def setUp(self):
2096 super(ScaleApplicationTest, self).setUp()
2097
2098 @asynctest.mock.patch("asyncio.sleep")
2099 def test_scale_application(
2100 self,
2101 mock_sleep,
2102 mock_wait_for_model,
2103 mock_disconnect_controller,
2104 mock_disconnect_model,
2105 mock_get_application,
2106 mock_get_model,
2107 mock_get_controller,
2108 ):
2109 mock_get_model.return_value = juju.model.Model()
2110 mock_get_application.return_value = FakeApplication()
garciadeblas82b591c2021-03-24 09:22:13 +01002111 self.loop.run_until_complete(self.libjuju.scale_application("model", "app", 2))
aktas2962f3e2021-03-15 11:05:35 +03002112 mock_wait_for_model.assert_called_once()
2113 mock_disconnect_controller.assert_called_once()
2114 mock_disconnect_model.assert_called_once()
2115
2116 def test_no_application(
2117 self,
2118 mock_wait_for,
2119 mock_disconnect_controller,
2120 mock_disconnect_model,
2121 mock_get_application,
2122 mock_get_model,
2123 mock_get_controller,
2124 ):
2125 mock_get_application.return_value = None
2126 mock_get_model.return_value = juju.model.Model()
2127 with self.assertRaises(JujuApplicationNotFound):
2128 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01002129 self.libjuju.scale_application("model", "app", 2)
aktas2962f3e2021-03-15 11:05:35 +03002130 )
2131 mock_disconnect_controller.assert_called()
2132 mock_disconnect_model.assert_called()
2133
2134 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01002135 self,
2136 mock_wait_for,
2137 mock_disconnect_controller,
2138 mock_disconnect_model,
2139 mock_get_application,
2140 mock_get_model,
2141 mock_get_controller,
aktas2962f3e2021-03-15 11:05:35 +03002142 ):
2143 mock_get_model.return_value = None
2144 mock_get_application.return_value = FakeApplication()
2145 with self.assertRaises(Exception):
2146 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01002147 self.libjuju.scale_application("model", "app", 2, total_timeout=0)
aktas2962f3e2021-03-15 11:05:35 +03002148 )
2149 mock_disconnect_controller.assert_called_once()
2150
2151
2152@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2153class GetUnitNumberTest(LibjujuTestCase):
2154 def setUp(self):
2155 super(GetUnitNumberTest, self).setUp()
2156
aktasfa02f8a2021-07-29 17:41:40 +03002157 def test_successful_get_unit_number(
aktas2962f3e2021-03-15 11:05:35 +03002158 self,
2159 mock_get_applications,
2160 ):
2161 mock_get_applications.return_value = FakeApplication()
2162 model = juju.model.Model()
2163 result = self.libjuju._get_application_count(model, "app")
2164 self.assertEqual(result, 2)
2165
2166 def test_non_existing_application(
2167 self,
2168 mock_get_applications,
2169 ):
2170 mock_get_applications.return_value = None
2171 model = juju.model.Model()
2172 result = self.libjuju._get_application_count(model, "app")
2173 self.assertEqual(result, None)
aktasfa02f8a2021-07-29 17:41:40 +03002174
2175
2176@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
2177class GetMachineInfoTest(LibjujuTestCase):
2178 def setUp(self):
2179 super(GetMachineInfoTest, self).setUp()
2180
2181 def test_successful(
2182 self,
2183 mock_machines,
2184 ):
2185 machine_id = "existing_machine"
2186 model = juju.model.Model()
2187 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2188 machine, series = self.libjuju._get_machine_info(
2189 machine_id=machine_id,
2190 model=model,
2191 )
2192 self.assertIsNotNone(machine, series)
2193
2194 def test_exception(
2195 self,
2196 mock_machines,
2197 ):
2198 machine_id = "not_existing_machine"
2199 machine = series = None
2200 model = juju.model.Model()
2201 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2202 with self.assertRaises(JujuMachineNotFound):
2203 machine, series = self.libjuju._get_machine_info(
2204 machine_id=machine_id,
2205 model=model,
2206 )
2207 self.assertIsNone(machine, series)
2208
2209
2210class GetUnitTest(LibjujuTestCase):
2211 def setUp(self):
2212 super(GetUnitTest, self).setUp()
2213
2214 def test_successful(self):
2215 result = self.libjuju._get_unit(FakeApplication(), "existing_machine_id")
2216 self.assertIsInstance(result, FakeUnit)
2217
2218 def test_return_none(self):
2219 result = self.libjuju._get_unit(FakeApplication(), "not_existing_machine_id")
2220 self.assertIsNone(result)
2221
2222
2223@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2224@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2225@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2226@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2227@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2228class CheckApplicationExists(LibjujuTestCase):
2229 def setUp(self):
2230 super(CheckApplicationExists, self).setUp()
2231
2232 def test_successful(
2233 self,
2234 mock_get_application,
2235 mock_disconnect_controller,
2236 mock_disconnect_model,
2237 mock_get_model,
2238 mock_get_controller,
2239 ):
2240 mock_get_model.return_value = juju.model.Model()
2241 mock_get_application.return_value = FakeApplication()
2242 result = self.loop.run_until_complete(
2243 self.libjuju.check_application_exists(
2244 "model",
2245 "app",
2246 )
2247 )
2248 self.assertEqual(result, True)
2249
2250 mock_get_application.assert_called_once()
2251 mock_get_controller.assert_called_once()
2252 mock_get_model.assert_called_once()
2253 mock_disconnect_controller.assert_called_once()
2254 mock_disconnect_model.assert_called_once()
2255
2256 def test_no_application(
2257 self,
2258 mock_get_application,
2259 mock_disconnect_controller,
2260 mock_disconnect_model,
2261 mock_get_model,
2262 mock_get_controller,
2263 ):
2264 mock_get_model.return_value = juju.model.Model()
2265 mock_get_application.return_value = None
2266 result = self.loop.run_until_complete(
2267 self.libjuju.check_application_exists(
2268 "model",
2269 "app",
2270 )
2271 )
2272 self.assertEqual(result, False)
2273
2274 mock_get_application.assert_called_once()
2275 mock_get_controller.assert_called_once()
2276 mock_get_model.assert_called_once()
2277 mock_disconnect_controller.assert_called_once()
2278 mock_disconnect_model.assert_called_once()
2279
2280
2281@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2282@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2283@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2284@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2285@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2286@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_machine_info")
2287class AddUnitTest(LibjujuTestCase):
2288 def setUp(self):
2289 super(AddUnitTest, self).setUp()
2290
2291 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
2292 @asynctest.mock.patch("asyncio.sleep")
2293 def test_successful(
2294 self,
2295 mock_sleep,
2296 mock_wait_for,
2297 mock_get_machine_info,
2298 mock_get_application,
2299 mock_disconnect_controller,
2300 mock_disconnect_model,
2301 mock_get_model,
2302 mock_get_controller,
2303 ):
2304 mock_get_model.return_value = juju.model.Model()
2305 mock_get_application.return_value = FakeApplication()
2306 mock_get_machine_info.return_value = FakeMachine(), "series"
2307 self.loop.run_until_complete(
2308 self.libjuju.add_unit(
2309 "existing_app",
2310 "model",
2311 "machine",
2312 )
2313 )
2314
2315 mock_wait_for.assert_called_once()
2316 mock_get_application.assert_called_once()
2317 mock_get_controller.assert_called_once()
2318 mock_get_model.assert_called_once()
2319 mock_disconnect_controller.assert_called_once()
2320 mock_disconnect_model.assert_called_once()
2321
2322 def test_no_app(
2323 self,
2324 mock_get_machine_info,
2325 mock_get_application,
2326 mock_disconnect_controller,
2327 mock_disconnect_model,
2328 mock_get_model,
2329 mock_get_controller,
2330 ):
2331 mock_get_model.return_value = juju.model.Model()
2332 mock_get_application.return_value = None
2333 with self.assertRaises(JujuApplicationNotFound):
2334 self.loop.run_until_complete(
2335 self.libjuju.add_unit(
2336 "existing_app",
2337 "model",
2338 "machine",
2339 )
2340 )
2341
2342 mock_get_application.assert_called_once()
2343 mock_get_controller.assert_called_once()
2344 mock_get_model.assert_called_once()
2345 mock_disconnect_controller.assert_called_once()
2346 mock_disconnect_model.assert_called_once()
2347
2348 def test_no_machine(
2349 self,
2350 mock_get_machine_info,
2351 mock_get_application,
2352 mock_disconnect_controller,
2353 mock_disconnect_model,
2354 mock_get_model,
2355 mock_get_controller,
2356 ):
2357 mock_get_model.return_value = juju.model.Model()
2358 mock_get_application.return_value = FakeApplication()
2359 mock_get_machine_info.side_effect = JujuMachineNotFound()
2360 with self.assertRaises(JujuMachineNotFound):
2361 self.loop.run_until_complete(
2362 self.libjuju.add_unit(
2363 "existing_app",
2364 "model",
2365 "machine",
2366 )
2367 )
2368
2369 mock_get_application.assert_called_once()
2370 mock_get_controller.assert_called_once()
2371 mock_get_model.assert_called_once()
2372 mock_disconnect_controller.assert_called_once()
2373 mock_disconnect_model.assert_called_once()
2374
2375
2376@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2377@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2378@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2379@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2380@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2381@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_unit")
2382class DestroyUnitTest(LibjujuTestCase):
2383 def setUp(self):
2384 super(DestroyUnitTest, self).setUp()
2385
2386 @asynctest.mock.patch("asyncio.sleep")
2387 def test_successful(
2388 self,
2389 mock_sleep,
2390 mock_get_unit,
2391 mock_get_application,
2392 mock_disconnect_controller,
2393 mock_disconnect_model,
2394 mock_get_model,
2395 mock_get_controller,
2396 ):
2397 mock_get_model.return_value = juju.model.Model()
2398 mock_get_application.return_value = FakeApplication()
2399
2400 self.loop.run_until_complete(
2401 self.libjuju.destroy_unit("app", "model", "machine", 0)
2402 )
2403
2404 mock_get_unit.assert_called()
2405 mock_get_application.assert_called_once()
2406 mock_get_controller.assert_called_once()
2407 mock_get_model.assert_called_once()
2408 mock_disconnect_controller.assert_called_once()
2409 mock_disconnect_model.assert_called_once()
2410
2411 def test_no_app(
2412 self,
2413 mock_get_unit,
2414 mock_get_application,
2415 mock_disconnect_controller,
2416 mock_disconnect_model,
2417 mock_get_model,
2418 mock_get_controller,
2419 ):
2420 mock_get_model.return_value = juju.model.Model()
2421 mock_get_application.return_value = None
2422
2423 with self.assertRaises(JujuApplicationNotFound):
2424 self.loop.run_until_complete(
2425 self.libjuju.destroy_unit("app", "model", "machine")
2426 )
2427
2428 mock_get_application.assert_called_once()
2429 mock_get_controller.assert_called_once()
2430 mock_get_model.assert_called_once()
2431 mock_disconnect_controller.assert_called_once()
2432 mock_disconnect_model.assert_called_once()
2433
2434 def test_no_unit(
2435 self,
2436 mock_get_unit,
2437 mock_get_application,
2438 mock_disconnect_controller,
2439 mock_disconnect_model,
2440 mock_get_model,
2441 mock_get_controller,
2442 ):
2443 mock_get_model.return_value = juju.model.Model()
2444 mock_get_application.return_value = FakeApplication()
2445 mock_get_unit.return_value = None
2446
2447 with self.assertRaises(JujuError):
2448 self.loop.run_until_complete(
2449 self.libjuju.destroy_unit("app", "model", "machine")
2450 )
2451
2452 mock_get_unit.assert_called_once()
2453 mock_get_application.assert_called_once()
2454 mock_get_controller.assert_called_once()
2455 mock_get_model.assert_called_once()
2456 mock_disconnect_controller.assert_called_once()
2457 mock_disconnect_model.assert_called_once()