blob: 1bbe55623ea355fc588871454a3431b33ec99d1a [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 ):
781
782 mock_get_model.return_value = juju.model.Model()
783 mock__get_application.return_value = FakeApplication()
David Garcia12b29242020-09-17 16:01:48 +0200784 output = None
785 status = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200786 with self.assertRaises(JujuActionNotFound):
787 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100788 self.libjuju.execute_action(
789 "app",
790 "model",
791 "action",
792 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200793 )
David Garcia12b29242020-09-17 16:01:48 +0200794 self.assertIsNone(output)
795 self.assertIsNone(status)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200796
David Garcia12b29242020-09-17 16:01:48 +0200797 mock_disconnect_controller.assert_called()
798 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200799
David Garcia59f520d2020-10-15 13:16:45 +0200800 @asynctest.mock.patch("asyncio.sleep")
801 @asynctest.mock.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
802 def test_no_leader(
803 self,
804 mock_is_leader_from_status,
805 mock_sleep,
806 mock_get_action_status,
807 mock_get_action_output,
808 mock_wait_for,
809 mock__get_application,
810 mock_disconnect_controller,
811 mock_disconnect_model,
812 mock_get_model,
813 mock_get_controller,
814 ):
815 mock_get_model.return_value = juju.model.Model()
816 mock__get_application.return_value = FakeApplication()
817 mock_is_leader_from_status.return_value = False
818 output = None
819 status = None
820 with self.assertRaises(JujuLeaderUnitNotFound):
821 output, status = self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100822 self.libjuju.execute_action(
823 "app",
824 "model",
825 "action",
826 )
David Garcia59f520d2020-10-15 13:16:45 +0200827 )
828 self.assertIsNone(output)
829 self.assertIsNone(status)
830
831 mock_disconnect_controller.assert_called()
832 mock_disconnect_model.assert_called()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200833
aktasfa02f8a2021-07-29 17:41:40 +0300834 def test_successful_exec(
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200835 self,
836 mock_get_action_status,
837 mock_get_action_output,
838 mock_wait_for,
839 mock__get_application,
840 mock_disconnect_controller,
841 mock_disconnect_model,
842 mock_get_model,
843 mock_get_controller,
844 ):
845 mock_get_model.return_value = juju.model.Model()
846 mock__get_application.return_value = FakeApplication()
847 mock_get_action_output.return_value = "output"
848 mock_get_action_status.return_value = {"id": "status"}
849 output, status = self.loop.run_until_complete(
850 self.libjuju.execute_action("app", "model", "existing_action")
851 )
852 self.assertEqual(output, "output")
853 self.assertEqual(status, "status")
854
855 mock_wait_for.assert_called_once()
856
857 mock_disconnect_controller.assert_called()
858 mock_disconnect_model.assert_called()
859
860
861@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
862@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
863@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
864@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
865@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
866class GetActionTest(LibjujuTestCase):
867 def setUp(self):
868 super(GetActionTest, self).setUp()
869
870 def test_exception(
871 self,
872 mock_get_application,
873 mock_disconnect_controller,
874 mock_disconnect_model,
875 mock_get_model,
876 mock_get_controller,
877 ):
878 mock_get_application.side_effect = Exception()
David Garcia12b29242020-09-17 16:01:48 +0200879 actions = None
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200880 with self.assertRaises(Exception):
881 actions = self.loop.run_until_complete(
882 self.libjuju.get_actions("app", "model")
883 )
884
David Garcia12b29242020-09-17 16:01:48 +0200885 self.assertIsNone(actions)
886 mock_disconnect_controller.assert_called_once()
887 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200888
889 def test_success(
890 self,
891 mock_get_application,
892 mock_disconnect_controller,
893 mock_disconnect_model,
894 mock_get_model,
895 mock_get_controller,
896 ):
897 mock_get_application.return_value = FakeApplication()
898
899 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
900
901 self.assertEqual(actions, ["existing_action"])
902
903 mock_get_controller.assert_called_once()
904 mock_get_model.assert_called_once()
905 mock_disconnect_controller.assert_called_once()
906 mock_disconnect_model.assert_called_once()
907
908
909@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
910@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
911@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
912@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
David Garcia85755d12020-09-21 19:51:23 +0200913@asynctest.mock.patch("juju.application.Application.get_metrics")
914@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
915class GetMetricsTest(LibjujuTestCase):
916 def setUp(self):
917 super(GetMetricsTest, self).setUp()
918
919 def test_get_metrics_success(
920 self,
921 mock_get_application,
922 mock_get_metrics,
923 mock_disconnect_controller,
924 mock_disconnect_model,
925 mock_get_model,
926 mock_get_controller,
927 ):
928 mock_get_application.return_value = FakeApplication()
929 mock_get_model.return_value = juju.model.Model()
930
931 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
932
933 mock_disconnect_controller.assert_called_once()
934 mock_disconnect_model.assert_called_once()
935
936 def test_get_metrics_exception(
937 self,
938 mock_get_application,
939 mock_get_metrics,
940 mock_disconnect_controller,
941 mock_disconnect_model,
942 mock_get_model,
943 mock_get_controller,
944 ):
945 mock_get_model.return_value = juju.model.Model()
946 mock_get_metrics.side_effect = Exception()
947 with self.assertRaises(Exception):
948 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
949
950 mock_disconnect_controller.assert_called_once()
951 mock_disconnect_model.assert_called_once()
952
953 def test_missing_args_exception(
954 self,
955 mock_get_application,
956 mock_get_metrics,
957 mock_disconnect_controller,
958 mock_disconnect_model,
959 mock_get_model,
960 mock_get_controller,
961 ):
962 mock_get_model.return_value = juju.model.Model()
963
964 with self.assertRaises(Exception):
965 self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
966
967 mock_get_controller.assert_not_called()
968 mock_get_model.assert_not_called()
969 mock_disconnect_controller.assert_not_called()
970 mock_disconnect_model.assert_not_called()
971
972
973@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
974@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
975@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
976@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +0200977@asynctest.mock.patch("juju.model.Model.add_relation")
978class AddRelationTest(LibjujuTestCase):
979 def setUp(self):
980 super(AddRelationTest, self).setUp()
981
982 @asynctest.mock.patch("logging.Logger.warning")
983 def test_not_found(
984 self,
985 mock_warning,
986 mock_add_relation,
987 mock_disconnect_controller,
988 mock_disconnect_model,
989 mock_get_model,
990 mock_get_controller,
991 ):
992 # TODO in libjuju.py should this fail only with a log message?
993 result = {"error": "not found", "response": "response", "request-id": 1}
994
995 mock_get_model.return_value = juju.model.Model()
996 mock_add_relation.side_effect = JujuAPIError(result)
997
998 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +0100999 self.libjuju.add_relation(
1000 "model",
1001 "app1:relation1",
1002 "app2:relation2",
1003 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001004 )
1005
1006 mock_warning.assert_called_with("Relation not found: not found")
1007 mock_disconnect_controller.assert_called_once()
1008 mock_disconnect_model.assert_called_once()
1009
1010 @asynctest.mock.patch("logging.Logger.warning")
Patricia Reinosoa07f6952023-01-04 10:40:10 +00001011 def test_not_found_in_error_code(
1012 self,
1013 mock_warning,
1014 mock_add_relation,
1015 mock_disconnect_controller,
1016 mock_disconnect_model,
1017 mock_get_model,
1018 mock_get_controller,
1019 ):
1020 result = {
1021 "error": "relation cannot be added",
1022 "error-code": "not found",
1023 "response": "response",
1024 "request-id": 1,
1025 }
1026
1027 mock_get_model.return_value = juju.model.Model()
1028 mock_add_relation.side_effect = JujuAPIError(result)
1029
1030 self.loop.run_until_complete(
1031 self.libjuju.add_relation(
1032 "model",
1033 "app1:relation1",
1034 "app2:relation2",
1035 )
1036 )
1037
1038 mock_warning.assert_called_with("Relation not found: relation cannot be added")
1039 mock_disconnect_controller.assert_called_once()
1040 mock_disconnect_model.assert_called_once()
1041
1042 @asynctest.mock.patch("logging.Logger.warning")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001043 def test_already_exists(
1044 self,
1045 mock_warning,
1046 mock_add_relation,
1047 mock_disconnect_controller,
1048 mock_disconnect_model,
1049 mock_get_model,
1050 mock_get_controller,
1051 ):
1052 # TODO in libjuju.py should this fail silently?
1053 result = {"error": "already exists", "response": "response", "request-id": 1}
1054
1055 mock_get_model.return_value = juju.model.Model()
1056 mock_add_relation.side_effect = JujuAPIError(result)
1057
1058 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001059 self.libjuju.add_relation(
1060 "model",
1061 "app1:relation1",
1062 "app2:relation2",
1063 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001064 )
1065
1066 mock_warning.assert_called_with("Relation already exists: already exists")
1067 mock_disconnect_controller.assert_called_once()
1068 mock_disconnect_model.assert_called_once()
1069
Patricia Reinosoa07f6952023-01-04 10:40:10 +00001070 @asynctest.mock.patch("logging.Logger.warning")
1071 def test_already_exists_error_code(
1072 self,
1073 mock_warning,
1074 mock_add_relation,
1075 mock_disconnect_controller,
1076 mock_disconnect_model,
1077 mock_get_model,
1078 mock_get_controller,
1079 ):
1080 result = {
1081 "error": "relation cannot be added",
1082 "error-code": "already exists",
1083 "response": "response",
1084 "request-id": 1,
1085 }
1086
1087 mock_get_model.return_value = juju.model.Model()
1088 mock_add_relation.side_effect = JujuAPIError(result)
1089
1090 self.loop.run_until_complete(
1091 self.libjuju.add_relation(
1092 "model",
1093 "app1:relation1",
1094 "app2:relation2",
1095 )
1096 )
1097
1098 mock_warning.assert_called_with(
1099 "Relation already exists: relation cannot be added"
1100 )
1101 mock_disconnect_controller.assert_called_once()
1102 mock_disconnect_model.assert_called_once()
1103
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001104 def test_exception(
1105 self,
1106 mock_add_relation,
1107 mock_disconnect_controller,
1108 mock_disconnect_model,
1109 mock_get_model,
1110 mock_get_controller,
1111 ):
1112 mock_get_model.return_value = juju.model.Model()
1113 result = {"error": "", "response": "response", "request-id": 1}
1114 mock_add_relation.side_effect = JujuAPIError(result)
1115
1116 with self.assertRaises(JujuAPIError):
1117 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001118 self.libjuju.add_relation(
1119 "model",
1120 "app1:relation1",
1121 "app2:relation2",
1122 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001123 )
1124
David Garcia12b29242020-09-17 16:01:48 +02001125 mock_disconnect_controller.assert_called_once()
1126 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001127
1128 def test_success(
1129 self,
1130 mock_add_relation,
1131 mock_disconnect_controller,
1132 mock_disconnect_model,
1133 mock_get_model,
1134 mock_get_controller,
1135 ):
1136 mock_get_model.return_value = juju.model.Model()
1137
1138 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001139 self.libjuju.add_relation(
1140 "model",
1141 "app1:relation1",
1142 "app2:relation2",
1143 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001144 )
1145
David Garcia12b29242020-09-17 16:01:48 +02001146 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
David Garcia8331f7c2020-08-25 16:10:07 +02001147 mock_disconnect_controller.assert_called_once()
1148 mock_disconnect_model.assert_called_once()
1149
1150 def test_saas(
1151 self,
1152 mock_add_relation,
1153 mock_disconnect_controller,
1154 mock_disconnect_model,
1155 mock_get_model,
1156 mock_get_controller,
1157 ):
1158 mock_get_model.return_value = juju.model.Model()
1159
1160 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001161 self.libjuju.add_relation(
1162 "model",
1163 "app1:relation1",
1164 "saas_name",
1165 )
David Garcia8331f7c2020-08-25 16:10:07 +02001166 )
1167
David Garcia12b29242020-09-17 16:01:48 +02001168 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001169 mock_disconnect_controller.assert_called_once()
1170 mock_disconnect_model.assert_called_once()
1171
1172
1173# TODO destroy_model testcase
1174
1175
aktas56120292021-02-26 15:32:39 +03001176@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1177@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1178@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1179@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1180@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1181class DestroyApplicationTest(LibjujuTestCase):
1182 def setUp(self):
1183 super(DestroyApplicationTest, self).setUp()
1184
1185 def test_success(
garciadeblas82b591c2021-03-24 09:22:13 +01001186 self,
1187 mock_get_controller,
1188 mock_get_model,
1189 mock_disconnect_controller,
1190 mock_get_application,
1191 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001192 ):
1193 mock_get_application.return_value = FakeApplication()
1194 mock_get_model.return_value = None
1195 self.loop.run_until_complete(
1196 self.libjuju.destroy_application(
1197 "existing_model",
1198 "existing_app",
1199 3600,
1200 )
1201 )
1202 mock_get_application.assert_called()
1203 mock_disconnect_controller.assert_called_once()
1204 mock_disconnect_model.assert_called_once()
1205
1206 def test_no_application(
garciadeblas82b591c2021-03-24 09:22:13 +01001207 self,
1208 mock_get_controller,
1209 mock_get_model,
1210 mock_disconnect_controller,
1211 mock_get_application,
1212 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001213 ):
1214 mock_get_model.return_value = None
1215 mock_get_application.return_value = None
1216
1217 self.loop.run_until_complete(
1218 self.libjuju.destroy_application(
1219 "existing_model",
1220 "existing_app",
1221 3600,
1222 )
1223 )
1224 mock_get_application.assert_called()
1225
1226 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01001227 self,
1228 mock_get_controller,
1229 mock_get_model,
1230 mock_disconnect_controller,
1231 mock_get_application,
1232 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001233 ):
1234 mock_get_application.return_value = FakeApplication
1235 mock_get_model.return_value = None
1236
1237 with self.assertRaises(Exception):
1238 self.loop.run_until_complete(
1239 self.libjuju.destroy_application(
1240 "existing_model",
1241 "existing_app",
1242 0,
1243 )
1244 )
1245 mock_get_application.assert_called_once()
1246
1247
David Garcia5ef42a12020-09-29 19:48:13 +02001248# @asynctest.mock.patch("juju.model.Model.get_machines")
1249# @asynctest.mock.patch("logging.Logger.debug")
1250# class DestroyMachineTest(LibjujuTestCase):
1251# def setUp(self):
1252# super(DestroyMachineTest, self).setUp()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001253
David Garcia5ef42a12020-09-29 19:48:13 +02001254# def test_success_manual_machine(
1255# self, mock_debug, mock_get_machines,
1256# ):
1257# mock_get_machines.side_effect = [
1258# {"machine": FakeManualMachine()},
1259# {"machine": FakeManualMachine()},
1260# {},
1261# ]
1262# self.loop.run_until_complete(
1263# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
1264# )
1265# calls = [
1266# asynctest.call("Waiting for machine machine is destroyed"),
1267# asynctest.call("Machine destroyed: machine"),
1268# ]
1269# mock_debug.assert_has_calls(calls)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001270
David Garcia5ef42a12020-09-29 19:48:13 +02001271# def test_no_machine(
1272# self, mock_debug, mock_get_machines,
1273# ):
1274# mock_get_machines.return_value = {}
1275# self.loop.run_until_complete(
1276# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
1277# )
1278# mock_debug.assert_called_with("Machine not found: machine")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001279
1280
1281@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1282@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1283@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1284@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1285@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1286class ConfigureApplicationTest(LibjujuTestCase):
1287 def setUp(self):
1288 super(ConfigureApplicationTest, self).setUp()
1289
1290 def test_success(
1291 self,
1292 mock_get_application,
1293 mock_disconnect_controller,
1294 mock_disconnect_model,
1295 mock_get_model,
1296 mock_get_controller,
1297 ):
1298
1299 mock_get_application.return_value = FakeApplication()
1300
1301 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001302 self.libjuju.configure_application(
1303 "model",
1304 "app",
1305 {"config"},
1306 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001307 )
1308 mock_get_application.assert_called_once()
1309 mock_disconnect_controller.assert_called_once()
1310 mock_disconnect_model.assert_called_once()
1311
1312 def test_exception(
1313 self,
1314 mock_get_application,
1315 mock_disconnect_controller,
1316 mock_disconnect_model,
1317 mock_get_model,
1318 mock_get_controller,
1319 ):
1320
1321 mock_get_application.side_effect = Exception()
1322
1323 with self.assertRaises(Exception):
1324 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001325 self.libjuju.configure_application(
1326 "model",
1327 "app",
1328 {"config"},
1329 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001330 )
David Garcia12b29242020-09-17 16:01:48 +02001331 mock_disconnect_controller.assert_called_once()
1332 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001333
David Garcia5b802c92020-11-11 16:56:06 +01001334 def test_controller_exception(
1335 self,
1336 mock_get_application,
1337 mock_disconnect_controller,
1338 mock_disconnect_model,
1339 mock_get_model,
1340 mock_get_controller,
1341 ):
1342
1343 result = {"error": "not found", "response": "response", "request-id": 1}
1344
1345 mock_get_controller.side_effect = JujuAPIError(result)
1346
1347 with self.assertRaises(JujuAPIError):
1348 self.loop.run_until_complete(
1349 self.libjuju.configure_application(
1350 "model",
1351 "app",
1352 {"config"},
1353 )
1354 )
1355 mock_get_model.assert_not_called()
1356 mock_disconnect_controller.assert_not_called()
1357 mock_disconnect_model.assert_not_called()
1358
1359 def test_get_model_exception(
1360 self,
1361 mock_get_application,
1362 mock_disconnect_controller,
1363 mock_disconnect_model,
1364 mock_get_model,
1365 mock_get_controller,
1366 ):
1367
1368 result = {"error": "not found", "response": "response", "request-id": 1}
1369 mock_get_model.side_effect = JujuAPIError(result)
1370
1371 with self.assertRaises(JujuAPIError):
1372 self.loop.run_until_complete(
1373 self.libjuju.configure_application(
1374 "model",
1375 "app",
1376 {"config"},
1377 )
1378 )
1379 mock_get_model.assert_called_once()
1380 mock_disconnect_controller.assert_called_once()
1381 mock_disconnect_model.assert_not_called()
1382
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001383
1384# TODO _get_api_endpoints_db test case
1385# TODO _update_api_endpoints_db test case
1386# TODO healthcheck test case
1387
1388
1389@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1390@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1391@asynctest.mock.patch("juju.controller.Controller.list_models")
1392class ListModelsTest(LibjujuTestCase):
1393 def setUp(self):
1394 super(ListModelsTest, self).setUp()
1395
1396 def test_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001397 self,
1398 mock_list_models,
1399 mock_disconnect_controller,
1400 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001401 ):
1402 mock_get_controller.return_value = juju.controller.Controller()
1403 mock_list_models.return_value = ["existingmodel"]
1404 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
1405
1406 mock_disconnect_controller.assert_called_once()
1407 self.assertEquals(models, ["existingmodel"])
1408
1409 def test_not_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001410 self,
1411 mock_list_models,
1412 mock_disconnect_controller,
1413 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001414 ):
1415 mock_get_controller.return_value = juju.controller.Controller()
1416 mock_list_models.return_value = ["existingmodel", "model"]
1417 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
1418
1419 mock_disconnect_controller.assert_called_once()
1420 self.assertEquals(models, [])
1421
1422 def test_no_contains_arg(
David Garcia5b802c92020-11-11 16:56:06 +01001423 self,
1424 mock_list_models,
1425 mock_disconnect_controller,
1426 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001427 ):
1428 mock_get_controller.return_value = juju.controller.Controller()
1429 mock_list_models.return_value = ["existingmodel", "model"]
1430 models = self.loop.run_until_complete(self.libjuju.list_models())
1431
1432 mock_disconnect_controller.assert_called_once()
1433 self.assertEquals(models, ["existingmodel", "model"])
David Garcia42f328a2020-08-25 15:03:01 +02001434
1435
1436@asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
1437class ModelsExistTest(LibjujuTestCase):
1438 def setUp(self):
1439 super(ModelsExistTest, self).setUp()
1440
1441 def test_model_names_none(self, mock_list_models):
1442 mock_list_models.return_value = []
1443 with self.assertRaises(Exception):
1444 self.loop.run_until_complete(self.libjuju.models_exist(None))
1445
1446 def test_model_names_empty(self, mock_list_models):
1447 mock_list_models.return_value = []
1448 with self.assertRaises(Exception):
1449 (exist, non_existing_models) = self.loop.run_until_complete(
1450 self.libjuju.models_exist([])
1451 )
1452
1453 def test_model_names_not_existing(self, mock_list_models):
1454 mock_list_models.return_value = ["prometheus", "grafana"]
1455 (exist, non_existing_models) = self.loop.run_until_complete(
1456 self.libjuju.models_exist(["prometheus2", "grafana"])
1457 )
1458 self.assertFalse(exist)
1459 self.assertEqual(non_existing_models, ["prometheus2"])
1460
1461 def test_model_names_exist(self, mock_list_models):
1462 mock_list_models.return_value = ["prometheus", "grafana"]
1463 (exist, non_existing_models) = self.loop.run_until_complete(
1464 self.libjuju.models_exist(["prometheus", "grafana"])
1465 )
1466 self.assertTrue(exist)
1467 self.assertEqual(non_existing_models, [])
David Garciabc538e42020-08-25 15:22:30 +02001468
1469
1470@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1471@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1472@asynctest.mock.patch("juju.controller.Controller.list_offers")
1473class ListOffers(LibjujuTestCase):
1474 def setUp(self):
1475 super(ListOffers, self).setUp()
1476
1477 def test_disconnect_controller(
David Garcia5b802c92020-11-11 16:56:06 +01001478 self,
1479 mock_list_offers,
1480 mock_disconnect_controller,
1481 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001482 ):
1483 mock_get_controller.return_value = juju.controller.Controller()
1484 mock_list_offers.side_effect = Exception()
1485 with self.assertRaises(Exception):
David Garcia582b9232021-10-26 12:30:44 +02001486 self.loop.run_until_complete(self.libjuju._list_offers("model"))
David Garciabc538e42020-08-25 15:22:30 +02001487 mock_disconnect_controller.assert_called_once()
1488
1489 def test_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001490 self,
1491 mock_list_offers,
1492 mock_disconnect_controller,
1493 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001494 ):
1495 mock_get_controller.return_value = juju.controller.Controller()
David Garcia582b9232021-10-26 12:30:44 +02001496 offer_results = Mock()
1497 offer_results.results = []
1498 mock_list_offers.return_value = offer_results
1499 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
David Garciabc538e42020-08-25 15:22:30 +02001500 self.assertEqual(offers, [])
1501 mock_disconnect_controller.assert_called_once()
1502
1503 def test_non_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001504 self,
1505 mock_list_offers,
1506 mock_disconnect_controller,
1507 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001508 ):
1509 mock_get_controller.return_value = juju.controller.Controller()
David Garcia582b9232021-10-26 12:30:44 +02001510 offer = Mock()
1511 offer_results = Mock()
1512 offer_results.results = [offer]
1513 mock_list_offers.return_value = offer_results
1514 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
1515 self.assertEqual(offers, [offer])
David Garciabc538e42020-08-25 15:22:30 +02001516 mock_disconnect_controller.assert_called_once()
David Garcia68b00722020-09-11 15:05:00 +02001517
David Garcia582b9232021-10-26 12:30:44 +02001518 def test_matching_offer_name(
1519 self,
1520 mock_list_offers,
1521 mock_disconnect_controller,
1522 mock_get_controller,
1523 ):
1524 mock_get_controller.return_value = juju.controller.Controller()
1525 offer_1 = Mock()
1526 offer_1.offer_name = "offer1"
1527 offer_2 = Mock()
1528 offer_2.offer_name = "offer2"
1529 offer_results = Mock()
1530 offer_results.results = [offer_1, offer_2]
1531 mock_list_offers.return_value = offer_results
1532 offers = self.loop.run_until_complete(
1533 self.libjuju._list_offers("model", offer_name="offer2")
1534 )
1535 self.assertEqual(offers, [offer_2])
1536 mock_disconnect_controller.assert_called_once()
1537
1538 def test_not_matching_offer_name(
1539 self,
1540 mock_list_offers,
1541 mock_disconnect_controller,
1542 mock_get_controller,
1543 ):
1544 mock_get_controller.return_value = juju.controller.Controller()
1545 offer_1 = Mock()
1546 offer_1.offer_name = "offer1"
1547 offer_2 = Mock()
1548 offer_2.offer_name = "offer2"
1549 offer_results = Mock()
1550 offer_results.results = [offer_1, offer_2]
1551 mock_list_offers.return_value = offer_results
1552 offers = self.loop.run_until_complete(
1553 self.libjuju._list_offers("model", offer_name="offer3")
1554 )
1555 self.assertEqual(offers, [])
1556 mock_disconnect_controller.assert_called_once()
1557
1558
1559@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1560@asynctest.mock.patch("juju.controller.Controller.get_model")
1561@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1562@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1563@asynctest.mock.patch("n2vc.libjuju.Libjuju._list_offers")
1564@asynctest.mock.patch("juju.model.Model.create_offer")
1565class OfferTest(LibjujuTestCase):
1566 def setUp(self):
1567 super(OfferTest, self).setUp()
1568
1569 def test_offer(
1570 self,
1571 mock_create_offer,
1572 mock__list_offers,
1573 mock_disconnect_controller,
1574 mock_disconnect_model,
1575 mock_get_model,
1576 mock_get_controller,
1577 ):
1578 controller = juju.controller.Controller()
1579 model = juju.model.Model()
1580 mock_get_controller.return_value = controller
1581 mock_get_model.return_value = model
1582 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1583 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1584 mock_create_offer.assert_called_with(
1585 "app-name:endpoint", offer_name="app-name-endpoint"
1586 )
1587 mock_disconnect_model.assert_called_once_with(model)
1588 mock_disconnect_controller.assert_called_once_with(controller)
1589
1590 def test_offer_exception(
1591 self,
1592 mock_create_offer,
1593 mock__list_offers,
1594 mock_disconnect_controller,
1595 mock_disconnect_model,
1596 mock_get_model,
1597 mock_get_controller,
1598 ):
1599 controller = juju.controller.Controller()
1600 model = juju.model.Model()
1601 mock_get_controller.return_value = controller
1602 mock_get_model.return_value = model
1603 mock__list_offers.return_value = []
1604 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1605 with self.assertRaises(Exception):
1606 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1607 mock_create_offer.assert_called_with(
1608 "app-name:endpoint", offer_name="app-name-endpoint"
1609 )
1610 mock_disconnect_model.assert_called_once_with(model)
1611 mock_disconnect_controller.assert_called_once_with(controller)
1612
David Garcia68b00722020-09-11 15:05:00 +02001613
1614@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1615@asynctest.mock.patch("juju.controller.Controller.get_model")
1616@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1617@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1618@asynctest.mock.patch("juju.model.Model.consume")
1619class ConsumeTest(LibjujuTestCase):
1620 def setUp(self):
David Garcia582b9232021-10-26 12:30:44 +02001621 self.offer_url = "admin/model.offer_name"
David Garcia68b00722020-09-11 15:05:00 +02001622 super(ConsumeTest, self).setUp()
David Garcia582b9232021-10-26 12:30:44 +02001623 self.provider_libjuju = self.libjuju
David Garcia68b00722020-09-11 15:05:00 +02001624
1625 def test_consume(
1626 self,
1627 mock_consume,
1628 mock_disconnect_controller,
1629 mock_disconnect_model,
1630 mock_get_model,
1631 mock_get_controller,
1632 ):
David Garcia582b9232021-10-26 12:30:44 +02001633 self_controller = juju.controller.Controller()
1634 provider_controller = juju.controller.Controller()
1635 mock_get_controller.side_effect = [self_controller, provider_controller]
David Garcia68b00722020-09-11 15:05:00 +02001636 mock_get_model.return_value = juju.model.Model()
1637
David Garcia582b9232021-10-26 12:30:44 +02001638 self.loop.run_until_complete(
1639 self.libjuju.consume(
1640 "model_name",
1641 Offer(self.offer_url, vca_id="vca-id"),
1642 self.provider_libjuju,
1643 )
1644 )
1645 mock_consume.assert_called_once_with(
1646 "admin/model.offer_name",
1647 application_alias="offer_name-model-vca-id",
1648 controller=provider_controller,
1649 )
David Garcia68b00722020-09-11 15:05:00 +02001650 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001651 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia68b00722020-09-11 15:05:00 +02001652
1653 def test_parsing_error_exception(
1654 self,
1655 mock_consume,
1656 mock_disconnect_controller,
1657 mock_disconnect_model,
1658 mock_get_model,
1659 mock_get_controller,
1660 ):
1661 mock_get_controller.return_value = juju.controller.Controller()
1662 mock_get_model.return_value = juju.model.Model()
1663 mock_consume.side_effect = juju.offerendpoints.ParseError("")
1664
1665 with self.assertRaises(juju.offerendpoints.ParseError):
1666 self.loop.run_until_complete(
David Garcia582b9232021-10-26 12:30:44 +02001667 self.libjuju.consume(
1668 "model_name", Offer(self.offer_url), self.provider_libjuju
1669 )
David Garcia68b00722020-09-11 15:05:00 +02001670 )
1671 mock_consume.assert_called_once()
1672 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001673 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia68b00722020-09-11 15:05:00 +02001674
1675 def test_juju_error_exception(
1676 self,
1677 mock_consume,
1678 mock_disconnect_controller,
1679 mock_disconnect_model,
1680 mock_get_model,
1681 mock_get_controller,
1682 ):
1683 mock_get_controller.return_value = juju.controller.Controller()
1684 mock_get_model.return_value = juju.model.Model()
1685 mock_consume.side_effect = juju.errors.JujuError("")
1686
1687 with self.assertRaises(juju.errors.JujuError):
1688 self.loop.run_until_complete(
David Garcia582b9232021-10-26 12:30:44 +02001689 self.libjuju.consume(
1690 "model_name", Offer(self.offer_url), self.provider_libjuju
1691 )
David Garcia68b00722020-09-11 15:05:00 +02001692 )
1693 mock_consume.assert_called_once()
1694 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001695 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia68b00722020-09-11 15:05:00 +02001696
1697 def test_juju_api_error_exception(
1698 self,
1699 mock_consume,
1700 mock_disconnect_controller,
1701 mock_disconnect_model,
1702 mock_get_model,
1703 mock_get_controller,
1704 ):
1705 mock_get_controller.return_value = juju.controller.Controller()
1706 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +02001707 mock_consume.side_effect = juju.errors.JujuAPIError(
1708 {"error": "", "response": "", "request-id": ""}
1709 )
David Garcia68b00722020-09-11 15:05:00 +02001710
1711 with self.assertRaises(juju.errors.JujuAPIError):
1712 self.loop.run_until_complete(
David Garcia582b9232021-10-26 12:30:44 +02001713 self.libjuju.consume(
1714 "model_name", Offer(self.offer_url), self.provider_libjuju
1715 )
David Garcia68b00722020-09-11 15:05:00 +02001716 )
1717 mock_consume.assert_called_once()
1718 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001719 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia12b29242020-09-17 16:01:48 +02001720
1721
David Garcia475a7222020-09-21 16:19:15 +02001722@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
David Garcia12b29242020-09-17 16:01:48 +02001723@asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
1724class AddK8sTest(LibjujuTestCase):
1725 def setUp(self):
1726 super(AddK8sTest, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001727 name = "cloud"
1728 rbac_id = generate_rbac_id()
1729 token = "token"
1730 client_cert_data = "cert"
1731 configuration = kubernetes.client.configuration.Configuration()
1732 storage_class = "storage_class"
1733 credential_name = name
1734
1735 self._add_k8s_args = {
1736 "name": name,
1737 "rbac_id": rbac_id,
1738 "token": token,
1739 "client_cert_data": client_cert_data,
1740 "configuration": configuration,
1741 "storage_class": storage_class,
1742 "credential_name": credential_name,
1743 }
David Garcia12b29242020-09-17 16:01:48 +02001744
David Garcia475a7222020-09-21 16:19:15 +02001745 def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001746 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001747 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001748 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001749
David Garcia475a7222020-09-21 16:19:15 +02001750 def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garcia12b29242020-09-17 16:01:48 +02001751 mock_add_cloud.side_effect = Exception()
1752 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001753 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001754 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001755 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001756
David Garcia475a7222020-09-21 16:19:15 +02001757 def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001758 self._add_k8s_args["name"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001759 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001760 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001761 mock_add_cloud.assert_not_called()
1762
David Garcia475a7222020-09-21 16:19:15 +02001763 def test_add_k8s_missing_storage_name(
1764 self, mock_add_cloud, mock_get_k8s_cloud_credential
1765 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001766 self._add_k8s_args["storage_class"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001767 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001768 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001769 mock_add_cloud.assert_not_called()
1770
David Garcia475a7222020-09-21 16:19:15 +02001771 def test_add_k8s_missing_configuration_keys(
1772 self, mock_add_cloud, mock_get_k8s_cloud_credential
1773 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001774 self._add_k8s_args["configuration"] = None
David Garcia12b29242020-09-17 16:01:48 +02001775 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001776 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001777 mock_add_cloud.assert_not_called()
1778
1779
1780@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1781@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1782@asynctest.mock.patch("juju.controller.Controller.add_cloud")
1783@asynctest.mock.patch("juju.controller.Controller.add_credential")
1784class AddCloudTest(LibjujuTestCase):
1785 def setUp(self):
1786 super(AddCloudTest, self).setUp()
1787 self.cloud = juju.client.client.Cloud()
1788 self.credential = juju.client.client.CloudCredential()
1789
1790 def test_add_cloud_with_credential(
1791 self,
1792 mock_add_credential,
1793 mock_add_cloud,
1794 mock_disconnect_controller,
1795 mock_get_controller,
1796 ):
1797 mock_get_controller.return_value = juju.controller.Controller()
1798
1799 cloud = self.loop.run_until_complete(
1800 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1801 )
1802 self.assertEqual(cloud, self.cloud)
1803 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1804 mock_add_credential.assert_called_once_with(
1805 "cloud", credential=self.credential, cloud="cloud"
1806 )
1807 mock_disconnect_controller.assert_called_once()
1808
1809 def test_add_cloud_no_credential(
1810 self,
1811 mock_add_credential,
1812 mock_add_cloud,
1813 mock_disconnect_controller,
1814 mock_get_controller,
1815 ):
1816 mock_get_controller.return_value = juju.controller.Controller()
1817
1818 cloud = self.loop.run_until_complete(
1819 self.libjuju.add_cloud("cloud", self.cloud)
1820 )
1821 self.assertEqual(cloud, self.cloud)
1822 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1823 mock_add_credential.assert_not_called()
1824 mock_disconnect_controller.assert_called_once()
1825
1826 def test_add_cloud_exception(
1827 self,
1828 mock_add_credential,
1829 mock_add_cloud,
1830 mock_disconnect_controller,
1831 mock_get_controller,
1832 ):
1833 mock_get_controller.return_value = juju.controller.Controller()
1834 mock_add_cloud.side_effect = Exception()
1835 with self.assertRaises(Exception):
1836 self.loop.run_until_complete(
1837 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1838 )
1839
1840 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1841 mock_add_credential.assert_not_called()
1842 mock_disconnect_controller.assert_called_once()
1843
1844 def test_add_credential_exception(
1845 self,
1846 mock_add_credential,
1847 mock_add_cloud,
1848 mock_disconnect_controller,
1849 mock_get_controller,
1850 ):
1851 mock_get_controller.return_value = juju.controller.Controller()
1852 mock_add_credential.side_effect = Exception()
1853 with self.assertRaises(Exception):
1854 self.loop.run_until_complete(
1855 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1856 )
1857
1858 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1859 mock_add_credential.assert_called_once_with(
1860 "cloud", credential=self.credential, cloud="cloud"
1861 )
1862 mock_disconnect_controller.assert_called_once()
1863
1864
1865@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1866@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1867@asynctest.mock.patch("juju.controller.Controller.remove_cloud")
1868class RemoveCloudTest(LibjujuTestCase):
1869 def setUp(self):
1870 super(RemoveCloudTest, self).setUp()
1871
1872 def test_remove_cloud(
David Garcia5b802c92020-11-11 16:56:06 +01001873 self,
1874 mock_remove_cloud,
1875 mock_disconnect_controller,
1876 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001877 ):
1878 mock_get_controller.return_value = juju.controller.Controller()
1879
1880 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1881 mock_remove_cloud.assert_called_once_with("cloud")
1882 mock_disconnect_controller.assert_called_once()
1883
1884 def test_remove_cloud_exception(
David Garcia5b802c92020-11-11 16:56:06 +01001885 self,
1886 mock_remove_cloud,
1887 mock_disconnect_controller,
1888 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001889 ):
1890 mock_get_controller.return_value = juju.controller.Controller()
1891 mock_remove_cloud.side_effect = Exception()
1892
1893 with self.assertRaises(Exception):
1894 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1895 mock_remove_cloud.assert_called_once_with("cloud")
1896 mock_disconnect_controller.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001897
1898
1899@asynctest.mock.patch("kubernetes.client.configuration.Configuration")
1900class GetK8sCloudCredentials(LibjujuTestCase):
1901 def setUp(self):
1902 super(GetK8sCloudCredentials, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001903 self.cert_data = "cert"
1904 self.token = "token"
David Garcia475a7222020-09-21 16:19:15 +02001905
1906 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1907 def test_not_supported(self, mock_exception, mock_configuration):
1908 mock_configuration.username = ""
1909 mock_configuration.password = ""
1910 mock_configuration.ssl_ca_cert = None
1911 mock_configuration.cert_file = None
1912 mock_configuration.key_file = None
1913 exception_raised = False
David Garciaf6e9b002020-11-27 15:32:02 +01001914 self.token = None
1915 self.cert_data = None
David Garcia475a7222020-09-21 16:19:15 +02001916 try:
David Garciaf6e9b002020-11-27 15:32:02 +01001917 _ = self.libjuju.get_k8s_cloud_credential(
1918 mock_configuration,
1919 self.cert_data,
1920 self.token,
1921 )
David Garcia475a7222020-09-21 16:19:15 +02001922 except JujuInvalidK8sConfiguration as e:
1923 exception_raised = True
1924 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01001925 e.message,
1926 "authentication method not supported",
David Garcia475a7222020-09-21 16:19:15 +02001927 )
1928 self.assertTrue(exception_raised)
1929
1930 def test_user_pass(self, mock_configuration):
1931 mock_configuration.username = "admin"
1932 mock_configuration.password = "admin"
1933 mock_configuration.ssl_ca_cert = None
1934 mock_configuration.cert_file = None
1935 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001936 self.token = None
1937 self.cert_data = None
1938 credential = self.libjuju.get_k8s_cloud_credential(
1939 mock_configuration,
1940 self.cert_data,
1941 self.token,
1942 )
David Garcia475a7222020-09-21 16:19:15 +02001943 self.assertEqual(
1944 credential,
1945 juju.client._definitions.CloudCredential(
1946 attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
1947 ),
1948 )
1949
David Garciaf6e9b002020-11-27 15:32:02 +01001950 def test_user_pass_with_cert(self, mock_configuration):
1951 mock_configuration.username = "admin"
1952 mock_configuration.password = "admin"
1953 mock_configuration.ssl_ca_cert = None
1954 mock_configuration.cert_file = None
1955 mock_configuration.key_file = None
1956 self.token = None
1957 credential = self.libjuju.get_k8s_cloud_credential(
1958 mock_configuration,
1959 self.cert_data,
1960 self.token,
1961 )
1962 self.assertEqual(
1963 credential,
1964 juju.client._definitions.CloudCredential(
1965 attrs={
1966 "ClientCertificateData": self.cert_data,
1967 "username": "admin",
1968 "password": "admin",
1969 },
1970 auth_type="userpasswithcert",
1971 ),
1972 )
1973
David Garcia475a7222020-09-21 16:19:15 +02001974 def test_user_no_pass(self, mock_configuration):
1975 mock_configuration.username = "admin"
1976 mock_configuration.password = ""
1977 mock_configuration.ssl_ca_cert = None
1978 mock_configuration.cert_file = None
1979 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001980 self.token = None
1981 self.cert_data = None
David Garciaeb8943a2021-04-12 12:07:37 +02001982 with patch.object(self.libjuju.log, "debug") as mock_debug:
David Garciaf6e9b002020-11-27 15:32:02 +01001983 credential = self.libjuju.get_k8s_cloud_credential(
1984 mock_configuration,
1985 self.cert_data,
1986 self.token,
1987 )
David Garcia475a7222020-09-21 16:19:15 +02001988 self.assertEqual(
1989 credential,
1990 juju.client._definitions.CloudCredential(
1991 attrs={"username": "admin", "password": ""}, auth_type="userpass"
1992 ),
1993 )
1994 mock_debug.assert_called_once_with(
1995 "credential for user admin has empty password"
1996 )
1997
David Garcia475a7222020-09-21 16:19:15 +02001998 def test_cert(self, mock_configuration):
1999 mock_configuration.username = ""
2000 mock_configuration.password = ""
2001 mock_configuration.api_key = {"authorization": "Bearer Token"}
2002 ssl_ca_cert = tempfile.NamedTemporaryFile()
2003 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
2004 ssl_ca_cert_file.write("cacert")
2005 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
2006 mock_configuration.cert_file = None
2007 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01002008 credential = self.libjuju.get_k8s_cloud_credential(
2009 mock_configuration,
2010 self.cert_data,
2011 self.token,
2012 )
David Garcia475a7222020-09-21 16:19:15 +02002013 self.assertEqual(
2014 credential,
2015 juju.client._definitions.CloudCredential(
David Garciaf6e9b002020-11-27 15:32:02 +01002016 attrs={"ClientCertificateData": self.cert_data, "Token": self.token},
David Garcia475a7222020-09-21 16:19:15 +02002017 auth_type="certificate",
2018 ),
2019 )
2020
David Garciaf6e9b002020-11-27 15:32:02 +01002021 # TODO: Fix this test when oauth authentication is supported
2022 # def test_oauth2(self, mock_configuration):
2023 # mock_configuration.username = ""
2024 # mock_configuration.password = ""
2025 # mock_configuration.api_key = {"authorization": "Bearer Token"}
2026 # key = tempfile.NamedTemporaryFile()
2027 # with open(key.name, "w") as key_file:
2028 # key_file.write("key")
2029 # mock_configuration.ssl_ca_cert = None
2030 # mock_configuration.cert_file = None
2031 # mock_configuration.key_file = key.name
2032 # credential = self.libjuju.get_k8s_cloud_credential(
2033 # mock_configuration,
2034 # self.cert_data,
2035 # self.token,
2036 # )
2037 # self.assertEqual(
2038 # credential,
2039 # juju.client._definitions.CloudCredential(
2040 # attrs={"ClientKeyData": "key", "Token": "Token"},
2041 # auth_type="oauth2",
2042 # ),
2043 # )
David Garcia475a7222020-09-21 16:19:15 +02002044
David Garciaf6e9b002020-11-27 15:32:02 +01002045 # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
2046 # def test_oauth2_missing_token(self, mock_exception, mock_configuration):
2047 # mock_configuration.username = ""
2048 # mock_configuration.password = ""
2049 # key = tempfile.NamedTemporaryFile()
2050 # with open(key.name, "w") as key_file:
2051 # key_file.write("key")
2052 # mock_configuration.ssl_ca_cert = None
2053 # mock_configuration.cert_file = None
2054 # mock_configuration.key_file = key.name
2055 # exception_raised = False
2056 # try:
2057 # _ = self.libjuju.get_k8s_cloud_credential(
2058 # mock_configuration,
2059 # self.cert_data,
2060 # self.token,
2061 # )
2062 # except JujuInvalidK8sConfiguration as e:
2063 # exception_raised = True
2064 # self.assertEqual(
2065 # e.message,
2066 # "missing token for auth type oauth2",
2067 # )
2068 # self.assertTrue(exception_raised)
David Garcia475a7222020-09-21 16:19:15 +02002069
2070 def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
2071 mock_configuration.username = "admin"
2072 mock_configuration.password = "pass"
2073 mock_configuration.api_key = {"authorization": "No_bearer_token"}
2074 mock_configuration.ssl_ca_cert = None
2075 mock_configuration.cert_file = None
2076 mock_configuration.key_file = None
2077 exception_raised = False
2078 try:
David Garciaf6e9b002020-11-27 15:32:02 +01002079 _ = self.libjuju.get_k8s_cloud_credential(
2080 mock_configuration,
2081 self.cert_data,
2082 self.token,
2083 )
David Garcia475a7222020-09-21 16:19:15 +02002084 except JujuInvalidK8sConfiguration as e:
2085 exception_raised = True
2086 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01002087 e.message,
2088 "Cannot set both token and user/pass",
David Garcia475a7222020-09-21 16:19:15 +02002089 )
2090 self.assertTrue(exception_raised)
aktas2962f3e2021-03-15 11:05:35 +03002091
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._get_application")
2096@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2097@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2098@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
2099class ScaleApplicationTest(LibjujuTestCase):
2100 def setUp(self):
2101 super(ScaleApplicationTest, self).setUp()
2102
2103 @asynctest.mock.patch("asyncio.sleep")
2104 def test_scale_application(
2105 self,
2106 mock_sleep,
2107 mock_wait_for_model,
2108 mock_disconnect_controller,
2109 mock_disconnect_model,
2110 mock_get_application,
2111 mock_get_model,
2112 mock_get_controller,
2113 ):
2114 mock_get_model.return_value = juju.model.Model()
2115 mock_get_application.return_value = FakeApplication()
garciadeblas82b591c2021-03-24 09:22:13 +01002116 self.loop.run_until_complete(self.libjuju.scale_application("model", "app", 2))
aktas2962f3e2021-03-15 11:05:35 +03002117 mock_wait_for_model.assert_called_once()
2118 mock_disconnect_controller.assert_called_once()
2119 mock_disconnect_model.assert_called_once()
2120
2121 def test_no_application(
2122 self,
2123 mock_wait_for,
2124 mock_disconnect_controller,
2125 mock_disconnect_model,
2126 mock_get_application,
2127 mock_get_model,
2128 mock_get_controller,
2129 ):
2130 mock_get_application.return_value = None
2131 mock_get_model.return_value = juju.model.Model()
2132 with self.assertRaises(JujuApplicationNotFound):
2133 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01002134 self.libjuju.scale_application("model", "app", 2)
aktas2962f3e2021-03-15 11:05:35 +03002135 )
2136 mock_disconnect_controller.assert_called()
2137 mock_disconnect_model.assert_called()
2138
2139 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01002140 self,
2141 mock_wait_for,
2142 mock_disconnect_controller,
2143 mock_disconnect_model,
2144 mock_get_application,
2145 mock_get_model,
2146 mock_get_controller,
aktas2962f3e2021-03-15 11:05:35 +03002147 ):
2148 mock_get_model.return_value = None
2149 mock_get_application.return_value = FakeApplication()
2150 with self.assertRaises(Exception):
2151 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01002152 self.libjuju.scale_application("model", "app", 2, total_timeout=0)
aktas2962f3e2021-03-15 11:05:35 +03002153 )
2154 mock_disconnect_controller.assert_called_once()
2155
2156
2157@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2158class GetUnitNumberTest(LibjujuTestCase):
2159 def setUp(self):
2160 super(GetUnitNumberTest, self).setUp()
2161
aktasfa02f8a2021-07-29 17:41:40 +03002162 def test_successful_get_unit_number(
aktas2962f3e2021-03-15 11:05:35 +03002163 self,
2164 mock_get_applications,
2165 ):
2166 mock_get_applications.return_value = FakeApplication()
2167 model = juju.model.Model()
2168 result = self.libjuju._get_application_count(model, "app")
2169 self.assertEqual(result, 2)
2170
2171 def test_non_existing_application(
2172 self,
2173 mock_get_applications,
2174 ):
2175 mock_get_applications.return_value = None
2176 model = juju.model.Model()
2177 result = self.libjuju._get_application_count(model, "app")
2178 self.assertEqual(result, None)
aktasfa02f8a2021-07-29 17:41:40 +03002179
2180
2181@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
2182class GetMachineInfoTest(LibjujuTestCase):
2183 def setUp(self):
2184 super(GetMachineInfoTest, self).setUp()
2185
2186 def test_successful(
2187 self,
2188 mock_machines,
2189 ):
2190 machine_id = "existing_machine"
2191 model = juju.model.Model()
2192 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2193 machine, series = self.libjuju._get_machine_info(
2194 machine_id=machine_id,
2195 model=model,
2196 )
2197 self.assertIsNotNone(machine, series)
2198
2199 def test_exception(
2200 self,
2201 mock_machines,
2202 ):
2203 machine_id = "not_existing_machine"
2204 machine = series = None
2205 model = juju.model.Model()
2206 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2207 with self.assertRaises(JujuMachineNotFound):
2208 machine, series = self.libjuju._get_machine_info(
2209 machine_id=machine_id,
2210 model=model,
2211 )
2212 self.assertIsNone(machine, series)
2213
2214
2215class GetUnitTest(LibjujuTestCase):
2216 def setUp(self):
2217 super(GetUnitTest, self).setUp()
2218
2219 def test_successful(self):
2220 result = self.libjuju._get_unit(FakeApplication(), "existing_machine_id")
2221 self.assertIsInstance(result, FakeUnit)
2222
2223 def test_return_none(self):
2224 result = self.libjuju._get_unit(FakeApplication(), "not_existing_machine_id")
2225 self.assertIsNone(result)
2226
2227
2228@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2229@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2230@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2231@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2232@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2233class CheckApplicationExists(LibjujuTestCase):
2234 def setUp(self):
2235 super(CheckApplicationExists, self).setUp()
2236
2237 def test_successful(
2238 self,
2239 mock_get_application,
2240 mock_disconnect_controller,
2241 mock_disconnect_model,
2242 mock_get_model,
2243 mock_get_controller,
2244 ):
2245 mock_get_model.return_value = juju.model.Model()
2246 mock_get_application.return_value = FakeApplication()
2247 result = self.loop.run_until_complete(
2248 self.libjuju.check_application_exists(
2249 "model",
2250 "app",
2251 )
2252 )
2253 self.assertEqual(result, True)
2254
2255 mock_get_application.assert_called_once()
2256 mock_get_controller.assert_called_once()
2257 mock_get_model.assert_called_once()
2258 mock_disconnect_controller.assert_called_once()
2259 mock_disconnect_model.assert_called_once()
2260
2261 def test_no_application(
2262 self,
2263 mock_get_application,
2264 mock_disconnect_controller,
2265 mock_disconnect_model,
2266 mock_get_model,
2267 mock_get_controller,
2268 ):
2269 mock_get_model.return_value = juju.model.Model()
2270 mock_get_application.return_value = None
2271 result = self.loop.run_until_complete(
2272 self.libjuju.check_application_exists(
2273 "model",
2274 "app",
2275 )
2276 )
2277 self.assertEqual(result, False)
2278
2279 mock_get_application.assert_called_once()
2280 mock_get_controller.assert_called_once()
2281 mock_get_model.assert_called_once()
2282 mock_disconnect_controller.assert_called_once()
2283 mock_disconnect_model.assert_called_once()
2284
2285
2286@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2287@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2288@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2289@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2290@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2291@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_machine_info")
2292class AddUnitTest(LibjujuTestCase):
2293 def setUp(self):
2294 super(AddUnitTest, self).setUp()
2295
2296 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
2297 @asynctest.mock.patch("asyncio.sleep")
2298 def test_successful(
2299 self,
2300 mock_sleep,
2301 mock_wait_for,
2302 mock_get_machine_info,
2303 mock_get_application,
2304 mock_disconnect_controller,
2305 mock_disconnect_model,
2306 mock_get_model,
2307 mock_get_controller,
2308 ):
2309 mock_get_model.return_value = juju.model.Model()
2310 mock_get_application.return_value = FakeApplication()
2311 mock_get_machine_info.return_value = FakeMachine(), "series"
2312 self.loop.run_until_complete(
2313 self.libjuju.add_unit(
2314 "existing_app",
2315 "model",
2316 "machine",
2317 )
2318 )
2319
2320 mock_wait_for.assert_called_once()
2321 mock_get_application.assert_called_once()
2322 mock_get_controller.assert_called_once()
2323 mock_get_model.assert_called_once()
2324 mock_disconnect_controller.assert_called_once()
2325 mock_disconnect_model.assert_called_once()
2326
2327 def test_no_app(
2328 self,
2329 mock_get_machine_info,
2330 mock_get_application,
2331 mock_disconnect_controller,
2332 mock_disconnect_model,
2333 mock_get_model,
2334 mock_get_controller,
2335 ):
2336 mock_get_model.return_value = juju.model.Model()
2337 mock_get_application.return_value = None
2338 with self.assertRaises(JujuApplicationNotFound):
2339 self.loop.run_until_complete(
2340 self.libjuju.add_unit(
2341 "existing_app",
2342 "model",
2343 "machine",
2344 )
2345 )
2346
2347 mock_get_application.assert_called_once()
2348 mock_get_controller.assert_called_once()
2349 mock_get_model.assert_called_once()
2350 mock_disconnect_controller.assert_called_once()
2351 mock_disconnect_model.assert_called_once()
2352
2353 def test_no_machine(
2354 self,
2355 mock_get_machine_info,
2356 mock_get_application,
2357 mock_disconnect_controller,
2358 mock_disconnect_model,
2359 mock_get_model,
2360 mock_get_controller,
2361 ):
2362 mock_get_model.return_value = juju.model.Model()
2363 mock_get_application.return_value = FakeApplication()
2364 mock_get_machine_info.side_effect = JujuMachineNotFound()
2365 with self.assertRaises(JujuMachineNotFound):
2366 self.loop.run_until_complete(
2367 self.libjuju.add_unit(
2368 "existing_app",
2369 "model",
2370 "machine",
2371 )
2372 )
2373
2374 mock_get_application.assert_called_once()
2375 mock_get_controller.assert_called_once()
2376 mock_get_model.assert_called_once()
2377 mock_disconnect_controller.assert_called_once()
2378 mock_disconnect_model.assert_called_once()
2379
2380
2381@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2382@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2383@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2384@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2385@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2386@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_unit")
2387class DestroyUnitTest(LibjujuTestCase):
2388 def setUp(self):
2389 super(DestroyUnitTest, self).setUp()
2390
2391 @asynctest.mock.patch("asyncio.sleep")
2392 def test_successful(
2393 self,
2394 mock_sleep,
2395 mock_get_unit,
2396 mock_get_application,
2397 mock_disconnect_controller,
2398 mock_disconnect_model,
2399 mock_get_model,
2400 mock_get_controller,
2401 ):
2402 mock_get_model.return_value = juju.model.Model()
2403 mock_get_application.return_value = FakeApplication()
2404
2405 self.loop.run_until_complete(
2406 self.libjuju.destroy_unit("app", "model", "machine", 0)
2407 )
2408
2409 mock_get_unit.assert_called()
2410 mock_get_application.assert_called_once()
2411 mock_get_controller.assert_called_once()
2412 mock_get_model.assert_called_once()
2413 mock_disconnect_controller.assert_called_once()
2414 mock_disconnect_model.assert_called_once()
2415
2416 def test_no_app(
2417 self,
2418 mock_get_unit,
2419 mock_get_application,
2420 mock_disconnect_controller,
2421 mock_disconnect_model,
2422 mock_get_model,
2423 mock_get_controller,
2424 ):
2425 mock_get_model.return_value = juju.model.Model()
2426 mock_get_application.return_value = None
2427
2428 with self.assertRaises(JujuApplicationNotFound):
2429 self.loop.run_until_complete(
2430 self.libjuju.destroy_unit("app", "model", "machine")
2431 )
2432
2433 mock_get_application.assert_called_once()
2434 mock_get_controller.assert_called_once()
2435 mock_get_model.assert_called_once()
2436 mock_disconnect_controller.assert_called_once()
2437 mock_disconnect_model.assert_called_once()
2438
2439 def test_no_unit(
2440 self,
2441 mock_get_unit,
2442 mock_get_application,
2443 mock_disconnect_controller,
2444 mock_disconnect_model,
2445 mock_get_model,
2446 mock_get_controller,
2447 ):
2448 mock_get_model.return_value = juju.model.Model()
2449 mock_get_application.return_value = FakeApplication()
2450 mock_get_unit.return_value = None
2451
2452 with self.assertRaises(JujuError):
2453 self.loop.run_until_complete(
2454 self.libjuju.destroy_unit("app", "model", "machine")
2455 )
2456
2457 mock_get_unit.assert_called_once()
2458 mock_get_application.assert_called_once()
2459 mock_get_controller.assert_called_once()
2460 mock_get_model.assert_called_once()
2461 mock_disconnect_controller.assert_called_once()
2462 mock_disconnect_model.assert_called_once()