Fix validation error for ImagePullPolicy in charms
[osm/devops.git] / installers / charm / lcm / tests / test_charm.py
1 #!/usr/bin/env python3
2 # Copyright 2021 Canonical Ltd.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
14 # under the License.
15 #
16 # For those usages not covered by the Apache License, Version 2.0 please
17 # contact: legal@canonical.com
18 #
19 # To get in touch with the maintainers, please contact:
20 # osm-charmers@lists.launchpad.net
21 ##
22
23 import sys
24 from typing import NoReturn
25 import unittest
26
27 from charm import LcmCharm
28 import mock
29 from ops.model import ActiveStatus, BlockedStatus
30 from ops.testing import Harness
31
32
33 class TestCharm(unittest.TestCase):
34 """LCM Charm unit tests."""
35
36 def setUp(self) -> NoReturn:
37 """Test setup"""
38 self.image_info = sys.modules["oci_image"].OCIImageResource().fetch()
39 self.harness = Harness(LcmCharm)
40 self.harness.set_leader(is_leader=True)
41 self.harness.begin()
42 self.config = {
43 "vca_host": "192.168.0.13",
44 "vca_port": 17070,
45 "vca_user": "admin",
46 "vca_secret": "admin",
47 "vca_pubkey": "key",
48 "vca_cacert": "cacert",
49 "vca_cloud": "cloud",
50 "vca_k8s_cloud": "k8scloud",
51 "database_commonkey": "commonkey",
52 "mongodb_uri": "",
53 "log_level": "INFO",
54 }
55 self.harness.update_config(self.config)
56
57 def test_config_changed_no_relations(
58 self,
59 ) -> NoReturn:
60 """Test ingress resources without HTTP."""
61
62 self.harness.charm.on.config_changed.emit()
63
64 # Assertions
65 self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
66 self.assertTrue(
67 all(
68 relation in self.harness.charm.unit.status.message
69 for relation in ["mongodb", "kafka", "ro"]
70 )
71 )
72
73 def test_config_changed_non_leader(
74 self,
75 ) -> NoReturn:
76 """Test ingress resources without HTTP."""
77 self.harness.set_leader(is_leader=False)
78 self.harness.charm.on.config_changed.emit()
79
80 # Assertions
81 self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
82
83 def test_with_relations_and_mongodb_config(
84 self,
85 ) -> NoReturn:
86 "Test with relations and mongodb config"
87 self.initialize_kafka_relation()
88 self.initialize_mongo_config()
89 self.initialize_ro_relation()
90 # Verifying status
91 self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
92
93 def test_with_relations(
94 self,
95 ) -> NoReturn:
96 "Test with relations (internal)"
97 self.initialize_kafka_relation()
98 self.initialize_mongo_relation()
99 self.initialize_ro_relation()
100 # Verifying status
101 self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
102
103 def test_exception_mongodb_relation_and_config(
104 self,
105 ) -> NoReturn:
106 "Test with all relations and config for mongodb. Must fail"
107 self.initialize_mongo_relation()
108 self.initialize_mongo_config()
109 # Verifying status
110 self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
111
112 def test_build_pod_spec(
113 self,
114 ) -> NoReturn:
115 expected_config = {
116 "OSMLCM_GLOBAL_LOGLEVEL": self.config["log_level"],
117 "OSMLCM_DATABASE_COMMONKEY": self.config["database_commonkey"],
118 }
119 expected_config.update(
120 {
121 f"OSMLCM_{k.upper()}": v
122 for k, v in self.config.items()
123 if k.startswith("vca_")
124 }
125 )
126 self.harness.charm._check_missing_dependencies = mock.Mock()
127 pod_spec = self.harness.charm.build_pod_spec(
128 {"imageDetails": {"imagePath": "lcm-image"}}
129 )
130 actual_config = pod_spec["containers"][0]["envConfig"]
131
132 self.assertDictContainsSubset(
133 expected_config,
134 actual_config,
135 )
136 for config_key in actual_config:
137 self.assertNotIn("VCA_MODEL_CONFIG", config_key)
138
139 def test_build_pod_spec_with_model_config(
140 self,
141 ) -> NoReturn:
142 self.harness.update_config(
143 {
144 "vca_model_config_agent_metadata_url": "string",
145 "vca_model_config_agent_stream": "string",
146 "vca_model_config_apt_ftp_proxy": "string",
147 "vca_model_config_apt_http_proxy": "string",
148 "vca_model_config_apt_https_proxy": "string",
149 "vca_model_config_apt_mirror": "string",
150 "vca_model_config_apt_no_proxy": "string",
151 "vca_model_config_automatically_retry_hooks": False,
152 "vca_model_config_backup_dir": "string",
153 "vca_model_config_cloudinit_userdata": "string",
154 "vca_model_config_container_image_metadata_url": "string",
155 "vca_model_config_container_image_stream": "string",
156 "vca_model_config_container_inherit_properties": "string",
157 "vca_model_config_container_networking_method": "string",
158 "vca_model_config_default_series": "string",
159 "vca_model_config_default_space": "string",
160 "vca_model_config_development": False,
161 "vca_model_config_disable_network_management": False,
162 "vca_model_config_egress_subnets": "string",
163 "vca_model_config_enable_os_refresh_update": False,
164 "vca_model_config_enable_os_upgrade": False,
165 "vca_model_config_fan_config": "string",
166 "vca_model_config_firewall_mode": "string",
167 "vca_model_config_ftp_proxy": "string",
168 "vca_model_config_http_proxy": "string",
169 "vca_model_config_https_proxy": "string",
170 "vca_model_config_ignore_machine_addresses": False,
171 "vca_model_config_image_metadata_url": "string",
172 "vca_model_config_image_stream": "string",
173 "vca_model_config_juju_ftp_proxy": "string",
174 "vca_model_config_juju_http_proxy": "string",
175 "vca_model_config_juju_https_proxy": "string",
176 "vca_model_config_juju_no_proxy": "string",
177 "vca_model_config_logforward_enabled": False,
178 "vca_model_config_logging_config": "string",
179 "vca_model_config_lxd_snap_channel": "string",
180 "vca_model_config_max_action_results_age": "string",
181 "vca_model_config_max_action_results_size": "string",
182 "vca_model_config_max_status_history_age": "string",
183 "vca_model_config_max_status_history_size": "string",
184 "vca_model_config_net_bond_reconfigure_delay": "string",
185 "vca_model_config_no_proxy": "string",
186 "vca_model_config_provisioner_harvest_mode": "string",
187 "vca_model_config_proxy_ssh": False,
188 "vca_model_config_snap_http_proxy": "string",
189 "vca_model_config_snap_https_proxy": "string",
190 "vca_model_config_snap_store_assertions": "string",
191 "vca_model_config_snap_store_proxy": "string",
192 "vca_model_config_snap_store_proxy_url": "string",
193 "vca_model_config_ssl_hostname_verification": False,
194 "vca_model_config_test_mode": False,
195 "vca_model_config_transmit_vendor_metrics": False,
196 "vca_model_config_update_status_hook_interval": "string",
197 }
198 )
199 expected_config = {
200 f"OSMLCM_{k.upper()}": v
201 for k, v in self.config.items()
202 if k.startswith("vca_model_config_")
203 }
204
205 self.harness.charm._check_missing_dependencies = mock.Mock()
206 pod_spec = self.harness.charm.build_pod_spec(
207 {"imageDetails": {"imagePath": "lcm-image"}}
208 )
209 actual_config = pod_spec["containers"][0]["envConfig"]
210
211 self.assertDictContainsSubset(
212 expected_config,
213 actual_config,
214 )
215
216 def initialize_kafka_relation(self):
217 kafka_relation_id = self.harness.add_relation("kafka", "kafka")
218 self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
219 self.harness.update_relation_data(
220 kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
221 )
222
223 def initialize_mongo_config(self):
224 self.harness.update_config({"mongodb_uri": "mongodb://mongo:27017"})
225
226 def initialize_mongo_relation(self):
227 mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
228 self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
229 self.harness.update_relation_data(
230 mongodb_relation_id,
231 "mongodb/0",
232 {"connection_string": "mongodb://mongo:27017"},
233 )
234
235 def initialize_ro_relation(self):
236 http_relation_id = self.harness.add_relation("ro", "ro")
237 self.harness.add_relation_unit(http_relation_id, "ro")
238 self.harness.update_relation_data(
239 http_relation_id,
240 "ro",
241 {"host": "ro", "port": 9090},
242 )
243
244
245 if __name__ == "__main__":
246 unittest.main()
247
248
249 # class TestCharm(unittest.TestCase):
250 # """LCM Charm unit tests."""
251
252 # def setUp(self) -> NoReturn:
253 # """Test setup"""
254 # self.harness = Harness(LcmCharm)
255 # self.harness.set_leader(is_leader=True)
256 # self.harness.begin()
257
258 # def test_on_start_without_relations(self) -> NoReturn:
259 # """Test installation without any relation."""
260 # self.harness.charm.on.start.emit()
261
262 # # Verifying status
263 # self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
264
265 # # Verifying status message
266 # self.assertGreater(len(self.harness.charm.unit.status.message), 0)
267 # self.assertTrue(
268 # self.harness.charm.unit.status.message.startswith("Waiting for ")
269 # )
270 # self.assertIn("kafka", self.harness.charm.unit.status.message)
271 # self.assertIn("mongodb", self.harness.charm.unit.status.message)
272 # self.assertIn("ro", self.harness.charm.unit.status.message)
273 # self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))
274
275 # def test_on_start_with_relations(self) -> NoReturn:
276 # """Test deployment without keystone."""
277 # expected_result = {
278 # "version": 3,
279 # "containers": [
280 # {
281 # "name": "lcm",
282 # "imageDetails": self.harness.charm.image.fetch(),
283 # "imagePullPolicy": "Always",
284 # "ports": [
285 # {
286 # "name": "lcm",
287 # "containerPort": 9999,
288 # "protocol": "TCP",
289 # }
290 # ],
291 # "envConfig": {
292 # "ALLOW_ANONYMOUS_LOGIN": "yes",
293 # "OSMLCM_GLOBAL_LOGLEVEL": "INFO",
294 # "OSMLCM_RO_HOST": "ro",
295 # "OSMLCM_RO_PORT": 9090,
296 # "OSMLCM_RO_TENANT": "osm",
297 # "OSMLCM_MESSAGE_DRIVER": "kafka",
298 # "OSMLCM_MESSAGE_HOST": "kafka",
299 # "OSMLCM_MESSAGE_PORT": 9092,
300 # "OSMLCM_DATABASE_DRIVER": "mongo",
301 # "OSMLCM_DATABASE_URI": "mongodb://mongo:27017",
302 # "OSMLCM_DATABASE_COMMONKEY": "osm",
303 # "OSMLCM_STORAGE_DRIVER": "mongo",
304 # "OSMLCM_STORAGE_PATH": "/app/storage",
305 # "OSMLCM_STORAGE_COLLECTION": "files",
306 # "OSMLCM_STORAGE_URI": "mongodb://mongo:27017",
307 # "OSMLCM_VCA_HOST": "admin",
308 # "OSMLCM_VCA_PORT": 17070,
309 # "OSMLCM_VCA_USER": "admin",
310 # "OSMLCM_VCA_PUBKEY": "secret",
311 # "OSMLCM_VCA_SECRET": "secret",
312 # "OSMLCM_VCA_CACERT": "",
313 # "OSMLCM_VCA_CLOUD": "localhost",
314 # "OSMLCM_VCA_K8S_CLOUD": "k8scloud",
315 # },
316 # }
317 # ],
318 # "kubernetesResources": {"ingressResources": []},
319 # }
320
321 # self.harness.charm.on.start.emit()
322
323 # # Check if kafka datastore is initialized
324 # self.assertIsNone(self.harness.charm.state.message_host)
325 # self.assertIsNone(self.harness.charm.state.message_port)
326
327 # # Check if mongodb datastore is initialized
328 # self.assertIsNone(self.harness.charm.state.database_uri)
329
330 # # Check if RO datastore is initialized
331 # self.assertIsNone(self.harness.charm.state.ro_host)
332 # self.assertIsNone(self.harness.charm.state.ro_port)
333
334 # # Initializing the kafka relation
335 # kafka_relation_id = self.harness.add_relation("kafka", "kafka")
336 # self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
337 # self.harness.update_relation_data(
338 # kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
339 # )
340
341 # # Initializing the mongo relation
342 # mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
343 # self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
344 # self.harness.update_relation_data(
345 # mongodb_relation_id,
346 # "mongodb/0",
347 # {"connection_string": "mongodb://mongo:27017"},
348 # )
349
350 # # Initializing the RO relation
351 # ro_relation_id = self.harness.add_relation("ro", "ro")
352 # self.harness.add_relation_unit(ro_relation_id, "ro/0")
353 # self.harness.update_relation_data(
354 # ro_relation_id, "ro/0", {"host": "ro", "port": 9090}
355 # )
356
357 # # Checking if kafka data is stored
358 # self.assertEqual(self.harness.charm.state.message_host, "kafka")
359 # self.assertEqual(self.harness.charm.state.message_port, 9092)
360
361 # # Checking if mongodb data is stored
362 # self.assertEqual(self.harness.charm.state.database_uri, "mongodb://mongo:27017")
363
364 # # Checking if RO data is stored
365 # self.assertEqual(self.harness.charm.state.ro_host, "ro")
366 # self.assertEqual(self.harness.charm.state.ro_port, 9090)
367
368 # # Verifying status
369 # self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
370
371 # pod_spec, _ = self.harness.get_pod_spec()
372
373 # self.assertDictEqual(expected_result, pod_spec)
374
375 # def test_on_kafka_relation_unit_changed(self) -> NoReturn:
376 # """Test to see if kafka relation is updated."""
377 # self.harness.charm.on.start.emit()
378
379 # self.assertIsNone(self.harness.charm.state.message_host)
380 # self.assertIsNone(self.harness.charm.state.message_port)
381
382 # relation_id = self.harness.add_relation("kafka", "kafka")
383 # self.harness.add_relation_unit(relation_id, "kafka/0")
384 # self.harness.update_relation_data(
385 # relation_id, "kafka/0", {"host": "kafka", "port": 9092}
386 # )
387
388 # self.assertEqual(self.harness.charm.state.message_host, "kafka")
389 # self.assertEqual(self.harness.charm.state.message_port, 9092)
390
391 # # Verifying status
392 # self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
393
394 # # Verifying status message
395 # self.assertGreater(len(self.harness.charm.unit.status.message), 0)
396 # self.assertTrue(
397 # self.harness.charm.unit.status.message.startswith("Waiting for ")
398 # )
399 # self.assertNotIn("kafka", self.harness.charm.unit.status.message)
400 # self.assertIn("mongodb", self.harness.charm.unit.status.message)
401 # self.assertIn("ro", self.harness.charm.unit.status.message)
402 # self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))
403
404 # def test_on_mongodb_unit_relation_changed(self) -> NoReturn:
405 # """Test to see if mongodb relation is updated."""
406 # self.harness.charm.on.start.emit()
407
408 # self.assertIsNone(self.harness.charm.state.database_uri)
409
410 # relation_id = self.harness.add_relation("mongodb", "mongodb")
411 # self.harness.add_relation_unit(relation_id, "mongodb/0")
412 # self.harness.update_relation_data(
413 # relation_id, "mongodb/0", {"connection_string": "mongodb://mongo:27017"}
414 # )
415
416 # self.assertEqual(self.harness.charm.state.database_uri, "mongodb://mongo:27017")
417
418 # # Verifying status
419 # self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
420
421 # # Verifying status message
422 # self.assertGreater(len(self.harness.charm.unit.status.message), 0)
423 # self.assertTrue(
424 # self.harness.charm.unit.status.message.startswith("Waiting for ")
425 # )
426 # self.assertIn("kafka", self.harness.charm.unit.status.message)
427 # self.assertNotIn("mongodb", self.harness.charm.unit.status.message)
428 # self.assertIn("ro", self.harness.charm.unit.status.message)
429 # self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))
430
431 # def test_on_ro_unit_relation_changed(self) -> NoReturn:
432 # """Test to see if RO relation is updated."""
433 # self.harness.charm.on.start.emit()
434
435 # self.assertIsNone(self.harness.charm.state.ro_host)
436 # self.assertIsNone(self.harness.charm.state.ro_port)
437
438 # relation_id = self.harness.add_relation("ro", "ro")
439 # self.harness.add_relation_unit(relation_id, "ro/0")
440 # self.harness.update_relation_data(
441 # relation_id, "ro/0", {"host": "ro", "port": 9090}
442 # )
443
444 # self.assertEqual(self.harness.charm.state.ro_host, "ro")
445 # self.assertEqual(self.harness.charm.state.ro_port, 9090)
446
447 # # Verifying status
448 # self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
449
450 # # Verifying status message
451 # self.assertGreater(len(self.harness.charm.unit.status.message), 0)
452 # self.assertTrue(
453 # self.harness.charm.unit.status.message.startswith("Waiting for ")
454 # )
455 # self.assertIn("kafka", self.harness.charm.unit.status.message)
456 # self.assertIn("mongodb", self.harness.charm.unit.status.message)
457 # self.assertNotIn("ro", self.harness.charm.unit.status.message)
458 # self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))
459
460
461 # if __name__ == "__main__":
462 # unittest.main()