mirror of
git://git.yoctoproject.org/poky.git
synced 2025-07-19 12:59:02 +02:00

Running `devtool search gcc` would result in errors for virtual recipes. The reason was the newly introduced :layer-<layername> override. When tinfoil parsed the recipes using the parseRecipeFile() function, it failed to properly identify the layername for virtual recipes, which resulted in the errors. Add tests that exercise these code paths through parseRecipeFile(). (From OE-Core rev: cf7f34f93f9f90279412ea57d6d5930854d411ba) Signed-off-by: Peter Kjellerstedt <peter.kjellerstedt@axis.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
253 lines
13 KiB
Python
253 lines
13 KiB
Python
#
|
|
# Copyright OpenEmbedded Contributors
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
|
|
import os
|
|
import re
|
|
import time
|
|
import logging
|
|
import bb.tinfoil
|
|
|
|
from oeqa.selftest.case import OESelftestTestCase
|
|
|
|
class TinfoilTests(OESelftestTestCase):
|
|
""" Basic tests for the tinfoil API """
|
|
|
|
def test_getvar(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(True)
|
|
machine = tinfoil.config_data.getVar('MACHINE')
|
|
if not machine:
|
|
self.fail('Unable to get MACHINE value - returned %s' % machine)
|
|
|
|
def test_expand(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(True)
|
|
expr = '${@os.getpid()}'
|
|
pid = tinfoil.config_data.expand(expr)
|
|
if not pid:
|
|
self.fail('Unable to expand "%s" - returned %s' % (expr, pid))
|
|
|
|
def test_getvar_bb_origenv(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(True)
|
|
origenv = tinfoil.config_data.getVar('BB_ORIGENV', False)
|
|
if not origenv:
|
|
self.fail('Unable to get BB_ORIGENV value - returned %s' % origenv)
|
|
self.assertEqual(origenv.getVar('HOME', False), os.environ['HOME'])
|
|
|
|
def test_parse_recipe(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=False, quiet=2)
|
|
testrecipe = 'mdadm'
|
|
best = tinfoil.find_best_provider(testrecipe)
|
|
if not best:
|
|
self.fail('Unable to find recipe providing %s' % testrecipe)
|
|
rd = tinfoil.parse_recipe_file(best[3])
|
|
self.assertEqual(testrecipe, rd.getVar('PN'))
|
|
|
|
def test_parse_virtual_recipe(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=False, quiet=2)
|
|
testrecipe = 'nativesdk-gcc'
|
|
best = tinfoil.find_best_provider(testrecipe)
|
|
if not best:
|
|
self.fail('Unable to find recipe providing %s' % testrecipe)
|
|
rd = tinfoil.parse_recipe_file(best[3])
|
|
self.assertEqual(testrecipe, rd.getVar('PN'))
|
|
self.assertIsNotNone(rd.getVar('FILE_LAYERNAME'))
|
|
|
|
def test_parse_recipe_copy_expand(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=False, quiet=2)
|
|
testrecipe = 'mdadm'
|
|
best = tinfoil.find_best_provider(testrecipe)
|
|
if not best:
|
|
self.fail('Unable to find recipe providing %s' % testrecipe)
|
|
rd = tinfoil.parse_recipe_file(best[3])
|
|
# Check we can get variable values
|
|
self.assertEqual(testrecipe, rd.getVar('PN'))
|
|
# Check that expanding a value that includes a variable reference works
|
|
self.assertEqual(testrecipe, rd.getVar('BPN'))
|
|
# Now check that changing the referenced variable's value in a copy gives that
|
|
# value when expanding
|
|
localdata = bb.data.createCopy(rd)
|
|
localdata.setVar('PN', 'hello')
|
|
self.assertEqual('hello', localdata.getVar('BPN'))
|
|
|
|
# The config_data API to parse_recipe_file is used by:
|
|
# layerindex-web layerindex/update_layer.py
|
|
def test_parse_recipe_custom_data(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=False, quiet=2)
|
|
localdata = bb.data.createCopy(tinfoil.config_data)
|
|
localdata.setVar("TESTVAR", "testval")
|
|
testrecipe = 'mdadm'
|
|
best = tinfoil.find_best_provider(testrecipe)
|
|
if not best:
|
|
self.fail('Unable to find recipe providing %s' % testrecipe)
|
|
rd = tinfoil.parse_recipe_file(best[3], config_data=localdata)
|
|
self.assertEqual("testval", rd.getVar('TESTVAR'))
|
|
|
|
def test_parse_virtual_recipe_custom_data(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=False, quiet=2)
|
|
localdata = bb.data.createCopy(tinfoil.config_data)
|
|
localdata.setVar("TESTVAR", "testval")
|
|
testrecipe = 'nativesdk-gcc'
|
|
best = tinfoil.find_best_provider(testrecipe)
|
|
if not best:
|
|
self.fail('Unable to find recipe providing %s' % testrecipe)
|
|
rd = tinfoil.parse_recipe_file(best[3], config_data=localdata)
|
|
self.assertEqual("testval", rd.getVar('TESTVAR'))
|
|
|
|
def test_list_recipes(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=False, quiet=2)
|
|
# Check pkg_pn
|
|
checkpns = ['tar', 'automake', 'coreutils', 'm4-native', 'nativesdk-gcc']
|
|
pkg_pn = tinfoil.cooker.recipecaches[''].pkg_pn
|
|
for pn in checkpns:
|
|
self.assertIn(pn, pkg_pn)
|
|
# Check pkg_fn
|
|
checkfns = {'nativesdk-gcc': '^virtual:nativesdk:.*', 'coreutils': '.*/coreutils_.*.bb'}
|
|
for fn, pn in tinfoil.cooker.recipecaches[''].pkg_fn.items():
|
|
if pn in checkpns:
|
|
if pn in checkfns:
|
|
self.assertTrue(re.match(checkfns[pn], fn), 'Entry for %s: %s did not match %s' % (pn, fn, checkfns[pn]))
|
|
checkpns.remove(pn)
|
|
if checkpns:
|
|
self.fail('Unable to find pkg_fn entries for: %s' % ', '.join(checkpns))
|
|
|
|
def test_wait_event(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=True)
|
|
|
|
tinfoil.set_event_mask(['bb.event.FilesMatchingFound', 'bb.command.CommandCompleted', 'bb.command.CommandFailed', 'bb.command.CommandExit'])
|
|
|
|
# Need to drain events otherwise events that were masked may still be in the queue
|
|
while tinfoil.wait_event():
|
|
pass
|
|
|
|
pattern = 'conf'
|
|
res = tinfoil.run_command('testCookerCommandEvent', pattern, handle_events=False)
|
|
self.assertTrue(res)
|
|
|
|
eventreceived = False
|
|
commandcomplete = False
|
|
start = time.time()
|
|
# Wait for maximum 60s in total so we'd detect spurious heartbeat events for example
|
|
while (not (eventreceived == True and commandcomplete == True)
|
|
and (time.time() - start < 60)):
|
|
# if we received both events (on let's say a good day), we are done
|
|
event = tinfoil.wait_event(1)
|
|
if event:
|
|
if isinstance(event, bb.command.CommandCompleted):
|
|
commandcomplete = True
|
|
elif isinstance(event, bb.event.FilesMatchingFound):
|
|
self.assertEqual(pattern, event._pattern)
|
|
self.assertIn('A', event._matches)
|
|
self.assertIn('B', event._matches)
|
|
eventreceived = True
|
|
elif isinstance(event, logging.LogRecord):
|
|
continue
|
|
else:
|
|
self.fail('Unexpected event: %s' % event)
|
|
|
|
self.assertTrue(commandcomplete, 'Timed out waiting for CommandCompleted event from bitbake server (Matching event received: %s)' % str(eventreceived))
|
|
self.assertTrue(eventreceived, 'Did not receive FilesMatchingFound event from bitbake server')
|
|
|
|
def test_setvariable_clean(self):
|
|
# First check that setVariable affects the datastore
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=True)
|
|
tinfoil.run_command('setVariable', 'TESTVAR', 'specialvalue')
|
|
self.assertEqual(tinfoil.config_data.getVar('TESTVAR'), 'specialvalue', 'Value set using setVariable is not reflected in client-side getVar()')
|
|
|
|
# Now check that the setVariable's effects are no longer present
|
|
# (this may legitimately break in future if we stop reinitialising
|
|
# the datastore, in which case we'll have to reconsider use of
|
|
# setVariable entirely)
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=True)
|
|
self.assertNotEqual(tinfoil.config_data.getVar('TESTVAR'), 'specialvalue', 'Value set using setVariable is still present!')
|
|
|
|
# Now check that setVar on the main datastore works (uses setVariable internally)
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=True)
|
|
tinfoil.config_data.setVar('TESTVAR', 'specialvalue')
|
|
value = tinfoil.run_command('getVariable', 'TESTVAR')
|
|
self.assertEqual(value, 'specialvalue', 'Value set using config_data.setVar() is not reflected in config_data.getVar()')
|
|
|
|
def test_datastore_operations(self):
|
|
with bb.tinfoil.Tinfoil() as tinfoil:
|
|
tinfoil.prepare(config_only=True)
|
|
# Test setVarFlag() / getVarFlag()
|
|
tinfoil.config_data.setVarFlag('TESTVAR', 'flagname', 'flagval')
|
|
value = tinfoil.config_data.getVarFlag('TESTVAR', 'flagname')
|
|
self.assertEqual(value, 'flagval', 'Value set using config_data.setVarFlag() is not reflected in config_data.getVarFlag()')
|
|
# Test delVarFlag()
|
|
tinfoil.config_data.setVarFlag('TESTVAR', 'otherflag', 'othervalue')
|
|
tinfoil.config_data.delVarFlag('TESTVAR', 'flagname')
|
|
value = tinfoil.config_data.getVarFlag('TESTVAR', 'flagname')
|
|
self.assertEqual(value, None, 'Varflag deleted using config_data.delVarFlag() is not reflected in config_data.getVarFlag()')
|
|
value = tinfoil.config_data.getVarFlag('TESTVAR', 'otherflag')
|
|
self.assertEqual(value, 'othervalue', 'Varflag deleted using config_data.delVarFlag() caused unrelated flag to be removed')
|
|
# Test delVar()
|
|
tinfoil.config_data.setVar('TESTVAR', 'varvalue')
|
|
value = tinfoil.config_data.getVar('TESTVAR')
|
|
self.assertEqual(value, 'varvalue', 'Value set using config_data.setVar() is not reflected in config_data.getVar()')
|
|
tinfoil.config_data.delVar('TESTVAR')
|
|
value = tinfoil.config_data.getVar('TESTVAR')
|
|
self.assertEqual(value, None, 'Variable deleted using config_data.delVar() appears to still have a value')
|
|
# Test renameVar()
|
|
tinfoil.config_data.setVar('TESTVAROLD', 'origvalue')
|
|
tinfoil.config_data.renameVar('TESTVAROLD', 'TESTVARNEW')
|
|
value = tinfoil.config_data.getVar('TESTVAROLD')
|
|
self.assertEqual(value, None, 'Variable renamed using config_data.renameVar() still seems to exist')
|
|
value = tinfoil.config_data.getVar('TESTVARNEW')
|
|
self.assertEqual(value, 'origvalue', 'Variable renamed using config_data.renameVar() does not appear with new name')
|
|
# Test overrides
|
|
tinfoil.config_data.setVar('TESTVAR', 'original')
|
|
tinfoil.config_data.setVar('TESTVAR:overrideone', 'one')
|
|
tinfoil.config_data.setVar('TESTVAR:overridetwo', 'two')
|
|
tinfoil.config_data.appendVar('OVERRIDES', ':overrideone')
|
|
value = tinfoil.config_data.getVar('TESTVAR')
|
|
self.assertEqual(value, 'one', 'Variable overrides not functioning correctly')
|
|
|
|
def test_variable_history(self):
|
|
# Basic test to ensure that variable history works when tracking=True
|
|
with bb.tinfoil.Tinfoil(tracking=True) as tinfoil:
|
|
tinfoil.prepare(config_only=False, quiet=2)
|
|
# Note that _tracking for any datastore we get will be
|
|
# false here, that's currently expected - so we can't check
|
|
# for that
|
|
history = tinfoil.config_data.varhistory.variable('DL_DIR')
|
|
for entry in history:
|
|
if entry['file'].endswith('/bitbake.conf'):
|
|
if entry['op'] in ['set', 'set?']:
|
|
break
|
|
else:
|
|
self.fail('Did not find history entry setting DL_DIR in bitbake.conf. History: %s' % history)
|
|
# Check it works for recipes as well
|
|
testrecipe = 'zlib'
|
|
rd = tinfoil.parse_recipe(testrecipe)
|
|
history = rd.varhistory.variable('LICENSE')
|
|
bbfound = -1
|
|
recipefound = -1
|
|
for i, entry in enumerate(history):
|
|
if entry['file'].endswith('/bitbake.conf'):
|
|
if entry['detail'] == 'INVALID' and entry['op'] in ['set', 'set?']:
|
|
bbfound = i
|
|
elif entry['file'].endswith('.bb'):
|
|
if entry['op'] == 'set':
|
|
recipefound = i
|
|
if bbfound == -1:
|
|
self.fail('Did not find history entry setting LICENSE in bitbake.conf parsing %s recipe. History: %s' % (testrecipe, history))
|
|
if recipefound == -1:
|
|
self.fail('Did not find history entry setting LICENSE in %s recipe. History: %s' % (testrecipe, history))
|
|
if bbfound > recipefound:
|
|
self.fail('History entry setting LICENSE in %s recipe and in bitbake.conf in wrong order. History: %s' % (testrecipe, history))
|