tinfoil.py 11 KB

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