Merge ~peppepetra/juju-lint:lp2043115 into juju-lint:master

Proposed by Giuseppe Petralia
Status: Needs review
Proposed branch: ~peppepetra/juju-lint:lp2043115
Merge into: juju-lint:master
Diff against target: 267 lines (+85/-28)
5 files modified
jujulint/checks/relations.py (+1/-0)
jujulint/model_input.py (+56/-13)
tests/unit/test_input.py (+1/-4)
tests/unit/test_jujulint.py (+4/-4)
tests/unit/test_relations.py (+23/-7)
Reviewer Review Type Date Requested Status
Gabriel Cocenza Needs Fixing
🤖 prod-jenkaas-bootstack continuous-integration Needs Fixing
BootStack Reviewers Pending
Review via email: mp+455419@code.launchpad.net

Commit message

Check relations by charm name and not application

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
~peppepetra/juju-lint:lp2043115 updated
487201a... by Giuseppe Petralia

Add comments

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
~peppepetra/juju-lint:lp2043115 updated
47ee7fb... by Giuseppe Petralia

Fix unit tests

4096722... by Giuseppe Petralia

Update unittests

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
~peppepetra/juju-lint:lp2043115 updated
66e750a... by Giuseppe Petralia

Fix linting

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Gabriel Cocenza (gabrielcocenza) wrote :

Thanks for this patch.

Please, see my comments to some enhancements.

Thanks

review: Needs Fixing

Unmerged commits

66e750a... by Giuseppe Petralia

Fix linting

4096722... by Giuseppe Petralia

Update unittests

47ee7fb... by Giuseppe Petralia

Fix unit tests

487201a... by Giuseppe Petralia

Add comments

cce09ac... by Giuseppe Petralia

