diff options
author | Trevor Gamblin <tgamblin@baylibre.com> | 2023-10-26 10:07:46 -0400 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2023-10-26 21:11:28 +0100 |
commit | 207a5a21d38f4ed1b71aed0158ce067b57502cc7 (patch) | |
tree | 2f612a8d475ed4d4dc0f994b3ca320e5e073c10e /meta/lib/patchtest/tests/test_metadata.py | |
parent | cdee2b22e1f3b35eb77fed0d431acdf3c358ee6c (diff) | |
download | poky-207a5a21d38f4ed1b71aed0158ce067b57502cc7.tar.gz |
patchtest: simplify test directory structure
Consolidate the various mbox tests into a new TestMbox class, metadata
tests into TestMetadata, and patch tests into TestPatch. Also update the
selftest filenames to match the changes. The test contents are not
significantly changed (other than to reference the new class names).
While this doesn't improve overall readability, it does result in more
obvious categorization, and more importantly reduces the number of calls
to setup tinfoil in the tests, resulting in a roughly 25% reduction in
runtime.
Before:
[tgamblin@megalith poky]$ time ./meta/lib/patchtest/selftest/selftest
XPASS: PatchSignedOffBy.test_signed_off_by_presence (file: PatchSignedOffBy.test_signed_off_by_presence.pass)
XFAIL: Shortlog.test_shortlog_format (file: Shortlog.test_shortlog_format.fail)
XFAIL: MboxFormat.test_mbox_format (file: MboxFormat.test_mbox_format.1.fail)
XPASS: Shortlog.test_shortlog_length (file: Shortlog.test_shortlog_length.pass)
XFAIL: CommitMessage.test_commit_message_presence (file: CommitMessage.test_commit_message_presence.fail)
XFAIL: SrcUri.test_src_uri_left_files (file: SrcUri.test_src_uri_left_files.fail)
XPASS: Author.test_author_valid (file: Author.test_author_valid.1.pass)
XFAIL: LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned (file: LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned.fail)
XPASS: CVE.test_cve_tag_format (file: CVE.test_cve_tag_format.pass)
XPASS: CVE.test_cve_presence_in_commit_message (file: CVE.test_cve_presence_in_commit_message.pass)
XFAIL: CVE.test_cve_tag_format (file: CVE.test_cve_tag_format.fail)
XFAIL: Author.test_author_valid (file: Author.test_author_valid.1.fail)
XFAIL: LicFilesChkSum.test_lic_files_chksum_presence (file: LicFilesChkSum.test_lic_files_chksum_presence.fail)
XSKIP: Merge.test_series_merge_on_head (file: Merge.test_series_merge_on_head.2.skip)
XPASS: MboxFormat.test_mbox_format (file: MboxFormat.test_mbox_format.pass)
XFAIL: SignedOffBy.test_signed_off_by_presence (file: SignedOffBy.test_signed_off_by_presence.1.fail)
XPASS: Shortlog.test_shortlog_format (file: Shortlog.test_shortlog_format.pass)
XFAIL: SignedOffBy.test_signed_off_by_presence (file: SignedOffBy.test_signed_off_by_presence.2.fail)
XFAIL: MboxFormat.test_mbox_format (file: MboxFormat.test_mbox_format.2.fail)
XFAIL: Summary.test_summary_presence (file: Summary.test_summary_presence.fail)
XPASS: Author.test_author_valid (file: Author.test_author_valid.2.pass)
XSKIP: Merge.test_series_merge_on_head (file: Merge.test_series_merge_on_head.1.skip)
XPASS: Bugzilla.test_bugzilla_entry_format (file: Bugzilla.test_bugzilla_entry_format.pass)
XFAIL: CVE.test_cve_presence_in_commit_message (file: CVE.test_cve_presence_in_commit_message.fail)
XPASS: SignedOffBy.test_signed_off_by_presence (file: SignedOffBy.test_signed_off_by_presence.pass)
XPASS: LicFilesChkSum.test_lic_files_chksum_presence (file: LicFilesChkSum.test_lic_files_chksum_presence.pass)
XPASS: CommitMessage.test_commit_message_presence (file: CommitMessage.test_commit_message_presence.pass)
XPASS: Summary.test_summary_presence (file: Summary.test_summary_presence.pass)
XPASS: LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned (file: LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned.pass)
XFAIL: Shortlog.test_shortlog_length (file: Shortlog.test_shortlog_length.fail)
XFAIL: PatchSignedOffBy.test_signed_off_by_presence (file: PatchSignedOffBy.test_signed_off_by_presence.fail)
XFAIL: Bugzilla.test_bugzilla_entry_format (file: Bugzilla.test_bugzilla_entry_format.fail)
XPASS: SrcUri.test_src_uri_left_files (file: SrcUri.test_src_uri_left_files.pass)
XFAIL: Author.test_author_valid (file: Author.test_author_valid.2.fail)
============================================================================
Testsuite summary for patchtest
============================================================================
============================================================================
real 24m14.386s
user 1m13.599s
sys 0m21.477s
After:
[tgamblin@megalith poky]$ time ./meta/lib/patchtest/selftest/selftest
XFAIL: TestMbox.test_bugzilla_entry_format (file: TestMbox.test_bugzilla_entry_format.fail)
XPASS: TestMetadata.test_summary_presence (file: TestMetadata.test_summary_presence.pass)
XFAIL: TestMbox.test_mbox_format (file: TestMbox.test_mbox_format.1.fail)
XFAIL: TestMetadata.test_src_uri_left_files (file: TestMetadata.test_src_uri_left_files.fail)
XSKIP: TestMbox.test_series_merge_on_head (file: TestMbox.test_series_merge_on_head.2.skip)
XPASS: TestMbox.test_commit_message_presence (file: TestMbox.test_commit_message_presence.pass)
XFAIL: TestMbox.test_commit_message_presence (file: TestMbox.test_commit_message_presence.fail)
XPASS: TestMbox.test_signed_off_by_presence (file: TestMbox.test_signed_off_by_presence.pass)
XFAIL: TestPatch.test_cve_tag_format (file: TestPatch.test_cve_tag_format.fail)
XFAIL: TestMbox.test_author_valid (file: TestMbox.test_author_valid.1.fail)
XFAIL: TestMbox.test_shortlog_length (file: TestMbox.test_shortlog_length.fail)
XPASS: TestMbox.test_mbox_format (file: TestMbox.test_mbox_format.pass)
XFAIL: TestPatch.test_signed_off_by_presence (file: TestPatch.test_signed_off_by_presence.fail)
XFAIL: TestMbox.test_shortlog_format (file: TestMbox.test_shortlog_format.fail)
XFAIL: TestMbox.test_mbox_format (file: TestMbox.test_mbox_format.2.fail)
XPASS: TestPatch.test_cve_tag_format (file: TestPatch.test_cve_tag_format.pass)
XSKIP: TestMbox.test_series_merge_on_head (file: TestMbox.test_series_merge_on_head.1.skip)
XPASS: TestMbox.test_author_valid (file: TestMbox.test_author_valid.2.pass)
XPASS: TestMetadata.test_lic_files_chksum_modified_not_mentioned (file: TestMetadata.test_lic_files_chksum_modified_not_mentioned.pass)
XPASS: TestMbox.test_bugzilla_entry_format (file: TestMbox.test_bugzilla_entry_format.pass)
XPASS: TestMetadata.test_src_uri_left_files (file: TestMetadata.test_src_uri_left_files.pass)
XPASS: TestMetadata.test_lic_files_chksum_presence (file: TestMetadata.test_lic_files_chksum_presence.pass)
XPASS: TestMbox.test_cve_presence_in_commit_message (file: TestMbox.test_cve_presence_in_commit_message.pass)
XFAIL: TestMbox.test_signed_off_by_presence (file: TestMbox.test_signed_off_by_presence.2.fail)
XFAIL: TestMbox.test_author_valid (file: TestMbox.test_author_valid.2.fail)
XFAIL: TestMetadata.test_lic_files_chksum_presence (file: TestMetadata.test_lic_files_chksum_presence.fail)
XPASS: TestMbox.test_shortlog_format (file: TestMbox.test_shortlog_format.pass)
XPASS: TestMbox.test_author_valid (file: TestMbox.test_author_valid.1.pass)
XPASS: TestPatch.test_signed_off_by_presence (file: TestPatch.test_signed_off_by_presence.pass)
XFAIL: TestMetadata.test_lic_files_chksum_modified_not_mentioned (file: TestMetadata.test_lic_files_chksum_modified_not_mentioned.fail)
XPASS: TestMbox.test_shortlog_length (file: TestMbox.test_shortlog_length.pass)
XFAIL: TestMbox.test_signed_off_by_presence (file: TestMbox.test_signed_off_by_presence.1.fail)
XFAIL: TestMbox.test_cve_presence_in_commit_message (file: TestMbox.test_cve_presence_in_commit_message.fail)
XFAIL: TestMetadata.test_summary_presence (file: TestMetadata.test_summary_presence.fail)
============================================================================
Testsuite summary for patchtest
============================================================================
============================================================================
real 18m39.749s
user 0m41.857s
sys 0m14.708s
(From OE-Core rev: f788592da2fd0e21638ce2c3326675a060ba51cf)
Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/patchtest/tests/test_metadata.py')
-rw-r--r-- | meta/lib/patchtest/tests/test_metadata.py | 204 |
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 | |||
7 | import base | ||
8 | import os | ||
9 | import pyparsing | ||
10 | from data import PatchTestInput, PatchTestDataStore | ||
11 | |||
12 | class 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) | ||