Merge ~gabrielcocenza/juju-lint:bug/1988851 into juju-lint:master
- Git
- lp:~gabrielcocenza/juju-lint
- bug/1988851
- Merge into master
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Eric Chen | ||||
Approved revision: | d520551fb9eb9060f7c7b00ce6688bfe9aa61958 | ||||
Merged at revision: | 3684a5c1f7e315832720e859f0e4a78c757e7d9a | ||||
Proposed branch: | ~gabrielcocenza/juju-lint:bug/1988851 | ||||
Merge into: | juju-lint:master | ||||
Prerequisite: | ~gabrielcocenza/juju-lint:bug/1979542 | ||||
Diff against target: |
1242 lines (+633/-141) 5 files modified
contrib/includes/networking/ovn.yaml (+14/-6) contrib/includes/networking/ovs.yaml (+10/-2) contrib/includes/openstack.yaml (+0/-5) jujulint/lint.py (+142/-48) tests/unit/test_jujulint.py (+467/-80) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Eric Chen | Approve | ||
🤖 prod-jenkaas-bootstack | continuous-integration | Approve | |
Nobuto Murata (community) | Approve | ||
Review via email: mp+429591@code.launchpad.net |
Commit message
check path_mtu values depending on the networking solution (ovs, ovn)
- added the possibility of adding custom messages and log level for
config checks (isset, eq, neq, gte and search)
Closes-Bug: #1988851
Description of the change
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Eric Chen (eric-chen) wrote : | # |
Do we need the function to adding custom messages in this PR? it seems an additional feature to me.
Eric Chen (eric-chen) wrote : | # |
Leave similar quiestion inline
Gabriel Cocenza (gabrielcocenza) wrote : | # |
Yes, it's actually two new features: ability of controlling log-level and custom message on every application config.
I think it's a good versatility to have this option of customizing messages and control the log-level on every application configuration. Let's get the neutron-api configuration of path-mtu for example:
- If we can't insert a custom message, the user would receive an error message saying:
Application neutron-api has config for path-mtu which is bigger than 1550: 2000
This standard message doesn't say much what actually this value can cause
The problem with this is:
- having a value bigger than 1550 it's not considered "wrong" depending on the networking solution, so it makes more sense send a warn message explaining what can happen if the value is bigger.
I can see this customization been useful on every "operator". Maybe using isset to False in a configuration is opinionated and not necessarily wrong.
pastebin of tests (lint, unit, func) https:/
Nobuto Murata (nobuto) : | # |
Gabriel Cocenza (gabrielcocenza) wrote : | # |
Thanks for your review Nobuto.
I've updated the patch including your suggestions.
Here[0] is the logs of unit, lint and functional tests.
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
PASSED: Continuous integration, rev:f33c606a7fb
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
FAILED: Continuous integration, rev:dcf5cae9837
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
FAILED: Continuous integration, rev:dcf5cae9837
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
FAILED: Continuous integration, rev:dcf5cae9837
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
FAILED: Continuous integration, rev:dcf5cae9837
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
PASSED: Continuous integration, rev:dcf5cae9837
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Nobuto Murata (nobuto) wrote : | # |
Left a nit-picking comment, other than that it looks good to me.
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
PASSED: Continuous integration, rev:d520551fb9e
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Eric Chen (eric-chen) : | # |
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Change successfully merged at revision 3684a5c1f7e3158
Preview Diff
1 | diff --git a/contrib/includes/networking/ovn.yaml b/contrib/includes/networking/ovn.yaml |
2 | index b4f4140..bba04d5 100644 |
3 | --- a/contrib/includes/networking/ovn.yaml |
4 | +++ b/contrib/includes/networking/ovn.yaml |
5 | @@ -1,9 +1,17 @@ |
6 | openstack config networking: &openstack-config-networking |
7 | - ovn-central: |
8 | - ovsdb-server-election-timer: |
9 | - gte: 4 |
10 | + ovn-central: |
11 | + ovsdb-server-election-timer: |
12 | + gte: 4 |
13 | + neutron-api: |
14 | + path-mtu: |
15 | + gte: 1558 |
16 | + log-level: warning |
17 | + custom-message: > |
18 | + Usable MTU for a tenant network is less than 1500. |
19 | + global-physnet-mtu: |
20 | + eq: 9000 |
21 | |
22 | openstack mandatory charms networking: &openstack-mandatory-charms-networking |
23 | - - ovn-central |
24 | - - ovn-chassis |
25 | - - neutron-api-plugin-ovn |
26 | + - ovn-central |
27 | + - ovn-chassis |
28 | + - neutron-api-plugin-ovn |
29 | diff --git a/contrib/includes/networking/ovs.yaml b/contrib/includes/networking/ovs.yaml |
30 | index 493195e..4cba606 100644 |
31 | --- a/contrib/includes/networking/ovs.yaml |
32 | +++ b/contrib/includes/networking/ovs.yaml |
33 | @@ -1,4 +1,12 @@ |
34 | -openstack config networking: &openstack-config-networking {} |
35 | +openstack config networking: &openstack-config-networking |
36 | + neutron-api: |
37 | + path-mtu: |
38 | + gte: 1550 |
39 | + log-level: warning |
40 | + custom-message: > |
41 | + Usable MTU for a tenant network is less than 1500. |
42 | + global-physnet-mtu: |
43 | + eq: 9000 |
44 | |
45 | openstack mandatory charms networking: &openstack-mandatory-charms-networking |
46 | - - neutron-openvswitch |
47 | + - neutron-openvswitch |
48 | diff --git a/contrib/includes/openstack.yaml b/contrib/includes/openstack.yaml |
49 | index 01317e2..86af4da 100644 |
50 | --- a/contrib/includes/openstack.yaml |
51 | +++ b/contrib/includes/openstack.yaml |
52 | @@ -14,11 +14,6 @@ openstack config base: &openstack-config-base |
53 | glance: |
54 | ceph-osd-replication-count: |
55 | eq: 3 |
56 | - neutron-api: |
57 | - path-mtu: |
58 | - eq: 9000 |
59 | - global-physnet-mtu: |
60 | - eq: 9000 |
61 | nova-compute: |
62 | cpu-model: |
63 | neq: "" |
64 | diff --git a/jujulint/lint.py b/jujulint/lint.py |
65 | index 8bbcff4..b8fa535 100755 |
66 | --- a/jujulint/lint.py |
67 | +++ b/jujulint/lint.py |
68 | @@ -40,8 +40,14 @@ from jujulint.model_input import input_handler |
69 | from jujulint.relations import RelationError, RelationsRulesBootStrap |
70 | |
71 | VALID_CONFIG_CHECKS = ("isset", "eq", "neq", "gte", "search") |
72 | - |
73 | -# Generic named tuple to represent the binary config operators (eq,neq,gte) |
74 | +VALID_LOG_LEVEL = { |
75 | + "debug": logging.DEBUG, |
76 | + "info": logging.INFO, |
77 | + "warning": logging.WARNING, |
78 | + "error": logging.ERROR, |
79 | +} |
80 | + |
81 | +# Generic named tuple to represent the binary config operators (eq, neq, gte) |
82 | ConfigOperator = collections.namedtuple( |
83 | "ConfigOperator", "name repr check error_template" |
84 | ) |
85 | @@ -212,7 +218,15 @@ class Linter: |
86 | |
87 | return _int * conv[suffix.lower()] |
88 | |
89 | - def isset(self, name, check_value, rule, config): |
90 | + def isset( |
91 | + self, |
92 | + name, |
93 | + check_value, |
94 | + rule, |
95 | + config, |
96 | + log_level=logging.ERROR, |
97 | + custom_message="", |
98 | + ): |
99 | """Check if value is set per rule constraints.""" |
100 | if rule in config: |
101 | if check_value is True: |
102 | @@ -225,7 +239,7 @@ class Linter: |
103 | ) |
104 | return True |
105 | actual_value = config[rule] |
106 | - self.handle_error( |
107 | + self.message_handler( |
108 | { |
109 | "id": "config-isset-check-false", |
110 | "tags": ["config", "isset"], |
111 | @@ -233,10 +247,12 @@ class Linter: |
112 | "application": name, |
113 | "rule": rule, |
114 | "actual_value": actual_value, |
115 | - "message": "Application {} has config for {}: {}.".format( |
116 | + "message": custom_message |
117 | + or "Application {} has config for {}: {}.".format( |
118 | name, rule, actual_value |
119 | ), |
120 | - } |
121 | + }, |
122 | + log_level=log_level, |
123 | ) |
124 | return False |
125 | elif check_value is False: |
126 | @@ -247,19 +263,29 @@ class Linter: |
127 | ) |
128 | ) |
129 | return True |
130 | - self.handle_error( |
131 | + self.message_handler( |
132 | { |
133 | "id": "config-isset-check-true", |
134 | "tags": ["config", "isset"], |
135 | "description": "Checks for config condition 'isset' true", |
136 | "application": name, |
137 | "rule": rule, |
138 | - "message": "Application {} has no config for {}.".format(name, rule), |
139 | - } |
140 | + "message": custom_message |
141 | + or "Application {} has no config for {}.".format(name, rule), |
142 | + }, |
143 | + log_level=log_level, |
144 | ) |
145 | return False |
146 | |
147 | - def eq(self, app_name, check_value, config_key, app_config): |
148 | + def eq( |
149 | + self, |
150 | + app_name, |
151 | + check_value, |
152 | + config_key, |
153 | + app_config, |
154 | + log_level=logging.ERROR, |
155 | + custom_message="", |
156 | + ): |
157 | """Check if value matches the provided value or regex, autodetecting regex.""" |
158 | operator = ConfigOperator( |
159 | name="eq", |
160 | @@ -269,10 +295,24 @@ class Linter: |
161 | ) |
162 | |
163 | return self.check_config_generic( |
164 | - operator, app_name, check_value, config_key, app_config |
165 | + operator, |
166 | + app_name, |
167 | + check_value, |
168 | + config_key, |
169 | + app_config, |
170 | + log_level, |
171 | + custom_message, |
172 | ) |
173 | |
174 | - def neq(self, app_name, check_value, config_key, app_config): |
175 | + def neq( |
176 | + self, |
177 | + app_name, |
178 | + check_value, |
179 | + config_key, |
180 | + app_config, |
181 | + log_level=logging.ERROR, |
182 | + custom_message="", |
183 | + ): |
184 | """Check if value does not match a the config.""" |
185 | operator = ConfigOperator( |
186 | name="neq", |
187 | @@ -282,10 +322,24 @@ class Linter: |
188 | ) |
189 | |
190 | return self.check_config_generic( |
191 | - operator, app_name, check_value, config_key, app_config |
192 | + operator, |
193 | + app_name, |
194 | + check_value, |
195 | + config_key, |
196 | + app_config, |
197 | + log_level, |
198 | + custom_message, |
199 | ) |
200 | |
201 | - def gte(self, app_name, check_value, config_key, app_config): |
202 | + def gte( |
203 | + self, |
204 | + app_name, |
205 | + check_value, |
206 | + config_key, |
207 | + app_config, |
208 | + log_level=logging.ERROR, |
209 | + custom_message="", |
210 | + ): |
211 | """Check if value is greater than or equal to the check value.""" |
212 | |
213 | def operator_gte_check(check_value, actual_value): |
214 | @@ -302,10 +356,24 @@ class Linter: |
215 | ) |
216 | |
217 | return self.check_config_generic( |
218 | - operator, app_name, check_value, config_key, app_config |
219 | + operator, |
220 | + app_name, |
221 | + check_value, |
222 | + config_key, |
223 | + app_config, |
224 | + log_level, |
225 | + custom_message, |
226 | ) |
227 | |
228 | - def search(self, app_name, check_value, config_key, app_config): |
229 | + def search( |
230 | + self, |
231 | + app_name, |
232 | + check_value, |
233 | + config_key, |
234 | + app_config, |
235 | + log_level=logging.ERROR, |
236 | + custom_message="", |
237 | + ): |
238 | """Scan through the charm config looking for a match using the regex pattern.""" |
239 | if config_key in app_config: |
240 | actual_value = app_config.get(config_key) |
241 | @@ -319,7 +387,7 @@ class Linter: |
242 | ) |
243 | ) |
244 | return True |
245 | - self.handle_error( |
246 | + self.message_handler( |
247 | { |
248 | "id": "config-search-check", |
249 | "tags": ["config", "search"], |
250 | @@ -328,13 +396,15 @@ class Linter: |
251 | "rule": config_key, |
252 | "expected_value": check_value, |
253 | "actual_value": actual_value, |
254 | - "message": "Application {} has an invalid config for '{}': regex {} not found at {}".format( |
255 | + "message": custom_message |
256 | + or "Application {} has an invalid config for '{}': regex {} not found at {}".format( |
257 | app_name, |
258 | config_key, |
259 | repr(check_value), |
260 | repr(actual_value), |
261 | ), |
262 | - } |
263 | + }, |
264 | + log_level=log_level, |
265 | ) |
266 | return False |
267 | |
268 | @@ -349,7 +419,14 @@ class Linter: |
269 | return False |
270 | |
271 | def check_config_generic( |
272 | - self, operator, app_name, check_value, config_key, app_config |
273 | + self, |
274 | + operator, |
275 | + app_name, |
276 | + check_value, |
277 | + config_key, |
278 | + app_config, |
279 | + log_level=logging.ERROR, |
280 | + custom_message="", |
281 | ): |
282 | """Apply the provided config operator to the configuration.""" |
283 | # First check if the config key is present |
284 | @@ -380,7 +457,7 @@ class Linter: |
285 | ) |
286 | return True |
287 | else: |
288 | - self.handle_error( |
289 | + self.message_handler( |
290 | { |
291 | "id": "config-{}-check".format(operator.name), |
292 | "tags": ["config", operator.name], |
293 | @@ -391,13 +468,15 @@ class Linter: |
294 | "rule": config_key, |
295 | "expected_value": check_value, |
296 | "actual_value": actual_value, |
297 | - "message": operator.error_template.format( |
298 | + "message": custom_message |
299 | + or operator.error_template.format( |
300 | app_name, |
301 | config_key, |
302 | repr(check_value), |
303 | repr(actual_value), |
304 | ), |
305 | - } |
306 | + }, |
307 | + log_level=log_level, |
308 | ) |
309 | return False |
310 | |
311 | @@ -428,11 +507,21 @@ class Linter: |
312 | ) |
313 | continue |
314 | |
315 | + custom_message = rules[rule].pop("custom-message", "") |
316 | + log_level = rules[rule].pop("log-level", "error").lower() |
317 | + |
318 | for check_op, check_value in rules[rule].items(): |
319 | # check_op should be the operator name, e.g. (eq, neq, gte, isset) |
320 | if check_op in VALID_CONFIG_CHECKS: |
321 | check_method = getattr(self, check_op) |
322 | - check_method(app_name, check_value, rule, config) |
323 | + check_method( |
324 | + app_name, |
325 | + check_value, |
326 | + rule, |
327 | + config, |
328 | + VALID_LOG_LEVEL.get(log_level, logging.ERROR), |
329 | + custom_message, |
330 | + ) |
331 | else: |
332 | self._log_with_header( |
333 | "Application {} has unknown check operation for {}: {}.".format( |
334 | @@ -635,7 +724,7 @@ class Linter: |
335 | for rule in relations_rules: |
336 | for endpoint, applications in rule.missing_relations.items(): |
337 | if applications: |
338 | - self.handle_error( |
339 | + self.message_handler( |
340 | { |
341 | "id": "missing-relations", |
342 | "tags": ["relation", "missing"], |
343 | @@ -646,7 +735,7 @@ class Linter: |
344 | ) |
345 | if rule.not_exist_error: |
346 | for relation in rule.not_exist_error: |
347 | - self.handle_error( |
348 | + self.message_handler( |
349 | { |
350 | "id": "relation-exist", |
351 | "tags": ["relation", "exist"], |
352 | @@ -657,7 +746,7 @@ class Linter: |
353 | ) |
354 | |
355 | if rule.missing_machines: |
356 | - self.handle_error( |
357 | + self.message_handler( |
358 | { |
359 | "id": "missing-machine", |
360 | "tags": ["missing", "machine"], |
361 | @@ -697,7 +786,7 @@ class Linter: |
362 | """Check we recognise the charms which are in the model.""" |
363 | for charm in self.model.charms: |
364 | if charm not in self.lint_rules["known charms"]: |
365 | - self.handle_error( |
366 | + self.message_handler( |
367 | { |
368 | "id": "unrecognised-charm", |
369 | "tags": ["charm", "unrecognised"], |
370 | @@ -710,11 +799,11 @@ class Linter: |
371 | for charm in self.lint_rules["operations mandatory"]: |
372 | error = self.check_charms_ops_mandatory(charm) |
373 | if error: |
374 | - self.handle_error(error) |
375 | + self.message_handler(error) |
376 | if self.cloud_type == "openstack": |
377 | for charm in self.lint_rules["openstack mandatory"]: |
378 | if charm not in self.model.charms: |
379 | - self.handle_error( |
380 | + self.message_handler( |
381 | { |
382 | "id": "openstack-charm-missing", |
383 | "tags": [ |
384 | @@ -731,7 +820,7 @@ class Linter: |
385 | ) |
386 | for charm in self.lint_rules["operations openstack mandatory"]: |
387 | if charm not in self.model.charms: |
388 | - self.handle_error( |
389 | + self.message_handler( |
390 | { |
391 | "id": "openstack-ops-charm-missing", |
392 | "tags": [ |
393 | @@ -752,7 +841,7 @@ class Linter: |
394 | elif self.cloud_type == "kubernetes": |
395 | for charm in self.lint_rules["kubernetes mandatory"]: |
396 | if charm not in self.model.charms: |
397 | - self.handle_error( |
398 | + self.message_handler( |
399 | { |
400 | "id": "kubernetes-charm-missing", |
401 | "tags": [ |
402 | @@ -769,7 +858,7 @@ class Linter: |
403 | ) |
404 | for charm in self.lint_rules["operations kubernetes mandatory"]: |
405 | if charm not in self.model.charms: |
406 | - self.handle_error( |
407 | + self.message_handler( |
408 | { |
409 | "id": "kubernetes-ops-charm-missing", |
410 | "tags": [ |
411 | @@ -895,7 +984,7 @@ class Linter: |
412 | |
413 | message = "Space binding mismatch: {}".format(mismatch) |
414 | if error: |
415 | - self.handle_error( |
416 | + self.message_handler( |
417 | { |
418 | "id": "space-binding-mismatch", |
419 | "tags": ["mismatch", "space", "binding"], |
420 | @@ -912,7 +1001,7 @@ class Linter: |
421 | if self.model.missing_subs: |
422 | for sub in self.model.missing_subs: |
423 | principals = ", ".join(sorted(self.model.missing_subs[sub])) |
424 | - self.handle_error( |
425 | + self.message_handler( |
426 | { |
427 | "id": "ops-subordinate-missing", |
428 | "tags": ["missing", "ops", "charm", "mandatory", "subordinate"], |
429 | @@ -928,7 +1017,7 @@ class Linter: |
430 | if self.model.extraneous_subs: |
431 | for sub in self.model.extraneous_subs: |
432 | principals = ", ".join(sorted(self.model.extraneous_subs[sub])) |
433 | - self.handle_error( |
434 | + self.message_handler( |
435 | { |
436 | "id": "subordinate-extraneous", |
437 | "tags": ["extraneous", "charm", "subordinate"], |
438 | @@ -943,7 +1032,7 @@ class Linter: |
439 | if self.model.duelling_subs: |
440 | for sub in self.model.duelling_subs: |
441 | machines = ", ".join(sorted(self.model.duelling_subs[sub])) |
442 | - self.handle_error( |
443 | + self.message_handler( |
444 | { |
445 | "id": "subordinate-duplicate", |
446 | "tags": ["duplicate", "charm", "subordinate"], |
447 | @@ -962,7 +1051,7 @@ class Linter: |
448 | az_map = ", ".join( |
449 | ["{}: {}".format(az, az_counter[az]) for az in sorted(az_counter)] |
450 | ) |
451 | - self.handle_error( |
452 | + self.message_handler( |
453 | { |
454 | "id": "AZ-unbalance", |
455 | "tags": ["AZ"], |
456 | @@ -987,7 +1076,7 @@ class Linter: |
457 | self.model.app_to_charm[app] = charm_name |
458 | self.model.charm_to_app.setdefault(charm_name, set()).add(app) |
459 | else: |
460 | - self.handle_error( |
461 | + self.message_handler( |
462 | { |
463 | "id": "charm-not-mapped", |
464 | "tags": ["charm", "mapped", "parsing"], |
465 | @@ -1060,7 +1149,7 @@ class Linter: |
466 | return |
467 | |
468 | status_msg = status.get("message") |
469 | - self.handle_error( |
470 | + self.message_handler( |
471 | { |
472 | "id": "status-unexpected", |
473 | "tags": ["status"], |
474 | @@ -1162,7 +1251,7 @@ class Linter: |
475 | azs.add(self.model.machines_to_az[machine]) |
476 | num_azs = len(azs) |
477 | if num_azs != 3: |
478 | - self.handle_error( |
479 | + self.message_handler( |
480 | { |
481 | "id": "AZ-invalid-number", |
482 | "tags": ["AZ"], |
483 | @@ -1306,15 +1395,20 @@ class Linter: |
484 | "Model contains no applications, skipping.", level=logging.WARN |
485 | ) |
486 | |
487 | - def collect(self, error): |
488 | + def collect(self, message): |
489 | """Collect an error and add it to the collector.""" |
490 | - self.output_collector["errors"].append(error) |
491 | + self.output_collector["errors"].append(message) |
492 | |
493 | - def handle_error(self, error): |
494 | - """Collect an error and add it to the collector.""" |
495 | - self._log_with_header(error["message"], level=logging.ERROR) |
496 | - if self.collect_errors: |
497 | - self.collect(error) |
498 | + def message_handler(self, message, log_level=logging.ERROR): |
499 | + """Handle message from checks and append error messages to the collector.""" |
500 | + if "message" not in message: |
501 | + log_level = logging.ERROR |
502 | + message = {"message": "wrong message_handler format"} |
503 | + |
504 | + self._log_with_header(message["message"], level=log_level) |
505 | + |
506 | + if self.collect_errors and log_level == logging.ERROR: |
507 | + self.collect(message) |
508 | |
509 | def _process_includes_in_rules(self, yaml_txt): |
510 | """ |
511 | diff --git a/tests/unit/test_jujulint.py b/tests/unit/test_jujulint.py |
512 | index 264b15e..77dbb5e 100644 |
513 | --- a/tests/unit/test_jujulint.py |
514 | +++ b/tests/unit/test_jujulint.py |
515 | @@ -8,6 +8,7 @@ import pytest |
516 | import yaml |
517 | |
518 | from jujulint import check_spaces, lint, relations |
519 | +from jujulint.lint import VALID_LOG_LEVEL |
520 | |
521 | |
522 | class TestUtils: |
523 | @@ -536,22 +537,79 @@ applications: |
524 | assert errors[0]["id"] == "kubernetes-ops-charm-missing" |
525 | assert errors[0]["charm"] == "ntp" |
526 | |
527 | - def test_config_eq(self, linter, juju_status): |
528 | - """Test the config condition 'eq'.""" |
529 | + @pytest.mark.parametrize( |
530 | + "custom_message, log_level, generate_error", |
531 | + [ |
532 | + ("", "", True), # generate error, no custom message |
533 | + ("custom message", "", True), # generate error with custom message |
534 | + ("", "foo", True), # generate error, no custom message |
535 | + ( |
536 | + "custom message", |
537 | + "warning", |
538 | + False, |
539 | + ), # doesn't generate error with custom message |
540 | + ( |
541 | + "custom message", |
542 | + "WARNING", |
543 | + False, |
544 | + ), # doesn't generate error with custom message |
545 | + ("", "info", False), # doesn't generate error, no custom message |
546 | + ("", "debug", False), # doesn't generate error, no custom message |
547 | + ], |
548 | + ) |
549 | + def test_config_eq( |
550 | + self, linter, juju_status, custom_message, log_level, generate_error |
551 | + ): |
552 | + """Test the config condition 'eq' with custom messages and log levels.""" |
553 | linter.lint_rules["config"] = {"ubuntu": {"fake-opt": {"eq": False}}} |
554 | juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": True} |
555 | + if custom_message: |
556 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"][ |
557 | + "custom-message" |
558 | + ] = custom_message |
559 | + if log_level: |
560 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"]["log-level"] = log_level |
561 | + |
562 | linter.do_lint(juju_status) |
563 | |
564 | errors = linter.output_collector["errors"] |
565 | - assert len(errors) == 1 |
566 | - assert errors[0]["id"] == "config-eq-check" |
567 | - assert errors[0]["application"] == "ubuntu" |
568 | - assert errors[0]["rule"] == "fake-opt" |
569 | - assert errors[0]["expected_value"] is False |
570 | - assert errors[0]["actual_value"] is True |
571 | |
572 | - def test_config_eq_suffix_match(self, linter, juju_status): |
573 | - """Test the config condition 'eq'. when suffix matches.""" |
574 | + if log_level.lower() != "error" and log_level.lower() in VALID_LOG_LEVEL: |
575 | + assert not generate_error |
576 | + assert len(errors) == 0 |
577 | + |
578 | + else: |
579 | + assert len(errors) == 1 |
580 | + assert errors[0]["id"] == "config-eq-check" |
581 | + assert errors[0]["application"] == "ubuntu" |
582 | + assert errors[0]["rule"] == "fake-opt" |
583 | + assert errors[0]["expected_value"] is False |
584 | + assert errors[0]["actual_value"] is True |
585 | + |
586 | + @pytest.mark.parametrize( |
587 | + "custom_message, log_level, generate_error", |
588 | + [ |
589 | + ("", "", True), # generate error, no custom message |
590 | + ("custom message", "", True), # generate error with custom message |
591 | + ("", "foo", True), # generate error, no custom message |
592 | + ( |
593 | + "custom message", |
594 | + "warning", |
595 | + False, |
596 | + ), # doesn't generate error with custom message |
597 | + ( |
598 | + "custom message", |
599 | + "WARNING", |
600 | + False, |
601 | + ), # doesn't generate error with custom message |
602 | + ("", "info", False), # doesn't generate error, no custom message |
603 | + ("", "debug", False), # doesn't generate error, no custom message |
604 | + ], |
605 | + ) |
606 | + def test_config_eq_suffix_match( |
607 | + self, linter, juju_status, custom_message, log_level, generate_error |
608 | + ): |
609 | + """Test the config condition 'eq'. when suffix matches with custom messages and log levels.""" |
610 | linter.lint_rules["config"] = { |
611 | "ubuntu": {"fake-opt": {"eq": False, "suffixes": ["host", "physical"]}} |
612 | } |
613 | @@ -559,31 +617,86 @@ applications: |
614 | juju_status["applications"]["ubuntu-host"] = juju_status["applications"].pop( |
615 | "ubuntu" |
616 | ) |
617 | + if custom_message: |
618 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"][ |
619 | + "custom-message" |
620 | + ] = custom_message |
621 | + if log_level: |
622 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"]["log-level"] = log_level |
623 | + |
624 | linter.do_lint(juju_status) |
625 | |
626 | errors = linter.output_collector["errors"] |
627 | - assert len(errors) == 1 |
628 | - assert errors[0]["id"] == "config-eq-check" |
629 | - assert errors[0]["application"] == "ubuntu-host" |
630 | - assert errors[0]["rule"] == "fake-opt" |
631 | - assert errors[0]["expected_value"] is False |
632 | - assert errors[0]["actual_value"] is True |
633 | |
634 | - def test_config_eq_suffix_match_charm_name(self, linter, juju_status): |
635 | + if log_level.lower() != "error" and log_level.lower() in VALID_LOG_LEVEL: |
636 | + assert not generate_error |
637 | + assert len(errors) == 0 |
638 | + else: |
639 | + assert len(errors) == 1 |
640 | + assert errors[0]["id"] == "config-eq-check" |
641 | + assert errors[0]["application"] == "ubuntu-host" |
642 | + assert errors[0]["rule"] == "fake-opt" |
643 | + assert errors[0]["expected_value"] is False |
644 | + assert errors[0]["actual_value"] is True |
645 | + if custom_message: |
646 | + assert errors[0]["message"] == custom_message |
647 | + else: |
648 | + assert errors[0]["message"] != custom_message |
649 | + |
650 | + @pytest.mark.parametrize( |
651 | + "custom_message, log_level, generate_error", |
652 | + [ |
653 | + ("", "", True), # generate error, no custom message |
654 | + ("custom message", "", True), # generate error with custom message |
655 | + ("", "foo", True), # generate error, no custom message |
656 | + ( |
657 | + "custom message", |
658 | + "warning", |
659 | + False, |
660 | + ), # doesn't generate error with custom message |
661 | + ( |
662 | + "custom message", |
663 | + "WARNING", |
664 | + False, |
665 | + ), # doesn't generate error with custom message |
666 | + ("", "info", False), # doesn't generate error, no custom message |
667 | + ("", "debug", False), # doesn't generate error, no custom message |
668 | + ], |
669 | + ) |
670 | + def test_config_eq_suffix_match_charm_name( |
671 | + self, linter, juju_status, custom_message, log_level, generate_error |
672 | + ): |
673 | """Test the config condition 'eq'. when suffix and base charm name.""" |
674 | linter.lint_rules["config"] = { |
675 | "ubuntu": {"fake-opt": {"eq": False, "suffixes": ["host", "physical"]}} |
676 | } |
677 | juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": True} |
678 | + if custom_message: |
679 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"][ |
680 | + "custom-message" |
681 | + ] = custom_message |
682 | + if log_level: |
683 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"]["log-level"] = log_level |
684 | + |
685 | linter.do_lint(juju_status) |
686 | |
687 | errors = linter.output_collector["errors"] |
688 | - assert len(errors) == 1 |
689 | - assert errors[0]["id"] == "config-eq-check" |
690 | - assert errors[0]["application"] == "ubuntu" |
691 | - assert errors[0]["rule"] == "fake-opt" |
692 | - assert errors[0]["expected_value"] is False |
693 | - assert errors[0]["actual_value"] is True |
694 | + |
695 | + if log_level.lower() != "error" and log_level.lower() in VALID_LOG_LEVEL: |
696 | + assert not generate_error |
697 | + assert len(errors) == 0 |
698 | + |
699 | + else: |
700 | + assert len(errors) == 1 |
701 | + assert errors[0]["id"] == "config-eq-check" |
702 | + assert errors[0]["application"] == "ubuntu" |
703 | + assert errors[0]["rule"] == "fake-opt" |
704 | + assert errors[0]["expected_value"] is False |
705 | + assert errors[0]["actual_value"] is True |
706 | + if custom_message: |
707 | + assert errors[0]["message"] == custom_message |
708 | + else: |
709 | + assert errors[0]["message"] != custom_message |
710 | |
711 | def test_config_eq_suffix_skip(self, linter, juju_status): |
712 | """Test the config condition 'eq'. when suffix doesn't match.""" |
713 | @@ -599,22 +712,61 @@ applications: |
714 | errors = linter.output_collector["errors"] |
715 | assert not errors |
716 | |
717 | - def test_config_eq_no_suffix_check_all(self, linter, juju_status): |
718 | + @pytest.mark.parametrize( |
719 | + "custom_message, log_level, generate_error", |
720 | + [ |
721 | + ("", "", True), # generate error, no custom message |
722 | + ("custom message", "", True), # generate error with custom message |
723 | + ("", "foo", True), # generate error, no custom message |
724 | + ( |
725 | + "custom message", |
726 | + "warning", |
727 | + False, |
728 | + ), # doesn't generate error with custom message |
729 | + ( |
730 | + "custom message", |
731 | + "WARNING", |
732 | + False, |
733 | + ), # doesn't generate error with custom message |
734 | + ("", "info", False), # doesn't generate error, no custom message |
735 | + ("", "debug", False), # doesn't generate error, no custom message |
736 | + ], |
737 | + ) |
738 | + def test_config_eq_no_suffix_check_all( |
739 | + self, linter, juju_status, custom_message, log_level, generate_error |
740 | + ): |
741 | """Test the config condition 'eq'. when no suffix all should be checked.""" |
742 | linter.lint_rules["config"] = {"ubuntu": {"fake-opt": {"eq": False}}} |
743 | juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": True} |
744 | juju_status["applications"]["ubuntu-host"] = juju_status["applications"].pop( |
745 | "ubuntu" |
746 | ) |
747 | + if custom_message: |
748 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"][ |
749 | + "custom-message" |
750 | + ] = custom_message |
751 | + if log_level: |
752 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"]["log-level"] = log_level |
753 | + |
754 | linter.do_lint(juju_status) |
755 | |
756 | errors = linter.output_collector["errors"] |
757 | - assert len(errors) == 1 |
758 | - assert errors[0]["id"] == "config-eq-check" |
759 | - assert errors[0]["application"] == "ubuntu-host" |
760 | - assert errors[0]["rule"] == "fake-opt" |
761 | - assert errors[0]["expected_value"] is False |
762 | - assert errors[0]["actual_value"] is True |
763 | + |
764 | + if log_level.lower() != "error" and log_level.lower() in VALID_LOG_LEVEL: |
765 | + assert not generate_error |
766 | + assert len(errors) == 0 |
767 | + |
768 | + else: |
769 | + assert len(errors) == 1 |
770 | + assert errors[0]["id"] == "config-eq-check" |
771 | + assert errors[0]["application"] == "ubuntu-host" |
772 | + assert errors[0]["rule"] == "fake-opt" |
773 | + assert errors[0]["expected_value"] is False |
774 | + assert errors[0]["actual_value"] is True |
775 | + if custom_message: |
776 | + assert errors[0]["message"] == custom_message |
777 | + else: |
778 | + assert errors[0]["message"] != custom_message |
779 | |
780 | def test_config_neq_valid(self, linter, juju_status): |
781 | """Test the config condition 'neq'.""" |
782 | @@ -625,46 +777,164 @@ applications: |
783 | errors = linter.output_collector["errors"] |
784 | assert len(errors) == 0 |
785 | |
786 | - def test_config_neq_invalid(self, linter, juju_status): |
787 | - """Test the config condition 'neq', valid.""" |
788 | + @pytest.mark.parametrize( |
789 | + "custom_message, log_level, generate_error", |
790 | + [ |
791 | + ("", "", True), # generate error, no custom message |
792 | + ("custom message", "", True), # generate error with custom message |
793 | + ("", "foo", True), # generate error, no custom message |
794 | + ( |
795 | + "custom message", |
796 | + "warning", |
797 | + False, |
798 | + ), # doesn't generate error with custom message |
799 | + ( |
800 | + "custom message", |
801 | + "WARNING", |
802 | + False, |
803 | + ), # doesn't generate error with custom message |
804 | + ("", "info", False), # doesn't generate error, no custom message |
805 | + ("", "debug", False), # doesn't generate error, no custom message |
806 | + ], |
807 | + ) |
808 | + def test_config_neq_invalid( |
809 | + self, linter, juju_status, custom_message, log_level, generate_error |
810 | + ): |
811 | + """Test the config condition 'neq', invalid with custom messages and log levels.""" |
812 | linter.lint_rules["config"] = {"ubuntu": {"fake-opt": {"neq": ""}}} |
813 | juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": ""} |
814 | + if custom_message: |
815 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"][ |
816 | + "custom-message" |
817 | + ] = custom_message |
818 | + if log_level: |
819 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"]["log-level"] = log_level |
820 | + |
821 | linter.do_lint(juju_status) |
822 | |
823 | errors = linter.output_collector["errors"] |
824 | - assert len(errors) == 1 |
825 | - assert errors[0]["id"] == "config-neq-check" |
826 | - assert errors[0]["application"] == "ubuntu" |
827 | - assert errors[0]["rule"] == "fake-opt" |
828 | - assert errors[0]["expected_value"] == "" |
829 | - assert errors[0]["actual_value"] == "" |
830 | |
831 | - def test_config_gte(self, linter, juju_status): |
832 | - """Test the config condition 'gte'.""" |
833 | + if log_level.lower() != "error" and log_level.lower() in VALID_LOG_LEVEL: |
834 | + assert not generate_error |
835 | + assert len(errors) == 0 |
836 | + |
837 | + else: |
838 | + assert len(errors) == 1 |
839 | + assert errors[0]["id"] == "config-neq-check" |
840 | + assert errors[0]["application"] == "ubuntu" |
841 | + assert errors[0]["rule"] == "fake-opt" |
842 | + assert errors[0]["expected_value"] == "" |
843 | + assert errors[0]["actual_value"] == "" |
844 | + if custom_message: |
845 | + assert errors[0]["message"] == custom_message |
846 | + else: |
847 | + assert errors[0]["message"] != custom_message |
848 | + |
849 | + @pytest.mark.parametrize( |
850 | + "custom_message, log_level, generate_error", |
851 | + [ |
852 | + ("", "", True), # generate error, no custom message |
853 | + ("custom message", "", True), # generate error with custom message |
854 | + ("", "foo", True), # generate error, no custom message |
855 | + ( |
856 | + "custom message", |
857 | + "warning", |
858 | + False, |
859 | + ), # doesn't generate error with custom message |
860 | + ( |
861 | + "custom message", |
862 | + "WARNING", |
863 | + False, |
864 | + ), # doesn't generate error with custom message |
865 | + ("", "info", False), # doesn't generate error, no custom message |
866 | + ("", "debug", False), # doesn't generate error, no custom message |
867 | + ], |
868 | + ) |
869 | + def test_config_gte( |
870 | + self, linter, juju_status, custom_message, log_level, generate_error |
871 | + ): |
872 | + """Test the config condition 'gte' with custom messages and log levels.""" |
873 | linter.lint_rules["config"] = {"ubuntu": {"fake-opt": {"gte": 3}}} |
874 | juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": 0} |
875 | + if custom_message: |
876 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"][ |
877 | + "custom-message" |
878 | + ] = custom_message |
879 | + if log_level: |
880 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"]["log-level"] = log_level |
881 | + |
882 | linter.do_lint(juju_status) |
883 | |
884 | errors = linter.output_collector["errors"] |
885 | - assert len(errors) == 1 |
886 | - assert errors[0]["id"] == "config-gte-check" |
887 | - assert errors[0]["application"] == "ubuntu" |
888 | - assert errors[0]["rule"] == "fake-opt" |
889 | - assert errors[0]["expected_value"] == 3 |
890 | - assert errors[0]["actual_value"] == 0 |
891 | |
892 | - def test_config_isset_false_fail(self, linter, juju_status): |
893 | - """Test error handling if config condition 'isset'=false is not met.""" |
894 | + if log_level.lower() != "error" and log_level.lower() in VALID_LOG_LEVEL: |
895 | + assert not generate_error |
896 | + assert len(errors) == 0 |
897 | + |
898 | + else: |
899 | + assert generate_error |
900 | + assert len(errors) == 1 |
901 | + assert errors[0]["id"] == "config-gte-check" |
902 | + assert errors[0]["application"] == "ubuntu" |
903 | + assert errors[0]["rule"] == "fake-opt" |
904 | + assert errors[0]["expected_value"] == 3 |
905 | + assert errors[0]["actual_value"] == 0 |
906 | + if custom_message: |
907 | + assert errors[0]["message"] == custom_message |
908 | + else: |
909 | + assert errors[0]["message"] != custom_message |
910 | + |
911 | + @pytest.mark.parametrize( |
912 | + "custom_message, log_level, generate_error", |
913 | + [ |
914 | + ("", "", True), # generate error, no custom message |
915 | + ("custom message", "", True), # generate error with custom message |
916 | + ("", "foo", True), # generate error, no custom message |
917 | + ( |
918 | + "custom message", |
919 | + "warning", |
920 | + False, |
921 | + ), # doesn't generate error with custom message |
922 | + ( |
923 | + "custom message", |
924 | + "WARNING", |
925 | + False, |
926 | + ), # doesn't generate error with custom message |
927 | + ("", "info", False), # doesn't generate error, no custom message |
928 | + ("", "debug", False), # doesn't generate error, no custom message |
929 | + ], |
930 | + ) |
931 | + def test_config_isset_false_fail( |
932 | + self, linter, juju_status, custom_message, log_level, generate_error |
933 | + ): |
934 | + """Test message handling if config condition 'isset'=false is not met.""" |
935 | linter.lint_rules["config"] = {"ubuntu": {"fake-opt": {"isset": False}}} |
936 | juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": 0} |
937 | + if custom_message: |
938 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"][ |
939 | + "custom-message" |
940 | + ] = custom_message |
941 | + if log_level: |
942 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"]["log-level"] = log_level |
943 | + |
944 | linter.do_lint(juju_status) |
945 | |
946 | errors = linter.output_collector["errors"] |
947 | - assert len(errors) == 1 |
948 | - assert errors[0]["id"] == "config-isset-check-false" |
949 | - assert errors[0]["application"] == "ubuntu" |
950 | - assert errors[0]["rule"] == "fake-opt" |
951 | - assert errors[0]["actual_value"] == 0 |
952 | + |
953 | + if log_level.lower() != "error" and log_level.lower() in VALID_LOG_LEVEL: |
954 | + assert not generate_error |
955 | + assert len(errors) == 0 |
956 | + |
957 | + else: |
958 | + assert len(errors) == 1 |
959 | + assert errors[0]["id"] == "config-isset-check-false" |
960 | + assert errors[0]["application"] == "ubuntu" |
961 | + assert errors[0]["rule"] == "fake-opt" |
962 | + assert errors[0]["actual_value"] == 0 |
963 | + if custom_message: |
964 | + assert errors[0]["message"] == custom_message |
965 | + else: |
966 | + assert errors[0]["message"] != custom_message |
967 | |
968 | def test_config_isset_false_pass(self, linter, juju_status): |
969 | """Test handling if config condition 'isset'=false is met.""" |
970 | @@ -675,17 +945,56 @@ applications: |
971 | errors = linter.output_collector["errors"] |
972 | assert len(errors) == 0 |
973 | |
974 | - def test_config_isset_true_fail(self, linter, juju_status): |
975 | - """Test error handling if config condition 'isset'=true is not met.""" |
976 | + @pytest.mark.parametrize( |
977 | + "custom_message, log_level, generate_error", |
978 | + [ |
979 | + ("", "", True), # generate error, no custom message |
980 | + ("custom message", "", True), # generate error with custom message |
981 | + ("", "foo", True), # generate error, no custom message |
982 | + ( |
983 | + "custom message", |
984 | + "warning", |
985 | + False, |
986 | + ), # doesn't generate error with custom message |
987 | + ( |
988 | + "custom message", |
989 | + "WARNING", |
990 | + False, |
991 | + ), # doesn't generate error with custom message |
992 | + ("", "info", False), # doesn't generate error, no custom message |
993 | + ("", "debug", False), # doesn't generate error, no custom message |
994 | + ], |
995 | + ) |
996 | + def test_config_isset_true_fail( |
997 | + self, linter, juju_status, custom_message, log_level, generate_error |
998 | + ): |
999 | + """Test message handling if config condition 'isset'=true is not met.""" |
1000 | linter.lint_rules["config"] = {"ubuntu": {"fake-opt": {"isset": True}}} |
1001 | juju_status["applications"]["ubuntu"]["options"] = {} |
1002 | + if custom_message: |
1003 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"][ |
1004 | + "custom-message" |
1005 | + ] = custom_message |
1006 | + if log_level: |
1007 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"]["log-level"] = log_level |
1008 | + |
1009 | linter.do_lint(juju_status) |
1010 | |
1011 | errors = linter.output_collector["errors"] |
1012 | - assert len(errors) == 1 |
1013 | - assert errors[0]["id"] == "config-isset-check-true" |
1014 | - assert errors[0]["application"] == "ubuntu" |
1015 | - assert errors[0]["rule"] == "fake-opt" |
1016 | + |
1017 | + if log_level.lower() != "error" and log_level.lower() in VALID_LOG_LEVEL: |
1018 | + assert not generate_error |
1019 | + assert len(errors) == 0 |
1020 | + |
1021 | + else: |
1022 | + assert len(errors) == 1 |
1023 | + assert errors[0]["id"] == "config-isset-check-true" |
1024 | + assert errors[0]["application"] == "ubuntu" |
1025 | + assert errors[0]["rule"] == "fake-opt" |
1026 | + if custom_message: |
1027 | + assert errors[0]["message"] == custom_message |
1028 | + else: |
1029 | + assert errors[0]["message"] != custom_message |
1030 | |
1031 | def test_config_isset_true_pass(self, linter, juju_status): |
1032 | """Test handling if config condition 'isset'=true is met.""" |
1033 | @@ -709,23 +1018,60 @@ applications: |
1034 | errors = linter.output_collector["errors"] |
1035 | assert len(errors) == 0 |
1036 | |
1037 | - def test_config_search_invalid(self, linter, juju_status): |
1038 | + @pytest.mark.parametrize( |
1039 | + "custom_message, log_level, generate_error", |
1040 | + [ |
1041 | + ("", "", True), # generate error, no custom message |
1042 | + ("custom message", "", True), # generate error with custom message |
1043 | + ("", "foo", True), # generate error, no custom message |
1044 | + ( |
1045 | + "custom message", |
1046 | + "warning", |
1047 | + False, |
1048 | + ), # doesn't generate error with custom message |
1049 | + ( |
1050 | + "custom message", |
1051 | + "WARNING", |
1052 | + False, |
1053 | + ), # doesn't generate error with custom message |
1054 | + ("", "info", False), # doesn't generate error, no custom message |
1055 | + ("", "debug", False), # doesn't generate error, no custom message |
1056 | + ], |
1057 | + ) |
1058 | + def test_config_search_invalid( |
1059 | + self, linter, juju_status, custom_message, log_level, generate_error |
1060 | + ): |
1061 | """Test the config condition 'search' when invalid.""" |
1062 | linter.lint_rules["config"] = { |
1063 | - "ubuntu": {"fake_opt": {"search": "\\W\\*, \\W\\*, 25000, 27500"}} |
1064 | + "ubuntu": {"fake-opt": {"search": "\\W\\*, \\W\\*, 25000, 27500"}} |
1065 | } |
1066 | juju_status["applications"]["ubuntu"]["options"] = { |
1067 | - "fake_opt": "[[/, queue1, 10, 20], [\\*, \\*, 10, 20]]" |
1068 | + "fake-opt": "[[/, queue1, 10, 20], [\\*, \\*, 10, 20]]" |
1069 | } |
1070 | + if custom_message: |
1071 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"][ |
1072 | + "custom-message" |
1073 | + ] = custom_message |
1074 | + if log_level: |
1075 | + linter.lint_rules["config"]["ubuntu"]["fake-opt"]["log-level"] = log_level |
1076 | + |
1077 | linter.do_lint(juju_status) |
1078 | |
1079 | errors = linter.output_collector["errors"] |
1080 | - assert len(errors) == 1 |
1081 | - assert errors[0]["id"] == "config-search-check" |
1082 | - assert errors[0]["application"] == "ubuntu" |
1083 | - assert errors[0]["rule"] == "fake_opt" |
1084 | - assert errors[0]["expected_value"] == "\\W\\*, \\W\\*, 25000, 27500" |
1085 | - assert errors[0]["actual_value"] == "[[/, queue1, 10, 20], [\\*, \\*, 10, 20]]" |
1086 | + |
1087 | + if log_level.lower() != "error" and log_level.lower() in VALID_LOG_LEVEL: |
1088 | + assert not generate_error |
1089 | + assert len(errors) == 0 |
1090 | + |
1091 | + else: |
1092 | + assert len(errors) == 1 |
1093 | + assert errors[0]["id"] == "config-search-check" |
1094 | + assert errors[0]["application"] == "ubuntu" |
1095 | + assert errors[0]["rule"] == "fake-opt" |
1096 | + assert errors[0]["expected_value"] == "\\W\\*, \\W\\*, 25000, 27500" |
1097 | + assert ( |
1098 | + errors[0]["actual_value"] == "[[/, queue1, 10, 20], [\\*, \\*, 10, 20]]" |
1099 | + ) |
1100 | |
1101 | def test_config_search_missing(self, linter, mocker): |
1102 | """Test the config search method logs warning if the config option is missing.""" |
1103 | @@ -1245,12 +1591,12 @@ applications: |
1104 | @pytest.mark.parametrize("input_file_type", ["juju-status", "juju-bundle"]) |
1105 | def test_check_relations(self, linter, input_files, mocker, input_file_type): |
1106 | """Ensure that check_relation pass.""" |
1107 | - mock_handle_error = mocker.patch("jujulint.lint.Linter.handle_error") |
1108 | + mock_message_handler = mocker.patch("jujulint.lint.Linter.message_handler") |
1109 | linter.lint_rules["relations"] = [ |
1110 | {"charm": "nrpe", "check": [["nrpe:juju-info", "ubuntu:juju-info"]]} |
1111 | ] |
1112 | linter.check_relations(input_files[input_file_type]) |
1113 | - mock_handle_error.assert_not_called() |
1114 | + mock_message_handler.assert_not_called() |
1115 | |
1116 | @pytest.mark.parametrize( |
1117 | "input_file_type", |
1118 | @@ -1260,11 +1606,11 @@ applications: |
1119 | ], |
1120 | ) |
1121 | def test_check_relations_exception_handling( |
1122 | - self, linter, juju_status, mocker, input_file_type, input_files |
1123 | + self, linter, mocker, input_file_type, input_files |
1124 | ): |
1125 | """Ensure that handle error if relation rules are in wrong format.""" |
1126 | mock_log = mocker.patch("jujulint.lint.Linter._log_with_header") |
1127 | - mock_handle_error = mocker.patch("jujulint.lint.Linter.handle_error") |
1128 | + mock_message_handler = mocker.patch("jujulint.lint.Linter.message_handler") |
1129 | linter.lint_rules["relations"] = [ |
1130 | {"charm": "ntp", "check": [["ntp", "ubuntu"]]} |
1131 | ] |
1132 | @@ -1275,17 +1621,17 @@ applications: |
1133 | expected_exception = relations.RelationError(expected_msg) |
1134 | |
1135 | linter.check_relations(input_files[input_file_type]) |
1136 | - mock_handle_error.assert_not_called() |
1137 | + mock_message_handler.assert_not_called() |
1138 | mock_log.assert_has_calls( |
1139 | [mocker.call(expected_exception.message, level=logging.ERROR)] |
1140 | ) |
1141 | |
1142 | @pytest.mark.parametrize("input_file_type", ["juju-status", "juju-bundle"]) |
1143 | def test_check_relations_missing_relations( |
1144 | - self, linter, juju_status, mocker, input_file_type, input_files |
1145 | + self, linter, mocker, input_file_type, input_files |
1146 | ): |
1147 | """Ensure that check_relation handle missing relations.""" |
1148 | - mock_handle_error = mocker.patch("jujulint.lint.Linter.handle_error") |
1149 | + mock_message_handler = mocker.patch("jujulint.lint.Linter.message_handler") |
1150 | # add a relation rule that doesn't happen in the model |
1151 | linter.lint_rules["relations"] = [ |
1152 | { |
1153 | @@ -1294,7 +1640,7 @@ applications: |
1154 | } |
1155 | ] |
1156 | linter.check_relations(input_files[input_file_type]) |
1157 | - mock_handle_error.assert_called_with( |
1158 | + mock_message_handler.assert_called_with( |
1159 | { |
1160 | "id": "missing-relations", |
1161 | "tags": ["relation", "missing"], |
1162 | @@ -1307,7 +1653,7 @@ applications: |
1163 | @pytest.mark.parametrize("input_file_type", ["juju-status", "juju-bundle"]) |
1164 | def test_check_relations_exist(self, linter, input_files, mocker, input_file_type): |
1165 | """Ensure that check_relation handle not exist error.""" |
1166 | - mock_handle_error = mocker.patch("jujulint.lint.Linter.handle_error") |
1167 | + mock_message_handler = mocker.patch("jujulint.lint.Linter.message_handler") |
1168 | not_exist_relation = [ |
1169 | "nrpe-host:nrpe-external-master", |
1170 | "elasticsearch:nrpe-external-master", |
1171 | @@ -1317,7 +1663,7 @@ applications: |
1172 | {"charm": "nrpe", "not-exist": [not_exist_relation]} |
1173 | ] |
1174 | linter.check_relations(input_files[input_file_type]) |
1175 | - mock_handle_error.assert_called_with( |
1176 | + mock_message_handler.assert_called_with( |
1177 | { |
1178 | "id": "relation-exist", |
1179 | "tags": ["relation", "exist"], |
1180 | @@ -1338,7 +1684,7 @@ applications: |
1181 | input_file.machines_data.update(new_machines) |
1182 | # map file again |
1183 | input_file.map_file() |
1184 | - mock_handle_error = mocker.patch("jujulint.lint.Linter.handle_error") |
1185 | + mock_message_handler = mocker.patch("jujulint.lint.Linter.message_handler") |
1186 | linter.lint_rules["relations"] = [ |
1187 | { |
1188 | "charm": "nrpe", |
1189 | @@ -1348,7 +1694,7 @@ applications: |
1190 | |
1191 | expected_missing_machines = ["2", "3"] |
1192 | linter.check_relations(input_file) |
1193 | - mock_handle_error.assert_called_with( |
1194 | + mock_message_handler.assert_called_with( |
1195 | { |
1196 | "id": "missing-machine", |
1197 | "tags": ["missing", "machine"], |
1198 | @@ -1358,3 +1704,44 @@ applications: |
1199 | ), |
1200 | } |
1201 | ) |
1202 | + |
1203 | + def test_path_mtu_for_ovs_ovn_rules(self, linter, rules_files): |
1204 | + """Test that ovs and ovn rules set right value of path-mtu.""" |
1205 | + for rule in [rules_file for rules_file in rules_files if "fcb" in rules_file]: |
1206 | + linter.filename = rule |
1207 | + linter.read_rules() |
1208 | + path_mtu = linter.lint_rules["openstack config"]["neutron-api"]["path-mtu"] |
1209 | + if "ovs" in rule: |
1210 | + assert path_mtu["gte"] == 1550 |
1211 | + else: |
1212 | + assert path_mtu["gte"] == 1558 |
1213 | + |
1214 | + assert path_mtu["log-level"] == "warning" |
1215 | + assert path_mtu["custom-message"] |
1216 | + |
1217 | + @pytest.mark.parametrize( |
1218 | + "message, log_level, error", |
1219 | + [ |
1220 | + ({}, None, True), # log wrong message_handler format as error message |
1221 | + ({}, logging.INFO, True), # log wrong message_handler format as error |
1222 | + ({"message": "my message"}, None, True), # log error message |
1223 | + ({"message": "my message"}, logging.INFO, False), # log info message |
1224 | + ({"message": "my message"}, logging.DEBUG, False), # log debug message |
1225 | + ({"message": "my message"}, logging.WARNING, False), # log warning message |
1226 | + ({"message": "my message"}, logging.ERROR, True), # log error message |
1227 | + ], |
1228 | + ) |
1229 | + def test_message_handler(self, linter, mocker, message, log_level, error): |
1230 | + """Test message_handler method.""" |
1231 | + logger_mock = mocker.patch.object(linter, "_log_with_header") |
1232 | + expected_message = message.get("message", "wrong message_handler format") |
1233 | + if message and not error: |
1234 | + linter.message_handler(message, log_level) |
1235 | + logger_mock.assert_has_calls( |
1236 | + [mocker.call(expected_message, level=log_level)] |
1237 | + ) |
1238 | + else: |
1239 | + linter.message_handler(message) |
1240 | + logger_mock.assert_has_calls( |
1241 | + [mocker.call(expected_message, level=logging.ERROR)] |
1242 | + ) |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.