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