Check relations by charm name and not application

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/jujulint/checks/relations.py b/jujulint/checks/relations.py
2index 6b85a6e..6ee514b 100644
3--- a/jujulint/checks/relations.py
4+++ b/jujulint/checks/relations.py
5@@ -193,6 +193,7 @@ class RelationRule:
6 relations_app_endpoint_0 = self.input_file.filter_by_relation(
7 {app_to_check_0}, endpoint_to_check_0
8 )
9+
10 if app_to_check_1 in relations_app_endpoint_0:
11 self.not_exist_error.append(relation)
12
13diff --git a/jujulint/model_input.py b/jujulint/model_input.py
14index 8233ebb..51e1cb0 100644
15--- a/jujulint/model_input.py
16+++ b/jujulint/model_input.py
17@@ -36,6 +36,13 @@ class BaseFile:
18 """Applications present in the file."""
19 return set(self.applications_data.keys())
20
21+ @property
22+ def charm_names(self) -> Set:
23+ """Charms present in the file."""
24+ return set(
25+ self.applications_data[app]["charm"] for app in self.applications_data
26+ )
27+
28 @staticmethod
29 def split_relation(relation: List[List[str]]) -> Tuple[str, str]:
30 """Split relations into apps and endpoints.
31@@ -78,16 +85,25 @@ class BaseFile:
32 # app == "*" means all apps
33 # a charm from relation rule can have different app names.
34 if app != "*" and app != charm:
35- if app not in self.applications:
36+ # Charm name may contain ch: or cs: at the beginning
37+ # or -<rev> at the end. Then we check that app name is contained
38+ # in charm_name
39+ found = False
40+ for name in self.charm_names:
41+ if app in name:
42+ found = True
43+ if not found:
44 LOGGER.warning(f"{app} not found on applications.")
45 return "", ""
46
47 # NOTE(gabrielcocenza) it's not always that a bundle will contain all endpoints under "bindings".
48 # See LP#1949883 and LP#1990017
49 # juju-info is represented by "" on endpoint-bindings
50- if endpoint != "juju-info" and endpoint not in self.applications_data[
51- app
52- ].get(endpoints_key, {}):
53+ if (
54+ endpoint != "juju-info"
55+ and app in self.applications_data
56+ and endpoint not in self.applications_data[app].get(endpoints_key, {})
57+ ):
58 LOGGER.warning(f"endpoint: {endpoint} not found on {app}")
59 return "", ""
60 return app, endpoint
61@@ -119,11 +135,25 @@ class BaseFile:
62 if endpoint
63 in self.applications_data.get(app, {}).get(endpoints_key, {})
64 }
65- return (
66- set([app])
67- if endpoint in self.applications_data.get(app, {}).get(endpoints_key, {})
68- else set()
69- )
70+
71+ # Create a dictionary where keys are applications names using charm = app
72+ # and values are list of endpoints connected
73+ endpoints = {}
74+ for application in self.applications_data:
75+ if app in self.applications_data[application].get("charm"):
76+ endpoints[application] = list(
77+ self.applications_data[application].get(endpoints_key, {}).keys()
78+ )
79+
80+ result = set()
81+
82+ # return the list of applications which have the relation in place
83+ # with the endpoint it is checking.
84+ for application in endpoints:
85+ if endpoint in endpoints[application]:
86+ result.add(application)
87+
88+ return result
89
90 def filter_machines_by_charm(self, charm: str) -> Set:
91 """Filter machines that has a specific charm.
92@@ -231,10 +261,10 @@ class JujuStatusFile(BaseFile):
93 BaseFile.check_app_endpoint_existence, endpoints_key="endpoint-bindings"
94 )
95
96- def filter_by_relation(self, apps: Set, endpoint: str) -> Set:
97+ def filter_by_relation(self, charms: Set, endpoint: str) -> Set:
98 """Filter applications that relate with an endpoint.
99
100- :param apps: Applications to filter relations using the endpoint.
101+ :param charms: Charms to filter relations using the endpoint.
102 :type apps: Set
103 :param endpoint: endpoint of the applications.
104 :type endpoint: str
105@@ -242,6 +272,12 @@ class JujuStatusFile(BaseFile):
106 :rtype: Set
107 """
108 apps_related = set()
109+ apps = set()
110+ for charm in charms:
111+ for app in self.applications_data:
112+ if charm in self.applications_data[app].get("charm", ""):
113+ apps.add(app)
114+
115 for app in apps:
116 relations = self.applications_data.get(app, {}).get("relations", {})
117 apps_related.update(relations.get(endpoint, []))
118@@ -333,10 +369,10 @@ class JujuBundleFile(BaseFile):
119 BaseFile.check_app_endpoint_existence, endpoints_key="bindings"
120 )
121
122- def filter_by_relation(self, apps: Set, endpoint: str) -> Set:
123+ def filter_by_relation(self, charms: Set, endpoint: str) -> Set:
124 """Filter applications that relate with an endpoint.
125
126- :param apps: Applications to filter relations using the endpoint.
127+ :param charms: Charms to filter relations using the endpoint.
128 :type apps: Set
129 :param endpoint: endpoint of the applications.
130 :type endpoint: str
131@@ -344,6 +380,13 @@ class JujuBundleFile(BaseFile):
132 :rtype: Set
133 """
134 apps_related = set()
135+
136+ apps = set()
137+ for charm in charms:
138+ for app in self.applications_data:
139+ if charm in self.applications_data[app].get("charm", ""):
140+ apps.add(app)
141+
142 for relation in self.relations_data:
143 for app in apps:
144 app_ep = f"{app}:{endpoint}"
145diff --git a/tests/unit/test_input.py b/tests/unit/test_input.py
146index f06ff4b..174f1a7 100644
147--- a/tests/unit/test_input.py
148+++ b/tests/unit/test_input.py
149@@ -202,10 +202,7 @@ def test_filter_by_app_and_endpoint(
150 def test_filter_by_relation(input_file_type, endpoint, expected_output, input_files):
151 """Test filter_by_relation method behave as expected."""
152 input_file = input_files[input_file_type]
153- assert (
154- input_file.filter_by_relation(input_file.charm_to_app["nrpe"], endpoint)
155- == expected_output
156- )
157+ assert input_file.filter_by_relation(["nrpe"], endpoint) == expected_output
158
159
160 @pytest.mark.parametrize(
161diff --git a/tests/unit/test_jujulint.py b/tests/unit/test_jujulint.py
162index b98474b..3afb836 100644
163--- a/tests/unit/test_jujulint.py
164+++ b/tests/unit/test_jujulint.py
165@@ -1786,8 +1786,8 @@ applications:
166 # add a relation rule that doesn't happen in the model
167 linter.lint_rules["relations"] = [
168 {
169- "charm": "nrpe",
170- "check": [["nrpe-host:local-monitors", "ubuntu:certificates"]],
171+ "charm": "keystone",
172+ "check": [["keystone:certificates", "ubuntu:certificates"]],
173 }
174 ]
175 linter.check_relations(input_files[input_file_type])
176@@ -1796,7 +1796,7 @@ applications:
177 "id": "missing-relations",
178 "tags": ["relation", "missing"],
179 "message": "Endpoint '{}' is missing relations with: {}".format(
180- "nrpe:local-monitors", ["ubuntu"]
181+ "keystone:certificates", ["ubuntu"]
182 ),
183 }
184 )
185@@ -1806,7 +1806,7 @@ applications:
186 """Ensure that check_relation handle not exist error."""
187 mock_message_handler = mocker.patch("jujulint.lint.Linter.message_handler")
188 not_exist_relation = [
189- "nrpe-host:nrpe-external-master",
190+ "nrpe:nrpe-external-master",
191 "elasticsearch:nrpe-external-master",
192 ]
193 # add a relation rule that happen in the model
194diff --git a/tests/unit/test_relations.py b/tests/unit/test_relations.py
195index 121fe9e..1b2744c 100644
196--- a/tests/unit/test_relations.py
197+++ b/tests/unit/test_relations.py
198@@ -11,29 +11,35 @@ RELATIONS = [["*:nrpe-external-master", "nrpe:nrpe-external-master"]]
199
200
201 @pytest.mark.parametrize(
202- "correct_relation, input_file_type",
203+ "correct_relation, input_file_type, expected_output",
204 [
205- (RELATIONS, "juju-status"),
206- (RELATIONS, "juju-bundle"),
207+ (RELATIONS, "juju-status", ["elasticsearch", "keystone"]),
208+ (RELATIONS, "juju-bundle", ["elasticsearch", "keystone"]),
209 (
210 [["nrpe:nrpe-external-master", "*:nrpe-external-master"]],
211 "juju-status",
212+ ["elasticsearch", "keystone"],
213 ), # inverting sequence doesn't change the endpoint
214 (
215 [["nrpe:nrpe-external-master", "*:nrpe-external-master"]],
216 "juju-bundle",
217+ ["elasticsearch", "keystone"],
218 ), # inverting sequence doesn't change the endpoint
219 (
220 [["nrpe:nrpe-external-master", "keystone:nrpe-external-master"]],
221 "juju-status",
222+ ["keystone"],
223 ), # able to find specific app relation
224 (
225 [["nrpe:nrpe-external-master", "keystone:nrpe-external-master"]],
226 "juju-bundle",
227+ ["keystone"],
228 ), # able to find specific app relation
229 ],
230 )
231-def test_relation_rule_valid(correct_relation, input_file_type, input_files):
232+def test_relation_rule_valid(
233+ correct_relation, input_file_type, expected_output, input_files
234+):
235 """Missing rules have empty set for endpoints with expected relations."""
236 relation_rule = relations.RelationRule(
237 input_file=input_files[input_file_type],
238@@ -44,7 +50,9 @@ def test_relation_rule_valid(correct_relation, input_file_type, input_files):
239 ubiquitous=True,
240 )
241 relation_rule.check()
242- assert relation_rule.missing_relations == {"nrpe:nrpe-external-master": list()}
243+ assert relation_rule.missing_relations == {
244+ "nrpe:nrpe-external-master": expected_output
245+ }
246 assert relation_rule.not_exist_error == list()
247 assert relation_rule.missing_machines == list()
248 assert relation_rule.__repr__() == "RelationRule(nrpe -> nrpe-external-master)"
249@@ -144,8 +152,16 @@ def test_relation_not_exist_raise(input_file_type, input_files):
250 @pytest.mark.parametrize(
251 "expected_missing, exception, input_file_type",
252 [
253- ({"nrpe:nrpe-external-master": ["foo-charm"]}, set(), "juju-status"),
254- ({"nrpe:nrpe-external-master": list()}, {"foo-charm"}, "juju-bundle"),
255+ (
256+ {"nrpe:nrpe-external-master": ["elasticsearch", "foo-charm", "keystone"]},
257+ set(),
258+ "juju-status",
259+ ),
260+ (
261+ {"nrpe:nrpe-external-master": ["elasticsearch", "keystone"]},
262+ {"foo-charm"},
263+ "juju-bundle",
264+ ),
265 ],
266 )
267 def test_missing_relation_and_exception(

Subscribers

People subscribed via source and target branches