blob: 056a98d3d68cbb953c6f74f586926aa6f0fedad7 [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")
1010 def test_already_exists(
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 # TODO in libjuju.py should this fail silently?
1020 result = {"error": "already exists", "response": "response", "request-id": 1}
1021
1022 mock_get_model.return_value = juju.model.Model()
1023 mock_add_relation.side_effect = JujuAPIError(result)
1024
1025 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001026 self.libjuju.add_relation(
1027 "model",
1028 "app1:relation1",
1029 "app2:relation2",
1030 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001031 )
1032
1033 mock_warning.assert_called_with("Relation already exists: already exists")
1034 mock_disconnect_controller.assert_called_once()
1035 mock_disconnect_model.assert_called_once()
1036
1037 def test_exception(
1038 self,
1039 mock_add_relation,
1040 mock_disconnect_controller,
1041 mock_disconnect_model,
1042 mock_get_model,
1043 mock_get_controller,
1044 ):
1045 mock_get_model.return_value = juju.model.Model()
1046 result = {"error": "", "response": "response", "request-id": 1}
1047 mock_add_relation.side_effect = JujuAPIError(result)
1048
1049 with self.assertRaises(JujuAPIError):
1050 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001051 self.libjuju.add_relation(
1052 "model",
1053 "app1:relation1",
1054 "app2:relation2",
1055 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001056 )
1057
David Garcia12b29242020-09-17 16:01:48 +02001058 mock_disconnect_controller.assert_called_once()
1059 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001060
1061 def test_success(
1062 self,
1063 mock_add_relation,
1064 mock_disconnect_controller,
1065 mock_disconnect_model,
1066 mock_get_model,
1067 mock_get_controller,
1068 ):
1069 mock_get_model.return_value = juju.model.Model()
1070
1071 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001072 self.libjuju.add_relation(
1073 "model",
1074 "app1:relation1",
1075 "app2:relation2",
1076 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001077 )
1078
David Garcia12b29242020-09-17 16:01:48 +02001079 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
David Garcia8331f7c2020-08-25 16:10:07 +02001080 mock_disconnect_controller.assert_called_once()
1081 mock_disconnect_model.assert_called_once()
1082
1083 def test_saas(
1084 self,
1085 mock_add_relation,
1086 mock_disconnect_controller,
1087 mock_disconnect_model,
1088 mock_get_model,
1089 mock_get_controller,
1090 ):
1091 mock_get_model.return_value = juju.model.Model()
1092
1093 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001094 self.libjuju.add_relation(
1095 "model",
1096 "app1:relation1",
1097 "saas_name",
1098 )
David Garcia8331f7c2020-08-25 16:10:07 +02001099 )
1100
David Garcia12b29242020-09-17 16:01:48 +02001101 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001102 mock_disconnect_controller.assert_called_once()
1103 mock_disconnect_model.assert_called_once()
1104
1105
1106# TODO destroy_model testcase
1107
1108
aktas56120292021-02-26 15:32:39 +03001109@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1110@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1111@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1112@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1113@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1114class DestroyApplicationTest(LibjujuTestCase):
1115 def setUp(self):
1116 super(DestroyApplicationTest, self).setUp()
1117
1118 def test_success(
garciadeblas82b591c2021-03-24 09:22:13 +01001119 self,
1120 mock_get_controller,
1121 mock_get_model,
1122 mock_disconnect_controller,
1123 mock_get_application,
1124 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001125 ):
1126 mock_get_application.return_value = FakeApplication()
1127 mock_get_model.return_value = None
1128 self.loop.run_until_complete(
1129 self.libjuju.destroy_application(
1130 "existing_model",
1131 "existing_app",
1132 3600,
1133 )
1134 )
1135 mock_get_application.assert_called()
1136 mock_disconnect_controller.assert_called_once()
1137 mock_disconnect_model.assert_called_once()
1138
1139 def test_no_application(
garciadeblas82b591c2021-03-24 09:22:13 +01001140 self,
1141 mock_get_controller,
1142 mock_get_model,
1143 mock_disconnect_controller,
1144 mock_get_application,
1145 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001146 ):
1147 mock_get_model.return_value = None
1148 mock_get_application.return_value = None
1149
1150 self.loop.run_until_complete(
1151 self.libjuju.destroy_application(
1152 "existing_model",
1153 "existing_app",
1154 3600,
1155 )
1156 )
1157 mock_get_application.assert_called()
1158
1159 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01001160 self,
1161 mock_get_controller,
1162 mock_get_model,
1163 mock_disconnect_controller,
1164 mock_get_application,
1165 mock_disconnect_model,
aktas56120292021-02-26 15:32:39 +03001166 ):
1167 mock_get_application.return_value = FakeApplication
1168 mock_get_model.return_value = None
1169
1170 with self.assertRaises(Exception):
1171 self.loop.run_until_complete(
1172 self.libjuju.destroy_application(
1173 "existing_model",
1174 "existing_app",
1175 0,
1176 )
1177 )
1178 mock_get_application.assert_called_once()
1179
1180
David Garcia5ef42a12020-09-29 19:48:13 +02001181# @asynctest.mock.patch("juju.model.Model.get_machines")
1182# @asynctest.mock.patch("logging.Logger.debug")
1183# class DestroyMachineTest(LibjujuTestCase):
1184# def setUp(self):
1185# super(DestroyMachineTest, self).setUp()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001186
David Garcia5ef42a12020-09-29 19:48:13 +02001187# def test_success_manual_machine(
1188# self, mock_debug, mock_get_machines,
1189# ):
1190# mock_get_machines.side_effect = [
1191# {"machine": FakeManualMachine()},
1192# {"machine": FakeManualMachine()},
1193# {},
1194# ]
1195# self.loop.run_until_complete(
1196# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
1197# )
1198# calls = [
1199# asynctest.call("Waiting for machine machine is destroyed"),
1200# asynctest.call("Machine destroyed: machine"),
1201# ]
1202# mock_debug.assert_has_calls(calls)
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001203
David Garcia5ef42a12020-09-29 19:48:13 +02001204# def test_no_machine(
1205# self, mock_debug, mock_get_machines,
1206# ):
1207# mock_get_machines.return_value = {}
1208# self.loop.run_until_complete(
1209# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
1210# )
1211# mock_debug.assert_called_with("Machine not found: machine")
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001212
1213
1214@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1215@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
1216@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1217@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1218@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
1219class ConfigureApplicationTest(LibjujuTestCase):
1220 def setUp(self):
1221 super(ConfigureApplicationTest, self).setUp()
1222
1223 def test_success(
1224 self,
1225 mock_get_application,
1226 mock_disconnect_controller,
1227 mock_disconnect_model,
1228 mock_get_model,
1229 mock_get_controller,
1230 ):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001231 mock_get_application.return_value = FakeApplication()
1232
1233 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001234 self.libjuju.configure_application(
1235 "model",
1236 "app",
1237 {"config"},
1238 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001239 )
1240 mock_get_application.assert_called_once()
1241 mock_disconnect_controller.assert_called_once()
1242 mock_disconnect_model.assert_called_once()
1243
1244 def test_exception(
1245 self,
1246 mock_get_application,
1247 mock_disconnect_controller,
1248 mock_disconnect_model,
1249 mock_get_model,
1250 mock_get_controller,
1251 ):
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001252 mock_get_application.side_effect = Exception()
1253
1254 with self.assertRaises(Exception):
1255 self.loop.run_until_complete(
David Garcia5b802c92020-11-11 16:56:06 +01001256 self.libjuju.configure_application(
1257 "model",
1258 "app",
1259 {"config"},
1260 )
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001261 )
David Garcia12b29242020-09-17 16:01:48 +02001262 mock_disconnect_controller.assert_called_once()
1263 mock_disconnect_model.assert_called_once()
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001264
David Garcia5b802c92020-11-11 16:56:06 +01001265 def test_controller_exception(
1266 self,
1267 mock_get_application,
1268 mock_disconnect_controller,
1269 mock_disconnect_model,
1270 mock_get_model,
1271 mock_get_controller,
1272 ):
David Garcia5b802c92020-11-11 16:56:06 +01001273 result = {"error": "not found", "response": "response", "request-id": 1}
1274
1275 mock_get_controller.side_effect = JujuAPIError(result)
1276
1277 with self.assertRaises(JujuAPIError):
1278 self.loop.run_until_complete(
1279 self.libjuju.configure_application(
1280 "model",
1281 "app",
1282 {"config"},
1283 )
1284 )
1285 mock_get_model.assert_not_called()
1286 mock_disconnect_controller.assert_not_called()
1287 mock_disconnect_model.assert_not_called()
1288
1289 def test_get_model_exception(
1290 self,
1291 mock_get_application,
1292 mock_disconnect_controller,
1293 mock_disconnect_model,
1294 mock_get_model,
1295 mock_get_controller,
1296 ):
David Garcia5b802c92020-11-11 16:56:06 +01001297 result = {"error": "not found", "response": "response", "request-id": 1}
1298 mock_get_model.side_effect = JujuAPIError(result)
1299
1300 with self.assertRaises(JujuAPIError):
1301 self.loop.run_until_complete(
1302 self.libjuju.configure_application(
1303 "model",
1304 "app",
1305 {"config"},
1306 )
1307 )
1308 mock_get_model.assert_called_once()
1309 mock_disconnect_controller.assert_called_once()
1310 mock_disconnect_model.assert_not_called()
1311
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001312
1313# TODO _get_api_endpoints_db test case
1314# TODO _update_api_endpoints_db test case
1315# TODO healthcheck test case
1316
1317
1318@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1319@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1320@asynctest.mock.patch("juju.controller.Controller.list_models")
1321class ListModelsTest(LibjujuTestCase):
1322 def setUp(self):
1323 super(ListModelsTest, self).setUp()
1324
1325 def test_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001326 self,
1327 mock_list_models,
1328 mock_disconnect_controller,
1329 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001330 ):
1331 mock_get_controller.return_value = juju.controller.Controller()
1332 mock_list_models.return_value = ["existingmodel"]
1333 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
1334
1335 mock_disconnect_controller.assert_called_once()
1336 self.assertEquals(models, ["existingmodel"])
1337
1338 def test_not_containing(
David Garcia5b802c92020-11-11 16:56:06 +01001339 self,
1340 mock_list_models,
1341 mock_disconnect_controller,
1342 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001343 ):
1344 mock_get_controller.return_value = juju.controller.Controller()
1345 mock_list_models.return_value = ["existingmodel", "model"]
1346 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
1347
1348 mock_disconnect_controller.assert_called_once()
1349 self.assertEquals(models, [])
1350
1351 def test_no_contains_arg(
David Garcia5b802c92020-11-11 16:56:06 +01001352 self,
1353 mock_list_models,
1354 mock_disconnect_controller,
1355 mock_get_controller,
Dominik Fleischmann7ff392f2020-07-07 13:11:19 +02001356 ):
1357 mock_get_controller.return_value = juju.controller.Controller()
1358 mock_list_models.return_value = ["existingmodel", "model"]
1359 models = self.loop.run_until_complete(self.libjuju.list_models())
1360
1361 mock_disconnect_controller.assert_called_once()
1362 self.assertEquals(models, ["existingmodel", "model"])
David Garcia42f328a2020-08-25 15:03:01 +02001363
1364
1365@asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
1366class ModelsExistTest(LibjujuTestCase):
1367 def setUp(self):
1368 super(ModelsExistTest, self).setUp()
1369
1370 def test_model_names_none(self, mock_list_models):
1371 mock_list_models.return_value = []
1372 with self.assertRaises(Exception):
1373 self.loop.run_until_complete(self.libjuju.models_exist(None))
1374
1375 def test_model_names_empty(self, mock_list_models):
1376 mock_list_models.return_value = []
1377 with self.assertRaises(Exception):
1378 (exist, non_existing_models) = self.loop.run_until_complete(
1379 self.libjuju.models_exist([])
1380 )
1381
1382 def test_model_names_not_existing(self, mock_list_models):
1383 mock_list_models.return_value = ["prometheus", "grafana"]
1384 (exist, non_existing_models) = self.loop.run_until_complete(
1385 self.libjuju.models_exist(["prometheus2", "grafana"])
1386 )
1387 self.assertFalse(exist)
1388 self.assertEqual(non_existing_models, ["prometheus2"])
1389
1390 def test_model_names_exist(self, mock_list_models):
1391 mock_list_models.return_value = ["prometheus", "grafana"]
1392 (exist, non_existing_models) = self.loop.run_until_complete(
1393 self.libjuju.models_exist(["prometheus", "grafana"])
1394 )
1395 self.assertTrue(exist)
1396 self.assertEqual(non_existing_models, [])
David Garciabc538e42020-08-25 15:22:30 +02001397
1398
1399@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1400@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1401@asynctest.mock.patch("juju.controller.Controller.list_offers")
1402class ListOffers(LibjujuTestCase):
1403 def setUp(self):
1404 super(ListOffers, self).setUp()
1405
1406 def test_disconnect_controller(
David Garcia5b802c92020-11-11 16:56:06 +01001407 self,
1408 mock_list_offers,
1409 mock_disconnect_controller,
1410 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001411 ):
1412 mock_get_controller.return_value = juju.controller.Controller()
1413 mock_list_offers.side_effect = Exception()
1414 with self.assertRaises(Exception):
David Garcia582b9232021-10-26 12:30:44 +02001415 self.loop.run_until_complete(self.libjuju._list_offers("model"))
David Garciabc538e42020-08-25 15:22:30 +02001416 mock_disconnect_controller.assert_called_once()
1417
1418 def test_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001419 self,
1420 mock_list_offers,
1421 mock_disconnect_controller,
1422 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001423 ):
1424 mock_get_controller.return_value = juju.controller.Controller()
David Garcia582b9232021-10-26 12:30:44 +02001425 offer_results = Mock()
1426 offer_results.results = []
1427 mock_list_offers.return_value = offer_results
1428 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
David Garciabc538e42020-08-25 15:22:30 +02001429 self.assertEqual(offers, [])
1430 mock_disconnect_controller.assert_called_once()
1431
1432 def test_non_empty_list(
David Garcia5b802c92020-11-11 16:56:06 +01001433 self,
1434 mock_list_offers,
1435 mock_disconnect_controller,
1436 mock_get_controller,
David Garciabc538e42020-08-25 15:22:30 +02001437 ):
1438 mock_get_controller.return_value = juju.controller.Controller()
David Garcia582b9232021-10-26 12:30:44 +02001439 offer = Mock()
1440 offer_results = Mock()
1441 offer_results.results = [offer]
1442 mock_list_offers.return_value = offer_results
1443 offers = self.loop.run_until_complete(self.libjuju._list_offers("model"))
1444 self.assertEqual(offers, [offer])
David Garciabc538e42020-08-25 15:22:30 +02001445 mock_disconnect_controller.assert_called_once()
David Garcia68b00722020-09-11 15:05:00 +02001446
David Garcia582b9232021-10-26 12:30:44 +02001447 def test_matching_offer_name(
1448 self,
1449 mock_list_offers,
1450 mock_disconnect_controller,
1451 mock_get_controller,
1452 ):
1453 mock_get_controller.return_value = juju.controller.Controller()
1454 offer_1 = Mock()
1455 offer_1.offer_name = "offer1"
1456 offer_2 = Mock()
1457 offer_2.offer_name = "offer2"
1458 offer_results = Mock()
1459 offer_results.results = [offer_1, offer_2]
1460 mock_list_offers.return_value = offer_results
1461 offers = self.loop.run_until_complete(
1462 self.libjuju._list_offers("model", offer_name="offer2")
1463 )
1464 self.assertEqual(offers, [offer_2])
1465 mock_disconnect_controller.assert_called_once()
1466
1467 def test_not_matching_offer_name(
1468 self,
1469 mock_list_offers,
1470 mock_disconnect_controller,
1471 mock_get_controller,
1472 ):
1473 mock_get_controller.return_value = juju.controller.Controller()
1474 offer_1 = Mock()
1475 offer_1.offer_name = "offer1"
1476 offer_2 = Mock()
1477 offer_2.offer_name = "offer2"
1478 offer_results = Mock()
1479 offer_results.results = [offer_1, offer_2]
1480 mock_list_offers.return_value = offer_results
1481 offers = self.loop.run_until_complete(
1482 self.libjuju._list_offers("model", offer_name="offer3")
1483 )
1484 self.assertEqual(offers, [])
1485 mock_disconnect_controller.assert_called_once()
1486
1487
1488@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1489@asynctest.mock.patch("juju.controller.Controller.get_model")
1490@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1491@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1492@asynctest.mock.patch("n2vc.libjuju.Libjuju._list_offers")
1493@asynctest.mock.patch("juju.model.Model.create_offer")
1494class OfferTest(LibjujuTestCase):
1495 def setUp(self):
1496 super(OfferTest, self).setUp()
1497
1498 def test_offer(
1499 self,
1500 mock_create_offer,
1501 mock__list_offers,
1502 mock_disconnect_controller,
1503 mock_disconnect_model,
1504 mock_get_model,
1505 mock_get_controller,
1506 ):
1507 controller = juju.controller.Controller()
1508 model = juju.model.Model()
1509 mock_get_controller.return_value = controller
1510 mock_get_model.return_value = model
1511 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1512 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1513 mock_create_offer.assert_called_with(
1514 "app-name:endpoint", offer_name="app-name-endpoint"
1515 )
1516 mock_disconnect_model.assert_called_once_with(model)
1517 mock_disconnect_controller.assert_called_once_with(controller)
1518
1519 def test_offer_exception(
1520 self,
1521 mock_create_offer,
1522 mock__list_offers,
1523 mock_disconnect_controller,
1524 mock_disconnect_model,
1525 mock_get_model,
1526 mock_get_controller,
1527 ):
1528 controller = juju.controller.Controller()
1529 model = juju.model.Model()
1530 mock_get_controller.return_value = controller
1531 mock_get_model.return_value = model
1532 mock__list_offers.return_value = []
1533 endpoint = RelationEndpoint("model.app-name.0", "vca", "endpoint")
1534 with self.assertRaises(Exception):
1535 self.loop.run_until_complete(self.libjuju.offer(endpoint))
1536 mock_create_offer.assert_called_with(
1537 "app-name:endpoint", offer_name="app-name-endpoint"
1538 )
1539 mock_disconnect_model.assert_called_once_with(model)
1540 mock_disconnect_controller.assert_called_once_with(controller)
1541
David Garcia68b00722020-09-11 15:05:00 +02001542
1543@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1544@asynctest.mock.patch("juju.controller.Controller.get_model")
1545@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1546@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1547@asynctest.mock.patch("juju.model.Model.consume")
1548class ConsumeTest(LibjujuTestCase):
1549 def setUp(self):
David Garcia582b9232021-10-26 12:30:44 +02001550 self.offer_url = "admin/model.offer_name"
David Garcia68b00722020-09-11 15:05:00 +02001551 super(ConsumeTest, self).setUp()
David Garcia582b9232021-10-26 12:30:44 +02001552 self.provider_libjuju = self.libjuju
David Garcia68b00722020-09-11 15:05:00 +02001553
1554 def test_consume(
1555 self,
1556 mock_consume,
1557 mock_disconnect_controller,
1558 mock_disconnect_model,
1559 mock_get_model,
1560 mock_get_controller,
1561 ):
David Garcia582b9232021-10-26 12:30:44 +02001562 self_controller = juju.controller.Controller()
1563 provider_controller = juju.controller.Controller()
1564 mock_get_controller.side_effect = [self_controller, provider_controller]
David Garcia68b00722020-09-11 15:05:00 +02001565 mock_get_model.return_value = juju.model.Model()
1566
David Garcia582b9232021-10-26 12:30:44 +02001567 self.loop.run_until_complete(
1568 self.libjuju.consume(
1569 "model_name",
1570 Offer(self.offer_url, vca_id="vca-id"),
1571 self.provider_libjuju,
1572 )
1573 )
1574 mock_consume.assert_called_once_with(
1575 "admin/model.offer_name",
1576 application_alias="offer_name-model-vca-id",
1577 controller=provider_controller,
1578 )
David Garcia68b00722020-09-11 15:05:00 +02001579 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001580 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia68b00722020-09-11 15:05:00 +02001581
1582 def test_parsing_error_exception(
1583 self,
1584 mock_consume,
1585 mock_disconnect_controller,
1586 mock_disconnect_model,
1587 mock_get_model,
1588 mock_get_controller,
1589 ):
1590 mock_get_controller.return_value = juju.controller.Controller()
1591 mock_get_model.return_value = juju.model.Model()
1592 mock_consume.side_effect = juju.offerendpoints.ParseError("")
1593
1594 with self.assertRaises(juju.offerendpoints.ParseError):
1595 self.loop.run_until_complete(
David Garcia582b9232021-10-26 12:30:44 +02001596 self.libjuju.consume(
1597 "model_name", Offer(self.offer_url), self.provider_libjuju
1598 )
David Garcia68b00722020-09-11 15:05:00 +02001599 )
1600 mock_consume.assert_called_once()
1601 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001602 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia68b00722020-09-11 15:05:00 +02001603
1604 def test_juju_error_exception(
1605 self,
1606 mock_consume,
1607 mock_disconnect_controller,
1608 mock_disconnect_model,
1609 mock_get_model,
1610 mock_get_controller,
1611 ):
1612 mock_get_controller.return_value = juju.controller.Controller()
1613 mock_get_model.return_value = juju.model.Model()
1614 mock_consume.side_effect = juju.errors.JujuError("")
1615
1616 with self.assertRaises(juju.errors.JujuError):
1617 self.loop.run_until_complete(
David Garcia582b9232021-10-26 12:30:44 +02001618 self.libjuju.consume(
1619 "model_name", Offer(self.offer_url), self.provider_libjuju
1620 )
David Garcia68b00722020-09-11 15:05:00 +02001621 )
1622 mock_consume.assert_called_once()
1623 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001624 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia68b00722020-09-11 15:05:00 +02001625
1626 def test_juju_api_error_exception(
1627 self,
1628 mock_consume,
1629 mock_disconnect_controller,
1630 mock_disconnect_model,
1631 mock_get_model,
1632 mock_get_controller,
1633 ):
1634 mock_get_controller.return_value = juju.controller.Controller()
1635 mock_get_model.return_value = juju.model.Model()
David Garcia12b29242020-09-17 16:01:48 +02001636 mock_consume.side_effect = juju.errors.JujuAPIError(
1637 {"error": "", "response": "", "request-id": ""}
1638 )
David Garcia68b00722020-09-11 15:05:00 +02001639
1640 with self.assertRaises(juju.errors.JujuAPIError):
1641 self.loop.run_until_complete(
David Garcia582b9232021-10-26 12:30:44 +02001642 self.libjuju.consume(
1643 "model_name", Offer(self.offer_url), self.provider_libjuju
1644 )
David Garcia68b00722020-09-11 15:05:00 +02001645 )
1646 mock_consume.assert_called_once()
1647 mock_disconnect_model.assert_called_once()
David Garcia582b9232021-10-26 12:30:44 +02001648 self.assertEqual(mock_disconnect_controller.call_count, 2)
David Garcia12b29242020-09-17 16:01:48 +02001649
1650
David Garcia475a7222020-09-21 16:19:15 +02001651@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
David Garcia12b29242020-09-17 16:01:48 +02001652@asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
1653class AddK8sTest(LibjujuTestCase):
1654 def setUp(self):
1655 super(AddK8sTest, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001656 name = "cloud"
1657 rbac_id = generate_rbac_id()
1658 token = "token"
1659 client_cert_data = "cert"
1660 configuration = kubernetes.client.configuration.Configuration()
1661 storage_class = "storage_class"
1662 credential_name = name
1663
1664 self._add_k8s_args = {
1665 "name": name,
1666 "rbac_id": rbac_id,
1667 "token": token,
1668 "client_cert_data": client_cert_data,
1669 "configuration": configuration,
1670 "storage_class": storage_class,
1671 "credential_name": credential_name,
1672 }
David Garcia12b29242020-09-17 16:01:48 +02001673
David Garcia475a7222020-09-21 16:19:15 +02001674 def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001675 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001676 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001677 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001678
David Garcia475a7222020-09-21 16:19:15 +02001679 def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garcia12b29242020-09-17 16:01:48 +02001680 mock_add_cloud.side_effect = Exception()
1681 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001682 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001683 mock_add_cloud.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001684 mock_get_k8s_cloud_credential.assert_called_once()
David Garcia12b29242020-09-17 16:01:48 +02001685
David Garcia475a7222020-09-21 16:19:15 +02001686 def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
David Garciaf6e9b002020-11-27 15:32:02 +01001687 self._add_k8s_args["name"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001688 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001689 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001690 mock_add_cloud.assert_not_called()
1691
David Garcia475a7222020-09-21 16:19:15 +02001692 def test_add_k8s_missing_storage_name(
1693 self, mock_add_cloud, mock_get_k8s_cloud_credential
1694 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001695 self._add_k8s_args["storage_class"] = ""
David Garcia12b29242020-09-17 16:01:48 +02001696 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001697 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001698 mock_add_cloud.assert_not_called()
1699
David Garcia475a7222020-09-21 16:19:15 +02001700 def test_add_k8s_missing_configuration_keys(
1701 self, mock_add_cloud, mock_get_k8s_cloud_credential
1702 ):
David Garciaf6e9b002020-11-27 15:32:02 +01001703 self._add_k8s_args["configuration"] = None
David Garcia12b29242020-09-17 16:01:48 +02001704 with self.assertRaises(Exception):
David Garciaf6e9b002020-11-27 15:32:02 +01001705 self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
David Garcia12b29242020-09-17 16:01:48 +02001706 mock_add_cloud.assert_not_called()
1707
1708
1709@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1710@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1711@asynctest.mock.patch("juju.controller.Controller.add_cloud")
1712@asynctest.mock.patch("juju.controller.Controller.add_credential")
1713class AddCloudTest(LibjujuTestCase):
1714 def setUp(self):
1715 super(AddCloudTest, self).setUp()
1716 self.cloud = juju.client.client.Cloud()
1717 self.credential = juju.client.client.CloudCredential()
1718
1719 def test_add_cloud_with_credential(
1720 self,
1721 mock_add_credential,
1722 mock_add_cloud,
1723 mock_disconnect_controller,
1724 mock_get_controller,
1725 ):
1726 mock_get_controller.return_value = juju.controller.Controller()
1727
1728 cloud = self.loop.run_until_complete(
1729 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1730 )
1731 self.assertEqual(cloud, self.cloud)
1732 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1733 mock_add_credential.assert_called_once_with(
1734 "cloud", credential=self.credential, cloud="cloud"
1735 )
1736 mock_disconnect_controller.assert_called_once()
1737
1738 def test_add_cloud_no_credential(
1739 self,
1740 mock_add_credential,
1741 mock_add_cloud,
1742 mock_disconnect_controller,
1743 mock_get_controller,
1744 ):
1745 mock_get_controller.return_value = juju.controller.Controller()
1746
1747 cloud = self.loop.run_until_complete(
1748 self.libjuju.add_cloud("cloud", self.cloud)
1749 )
1750 self.assertEqual(cloud, self.cloud)
1751 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1752 mock_add_credential.assert_not_called()
1753 mock_disconnect_controller.assert_called_once()
1754
1755 def test_add_cloud_exception(
1756 self,
1757 mock_add_credential,
1758 mock_add_cloud,
1759 mock_disconnect_controller,
1760 mock_get_controller,
1761 ):
1762 mock_get_controller.return_value = juju.controller.Controller()
1763 mock_add_cloud.side_effect = Exception()
1764 with self.assertRaises(Exception):
1765 self.loop.run_until_complete(
1766 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1767 )
1768
1769 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1770 mock_add_credential.assert_not_called()
1771 mock_disconnect_controller.assert_called_once()
1772
1773 def test_add_credential_exception(
1774 self,
1775 mock_add_credential,
1776 mock_add_cloud,
1777 mock_disconnect_controller,
1778 mock_get_controller,
1779 ):
1780 mock_get_controller.return_value = juju.controller.Controller()
1781 mock_add_credential.side_effect = Exception()
1782 with self.assertRaises(Exception):
1783 self.loop.run_until_complete(
1784 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1785 )
1786
1787 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1788 mock_add_credential.assert_called_once_with(
1789 "cloud", credential=self.credential, cloud="cloud"
1790 )
1791 mock_disconnect_controller.assert_called_once()
1792
1793
1794@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1795@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1796@asynctest.mock.patch("juju.controller.Controller.remove_cloud")
1797class RemoveCloudTest(LibjujuTestCase):
1798 def setUp(self):
1799 super(RemoveCloudTest, self).setUp()
1800
1801 def test_remove_cloud(
David Garcia5b802c92020-11-11 16:56:06 +01001802 self,
1803 mock_remove_cloud,
1804 mock_disconnect_controller,
1805 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001806 ):
1807 mock_get_controller.return_value = juju.controller.Controller()
1808
1809 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1810 mock_remove_cloud.assert_called_once_with("cloud")
1811 mock_disconnect_controller.assert_called_once()
1812
1813 def test_remove_cloud_exception(
David Garcia5b802c92020-11-11 16:56:06 +01001814 self,
1815 mock_remove_cloud,
1816 mock_disconnect_controller,
1817 mock_get_controller,
David Garcia12b29242020-09-17 16:01:48 +02001818 ):
1819 mock_get_controller.return_value = juju.controller.Controller()
1820 mock_remove_cloud.side_effect = Exception()
1821
1822 with self.assertRaises(Exception):
1823 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1824 mock_remove_cloud.assert_called_once_with("cloud")
1825 mock_disconnect_controller.assert_called_once()
David Garcia475a7222020-09-21 16:19:15 +02001826
1827
1828@asynctest.mock.patch("kubernetes.client.configuration.Configuration")
1829class GetK8sCloudCredentials(LibjujuTestCase):
1830 def setUp(self):
1831 super(GetK8sCloudCredentials, self).setUp()
David Garciaf6e9b002020-11-27 15:32:02 +01001832 self.cert_data = "cert"
1833 self.token = "token"
David Garcia475a7222020-09-21 16:19:15 +02001834
1835 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1836 def test_not_supported(self, mock_exception, mock_configuration):
1837 mock_configuration.username = ""
1838 mock_configuration.password = ""
1839 mock_configuration.ssl_ca_cert = None
1840 mock_configuration.cert_file = None
1841 mock_configuration.key_file = None
1842 exception_raised = False
David Garciaf6e9b002020-11-27 15:32:02 +01001843 self.token = None
1844 self.cert_data = None
David Garcia475a7222020-09-21 16:19:15 +02001845 try:
David Garciaf6e9b002020-11-27 15:32:02 +01001846 _ = self.libjuju.get_k8s_cloud_credential(
1847 mock_configuration,
1848 self.cert_data,
1849 self.token,
1850 )
David Garcia475a7222020-09-21 16:19:15 +02001851 except JujuInvalidK8sConfiguration as e:
1852 exception_raised = True
1853 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01001854 e.message,
1855 "authentication method not supported",
David Garcia475a7222020-09-21 16:19:15 +02001856 )
1857 self.assertTrue(exception_raised)
1858
1859 def test_user_pass(self, mock_configuration):
1860 mock_configuration.username = "admin"
1861 mock_configuration.password = "admin"
1862 mock_configuration.ssl_ca_cert = None
1863 mock_configuration.cert_file = None
1864 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001865 self.token = None
1866 self.cert_data = None
1867 credential = self.libjuju.get_k8s_cloud_credential(
1868 mock_configuration,
1869 self.cert_data,
1870 self.token,
1871 )
David Garcia475a7222020-09-21 16:19:15 +02001872 self.assertEqual(
1873 credential,
1874 juju.client._definitions.CloudCredential(
1875 attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
1876 ),
1877 )
1878
David Garciaf6e9b002020-11-27 15:32:02 +01001879 def test_user_pass_with_cert(self, mock_configuration):
1880 mock_configuration.username = "admin"
1881 mock_configuration.password = "admin"
1882 mock_configuration.ssl_ca_cert = None
1883 mock_configuration.cert_file = None
1884 mock_configuration.key_file = None
1885 self.token = None
1886 credential = self.libjuju.get_k8s_cloud_credential(
1887 mock_configuration,
1888 self.cert_data,
1889 self.token,
1890 )
1891 self.assertEqual(
1892 credential,
1893 juju.client._definitions.CloudCredential(
1894 attrs={
1895 "ClientCertificateData": self.cert_data,
1896 "username": "admin",
1897 "password": "admin",
1898 },
1899 auth_type="userpasswithcert",
1900 ),
1901 )
1902
David Garcia475a7222020-09-21 16:19:15 +02001903 def test_user_no_pass(self, mock_configuration):
1904 mock_configuration.username = "admin"
1905 mock_configuration.password = ""
1906 mock_configuration.ssl_ca_cert = None
1907 mock_configuration.cert_file = None
1908 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001909 self.token = None
1910 self.cert_data = None
David Garciaeb8943a2021-04-12 12:07:37 +02001911 with patch.object(self.libjuju.log, "debug") as mock_debug:
David Garciaf6e9b002020-11-27 15:32:02 +01001912 credential = 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 self.assertEqual(
1918 credential,
1919 juju.client._definitions.CloudCredential(
1920 attrs={"username": "admin", "password": ""}, auth_type="userpass"
1921 ),
1922 )
1923 mock_debug.assert_called_once_with(
1924 "credential for user admin has empty password"
1925 )
1926
David Garcia475a7222020-09-21 16:19:15 +02001927 def test_cert(self, mock_configuration):
1928 mock_configuration.username = ""
1929 mock_configuration.password = ""
1930 mock_configuration.api_key = {"authorization": "Bearer Token"}
1931 ssl_ca_cert = tempfile.NamedTemporaryFile()
1932 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
1933 ssl_ca_cert_file.write("cacert")
1934 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
1935 mock_configuration.cert_file = None
1936 mock_configuration.key_file = None
David Garciaf6e9b002020-11-27 15:32:02 +01001937 credential = self.libjuju.get_k8s_cloud_credential(
1938 mock_configuration,
1939 self.cert_data,
1940 self.token,
1941 )
David Garcia475a7222020-09-21 16:19:15 +02001942 self.assertEqual(
1943 credential,
1944 juju.client._definitions.CloudCredential(
David Garciaf6e9b002020-11-27 15:32:02 +01001945 attrs={"ClientCertificateData": self.cert_data, "Token": self.token},
David Garcia475a7222020-09-21 16:19:15 +02001946 auth_type="certificate",
1947 ),
1948 )
1949
David Garciaf6e9b002020-11-27 15:32:02 +01001950 # TODO: Fix this test when oauth authentication is supported
1951 # def test_oauth2(self, mock_configuration):
1952 # mock_configuration.username = ""
1953 # mock_configuration.password = ""
1954 # mock_configuration.api_key = {"authorization": "Bearer Token"}
1955 # key = tempfile.NamedTemporaryFile()
1956 # with open(key.name, "w") as key_file:
1957 # key_file.write("key")
1958 # mock_configuration.ssl_ca_cert = None
1959 # mock_configuration.cert_file = None
1960 # mock_configuration.key_file = key.name
1961 # credential = self.libjuju.get_k8s_cloud_credential(
1962 # mock_configuration,
1963 # self.cert_data,
1964 # self.token,
1965 # )
1966 # self.assertEqual(
1967 # credential,
1968 # juju.client._definitions.CloudCredential(
1969 # attrs={"ClientKeyData": "key", "Token": "Token"},
1970 # auth_type="oauth2",
1971 # ),
1972 # )
David Garcia475a7222020-09-21 16:19:15 +02001973
David Garciaf6e9b002020-11-27 15:32:02 +01001974 # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1975 # def test_oauth2_missing_token(self, mock_exception, mock_configuration):
1976 # mock_configuration.username = ""
1977 # mock_configuration.password = ""
1978 # key = tempfile.NamedTemporaryFile()
1979 # with open(key.name, "w") as key_file:
1980 # key_file.write("key")
1981 # mock_configuration.ssl_ca_cert = None
1982 # mock_configuration.cert_file = None
1983 # mock_configuration.key_file = key.name
1984 # exception_raised = False
1985 # try:
1986 # _ = self.libjuju.get_k8s_cloud_credential(
1987 # mock_configuration,
1988 # self.cert_data,
1989 # self.token,
1990 # )
1991 # except JujuInvalidK8sConfiguration as e:
1992 # exception_raised = True
1993 # self.assertEqual(
1994 # e.message,
1995 # "missing token for auth type oauth2",
1996 # )
1997 # self.assertTrue(exception_raised)
David Garcia475a7222020-09-21 16:19:15 +02001998
1999 def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
2000 mock_configuration.username = "admin"
2001 mock_configuration.password = "pass"
2002 mock_configuration.api_key = {"authorization": "No_bearer_token"}
2003 mock_configuration.ssl_ca_cert = None
2004 mock_configuration.cert_file = None
2005 mock_configuration.key_file = None
2006 exception_raised = False
2007 try:
David Garciaf6e9b002020-11-27 15:32:02 +01002008 _ = 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 except JujuInvalidK8sConfiguration as e:
2014 exception_raised = True
2015 self.assertEqual(
David Garcia5b802c92020-11-11 16:56:06 +01002016 e.message,
2017 "Cannot set both token and user/pass",
David Garcia475a7222020-09-21 16:19:15 +02002018 )
2019 self.assertTrue(exception_raised)
aktas2962f3e2021-03-15 11:05:35 +03002020
2021
2022@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2023@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2024@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2025@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2026@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2027@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
2028class ScaleApplicationTest(LibjujuTestCase):
2029 def setUp(self):
2030 super(ScaleApplicationTest, self).setUp()
2031
2032 @asynctest.mock.patch("asyncio.sleep")
2033 def test_scale_application(
2034 self,
2035 mock_sleep,
2036 mock_wait_for_model,
2037 mock_disconnect_controller,
2038 mock_disconnect_model,
2039 mock_get_application,
2040 mock_get_model,
2041 mock_get_controller,
2042 ):
2043 mock_get_model.return_value = juju.model.Model()
2044 mock_get_application.return_value = FakeApplication()
garciadeblas82b591c2021-03-24 09:22:13 +01002045 self.loop.run_until_complete(self.libjuju.scale_application("model", "app", 2))
aktas2962f3e2021-03-15 11:05:35 +03002046 mock_wait_for_model.assert_called_once()
2047 mock_disconnect_controller.assert_called_once()
2048 mock_disconnect_model.assert_called_once()
2049
2050 def test_no_application(
2051 self,
2052 mock_wait_for,
2053 mock_disconnect_controller,
2054 mock_disconnect_model,
2055 mock_get_application,
2056 mock_get_model,
2057 mock_get_controller,
2058 ):
2059 mock_get_application.return_value = None
2060 mock_get_model.return_value = juju.model.Model()
2061 with self.assertRaises(JujuApplicationNotFound):
2062 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01002063 self.libjuju.scale_application("model", "app", 2)
aktas2962f3e2021-03-15 11:05:35 +03002064 )
2065 mock_disconnect_controller.assert_called()
2066 mock_disconnect_model.assert_called()
2067
2068 def test_exception(
garciadeblas82b591c2021-03-24 09:22:13 +01002069 self,
2070 mock_wait_for,
2071 mock_disconnect_controller,
2072 mock_disconnect_model,
2073 mock_get_application,
2074 mock_get_model,
2075 mock_get_controller,
aktas2962f3e2021-03-15 11:05:35 +03002076 ):
2077 mock_get_model.return_value = None
2078 mock_get_application.return_value = FakeApplication()
2079 with self.assertRaises(Exception):
2080 self.loop.run_until_complete(
garciadeblas82b591c2021-03-24 09:22:13 +01002081 self.libjuju.scale_application("model", "app", 2, total_timeout=0)
aktas2962f3e2021-03-15 11:05:35 +03002082 )
2083 mock_disconnect_controller.assert_called_once()
2084
2085
2086@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2087class GetUnitNumberTest(LibjujuTestCase):
2088 def setUp(self):
2089 super(GetUnitNumberTest, self).setUp()
2090
aktasfa02f8a2021-07-29 17:41:40 +03002091 def test_successful_get_unit_number(
aktas2962f3e2021-03-15 11:05:35 +03002092 self,
2093 mock_get_applications,
2094 ):
2095 mock_get_applications.return_value = FakeApplication()
2096 model = juju.model.Model()
2097 result = self.libjuju._get_application_count(model, "app")
2098 self.assertEqual(result, 2)
2099
2100 def test_non_existing_application(
2101 self,
2102 mock_get_applications,
2103 ):
2104 mock_get_applications.return_value = None
2105 model = juju.model.Model()
2106 result = self.libjuju._get_application_count(model, "app")
2107 self.assertEqual(result, None)
aktasfa02f8a2021-07-29 17:41:40 +03002108
2109
2110@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
2111class GetMachineInfoTest(LibjujuTestCase):
2112 def setUp(self):
2113 super(GetMachineInfoTest, self).setUp()
2114
2115 def test_successful(
2116 self,
2117 mock_machines,
2118 ):
2119 machine_id = "existing_machine"
2120 model = juju.model.Model()
2121 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2122 machine, series = self.libjuju._get_machine_info(
2123 machine_id=machine_id,
2124 model=model,
2125 )
2126 self.assertIsNotNone(machine, series)
2127
2128 def test_exception(
2129 self,
2130 mock_machines,
2131 ):
2132 machine_id = "not_existing_machine"
2133 machine = series = None
2134 model = juju.model.Model()
2135 mock_machines.return_value = {"existing_machine": FakeManualMachine()}
2136 with self.assertRaises(JujuMachineNotFound):
2137 machine, series = self.libjuju._get_machine_info(
2138 machine_id=machine_id,
2139 model=model,
2140 )
2141 self.assertIsNone(machine, series)
2142
2143
2144class GetUnitTest(LibjujuTestCase):
2145 def setUp(self):
2146 super(GetUnitTest, self).setUp()
2147
2148 def test_successful(self):
2149 result = self.libjuju._get_unit(FakeApplication(), "existing_machine_id")
2150 self.assertIsInstance(result, FakeUnit)
2151
2152 def test_return_none(self):
2153 result = self.libjuju._get_unit(FakeApplication(), "not_existing_machine_id")
2154 self.assertIsNone(result)
2155
2156
2157@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2158@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2159@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2160@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2161@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2162class CheckApplicationExists(LibjujuTestCase):
2163 def setUp(self):
2164 super(CheckApplicationExists, self).setUp()
2165
2166 def test_successful(
2167 self,
2168 mock_get_application,
2169 mock_disconnect_controller,
2170 mock_disconnect_model,
2171 mock_get_model,
2172 mock_get_controller,
2173 ):
2174 mock_get_model.return_value = juju.model.Model()
2175 mock_get_application.return_value = FakeApplication()
2176 result = self.loop.run_until_complete(
2177 self.libjuju.check_application_exists(
2178 "model",
2179 "app",
2180 )
2181 )
2182 self.assertEqual(result, True)
2183
2184 mock_get_application.assert_called_once()
2185 mock_get_controller.assert_called_once()
2186 mock_get_model.assert_called_once()
2187 mock_disconnect_controller.assert_called_once()
2188 mock_disconnect_model.assert_called_once()
2189
2190 def test_no_application(
2191 self,
2192 mock_get_application,
2193 mock_disconnect_controller,
2194 mock_disconnect_model,
2195 mock_get_model,
2196 mock_get_controller,
2197 ):
2198 mock_get_model.return_value = juju.model.Model()
2199 mock_get_application.return_value = None
2200 result = self.loop.run_until_complete(
2201 self.libjuju.check_application_exists(
2202 "model",
2203 "app",
2204 )
2205 )
2206 self.assertEqual(result, False)
2207
2208 mock_get_application.assert_called_once()
2209 mock_get_controller.assert_called_once()
2210 mock_get_model.assert_called_once()
2211 mock_disconnect_controller.assert_called_once()
2212 mock_disconnect_model.assert_called_once()
2213
2214
2215@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2216@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2217@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2218@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2219@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2220@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_machine_info")
2221class AddUnitTest(LibjujuTestCase):
2222 def setUp(self):
2223 super(AddUnitTest, self).setUp()
2224
2225 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
2226 @asynctest.mock.patch("asyncio.sleep")
2227 def test_successful(
2228 self,
2229 mock_sleep,
2230 mock_wait_for,
2231 mock_get_machine_info,
2232 mock_get_application,
2233 mock_disconnect_controller,
2234 mock_disconnect_model,
2235 mock_get_model,
2236 mock_get_controller,
2237 ):
2238 mock_get_model.return_value = juju.model.Model()
2239 mock_get_application.return_value = FakeApplication()
2240 mock_get_machine_info.return_value = FakeMachine(), "series"
2241 self.loop.run_until_complete(
2242 self.libjuju.add_unit(
2243 "existing_app",
2244 "model",
2245 "machine",
2246 )
2247 )
2248
2249 mock_wait_for.assert_called_once()
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_app(
2257 self,
2258 mock_get_machine_info,
2259 mock_get_application,
2260 mock_disconnect_controller,
2261 mock_disconnect_model,
2262 mock_get_model,
2263 mock_get_controller,
2264 ):
2265 mock_get_model.return_value = juju.model.Model()
2266 mock_get_application.return_value = None
2267 with self.assertRaises(JujuApplicationNotFound):
2268 self.loop.run_until_complete(
2269 self.libjuju.add_unit(
2270 "existing_app",
2271 "model",
2272 "machine",
2273 )
2274 )
2275
2276 mock_get_application.assert_called_once()
2277 mock_get_controller.assert_called_once()
2278 mock_get_model.assert_called_once()
2279 mock_disconnect_controller.assert_called_once()
2280 mock_disconnect_model.assert_called_once()
2281
2282 def test_no_machine(
2283 self,
2284 mock_get_machine_info,
2285 mock_get_application,
2286 mock_disconnect_controller,
2287 mock_disconnect_model,
2288 mock_get_model,
2289 mock_get_controller,
2290 ):
2291 mock_get_model.return_value = juju.model.Model()
2292 mock_get_application.return_value = FakeApplication()
2293 mock_get_machine_info.side_effect = JujuMachineNotFound()
2294 with self.assertRaises(JujuMachineNotFound):
2295 self.loop.run_until_complete(
2296 self.libjuju.add_unit(
2297 "existing_app",
2298 "model",
2299 "machine",
2300 )
2301 )
2302
2303 mock_get_application.assert_called_once()
2304 mock_get_controller.assert_called_once()
2305 mock_get_model.assert_called_once()
2306 mock_disconnect_controller.assert_called_once()
2307 mock_disconnect_model.assert_called_once()
2308
2309
2310@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
2311@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
2312@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
2313@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
2314@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
2315@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_unit")
2316class DestroyUnitTest(LibjujuTestCase):
2317 def setUp(self):
2318 super(DestroyUnitTest, self).setUp()
2319
2320 @asynctest.mock.patch("asyncio.sleep")
2321 def test_successful(
2322 self,
2323 mock_sleep,
2324 mock_get_unit,
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 = FakeApplication()
2333
2334 self.loop.run_until_complete(
2335 self.libjuju.destroy_unit("app", "model", "machine", 0)
2336 )
2337
2338 mock_get_unit.assert_called()
2339 mock_get_application.assert_called_once()
2340 mock_get_controller.assert_called_once()
2341 mock_get_model.assert_called_once()
2342 mock_disconnect_controller.assert_called_once()
2343 mock_disconnect_model.assert_called_once()
2344
2345 def test_no_app(
2346 self,
2347 mock_get_unit,
2348 mock_get_application,
2349 mock_disconnect_controller,
2350 mock_disconnect_model,
2351 mock_get_model,
2352 mock_get_controller,
2353 ):
2354 mock_get_model.return_value = juju.model.Model()
2355 mock_get_application.return_value = None
2356
2357 with self.assertRaises(JujuApplicationNotFound):
2358 self.loop.run_until_complete(
2359 self.libjuju.destroy_unit("app", "model", "machine")
2360 )
2361
2362 mock_get_application.assert_called_once()
2363 mock_get_controller.assert_called_once()
2364 mock_get_model.assert_called_once()
2365 mock_disconnect_controller.assert_called_once()
2366 mock_disconnect_model.assert_called_once()
2367
2368 def test_no_unit(
2369 self,
2370 mock_get_unit,
2371 mock_get_application,
2372 mock_disconnect_controller,
2373 mock_disconnect_model,
2374 mock_get_model,
2375 mock_get_controller,
2376 ):
2377 mock_get_model.return_value = juju.model.Model()
2378 mock_get_application.return_value = FakeApplication()
2379 mock_get_unit.return_value = None
2380
2381 with self.assertRaises(JujuError):
2382 self.loop.run_until_complete(
2383 self.libjuju.destroy_unit("app", "model", "machine")
2384 )
2385
2386 mock_get_unit.assert_called_once()
2387 mock_get_application.assert_called_once()
2388 mock_get_controller.assert_called_once()
2389 mock_get_model.assert_called_once()
2390 mock_disconnect_controller.assert_called_once()
2391 mock_disconnect_model.assert_called_once()