poky/scripts/lib/compatlayer/cases/common.py
Patrick Ohly 3cdeea61c1 yocto-compat-layer.py: apply test_signatures to all layers
Software layers were previously allowed to change signatures, but
that's not desired for those layers either. The rule that a layer
which is "Yocto Compatible 2.0" must not change signatures unless
explicitly requested holds for all kinds of layers.

However, as this is something that software layers might not be able
to do right away, testing for signature changes in software layers can
be disabled. It's on by default, as that was Richard's
recommendation. Whether that should change needs further discussion as
part of finalizing "Yocto Compatible 2.0".

As it might still change, the tool now has both a with/without
parameter so that users of the tool can choose the desired behavior
without being affected by future changes to the default.

(From OE-Core rev: e7fe215f50a1b75771f33fffdda529a95c026d3f)

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2017-07-06 14:38:14 +01:00

93 lines
4.1 KiB
Python

# Copyright (C) 2017 Intel Corporation
# Released under the MIT license (see COPYING.MIT)
import os
import unittest
from compatlayer import get_signatures, LayerType, check_command, get_depgraph
from compatlayer.case import OECompatLayerTestCase
class CommonCompatLayer(OECompatLayerTestCase):
def test_readme(self):
readme_file = os.path.join(self.tc.layer['path'], 'README')
self.assertTrue(os.path.isfile(readme_file),
msg="Layer doesn't contains README file.")
data = ''
with open(readme_file, 'r') as f:
data = f.read()
self.assertTrue(data,
msg="Layer contains README file but is empty.")
def test_parse(self):
check_command('Layer %s failed to parse.' % self.tc.layer['name'],
'bitbake -p')
def test_show_environment(self):
check_command('Layer %s failed to show environment.' % self.tc.layer['name'],
'bitbake -e')
def test_signatures(self):
if self.tc.layer['type'] == LayerType.SOFTWARE and \
not self.tc.test_software_layer_signatures:
raise unittest.SkipTest("Not testing for signature changes in a software layer %s." \
% self.tc.layer['name'])
# task -> (old signature, new signature)
sig_diff = {}
curr_sigs, _ = get_signatures(self.td['builddir'], failsafe=True)
for task in self.td['sigs']:
if task in curr_sigs and \
self.td['sigs'][task] != curr_sigs[task]:
sig_diff[task] = (self.td['sigs'][task], curr_sigs[task])
if sig_diff:
# Beware, depgraph uses task=<pn>.<taskname> whereas get_signatures()
# uses <pn>:<taskname>. Need to convert sometimes. The output follows
# the convention from get_signatures() because that seems closer to
# normal bitbake output.
def sig2graph(task):
pn, taskname = task.rsplit(':', 1)
return pn + '.' + taskname
def graph2sig(task):
pn, taskname = task.rsplit('.', 1)
return pn + ':' + taskname
depgraph = get_depgraph(failsafe=True)
depends = depgraph['tdepends']
# If a task A has a changed signature, but none of its
# dependencies, then we need to report it because it is
# the one which introduces a change. Any task depending on
# A (directly or indirectly) will also have a changed
# signature, but we don't need to report it. It might have
# its own changes, which will become apparent once the
# issues that we do report are fixed and the test gets run
# again.
sig_diff_filtered = []
for task, (old_sig, new_sig) in sig_diff.items():
deps_tainted = False
for dep in depends.get(sig2graph(task), ()):
if graph2sig(dep) in sig_diff:
deps_tainted = True
break
if not deps_tainted:
sig_diff_filtered.append((task, old_sig, new_sig))
msg = []
msg.append('Layer %s changed %d signatures, initial differences (first hash without, second with layer):' %
(self.tc.layer['name'], len(sig_diff)))
for diff in sorted(sig_diff_filtered):
recipe, taskname = diff[0].rsplit(':', 1)
cmd = 'bitbake-diffsigs --task %s %s --signature %s %s' % \
(recipe, taskname, diff[1], diff[2])
msg.append(' %s: %s -> %s' % diff)
msg.append(' %s' % cmd)
try:
output = check_command('Determining signature difference failed.',
cmd).decode('utf-8')
except RuntimeError as error:
output = str(error)
if output:
msg.extend([' ' + line for line in output.splitlines()])
msg.append('')
self.fail('\n'.join(msg))