summaryrefslogtreecommitdiffstats
path: root/meta/lib/patchtest/tests/test_metadata.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/patchtest/tests/test_metadata.py')
-rw-r--r--meta/lib/patchtest/tests/test_metadata.py204
1 files changed, 204 insertions, 0 deletions
diff --git a/meta/lib/patchtest/tests/test_metadata.py b/meta/lib/patchtest/tests/test_metadata.py
new file mode 100644
index 0000000000..34e119174f
--- /dev/null
+++ b/meta/lib/patchtest/tests/test_metadata.py
@@ -0,0 +1,204 @@
1# Checks related to the patch's LIC_FILES_CHKSUM metadata variable
2#
3# Copyright (C) 2016 Intel Corporation
4#
5# SPDX-License-Identifier: GPL-2.0-only
6
7import base
8import os
9import pyparsing
10from data import PatchTestInput, PatchTestDataStore
11
12class TestMetadata(base.Metadata):
13 metadata_lic = 'LICENSE'
14 invalid_license = 'PATCHTESTINVALID'
15 metadata_chksum = 'LIC_FILES_CHKSUM'
16 license_var = 'LICENSE'
17 closed = 'CLOSED'
18 lictag_re = pyparsing.AtLineStart("License-Update:")
19 add_mark = pyparsing.Regex('\+ ')
20 max_length = 200
21 metadata_src_uri = 'SRC_URI'
22 md5sum = 'md5sum'
23 sha256sum = 'sha256sum'
24 git_regex = pyparsing.Regex('^git\:\/\/.*')
25 metadata_summary = 'SUMMARY'
26
27 def test_license_presence(self):
28 if not self.added:
29 self.skip('No added recipes, skipping test')
30
31 # TODO: this is a workaround so we can parse the recipe not
32 # containing the LICENSE var: add some default license instead
33 # of INVALID into auto.conf, then remove this line at the end
34 auto_conf = os.path.join(os.environ.get('BUILDDIR'), 'conf', 'auto.conf')
35 open_flag = 'w'
36 if os.path.exists(auto_conf):
37 open_flag = 'a'
38 with open(auto_conf, open_flag) as fd:
39 for pn in self.added:
40 fd.write('LICENSE ??= "%s"\n' % self.invalid_license)
41
42 no_license = False
43 for pn in self.added:
44 rd = self.tinfoil.parse_recipe(pn)
45 license = rd.getVar(self.metadata_lic)
46 if license == self.invalid_license:
47 no_license = True
48 break
49
50 # remove auto.conf line or the file itself
51 if open_flag == 'w':
52 os.remove(auto_conf)
53 else:
54 fd = open(auto_conf, 'r')
55 lines = fd.readlines()
56 fd.close()
57 with open(auto_conf, 'w') as fd:
58 fd.write(''.join(lines[:-1]))
59
60 if no_license:
61 self.fail('Recipe does not have the LICENSE field set.')
62
63 def test_lic_files_chksum_presence(self):
64 if not self.added:
65 self.skip('No added recipes, skipping test')
66
67 for pn in self.added:
68 rd = self.tinfoil.parse_recipe(pn)
69 pathname = rd.getVar('FILE')
70 # we are not interested in images
71 if '/images/' in pathname:
72 continue
73 lic_files_chksum = rd.getVar(self.metadata_chksum)
74 if rd.getVar(self.license_var) == self.closed:
75 continue
76 if not lic_files_chksum:
77 self.fail('%s is missing in newly added recipe' % self.metadata_chksum)
78
79 def pretest_lic_files_chksum_modified_not_mentioned(self):
80 if not self.modified:
81 self.skip('No modified recipes, skipping pretest')
82 # get the proper metadata values
83 for pn in self.modified:
84 rd = self.tinfoil.parse_recipe(pn)
85 pathname = rd.getVar('FILE')
86 # we are not interested in images
87 if '/images/' in pathname:
88 continue
89 PatchTestDataStore['%s-%s-%s' % (self.shortid(),self.metadata_chksum,pn)] = rd.getVar(self.metadata_chksum)
90
91 def test_lic_files_chksum_modified_not_mentioned(self):
92 if not self.modified:
93 self.skip('No modified recipes, skipping test')
94
95 # get the proper metadata values
96 for pn in self.modified:
97 rd = self.tinfoil.parse_recipe(pn)
98 pathname = rd.getVar('FILE')
99 # we are not interested in images
100 if '/images/' in pathname:
101 continue
102 PatchTestDataStore['%s-%s-%s' % (self.shortid(),self.metadata_chksum,pn)] = rd.getVar(self.metadata_chksum)
103 # compare if there were changes between pre-merge and merge
104 for pn in self.modified:
105 pretest = PatchTestDataStore['pre%s-%s-%s' % (self.shortid(),self.metadata_chksum, pn)]
106 test = PatchTestDataStore['%s-%s-%s' % (self.shortid(),self.metadata_chksum, pn)]
107
108 # TODO: this is workaround to avoid false-positives when pretest metadata is empty (not reason found yet)
109 # For more info, check bug 12284
110 if not pretest:
111 return
112
113 if pretest != test:
114 # if any patch on the series contain reference on the metadata, fail
115 for commit in self.commits:
116 if self.lictag_re.search_string(commit.commit_message):
117 break
118 else:
119 self.fail('LIC_FILES_CHKSUM changed on target %s but there is no "License-Update:" tag in commit message. Include it with a brief description' % pn,
120 data=[('Current checksum', pretest), ('New checksum', test)])
121
122 def test_max_line_length(self):
123 for patch in self.patchset:
124 # for the moment, we are just interested in metadata
125 if patch.path.endswith('.patch'):
126 continue
127 payload = str(patch)
128 for line in payload.splitlines():
129 if self.add_mark.search_string(line):
130 current_line_length = len(line[1:])
131 if current_line_length > self.max_length:
132 self.fail('Patch line too long (current length %s, maximum is %s)' % (current_line_length, self.max_length),
133 data=[('Patch', patch.path), ('Line', '%s ...' % line[0:80])])
134
135 def pretest_src_uri_left_files(self):
136 # these tests just make sense on patches that can be merged
137 if not PatchTestInput.repo.canbemerged:
138 self.skip('Patch cannot be merged')
139 if not self.modified:
140 self.skip('No modified recipes, skipping pretest')
141
142 # get the proper metadata values
143 for pn in self.modified:
144 # we are not interested in images
145 if 'core-image' in pn:
146 continue
147 rd = self.tinfoil.parse_recipe(pn)
148 PatchTestDataStore['%s-%s-%s' % (self.shortid(), self.metadata_src_uri, pn)] = rd.getVar(self.metadata_src_uri)
149
150 def test_src_uri_left_files(self):
151 # these tests just make sense on patches that can be merged
152 if not PatchTestInput.repo.canbemerged:
153 self.skip('Patch cannot be merged')
154 if not self.modified:
155 self.skip('No modified recipes, skipping pretest')
156
157 # get the proper metadata values
158 for pn in self.modified:
159 # we are not interested in images
160 if 'core-image' in pn:
161 continue
162 rd = self.tinfoil.parse_recipe(pn)
163 PatchTestDataStore['%s-%s-%s' % (self.shortid(), self.metadata_src_uri, pn)] = rd.getVar(self.metadata_src_uri)
164
165 for pn in self.modified:
166 pretest_src_uri = PatchTestDataStore['pre%s-%s-%s' % (self.shortid(), self.metadata_src_uri, pn)].split()
167 test_src_uri = PatchTestDataStore['%s-%s-%s' % (self.shortid(), self.metadata_src_uri, pn)].split()
168
169 pretest_files = set([os.path.basename(patch) for patch in pretest_src_uri if patch.startswith('file://')])
170 test_files = set([os.path.basename(patch) for patch in test_src_uri if patch.startswith('file://')])
171
172 # check if files were removed
173 if len(test_files) < len(pretest_files):
174
175 # get removals from patchset
176 filesremoved_from_patchset = set()
177 for patch in self.patchset:
178 if patch.is_removed_file:
179 filesremoved_from_patchset.add(os.path.basename(patch.path))
180
181 # get the deleted files from the SRC_URI
182 filesremoved_from_usr_uri = pretest_files - test_files
183
184 # finally, get those patches removed at SRC_URI and not removed from the patchset
185 # TODO: we are not taking into account renames, so test may raise false positives
186 not_removed = filesremoved_from_usr_uri - filesremoved_from_patchset
187 if not_removed:
188 self.fail('Patches not removed from tree. Remove them and amend the submitted mbox',
189 data=[('Patch', f) for f in not_removed])
190
191 def test_summary_presence(self):
192 if not self.added:
193 self.skip('No added recipes, skipping test')
194
195 for pn in self.added:
196 # we are not interested in images
197 if 'core-image' in pn:
198 continue
199 rd = self.tinfoil.parse_recipe(pn)
200 summary = rd.getVar(self.metadata_summary)
201
202 # "${PN} version ${PN}-${PR}" is the default, so fail if default
203 if summary.startswith('%s version' % pn):
204 self.fail('%s is missing in newly added recipe' % self.metadata_summary)