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