poky/meta/lib/patchtest/tests/test_metadata.py
Trevor Gamblin bb0f1625d7 patchtest: patterns: add module, refactor
Currently, patchtest has a lot of spread-out definitions for patterns
used in various setup and test functions. Organize these by putting them
all into a new patterns.py module. This allows the tests/pyparsing
directory to be removed, as it is now redundant. Also remove some
definitions where they were duplicated or unused, and perform some
renames to improve readability and avoid collisions. Many of these
variables are composed from others, so the file is only partially
sorted.

(From OE-Core rev: 1ab55d495957918be532a36224b5598c9955a44d)

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2024-09-30 17:00:50 +01:00

182 lines
7.9 KiB
Python

# Checks related to the patch's LIC_FILES_CHKSUM metadata variable
#
# Copyright (C) 2016 Intel Corporation
#
# SPDX-License-Identifier: GPL-2.0-only
import base
import os
import patterns
import pyparsing
from data import PatchTestInput, PatchTestDataStore
class TestMetadata(base.Metadata):
def test_license_presence(self):
if not self.added:
self.skip('No added recipes, skipping test')
# TODO: this is a workaround so we can parse the recipe not
# containing the LICENSE var: add some default license instead
# of INVALID into auto.conf, then remove this line at the end
auto_conf = os.path.join(os.environ.get('BUILDDIR'), 'conf', 'auto.conf')
open_flag = 'w'
if os.path.exists(auto_conf):
open_flag = 'a'
with open(auto_conf, open_flag) as fd:
for pn in self.added:
fd.write('LICENSE ??= "%s"\n' % patterns.invalid_license)
no_license = False
for pn in self.added:
rd = self.tinfoil.parse_recipe(pn)
license = rd.getVar(patterns.metadata_lic)
if license == patterns.invalid_license:
no_license = True
break
# remove auto.conf line or the file itself
if open_flag == 'w':
os.remove(auto_conf)
else:
fd = open(auto_conf, 'r')
lines = fd.readlines()
fd.close()
with open(auto_conf, 'w') as fd:
fd.write(''.join(lines[:-1]))
if no_license:
self.fail('Recipe does not have the LICENSE field set.')
def test_lic_files_chksum_presence(self):
if not self.added:
self.skip('No added recipes, skipping test')
for pn in self.added:
rd = self.tinfoil.parse_recipe(pn)
pathname = rd.getVar('FILE')
# we are not interested in images
if '/images/' in pathname:
continue
lic_files_chksum = rd.getVar(patterns.metadata_chksum)
if rd.getVar(patterns.license_var) == patterns.closed:
continue
if not lic_files_chksum:
self.fail('%s is missing in newly added recipe' % patterns.metadata_chksum)
def test_lic_files_chksum_modified_not_mentioned(self):
if not self.modified:
self.skip('No modified recipes, skipping test')
for patch in self.patchset:
# for the moment, we are just interested in metadata
if patch.path.endswith('.patch'):
continue
payload = str(patch)
if (patterns.lic_chksum_added.search_string(payload) or patterns.lic_chksum_removed.search_string(payload)):
# if any patch on the series contain reference on the metadata, fail
for commit in self.commits:
if patterns.lictag_re.search_string(commit.commit_message):
break
else:
self.fail('LIC_FILES_CHKSUM changed without "License-Update:" tag and description in commit message')
def test_max_line_length(self):
for patch in self.patchset:
# for the moment, we are just interested in metadata
if patch.path.endswith('.patch'):
continue
payload = str(patch)
for line in payload.splitlines():
if patterns.add_mark.search_string(line):
current_line_length = len(line[1:])
if current_line_length > patterns.patch_max_line_length:
self.fail('Patch line too long (current length %s, maximum is %s)' % (current_line_length, patterns.patch_max_line_length),
data=[('Patch', patch.path), ('Line', '%s ...' % line[0:80])])
def pretest_src_uri_left_files(self):
# these tests just make sense on patches that can be merged
if not PatchTestInput.repo.canbemerged:
self.skip('Patch cannot be merged')
if not self.modified:
self.skip('No modified recipes, skipping pretest')
# get the proper metadata values
for pn in self.modified:
# we are not interested in images
if 'core-image' in pn:
continue
rd = self.tinfoil.parse_recipe(pn)
PatchTestDataStore['%s-%s-%s' % (self.shortid(), patterns.metadata_src_uri, pn)] = rd.getVar(patterns.metadata_src_uri)
def test_src_uri_left_files(self):
# these tests just make sense on patches that can be merged
if not PatchTestInput.repo.canbemerged:
self.skip('Patch cannot be merged')
if not self.modified:
self.skip('No modified recipes, skipping pretest')
# get the proper metadata values
for pn in self.modified:
# we are not interested in images
if 'core-image' in pn:
continue
rd = self.tinfoil.parse_recipe(pn)
PatchTestDataStore['%s-%s-%s' % (self.shortid(), patterns.metadata_src_uri, pn)] = rd.getVar(patterns.metadata_src_uri)
for pn in self.modified:
pretest_src_uri = PatchTestDataStore['pre%s-%s-%s' % (self.shortid(), patterns.metadata_src_uri, pn)].split()
test_src_uri = PatchTestDataStore['%s-%s-%s' % (self.shortid(), patterns.metadata_src_uri, pn)].split()
pretest_files = set([os.path.basename(patch) for patch in pretest_src_uri if patch.startswith('file://')])
test_files = set([os.path.basename(patch) for patch in test_src_uri if patch.startswith('file://')])
# check if files were removed
if len(test_files) < len(pretest_files):
# get removals from patchset
filesremoved_from_patchset = set()
for patch in self.patchset:
if patch.is_removed_file:
filesremoved_from_patchset.add(os.path.basename(patch.path))
# get the deleted files from the SRC_URI
filesremoved_from_usr_uri = pretest_files - test_files
# finally, get those patches removed at SRC_URI and not removed from the patchset
# TODO: we are not taking into account renames, so test may raise false positives
not_removed = filesremoved_from_usr_uri - filesremoved_from_patchset
if not_removed:
self.fail('Patches not removed from tree. Remove them and amend the submitted mbox',
data=[('Patch', f) for f in not_removed])
def test_summary_presence(self):
if not self.added:
self.skip('No added recipes, skipping test')
for pn in self.added:
# we are not interested in images
if 'core-image' in pn:
continue
rd = self.tinfoil.parse_recipe(pn)
summary = rd.getVar(patterns.metadata_summary)
# "${PN} version ${PN}-${PR}" is the default, so fail if default
if summary.startswith('%s version' % pn):
self.fail('%s is missing in newly added recipe' % patterns.metadata_summary)
def test_cve_check_ignore(self):
# Skip if we neither modified a recipe or target branches are not
# Nanbield and newer. CVE_CHECK_IGNORE was first deprecated in Nanbield.
if not self.modified or PatchTestInput.repo.branch == "kirkstone" or PatchTestInput.repo.branch == "dunfell":
self.skip('No modified recipes or older target branch, skipping test')
for pn in self.modified:
# we are not interested in images
if 'core-image' in pn:
continue
rd = self.tinfoil.parse_recipe(pn)
cve_check_ignore = rd.getVar(patterns.cve_check_ignore_var)
if cve_check_ignore is not None:
self.fail('%s is deprecated and should be replaced by %s' % (patterns.cve_check_ignore_var, patterns.cve_status_var))