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