Code Coverage

Cobertura Coverage Report > n2vc.tests.unit >

test_k8s_juju_conn.py

Trend

File Coverage summary

NameClassesLinesConditionals
test_k8s_juju_conn.py
100%
1/1
99%
433/434
100%
0/0

Coverage Breakdown by Class

NameLinesConditionals
test_k8s_juju_conn.py
99%
433/434
N/A

Source

n2vc/tests/unit/test_k8s_juju_conn.py
1 # 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
15
16 1 import asyncio
17 1 import logging
18 1 import asynctest
19 1 from unittest.mock import Mock
20 1 from n2vc.definitions import Offer, RelationEndpoint
21 1 from n2vc.k8s_juju_conn import K8sJujuConnector, RBAC_LABEL_KEY_NAME
22 1 from osm_common import fslocal
23 1 from .utils import kubeconfig, FakeModel, FakeFileWrapper, AsyncMock, FakeApplication
24 1 from n2vc.exceptions import MethodNotImplemented, K8sException
25 1 from n2vc.vca.connection_data import ConnectionData
26
27
28 1 class K8sJujuConnTestCase(asynctest.TestCase):
29 1     @asynctest.mock.patch("n2vc.k8s_juju_conn.Libjuju")
30 1     @asynctest.mock.patch("n2vc.k8s_juju_conn.MotorStore")
31 1     @asynctest.mock.patch("n2vc.k8s_juju_conn.get_connection")
32 1     @asynctest.mock.patch("n2vc.vca.connection_data.base64_to_cacert")
33 1     def setUp(
34         self,
35         mock_base64_to_cacert=None,
36         mock_get_connection=None,
37         mock_store=None,
38         mock_libjuju=None,
39     ):
40 1         self.loop = asyncio.get_event_loop()
41 1         self.db = Mock()
42 1         mock_base64_to_cacert.return_value = """
43     -----BEGIN CERTIFICATE-----
44     SOMECERT
45     -----END CERTIFICATE-----"""
46 1         mock_libjuju.return_value = Mock()
47 1         mock_store.return_value = AsyncMock()
48 1         mock_vca_connection = Mock()
49 1         mock_get_connection.return_value = mock_vca_connection
50 1         mock_vca_connection.data.return_value = ConnectionData(
51             **{
52                 "endpoints": ["1.2.3.4:17070"],
53                 "user": "user",
54                 "secret": "secret",
55                 "cacert": "cacert",
56                 "pubkey": "pubkey",
57                 "lxd-cloud": "cloud",
58                 "lxd-credentials": "credentials",
59                 "k8s-cloud": "k8s_cloud",
60                 "k8s-credentials": "k8s_credentials",
61                 "model-config": {},
62                 "api-proxy": "api_proxy",
63             }
64         )
65 1         logging.disable(logging.CRITICAL)
66
67 1         self.kdu_name = "kdu_name"
68 1         self.kdu_instance = "{}-{}".format(self.kdu_name, "id")
69 1         self.default_namespace = self.kdu_instance
70
71 1         self.k8s_juju_conn = K8sJujuConnector(
72             fs=fslocal.FsLocal(),
73             db=self.db,
74             log=None,
75             on_update_db=None,
76         )
77 1         self.k8s_juju_conn._store.get_vca_id.return_value = None
78 1         self.k8s_juju_conn.libjuju = Mock()
79         # Mock Kubectl
80 1         self.kubectl = Mock()
81 1         self.kubectl.get_secret_data = AsyncMock()
82 1         self.kubectl.get_secret_data.return_value = ("token", "cacert")
83 1         self.kubectl.get_services.return_value = [{}]
84 1         self.k8s_juju_conn._get_kubectl = Mock()
85 1         self.k8s_juju_conn._get_kubectl.return_value = self.kubectl
86 1         self.k8s_juju_conn._obtain_namespace_from_db = Mock(
87             return_value=self.default_namespace
88         )
89
90
91 1 class InitEnvTest(K8sJujuConnTestCase):
92 1     def setUp(self):
93 1         super(InitEnvTest, self).setUp()
94 1         self.k8s_juju_conn.libjuju.add_k8s = AsyncMock()
95
96 1     def test_with_cluster_uuid(
97         self,
98     ):
99 1         reuse_cluster_uuid = "uuid"
100 1         uuid, created = self.loop.run_until_complete(
101             self.k8s_juju_conn.init_env(
102                 k8s_creds=kubeconfig, reuse_cluster_uuid=reuse_cluster_uuid
103             )
104         )
105
106 1         self.assertTrue(created)
107 1         self.assertEqual(uuid, reuse_cluster_uuid)
108 1         self.kubectl.get_default_storage_class.assert_called_once()
109 1         self.k8s_juju_conn.libjuju.add_k8s.assert_called_once()
110
111 1     def test_with_no_cluster_uuid(
112         self,
113     ):
114 1         uuid, created = self.loop.run_until_complete(
115             self.k8s_juju_conn.init_env(k8s_creds=kubeconfig)
116         )
117
118 1         self.assertTrue(created)
119 1         self.assertTrue(isinstance(uuid, str))
120 1         self.kubectl.get_default_storage_class.assert_called_once()
121 1         self.k8s_juju_conn.libjuju.add_k8s.assert_called_once()
122
123 1     def test_init_env_exception(
124         self,
125     ):
126 1         self.k8s_juju_conn.libjuju.add_k8s.side_effect = Exception()
127 1         created = None
128 1         uuid = None
129 1         with self.assertRaises(Exception):
130 1             uuid, created = self.loop.run_until_complete(
131                 self.k8s_juju_conn.init_env(k8s_creds=kubeconfig)
132             )
133 1         self.assertIsNone(created)
134 1         self.assertIsNone(uuid)
135 1         self.kubectl.create_cluster_role.assert_called_once()
136 1         self.kubectl.create_service_account.assert_called_once()
137 1         self.kubectl.create_cluster_role_binding.assert_called_once()
138 1         self.kubectl.get_default_storage_class.assert_called_once()
139 1         self.kubectl.delete_cluster_role.assert_called_once()
140 1         self.kubectl.delete_service_account.assert_called_once()
141 1         self.kubectl.delete_cluster_role_binding.assert_called_once()
142 1         self.k8s_juju_conn.libjuju.add_k8s.assert_called_once()
143
144
145 1 class NotImplementedTest(K8sJujuConnTestCase):
146 1     def setUp(self):
147 1         super(NotImplementedTest, self).setUp()
148
149 1     def test_repo_add(self):
150 1         with self.assertRaises(MethodNotImplemented):
151 1             self.loop.run_until_complete(self.k8s_juju_conn.repo_add("", ""))
152
153 1     def test_repo_list(self):
154 1         with self.assertRaises(MethodNotImplemented):
155 1             self.loop.run_until_complete(self.k8s_juju_conn.repo_list())
156
157 1     def test_repo_remove(self):
158 1         with self.assertRaises(MethodNotImplemented):
159 1             self.loop.run_until_complete(self.k8s_juju_conn.repo_remove(""))
160
161 1     def test_synchronize_repos(self):
162 1         self.assertIsNone(
163             self.loop.run_until_complete(self.k8s_juju_conn.synchronize_repos("", ""))
164         )
165
166 1     def test_upgrade(self):
167 1         with self.assertRaises(MethodNotImplemented):
168 1             self.loop.run_until_complete(self.k8s_juju_conn.upgrade("", ""))
169
170 1     def test_rollback(self):
171 1         with self.assertRaises(MethodNotImplemented):
172 1             self.loop.run_until_complete(self.k8s_juju_conn.rollback("", ""))
173
174 1     def test_get_namespace(self):
175 1         self.assertIsNone(self.k8s_juju_conn.get_namespace(""))
176
177 1     def test_instances_list(self):
178 1         res = self.loop.run_until_complete(self.k8s_juju_conn.instances_list(""))
179 1         self.assertEqual(res, [])
180
181
182 1 class ResetTest(K8sJujuConnTestCase):
183 1     def setUp(self):
184 1         super(ResetTest, self).setUp()
185 1         self.k8s_juju_conn.libjuju.remove_cloud = AsyncMock()
186 1         self.k8s_juju_conn.libjuju.get_cloud_credentials = AsyncMock()
187 1         cloud_creds = Mock()
188 1         cloud_creds.result = {"attrs": {RBAC_LABEL_KEY_NAME: "asd"}}
189 1         self.k8s_juju_conn.libjuju.get_cloud_credentials.return_value = [cloud_creds]
190 1         self.k8s_juju_conn.get_credentials = Mock()
191 1         self.k8s_juju_conn.get_credentials.return_value = kubeconfig
192
193 1     def test_success(self):
194 1         removed = self.loop.run_until_complete(self.k8s_juju_conn.reset("uuid"))
195 1         self.assertTrue(removed)
196 1         self.k8s_juju_conn.libjuju.remove_cloud.assert_called_once()
197
198 1     def test_exception(self):
199 1         removed = None
200 1         self.k8s_juju_conn.libjuju.remove_cloud.side_effect = Exception()
201 1         with self.assertRaises(Exception):
202 1             removed = self.loop.run_until_complete(self.k8s_juju_conn.reset("uuid"))
203 1         self.assertIsNone(removed)
204 1         self.k8s_juju_conn.libjuju.remove_cloud.assert_called_once()
205
206
207 1 @asynctest.mock.patch("os.chdir")
208 1 class InstallTest(K8sJujuConnTestCase):
209 1     def setUp(self):
210 1         super(InstallTest, self).setUp()
211 1         self.db_dict = {"filter": {"_id": "id"}}
212 1         self.local_bundle = "bundle"
213 1         self.cs_bundle = "cs:bundle"
214 1         self.http_bundle = "https://example.com/bundle.yaml"
215 1         self.cluster_uuid = "cluster"
216 1         self.k8s_juju_conn.libjuju.add_model = AsyncMock()
217 1         self.k8s_juju_conn.libjuju.deploy = AsyncMock()
218
219 1     def test_success_local(self, mock_chdir):
220 1         self.loop.run_until_complete(
221             self.k8s_juju_conn.install(
222                 self.cluster_uuid,
223                 self.local_bundle,
224                 self.kdu_instance,
225                 atomic=True,
226                 kdu_name=self.kdu_name,
227                 db_dict=self.db_dict,
228                 timeout=1800,
229                 params=None,
230             )
231         )
232 1         self.assertEqual(mock_chdir.call_count, 2)
233 1         self.k8s_juju_conn.libjuju.add_model.assert_called_once()
234 1         self.k8s_juju_conn.libjuju.deploy.assert_called_once_with(
235             "local:{}".format(self.local_bundle),
236             model_name=self.default_namespace,
237             wait=True,
238             timeout=1800,
239             instantiation_params=None,
240         )
241
242 1     def test_success_cs(self, mock_chdir):
243 1         self.loop.run_until_complete(
244             self.k8s_juju_conn.install(
245                 self.cluster_uuid,
246                 self.cs_bundle,
247                 self.kdu_instance,
248                 atomic=True,
249                 kdu_name=self.kdu_name,
250                 db_dict=self.db_dict,
251                 timeout=1800,
252                 params={},
253             )
254         )
255 1         self.k8s_juju_conn.libjuju.add_model.assert_called_once()
256 1         self.k8s_juju_conn.libjuju.deploy.assert_called_once_with(
257             self.cs_bundle,
258             model_name=self.default_namespace,
259             wait=True,
260             timeout=1800,
261             instantiation_params=None,
262         )
263
264 1     def test_success_http(self, mock_chdir):
265 1         params = {"overlay": {"applications": {"squid": {"scale": 2}}}}
266 1         self.loop.run_until_complete(
267             self.k8s_juju_conn.install(
268                 self.cluster_uuid,
269                 self.http_bundle,
270                 self.kdu_instance,
271                 atomic=True,
272                 kdu_name=self.kdu_name,
273                 db_dict=self.db_dict,
274                 timeout=1800,
275                 params=params,
276             )
277         )
278 1         self.k8s_juju_conn.libjuju.add_model.assert_called_once()
279 1         self.k8s_juju_conn.libjuju.deploy.assert_called_once_with(
280             self.http_bundle,
281             model_name=self.default_namespace,
282             wait=True,
283             timeout=1800,
284             instantiation_params=params.get("overlay"),
285         )
286
287 1     def test_success_not_kdu_name(self, mock_chdir):
288 1         params = {"some_key": {"applications": {"squid": {"scale": 2}}}}
289 1         self.loop.run_until_complete(
290             self.k8s_juju_conn.install(
291                 self.cluster_uuid,
292                 self.cs_bundle,
293                 self.kdu_instance,
294                 atomic=True,
295                 db_dict=self.db_dict,
296                 timeout=1800,
297                 params=params,
298             )
299         )
300 1         self.k8s_juju_conn.libjuju.add_model.assert_called_once()
301 1         self.k8s_juju_conn.libjuju.deploy.assert_called_once_with(
302             self.cs_bundle,
303             model_name=self.default_namespace,
304             wait=True,
305             timeout=1800,
306             instantiation_params=None,
307         )
308
309 1     def test_missing_db_dict(self, mock_chdir):
310 1         kdu_instance = None
311 1         with self.assertRaises(K8sException):
312 1             self.loop.run_until_complete(
313                 self.k8s_juju_conn.install(
314                     self.cluster_uuid,
315                     self.cs_bundle,
316                     self.kdu_instance,
317                     atomic=True,
318                     kdu_name=self.kdu_name,
319                     timeout=1800,
320                 )
321             )
322 1         self.assertIsNone(kdu_instance)
323 1         self.k8s_juju_conn.libjuju.add_model.assert_not_called()
324 1         self.k8s_juju_conn.libjuju.deploy.assert_not_called()
325
326 1     @asynctest.mock.patch("os.getcwd")
327 1     def test_getcwd_exception(self, mock_getcwd, mock_chdir):
328 1         mock_getcwd.side_effect = FileNotFoundError()
329 1         self.loop.run_until_complete(
330             self.k8s_juju_conn.install(
331                 self.cluster_uuid,
332                 self.cs_bundle,
333                 self.kdu_instance,
334                 atomic=True,
335                 kdu_name=self.kdu_name,
336                 db_dict=self.db_dict,
337                 timeout=1800,
338             )
339         )
340 1         self.k8s_juju_conn.libjuju.add_model.assert_called_once()
341 1         self.k8s_juju_conn.libjuju.deploy.assert_called_once_with(
342             self.cs_bundle,
343             model_name=self.default_namespace,
344             wait=True,
345             timeout=1800,
346             instantiation_params=None,
347         )
348
349 1     def test_missing_bundle(self, mock_chdir):
350 1         with self.assertRaises(K8sException):
351 1             self.loop.run_until_complete(
352                 self.k8s_juju_conn.install(
353                     self.cluster_uuid,
354                     "",
355                     self.kdu_instance,
356                     atomic=True,
357                     kdu_name=self.kdu_name,
358                     timeout=1800,
359                     db_dict=self.db_dict,
360                 )
361             )
362 1         self.k8s_juju_conn.libjuju.add_model.assert_not_called()
363 1         self.k8s_juju_conn.libjuju.deploy.assert_not_called()
364
365 1     def test_missing_exception(self, mock_chdir):
366 1         self.k8s_juju_conn.libjuju.deploy.side_effect = Exception()
367 1         with self.assertRaises(Exception):
368 1             self.loop.run_until_complete(
369                 self.k8s_juju_conn.install(
370                     self.cluster_uuid,
371                     self.local_bundle,
372                     self.kdu_instance,
373                     atomic=True,
374                     kdu_name=self.kdu_name,
375                     db_dict=self.db_dict,
376                     timeout=1800,
377                 )
378             )
379 1         self.k8s_juju_conn.libjuju.add_model.assert_called_once()
380 1         self.k8s_juju_conn.libjuju.deploy.assert_called_once_with(
381             "local:{}".format(self.local_bundle),
382             model_name=self.default_namespace,
383             wait=True,
384             timeout=1800,
385             instantiation_params=None,
386         )
387
388
389 1 class UninstallTest(K8sJujuConnTestCase):
390 1     def setUp(self):
391 1         super(UninstallTest, self).setUp()
392 1         self.k8s_juju_conn.libjuju.destroy_model = AsyncMock()
393
394 1     def test_success(self):
395 1         destroyed = self.loop.run_until_complete(
396             self.k8s_juju_conn.uninstall("cluster_uuid", "model_name")
397         )
398 1         self.assertTrue(destroyed)
399 1         self.k8s_juju_conn.libjuju.destroy_model.assert_called_once()
400
401 1     def test_exception(self):
402 1         destroyed = None
403 1         self.k8s_juju_conn.libjuju.destroy_model.side_effect = Exception()
404 1         with self.assertRaises(Exception):
405 1             destroyed = self.loop.run_until_complete(
406                 self.k8s_juju_conn.uninstall("cluster_uuid", "model_name")
407             )
408 1         self.assertIsNone(destroyed)
409 1         self.k8s_juju_conn.libjuju.destroy_model.assert_called_once()
410
411
412 1 class ExecPrimitivesTest(K8sJujuConnTestCase):
413 1     def setUp(self):
414 1         super(ExecPrimitivesTest, self).setUp()
415 1         self.action_name = "touch"
416 1         self.application_name = "myapp"
417 1         self.k8s_juju_conn.libjuju.get_actions = AsyncMock()
418 1         self.k8s_juju_conn.libjuju.execute_action = AsyncMock()
419
420 1     def test_success(self):
421 1         params = {"application-name": self.application_name}
422 1         self.k8s_juju_conn.libjuju.get_actions.return_value = [self.action_name]
423 1         self.k8s_juju_conn.libjuju.execute_action.return_value = (
424             "success",
425             "completed",
426         )
427
428 1         output = self.loop.run_until_complete(
429             self.k8s_juju_conn.exec_primitive(
430                 "cluster", self.kdu_instance, self.action_name, params=params
431             )
432         )
433
434 1         self.assertEqual(output, "success")
435 1         self.k8s_juju_conn._obtain_namespace_from_db.assert_called_once_with(
436             kdu_instance=self.kdu_instance
437         )
438 1         self.k8s_juju_conn.libjuju.get_actions.assert_called_once_with(
439             application_name=self.application_name, model_name=self.default_namespace
440         )
441 1         self.k8s_juju_conn.libjuju.execute_action.assert_called_once_with(
442             application_name=self.application_name,
443             model_name=self.default_namespace,
444             action_name=self.action_name,
445             **params
446         )
447
448 1     def test_exception(self):
449 1         params = {"application-name": self.application_name}
450 1         self.k8s_juju_conn.libjuju.get_actions.return_value = [self.action_name]
451 1         self.k8s_juju_conn.libjuju.execute_action.side_effect = Exception()
452 1         output = None
453
454 1         with self.assertRaises(Exception):
455 1             output = self.loop.run_until_complete(
456                 self.k8s_juju_conn.exec_primitive(
457                     "cluster", self.kdu_instance, self.action_name, params=params
458                 )
459             )
460
461 1         self.assertIsNone(output)
462 1         self.k8s_juju_conn._obtain_namespace_from_db.assert_called_once_with(
463             kdu_instance=self.kdu_instance
464         )
465 1         self.k8s_juju_conn.libjuju.get_actions.assert_called_once_with(
466             application_name=self.application_name, model_name=self.default_namespace
467         )
468 1         self.k8s_juju_conn.libjuju.execute_action.assert_called_once_with(
469             application_name=self.application_name,
470             model_name=self.default_namespace,
471             action_name=self.action_name,
472             **params
473         )
474
475 1     def test_missing_application_name_in_params(self):
476 1         params = {}
477 1         output = None
478
479 1         with self.assertRaises(K8sException):
480 1             output = self.loop.run_until_complete(
481                 self.k8s_juju_conn.exec_primitive(
482                     "cluster", self.kdu_instance, self.action_name, params=params
483                 )
484             )
485
486 1         self.assertIsNone(output)
487 1         self.k8s_juju_conn.libjuju.get_actions.assert_not_called()
488 1         self.k8s_juju_conn.libjuju.execute_action.assert_not_called()
489
490 1     def test_missing_params(self):
491 1         output = None
492 1         with self.assertRaises(K8sException):
493 1             output = self.loop.run_until_complete(
494                 self.k8s_juju_conn.exec_primitive(
495                     "cluster", self.kdu_instance, self.action_name
496                 )
497             )
498
499 1         self.assertIsNone(output)
500 1         self.k8s_juju_conn.libjuju.get_actions.assert_not_called()
501 1         self.k8s_juju_conn.libjuju.execute_action.assert_not_called()
502
503 1     def test_missing_action(self):
504 1         output = None
505 1         params = {"application-name": self.application_name}
506 1         self.k8s_juju_conn.libjuju.get_actions.return_value = [self.action_name]
507 1         self.k8s_juju_conn.libjuju.execute_action.return_value = (
508             "success",
509             "completed",
510         )
511 1         with self.assertRaises(K8sException):
512 1             output = self.loop.run_until_complete(
513                 self.k8s_juju_conn.exec_primitive(
514                     "cluster", self.kdu_instance, "non-existing-action", params=params
515                 )
516             )
517
518 1         self.assertIsNone(output)
519 1         self.k8s_juju_conn._obtain_namespace_from_db.assert_called_once_with(
520             kdu_instance=self.kdu_instance
521         )
522 1         self.k8s_juju_conn.libjuju.get_actions.assert_called_once_with(
523             application_name=self.application_name, model_name=self.default_namespace
524         )
525 1         self.k8s_juju_conn.libjuju.execute_action.assert_not_called()
526
527 1     def test_missing_not_completed(self):
528 1         output = None
529 1         params = {"application-name": self.application_name}
530 1         self.k8s_juju_conn.libjuju.get_actions.return_value = [self.action_name]
531 1         self.k8s_juju_conn.libjuju.execute_action.return_value = (None, "failed")
532 1         with self.assertRaises(K8sException):
533 1             output = self.loop.run_until_complete(
534                 self.k8s_juju_conn.exec_primitive(
535                     "cluster", self.kdu_instance, self.action_name, params=params
536                 )
537             )
538
539 1         self.assertIsNone(output)
540 1         self.k8s_juju_conn._obtain_namespace_from_db.assert_called_once_with(
541             kdu_instance=self.kdu_instance
542         )
543 1         self.k8s_juju_conn.libjuju.get_actions.assert_called_once_with(
544             application_name=self.application_name, model_name=self.default_namespace
545         )
546 1         self.k8s_juju_conn.libjuju.execute_action.assert_called_once_with(
547             application_name=self.application_name,
548             model_name=self.default_namespace,
549             action_name=self.action_name,
550             **params
551         )
552
553
554 1 class InspectKduTest(K8sJujuConnTestCase):
555 1     def setUp(self):
556 1         super(InspectKduTest, self).setUp()
557
558 1     @asynctest.mock.patch("builtins.open")
559 1     @asynctest.mock.patch("os.path.exists")
560 1     def test_existing_file(self, mock_exists, mock_open):
561 1         mock_exists.return_value = True
562 1         content = """{
563             'description': 'test bundle',
564             'bundle': 'kubernetes',
565             'applications': {'app':{ }, 'app2': { }}
566         }"""
567 1         mock_open.return_value = FakeFileWrapper(content=content)
568 1         kdu = self.loop.run_until_complete(self.k8s_juju_conn.inspect_kdu("model"))
569 1         self.assertEqual(kdu, {"app": {}, "app2": {}})
570 1         mock_exists.assert_called_once()
571 1         mock_open.assert_called_once()
572
573 1     @asynctest.mock.patch("builtins.open")
574 1     @asynctest.mock.patch("os.path.exists")
575 1     def test_not_existing_file(self, mock_exists, mock_open):
576 1         kdu = None
577 1         mock_exists.return_value = False
578 1         with self.assertRaises(K8sException):
579 1             kdu = self.loop.run_until_complete(self.k8s_juju_conn.inspect_kdu("model"))
580 1         self.assertEqual(kdu, None)
581 1         mock_exists.assert_called_once_with("model")
582 1         mock_open.assert_not_called()
583
584
585 1 class HelpKduTest(K8sJujuConnTestCase):
586 1     def setUp(self):
587 1         super(HelpKduTest, self).setUp()
588
589 1     @asynctest.mock.patch("builtins.open")
590 1     @asynctest.mock.patch("os.listdir")
591 1     def test_existing_file(self, mock_listdir, mock_open):
592 1         content = "Readme file content"
593 1         mock_open.return_value = FakeFileWrapper(content=content)
594 1         for file in ["README.md", "README.txt", "README"]:
595 1             mock_listdir.return_value = [file]
596 1             help = self.loop.run_until_complete(
597                 self.k8s_juju_conn.help_kdu("kdu_instance")
598             )
599 1             self.assertEqual(help, content)
600
601 1         self.assertEqual(mock_listdir.call_count, 3)
602 1         self.assertEqual(mock_open.call_count, 3)
603
604 1     @asynctest.mock.patch("builtins.open")
605 1     @asynctest.mock.patch("os.listdir")
606 1     def test_not_existing_file(self, mock_listdir, mock_open):
607 1         for file in ["src/charm.py", "tox.ini", "requirements.txt"]:
608 1             mock_listdir.return_value = [file]
609 1             help = self.loop.run_until_complete(
610                 self.k8s_juju_conn.help_kdu("kdu_instance")
611             )
612 1             self.assertEqual(help, None)
613
614 1         self.assertEqual(mock_listdir.call_count, 3)
615 1         self.assertEqual(mock_open.call_count, 0)
616
617
618 1 class StatusKduTest(K8sJujuConnTestCase):
619 1     def setUp(self):
620 1         super(StatusKduTest, self).setUp()
621 1         self.k8s_juju_conn.libjuju.get_model_status = AsyncMock()
622
623 1     def test_success(self):
624 1         applications = {"app": {"status": {"status": "active"}}}
625 1         model = FakeModel(applications=applications)
626 1         self.k8s_juju_conn.libjuju.get_model_status.return_value = model
627 1         status = self.loop.run_until_complete(
628             self.k8s_juju_conn.status_kdu("cluster", "kdu_instance")
629         )
630 1         self.assertEqual(status, {"app": {"status": "active"}})
631 1         self.k8s_juju_conn.libjuju.get_model_status.assert_called_once()
632
633 1     def test_exception(self):
634 1         self.k8s_juju_conn.libjuju.get_model_status.side_effect = Exception()
635 1         status = None
636 1         with self.assertRaises(Exception):
637 1             status = self.loop.run_until_complete(
638                 self.k8s_juju_conn.status_kdu("cluster", "kdu_instance")
639             )
640 1         self.assertIsNone(status)
641 1         self.k8s_juju_conn.libjuju.get_model_status.assert_called_once()
642
643
644 1 class GetServicesTest(K8sJujuConnTestCase):
645 1     def setUp(self):
646 1         super(GetServicesTest, self).setUp()
647
648 1     @asynctest.mock.patch("n2vc.k8s_juju_conn.K8sJujuConnector.get_credentials")
649 1     def test_success(self, mock_get_credentials):
650 1         mock_get_credentials.return_value = kubeconfig
651 1         self.loop.run_until_complete(self.k8s_juju_conn.get_services("", "", ""))
652 1         mock_get_credentials.assert_called_once()
653 1         self.kubectl.get_services.assert_called_once()
654
655
656 1 class GetServiceTest(K8sJujuConnTestCase):
657 1     def setUp(self):
658 1         super(GetServiceTest, self).setUp()
659
660 1     @asynctest.mock.patch("n2vc.k8s_juju_conn.K8sJujuConnector.get_credentials")
661 1     def test_success(self, mock_get_credentials):
662 1         mock_get_credentials.return_value = kubeconfig
663 1         self.loop.run_until_complete(self.k8s_juju_conn.get_service("", "", ""))
664 1         mock_get_credentials.assert_called_once()
665 1         self.kubectl.get_services.assert_called_once()
666
667
668 1 class GetCredentialsTest(K8sJujuConnTestCase):
669 1     def setUp(self):
670 1         super(GetCredentialsTest, self).setUp()
671
672 1     @asynctest.mock.patch("yaml.safe_dump")
673 1     def test_success(self, mock_safe_dump):
674 1         self.k8s_juju_conn.db.get_one.return_value = {
675             "_id": "id",
676             "credentials": "credentials",
677             "schema_version": "2",
678         }
679 1         self.k8s_juju_conn.get_credentials("cluster_uuid")
680 1         self.k8s_juju_conn.db.get_one.assert_called_once()
681 1         self.k8s_juju_conn.db.encrypt_decrypt_fields.assert_called_once()
682 1         mock_safe_dump.assert_called_once()
683
684
685 1 class UpdateVcaStatusTest(K8sJujuConnTestCase):
686 1     def setUp(self):
687 1         super(UpdateVcaStatusTest, self).setUp()
688 1         self.vcaStatus = {"model": {"applications": {"app": {"actions": {}}}}}
689 1         self.k8s_juju_conn.libjuju.get_executed_actions = AsyncMock()
690 1         self.k8s_juju_conn.libjuju.get_actions = AsyncMock()
691 1         self.k8s_juju_conn.libjuju.get_application_configs = AsyncMock()
692
693 1     def test_success(self):
694 1         self.loop.run_until_complete(
695             self.k8s_juju_conn.update_vca_status(self.vcaStatus, self.kdu_instance)
696         )
697 1         self.k8s_juju_conn.libjuju.get_executed_actions.assert_called_once()
698 1         self.k8s_juju_conn.libjuju.get_application_configs.assert_called_once()
699
700 1     def test_exception(self):
701 1         self.k8s_juju_conn.libjuju.get_model.return_value = None
702 1         self.k8s_juju_conn.libjuju.get_executed_actions.side_effect = Exception()
703 1         with self.assertRaises(Exception):
704 1             self.loop.run_until_complete(
705                 self.k8s_juju_conn.update_vca_status(self.vcaStatus, self.kdu_instance)
706             )
707 1             self.k8s_juju_conn.libjuju.get_executed_actions.assert_not_called()
708 0             self.k8s_juju_conn.libjuju.get_application_configs.assert_not_called_once()
709
710
711 1 class ScaleTest(K8sJujuConnTestCase):
712 1     def setUp(self):
713 1         super(ScaleTest, self).setUp()
714 1         self.application_name = "app"
715 1         self.kdu_name = "kdu-instance"
716 1         self._scale = 2
717 1         self.k8s_juju_conn.libjuju.scale_application = AsyncMock()
718
719 1     def test_success(self):
720 1         self.loop.run_until_complete(
721             self.k8s_juju_conn.scale(self.kdu_name, self._scale, self.application_name)
722         )
723 1         self.k8s_juju_conn.libjuju.scale_application.assert_called_once()
724
725 1     def test_exception(self):
726 1         self.k8s_juju_conn.libjuju.scale_application.side_effect = Exception()
727 1         with self.assertRaises(Exception):
728 1             self.loop.run_until_complete(
729                 self.k8s_juju_conn.scale(
730                     self.kdu_name, self._scale, self.application_name
731                 )
732             )
733 1         self.k8s_juju_conn.libjuju.scale_application.assert_called_once()
734
735
736 1 class GetScaleCount(K8sJujuConnTestCase):
737 1     def setUp(self):
738 1         super(GetScaleCount, self).setUp()
739 1         self.k8s_juju_conn.libjuju.get_model_status = AsyncMock()
740
741 1     def test_success(self):
742 1         applications = {"app": FakeApplication()}
743 1         model = FakeModel(applications=applications)
744 1         self.k8s_juju_conn.libjuju.get_model_status.return_value = model
745 1         status = self.loop.run_until_complete(
746             self.k8s_juju_conn.get_scale_count("app", "kdu_instance")
747         )
748 1         self.assertEqual(status, 2)
749 1         self.k8s_juju_conn.libjuju.get_model_status.assert_called_once()
750
751 1     def test_exception(self):
752 1         self.k8s_juju_conn.libjuju.get_model_status.side_effect = Exception()
753 1         status = None
754 1         with self.assertRaises(Exception):
755 1             status = self.loop.run_until_complete(
756                 self.k8s_juju_conn.status_kdu("app", "kdu_instance")
757             )
758 1         self.assertIsNone(status)
759 1         self.k8s_juju_conn.libjuju.get_model_status.assert_called_once()
760
761
762 1 class AddRelationTest(K8sJujuConnTestCase):
763 1     def setUp(self):
764 1         super(AddRelationTest, self).setUp()
765 1         self.k8s_juju_conn.libjuju.add_relation = AsyncMock()
766 1         self.k8s_juju_conn.libjuju.offer = AsyncMock()
767 1         self.k8s_juju_conn.libjuju.get_controller = AsyncMock()
768 1         self.k8s_juju_conn.libjuju.consume = AsyncMock()
769
770 1     def test_standard_relation_same_model_and_controller(self):
771 1         relation_endpoint_1 = RelationEndpoint("model-1.app1.0", None, "endpoint1")
772 1         relation_endpoint_2 = RelationEndpoint("model-1.app2.1", None, "endpoint2")
773 1         self.loop.run_until_complete(
774             self.k8s_juju_conn.add_relation(relation_endpoint_1, relation_endpoint_2)
775         )
776 1         self.k8s_juju_conn.libjuju.add_relation.assert_called_once_with(
777             model_name="model-1",
778             endpoint_1="app1:endpoint1",
779             endpoint_2="app2:endpoint2",
780         )
781 1         self.k8s_juju_conn.libjuju.offer.assert_not_called()
782 1         self.k8s_juju_conn.libjuju.consume.assert_not_called()
783
784 1     def test_cmr_relation_same_controller(self):
785 1         relation_endpoint_1 = RelationEndpoint("model-1.app1.0", None, "endpoint")
786 1         relation_endpoint_2 = RelationEndpoint("model-2.app2.1", None, "endpoint")
787 1         offer = Offer("admin/model-1.app1")
788 1         self.k8s_juju_conn.libjuju.offer.return_value = offer
789 1         self.k8s_juju_conn.libjuju.consume.return_value = "saas"
790 1         self.loop.run_until_complete(
791             self.k8s_juju_conn.add_relation(relation_endpoint_1, relation_endpoint_2)
792         )
793 1         self.k8s_juju_conn.libjuju.offer.assert_called_once_with(relation_endpoint_1)
794 1         self.k8s_juju_conn.libjuju.consume.assert_called_once()
795 1         self.k8s_juju_conn.libjuju.add_relation.assert_called_once_with(
796             "model-2", "app2:endpoint", "saas"
797         )
798
799 1     def test_cmr_relation_different_controller(self):
800 1         self.k8s_juju_conn._get_libjuju = AsyncMock(
801             return_value=self.k8s_juju_conn.libjuju
802         )
803 1         relation_endpoint_1 = RelationEndpoint("model-1.app1.0", "vca-id-1", "endpoint")
804 1         relation_endpoint_2 = RelationEndpoint("model-1.app2.1", "vca-id-2", "endpoint")
805 1         offer = Offer("admin/model-1.app1")
806 1         self.k8s_juju_conn.libjuju.offer.return_value = offer
807 1         self.k8s_juju_conn.libjuju.consume.return_value = "saas"
808 1         self.loop.run_until_complete(
809             self.k8s_juju_conn.add_relation(relation_endpoint_1, relation_endpoint_2)
810         )
811 1         self.k8s_juju_conn.libjuju.offer.assert_called_once_with(relation_endpoint_1)
812 1         self.k8s_juju_conn.libjuju.consume.assert_called_once()
813 1         self.k8s_juju_conn.libjuju.add_relation.assert_called_once_with(
814             "model-1", "app2:endpoint", "saas"
815         )
816
817 1     def test_relation_exception(self):
818 1         relation_endpoint_1 = RelationEndpoint("model-1.app1.0", None, "endpoint")
819 1         relation_endpoint_2 = RelationEndpoint("model-2.app2.1", None, "endpoint")
820 1         self.k8s_juju_conn.libjuju.offer.side_effect = Exception()
821 1         with self.assertRaises(Exception):
822 1             self.loop.run_until_complete(
823                 self.k8s_juju_conn.add_relation(
824                     relation_endpoint_1, relation_endpoint_2
825                 )
826             )