1c342db35SBrad Bishop# 2c342db35SBrad Bishop# SPDX-License-Identifier: MIT 3c342db35SBrad Bishop# 4c342db35SBrad Bishop 5eb8dc403SDave Cobbleyimport os 6eb8dc403SDave Cobbleyimport re 7eb8dc403SDave Cobbleyimport time 8eb8dc403SDave Cobbleyimport logging 9eb8dc403SDave Cobbleyimport bb.tinfoil 10eb8dc403SDave Cobbley 11eb8dc403SDave Cobbleyfrom oeqa.selftest.case import OESelftestTestCase 12eb8dc403SDave Cobbleyfrom oeqa.utils.commands import runCmd 13eb8dc403SDave Cobbley 14eb8dc403SDave Cobbleyclass TinfoilTests(OESelftestTestCase): 15eb8dc403SDave Cobbley """ Basic tests for the tinfoil API """ 16eb8dc403SDave Cobbley 17eb8dc403SDave Cobbley def test_getvar(self): 18eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 19eb8dc403SDave Cobbley tinfoil.prepare(True) 20eb8dc403SDave Cobbley machine = tinfoil.config_data.getVar('MACHINE') 21eb8dc403SDave Cobbley if not machine: 22eb8dc403SDave Cobbley self.fail('Unable to get MACHINE value - returned %s' % machine) 23eb8dc403SDave Cobbley 24eb8dc403SDave Cobbley def test_expand(self): 25eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 26eb8dc403SDave Cobbley tinfoil.prepare(True) 27eb8dc403SDave Cobbley expr = '${@os.getpid()}' 28eb8dc403SDave Cobbley pid = tinfoil.config_data.expand(expr) 29eb8dc403SDave Cobbley if not pid: 30eb8dc403SDave Cobbley self.fail('Unable to expand "%s" - returned %s' % (expr, pid)) 31eb8dc403SDave Cobbley 32eb8dc403SDave Cobbley def test_getvar_bb_origenv(self): 33eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 34eb8dc403SDave Cobbley tinfoil.prepare(True) 35eb8dc403SDave Cobbley origenv = tinfoil.config_data.getVar('BB_ORIGENV', False) 36eb8dc403SDave Cobbley if not origenv: 37eb8dc403SDave Cobbley self.fail('Unable to get BB_ORIGENV value - returned %s' % origenv) 38eb8dc403SDave Cobbley self.assertEqual(origenv.getVar('HOME', False), os.environ['HOME']) 39eb8dc403SDave Cobbley 40eb8dc403SDave Cobbley def test_parse_recipe(self): 41eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 42eb8dc403SDave Cobbley tinfoil.prepare(config_only=False, quiet=2) 43eb8dc403SDave Cobbley testrecipe = 'mdadm' 44eb8dc403SDave Cobbley best = tinfoil.find_best_provider(testrecipe) 45eb8dc403SDave Cobbley if not best: 46eb8dc403SDave Cobbley self.fail('Unable to find recipe providing %s' % testrecipe) 47eb8dc403SDave Cobbley rd = tinfoil.parse_recipe_file(best[3]) 48eb8dc403SDave Cobbley self.assertEqual(testrecipe, rd.getVar('PN')) 49eb8dc403SDave Cobbley 50eb8dc403SDave Cobbley def test_parse_recipe_copy_expand(self): 51eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 52eb8dc403SDave Cobbley tinfoil.prepare(config_only=False, quiet=2) 53eb8dc403SDave Cobbley testrecipe = 'mdadm' 54eb8dc403SDave Cobbley best = tinfoil.find_best_provider(testrecipe) 55eb8dc403SDave Cobbley if not best: 56eb8dc403SDave Cobbley self.fail('Unable to find recipe providing %s' % testrecipe) 57eb8dc403SDave Cobbley rd = tinfoil.parse_recipe_file(best[3]) 58eb8dc403SDave Cobbley # Check we can get variable values 59eb8dc403SDave Cobbley self.assertEqual(testrecipe, rd.getVar('PN')) 60eb8dc403SDave Cobbley # Check that expanding a value that includes a variable reference works 61eb8dc403SDave Cobbley self.assertEqual(testrecipe, rd.getVar('BPN')) 62eb8dc403SDave Cobbley # Now check that changing the referenced variable's value in a copy gives that 63eb8dc403SDave Cobbley # value when expanding 64eb8dc403SDave Cobbley localdata = bb.data.createCopy(rd) 65eb8dc403SDave Cobbley localdata.setVar('PN', 'hello') 66eb8dc403SDave Cobbley self.assertEqual('hello', localdata.getVar('BPN')) 67eb8dc403SDave Cobbley 68eb8dc403SDave Cobbley def test_list_recipes(self): 69eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 70eb8dc403SDave Cobbley tinfoil.prepare(config_only=False, quiet=2) 71eb8dc403SDave Cobbley # Check pkg_pn 72eb8dc403SDave Cobbley checkpns = ['tar', 'automake', 'coreutils', 'm4-native', 'nativesdk-gcc'] 73eb8dc403SDave Cobbley pkg_pn = tinfoil.cooker.recipecaches[''].pkg_pn 74eb8dc403SDave Cobbley for pn in checkpns: 75eb8dc403SDave Cobbley self.assertIn(pn, pkg_pn) 76eb8dc403SDave Cobbley # Check pkg_fn 77eb8dc403SDave Cobbley checkfns = {'nativesdk-gcc': '^virtual:nativesdk:.*', 'coreutils': '.*/coreutils_.*.bb'} 78eb8dc403SDave Cobbley for fn, pn in tinfoil.cooker.recipecaches[''].pkg_fn.items(): 79eb8dc403SDave Cobbley if pn in checkpns: 80eb8dc403SDave Cobbley if pn in checkfns: 81eb8dc403SDave Cobbley self.assertTrue(re.match(checkfns[pn], fn), 'Entry for %s: %s did not match %s' % (pn, fn, checkfns[pn])) 82eb8dc403SDave Cobbley checkpns.remove(pn) 83eb8dc403SDave Cobbley if checkpns: 84eb8dc403SDave Cobbley self.fail('Unable to find pkg_fn entries for: %s' % ', '.join(checkpns)) 85eb8dc403SDave Cobbley 86eb8dc403SDave Cobbley def test_wait_event(self): 87eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 88eb8dc403SDave Cobbley tinfoil.prepare(config_only=True) 89eb8dc403SDave Cobbley 90*9aee5003SAndrew Geissler tinfoil.set_event_mask(['bb.event.FilesMatchingFound', 'bb.command.CommandCompleted', 'bb.command.CommandFailed', 'bb.command.CommandExit']) 91eb8dc403SDave Cobbley 92eb8dc403SDave Cobbley # Need to drain events otherwise events that were masked may still be in the queue 93eb8dc403SDave Cobbley while tinfoil.wait_event(): 94eb8dc403SDave Cobbley pass 95eb8dc403SDave Cobbley 96eb8dc403SDave Cobbley pattern = 'conf' 97*9aee5003SAndrew Geissler res = tinfoil.run_command('testCookerCommandEvent', pattern, handle_events=False) 98eb8dc403SDave Cobbley self.assertTrue(res) 99eb8dc403SDave Cobbley 100eb8dc403SDave Cobbley eventreceived = False 101eb8dc403SDave Cobbley commandcomplete = False 102eb8dc403SDave Cobbley start = time.time() 103d1e89497SAndrew Geissler # Wait for maximum 60s in total so we'd detect spurious heartbeat events for example 104d1e89497SAndrew Geissler while (not (eventreceived == True and commandcomplete == True) 105d1e89497SAndrew Geissler and (time.time() - start < 60)): 106d1e89497SAndrew Geissler # if we received both events (on let's say a good day), we are done 107eb8dc403SDave Cobbley event = tinfoil.wait_event(1) 108eb8dc403SDave Cobbley if event: 109eb8dc403SDave Cobbley if isinstance(event, bb.command.CommandCompleted): 110eb8dc403SDave Cobbley commandcomplete = True 111eb8dc403SDave Cobbley elif isinstance(event, bb.event.FilesMatchingFound): 112eb8dc403SDave Cobbley self.assertEqual(pattern, event._pattern) 11393c203f3SPatrick Williams self.assertIn('A', event._matches) 11493c203f3SPatrick Williams self.assertIn('B', event._matches) 115eb8dc403SDave Cobbley eventreceived = True 116eb8dc403SDave Cobbley elif isinstance(event, logging.LogRecord): 117eb8dc403SDave Cobbley continue 118eb8dc403SDave Cobbley else: 119eb8dc403SDave Cobbley self.fail('Unexpected event: %s' % event) 120eb8dc403SDave Cobbley 121*9aee5003SAndrew Geissler self.assertTrue(commandcomplete, 'Timed out waiting for CommandCompleted event from bitbake server (Matching event received: %s)' % str(eventreceived)) 122eb8dc403SDave Cobbley self.assertTrue(eventreceived, 'Did not receive FilesMatchingFound event from bitbake server') 123eb8dc403SDave Cobbley 124eb8dc403SDave Cobbley def test_setvariable_clean(self): 125eb8dc403SDave Cobbley # First check that setVariable affects the datastore 126eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 127eb8dc403SDave Cobbley tinfoil.prepare(config_only=True) 128eb8dc403SDave Cobbley tinfoil.run_command('setVariable', 'TESTVAR', 'specialvalue') 129eb8dc403SDave Cobbley self.assertEqual(tinfoil.config_data.getVar('TESTVAR'), 'specialvalue', 'Value set using setVariable is not reflected in client-side getVar()') 130eb8dc403SDave Cobbley 131eb8dc403SDave Cobbley # Now check that the setVariable's effects are no longer present 132eb8dc403SDave Cobbley # (this may legitimately break in future if we stop reinitialising 133eb8dc403SDave Cobbley # the datastore, in which case we'll have to reconsider use of 134eb8dc403SDave Cobbley # setVariable entirely) 135eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 136eb8dc403SDave Cobbley tinfoil.prepare(config_only=True) 137eb8dc403SDave Cobbley self.assertNotEqual(tinfoil.config_data.getVar('TESTVAR'), 'specialvalue', 'Value set using setVariable is still present!') 138eb8dc403SDave Cobbley 139eb8dc403SDave Cobbley # Now check that setVar on the main datastore works (uses setVariable internally) 140eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 141eb8dc403SDave Cobbley tinfoil.prepare(config_only=True) 142eb8dc403SDave Cobbley tinfoil.config_data.setVar('TESTVAR', 'specialvalue') 143eb8dc403SDave Cobbley value = tinfoil.run_command('getVariable', 'TESTVAR') 144eb8dc403SDave Cobbley self.assertEqual(value, 'specialvalue', 'Value set using config_data.setVar() is not reflected in config_data.getVar()') 145eb8dc403SDave Cobbley 146eb8dc403SDave Cobbley def test_datastore_operations(self): 147eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil() as tinfoil: 148eb8dc403SDave Cobbley tinfoil.prepare(config_only=True) 149eb8dc403SDave Cobbley # Test setVarFlag() / getVarFlag() 150eb8dc403SDave Cobbley tinfoil.config_data.setVarFlag('TESTVAR', 'flagname', 'flagval') 151eb8dc403SDave Cobbley value = tinfoil.config_data.getVarFlag('TESTVAR', 'flagname') 152eb8dc403SDave Cobbley self.assertEqual(value, 'flagval', 'Value set using config_data.setVarFlag() is not reflected in config_data.getVarFlag()') 153eb8dc403SDave Cobbley # Test delVarFlag() 154eb8dc403SDave Cobbley tinfoil.config_data.setVarFlag('TESTVAR', 'otherflag', 'othervalue') 155eb8dc403SDave Cobbley tinfoil.config_data.delVarFlag('TESTVAR', 'flagname') 156eb8dc403SDave Cobbley value = tinfoil.config_data.getVarFlag('TESTVAR', 'flagname') 157eb8dc403SDave Cobbley self.assertEqual(value, None, 'Varflag deleted using config_data.delVarFlag() is not reflected in config_data.getVarFlag()') 158eb8dc403SDave Cobbley value = tinfoil.config_data.getVarFlag('TESTVAR', 'otherflag') 159eb8dc403SDave Cobbley self.assertEqual(value, 'othervalue', 'Varflag deleted using config_data.delVarFlag() caused unrelated flag to be removed') 160eb8dc403SDave Cobbley # Test delVar() 161eb8dc403SDave Cobbley tinfoil.config_data.setVar('TESTVAR', 'varvalue') 162eb8dc403SDave Cobbley value = tinfoil.config_data.getVar('TESTVAR') 163eb8dc403SDave Cobbley self.assertEqual(value, 'varvalue', 'Value set using config_data.setVar() is not reflected in config_data.getVar()') 164eb8dc403SDave Cobbley tinfoil.config_data.delVar('TESTVAR') 165eb8dc403SDave Cobbley value = tinfoil.config_data.getVar('TESTVAR') 166eb8dc403SDave Cobbley self.assertEqual(value, None, 'Variable deleted using config_data.delVar() appears to still have a value') 167eb8dc403SDave Cobbley # Test renameVar() 168eb8dc403SDave Cobbley tinfoil.config_data.setVar('TESTVAROLD', 'origvalue') 169eb8dc403SDave Cobbley tinfoil.config_data.renameVar('TESTVAROLD', 'TESTVARNEW') 170eb8dc403SDave Cobbley value = tinfoil.config_data.getVar('TESTVAROLD') 171eb8dc403SDave Cobbley self.assertEqual(value, None, 'Variable renamed using config_data.renameVar() still seems to exist') 172eb8dc403SDave Cobbley value = tinfoil.config_data.getVar('TESTVARNEW') 173eb8dc403SDave Cobbley self.assertEqual(value, 'origvalue', 'Variable renamed using config_data.renameVar() does not appear with new name') 174eb8dc403SDave Cobbley # Test overrides 175eb8dc403SDave Cobbley tinfoil.config_data.setVar('TESTVAR', 'original') 176213cb269SPatrick Williams tinfoil.config_data.setVar('TESTVAR:overrideone', 'one') 177213cb269SPatrick Williams tinfoil.config_data.setVar('TESTVAR:overridetwo', 'two') 178eb8dc403SDave Cobbley tinfoil.config_data.appendVar('OVERRIDES', ':overrideone') 179eb8dc403SDave Cobbley value = tinfoil.config_data.getVar('TESTVAR') 180eb8dc403SDave Cobbley self.assertEqual(value, 'one', 'Variable overrides not functioning correctly') 181eb8dc403SDave Cobbley 182eb8dc403SDave Cobbley def test_variable_history(self): 183eb8dc403SDave Cobbley # Basic test to ensure that variable history works when tracking=True 184eb8dc403SDave Cobbley with bb.tinfoil.Tinfoil(tracking=True) as tinfoil: 185eb8dc403SDave Cobbley tinfoil.prepare(config_only=False, quiet=2) 186eb8dc403SDave Cobbley # Note that _tracking for any datastore we get will be 187eb8dc403SDave Cobbley # false here, that's currently expected - so we can't check 188eb8dc403SDave Cobbley # for that 189eb8dc403SDave Cobbley history = tinfoil.config_data.varhistory.variable('DL_DIR') 190eb8dc403SDave Cobbley for entry in history: 191eb8dc403SDave Cobbley if entry['file'].endswith('/bitbake.conf'): 192eb8dc403SDave Cobbley if entry['op'] in ['set', 'set?']: 193eb8dc403SDave Cobbley break 194eb8dc403SDave Cobbley else: 195eb8dc403SDave Cobbley self.fail('Did not find history entry setting DL_DIR in bitbake.conf. History: %s' % history) 196eb8dc403SDave Cobbley # Check it works for recipes as well 197eb8dc403SDave Cobbley testrecipe = 'zlib' 198eb8dc403SDave Cobbley rd = tinfoil.parse_recipe(testrecipe) 199eb8dc403SDave Cobbley history = rd.varhistory.variable('LICENSE') 200eb8dc403SDave Cobbley bbfound = -1 201eb8dc403SDave Cobbley recipefound = -1 202eb8dc403SDave Cobbley for i, entry in enumerate(history): 203eb8dc403SDave Cobbley if entry['file'].endswith('/bitbake.conf'): 204eb8dc403SDave Cobbley if entry['detail'] == 'INVALID' and entry['op'] in ['set', 'set?']: 205eb8dc403SDave Cobbley bbfound = i 206eb8dc403SDave Cobbley elif entry['file'].endswith('.bb'): 207eb8dc403SDave Cobbley if entry['op'] == 'set': 208eb8dc403SDave Cobbley recipefound = i 209eb8dc403SDave Cobbley if bbfound == -1: 210eb8dc403SDave Cobbley self.fail('Did not find history entry setting LICENSE in bitbake.conf parsing %s recipe. History: %s' % (testrecipe, history)) 211eb8dc403SDave Cobbley if recipefound == -1: 212eb8dc403SDave Cobbley self.fail('Did not find history entry setting LICENSE in %s recipe. History: %s' % (testrecipe, history)) 213eb8dc403SDave Cobbley if bbfound > recipefound: 214eb8dc403SDave Cobbley self.fail('History entry setting LICENSE in %s recipe and in bitbake.conf in wrong order. History: %s' % (testrecipe, history)) 215