xref: /openbmc/openbmc/poky/bitbake/lib/bb/tests/data.py (revision 1a4b7ee2)
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# BitBake Tests for the Data Store (data.py/data_smart.py)
5#
6# Copyright (C) 2010 Chris Larson
7# Copyright (C) 2012 Richard Purdie
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21#
22
23import unittest
24import bb
25import bb.data
26import bb.parse
27import logging
28
29class LogRecord():
30    def __enter__(self):
31        logs = []
32        class LogHandler(logging.Handler):
33            def emit(self, record):
34                logs.append(record)
35        logger = logging.getLogger("BitBake")
36        handler = LogHandler()
37        self.handler = handler
38        logger.addHandler(handler)
39        return logs
40    def __exit__(self, type, value, traceback):
41        logger = logging.getLogger("BitBake")
42        logger.removeHandler(self.handler)
43        return
44
45def logContains(item, logs):
46    for l in logs:
47        m = l.getMessage()
48        if item in m:
49            return True
50    return False
51
52class DataExpansions(unittest.TestCase):
53    def setUp(self):
54        self.d = bb.data.init()
55        self.d["foo"] = "value_of_foo"
56        self.d["bar"] = "value_of_bar"
57        self.d["value_of_foo"] = "value_of_'value_of_foo'"
58
59    def test_one_var(self):
60        val = self.d.expand("${foo}")
61        self.assertEqual(str(val), "value_of_foo")
62
63    def test_indirect_one_var(self):
64        val = self.d.expand("${${foo}}")
65        self.assertEqual(str(val), "value_of_'value_of_foo'")
66
67    def test_indirect_and_another(self):
68        val = self.d.expand("${${foo}} ${bar}")
69        self.assertEqual(str(val), "value_of_'value_of_foo' value_of_bar")
70
71    def test_python_snippet(self):
72        val = self.d.expand("${@5*12}")
73        self.assertEqual(str(val), "60")
74
75    def test_expand_in_python_snippet(self):
76        val = self.d.expand("${@'boo ' + '${foo}'}")
77        self.assertEqual(str(val), "boo value_of_foo")
78
79    def test_python_snippet_getvar(self):
80        val = self.d.expand("${@d.getVar('foo') + ' ${bar}'}")
81        self.assertEqual(str(val), "value_of_foo value_of_bar")
82
83    def test_python_unexpanded(self):
84        self.d.setVar("bar", "${unsetvar}")
85        val = self.d.expand("${@d.getVar('foo') + ' ${bar}'}")
86        self.assertEqual(str(val), "${@d.getVar('foo') + ' ${unsetvar}'}")
87
88    def test_python_snippet_syntax_error(self):
89        self.d.setVar("FOO", "${@foo = 5}")
90        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
91
92    def test_python_snippet_runtime_error(self):
93        self.d.setVar("FOO", "${@int('test')}")
94        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
95
96    def test_python_snippet_error_path(self):
97        self.d.setVar("FOO", "foo value ${BAR}")
98        self.d.setVar("BAR", "bar value ${@int('test')}")
99        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
100
101    def test_value_containing_value(self):
102        val = self.d.expand("${@d.getVar('foo') + ' ${bar}'}")
103        self.assertEqual(str(val), "value_of_foo value_of_bar")
104
105    def test_reference_undefined_var(self):
106        val = self.d.expand("${undefinedvar} meh")
107        self.assertEqual(str(val), "${undefinedvar} meh")
108
109    def test_double_reference(self):
110        self.d.setVar("BAR", "bar value")
111        self.d.setVar("FOO", "${BAR} foo ${BAR}")
112        val = self.d.getVar("FOO")
113        self.assertEqual(str(val), "bar value foo bar value")
114
115    def test_direct_recursion(self):
116        self.d.setVar("FOO", "${FOO}")
117        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
118
119    def test_indirect_recursion(self):
120        self.d.setVar("FOO", "${BAR}")
121        self.d.setVar("BAR", "${BAZ}")
122        self.d.setVar("BAZ", "${FOO}")
123        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
124
125    def test_recursion_exception(self):
126        self.d.setVar("FOO", "${BAR}")
127        self.d.setVar("BAR", "${${@'FOO'}}")
128        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
129
130    def test_incomplete_varexp_single_quotes(self):
131        self.d.setVar("FOO", "sed -i -e 's:IP{:I${:g' $pc")
132        val = self.d.getVar("FOO")
133        self.assertEqual(str(val), "sed -i -e 's:IP{:I${:g' $pc")
134
135    def test_nonstring(self):
136        self.d.setVar("TEST", 5)
137        val = self.d.getVar("TEST")
138        self.assertEqual(str(val), "5")
139
140    def test_rename(self):
141        self.d.renameVar("foo", "newfoo")
142        self.assertEqual(self.d.getVar("newfoo", False), "value_of_foo")
143        self.assertEqual(self.d.getVar("foo", False), None)
144
145    def test_deletion(self):
146        self.d.delVar("foo")
147        self.assertEqual(self.d.getVar("foo", False), None)
148
149    def test_keys(self):
150        keys = list(self.d.keys())
151        self.assertCountEqual(keys, ['value_of_foo', 'foo', 'bar'])
152
153    def test_keys_deletion(self):
154        newd = bb.data.createCopy(self.d)
155        newd.delVar("bar")
156        keys = list(newd.keys())
157        self.assertCountEqual(keys, ['value_of_foo', 'foo'])
158
159class TestNestedExpansions(unittest.TestCase):
160    def setUp(self):
161        self.d = bb.data.init()
162        self.d["foo"] = "foo"
163        self.d["bar"] = "bar"
164        self.d["value_of_foobar"] = "187"
165
166    def test_refs(self):
167        val = self.d.expand("${value_of_${foo}${bar}}")
168        self.assertEqual(str(val), "187")
169
170    #def test_python_refs(self):
171    #    val = self.d.expand("${@${@3}**2 + ${@4}**2}")
172    #    self.assertEqual(str(val), "25")
173
174    def test_ref_in_python_ref(self):
175        val = self.d.expand("${@'${foo}' + 'bar'}")
176        self.assertEqual(str(val), "foobar")
177
178    def test_python_ref_in_ref(self):
179        val = self.d.expand("${${@'f'+'o'+'o'}}")
180        self.assertEqual(str(val), "foo")
181
182    def test_deep_nesting(self):
183        depth = 100
184        val = self.d.expand("${" * depth + "foo" + "}" * depth)
185        self.assertEqual(str(val), "foo")
186
187    #def test_deep_python_nesting(self):
188    #    depth = 50
189    #    val = self.d.expand("${@" * depth + "1" + "+1}" * depth)
190    #    self.assertEqual(str(val), str(depth + 1))
191
192    def test_mixed(self):
193        val = self.d.expand("${value_of_${@('${foo}'+'bar')[0:3]}${${@'BAR'.lower()}}}")
194        self.assertEqual(str(val), "187")
195
196    def test_runtime(self):
197        val = self.d.expand("${${@'value_of' + '_f'+'o'+'o'+'b'+'a'+'r'}}")
198        self.assertEqual(str(val), "187")
199
200class TestMemoize(unittest.TestCase):
201    def test_memoized(self):
202        d = bb.data.init()
203        d.setVar("FOO", "bar")
204        self.assertTrue(d.getVar("FOO", False) is d.getVar("FOO", False))
205
206    def test_not_memoized(self):
207        d1 = bb.data.init()
208        d2 = bb.data.init()
209        d1.setVar("FOO", "bar")
210        d2.setVar("FOO", "bar2")
211        self.assertTrue(d1.getVar("FOO", False) is not d2.getVar("FOO", False))
212
213    def test_changed_after_memoized(self):
214        d = bb.data.init()
215        d.setVar("foo", "value of foo")
216        self.assertEqual(str(d.getVar("foo", False)), "value of foo")
217        d.setVar("foo", "second value of foo")
218        self.assertEqual(str(d.getVar("foo", False)), "second value of foo")
219
220    def test_same_value(self):
221        d = bb.data.init()
222        d.setVar("foo", "value of")
223        d.setVar("bar", "value of")
224        self.assertEqual(d.getVar("foo", False),
225                         d.getVar("bar", False))
226
227class TestConcat(unittest.TestCase):
228    def setUp(self):
229        self.d = bb.data.init()
230        self.d.setVar("FOO", "foo")
231        self.d.setVar("VAL", "val")
232        self.d.setVar("BAR", "bar")
233
234    def test_prepend(self):
235        self.d.setVar("TEST", "${VAL}")
236        self.d.prependVar("TEST", "${FOO}:")
237        self.assertEqual(self.d.getVar("TEST"), "foo:val")
238
239    def test_append(self):
240        self.d.setVar("TEST", "${VAL}")
241        self.d.appendVar("TEST", ":${BAR}")
242        self.assertEqual(self.d.getVar("TEST"), "val:bar")
243
244    def test_multiple_append(self):
245        self.d.setVar("TEST", "${VAL}")
246        self.d.prependVar("TEST", "${FOO}:")
247        self.d.appendVar("TEST", ":val2")
248        self.d.appendVar("TEST", ":${BAR}")
249        self.assertEqual(self.d.getVar("TEST"), "foo:val:val2:bar")
250
251class TestConcatOverride(unittest.TestCase):
252    def setUp(self):
253        self.d = bb.data.init()
254        self.d.setVar("FOO", "foo")
255        self.d.setVar("VAL", "val")
256        self.d.setVar("BAR", "bar")
257
258    def test_prepend(self):
259        self.d.setVar("TEST", "${VAL}")
260        self.d.setVar("TEST_prepend", "${FOO}:")
261        self.assertEqual(self.d.getVar("TEST"), "foo:val")
262
263    def test_append(self):
264        self.d.setVar("TEST", "${VAL}")
265        self.d.setVar("TEST_append", ":${BAR}")
266        self.assertEqual(self.d.getVar("TEST"), "val:bar")
267
268    def test_multiple_append(self):
269        self.d.setVar("TEST", "${VAL}")
270        self.d.setVar("TEST_prepend", "${FOO}:")
271        self.d.setVar("TEST_append", ":val2")
272        self.d.setVar("TEST_append", ":${BAR}")
273        self.assertEqual(self.d.getVar("TEST"), "foo:val:val2:bar")
274
275    def test_append_unset(self):
276        self.d.setVar("TEST_prepend", "${FOO}:")
277        self.d.setVar("TEST_append", ":val2")
278        self.d.setVar("TEST_append", ":${BAR}")
279        self.assertEqual(self.d.getVar("TEST"), "foo::val2:bar")
280
281    def test_remove(self):
282        self.d.setVar("TEST", "${VAL} ${BAR}")
283        self.d.setVar("TEST_remove", "val")
284        self.assertEqual(self.d.getVar("TEST"), " bar")
285
286    def test_remove_cleared(self):
287        self.d.setVar("TEST", "${VAL} ${BAR}")
288        self.d.setVar("TEST_remove", "val")
289        self.d.setVar("TEST", "${VAL} ${BAR}")
290        self.assertEqual(self.d.getVar("TEST"), "val bar")
291
292    # Ensure the value is unchanged if we have an inactive remove override
293    # (including that whitespace is preserved)
294    def test_remove_inactive_override(self):
295        self.d.setVar("TEST", "${VAL} ${BAR}    123")
296        self.d.setVar("TEST_remove_inactiveoverride", "val")
297        self.assertEqual(self.d.getVar("TEST"), "val bar    123")
298
299    def test_doubleref_remove(self):
300        self.d.setVar("TEST", "${VAL} ${BAR}")
301        self.d.setVar("TEST_remove", "val")
302        self.d.setVar("TEST_TEST", "${TEST} ${TEST}")
303        self.assertEqual(self.d.getVar("TEST_TEST"), " bar  bar")
304
305    def test_empty_remove(self):
306        self.d.setVar("TEST", "")
307        self.d.setVar("TEST_remove", "val")
308        self.assertEqual(self.d.getVar("TEST"), "")
309
310    def test_remove_expansion(self):
311        self.d.setVar("BAR", "Z")
312        self.d.setVar("TEST", "${BAR}/X Y")
313        self.d.setVar("TEST_remove", "${BAR}/X")
314        self.assertEqual(self.d.getVar("TEST"), " Y")
315
316    def test_remove_expansion_items(self):
317        self.d.setVar("TEST", "A B C D")
318        self.d.setVar("BAR", "B D")
319        self.d.setVar("TEST_remove", "${BAR}")
320        self.assertEqual(self.d.getVar("TEST"), "A  C ")
321
322    def test_remove_preserve_whitespace(self):
323        # When the removal isn't active, the original value should be preserved
324        self.d.setVar("TEST", " A B")
325        self.d.setVar("TEST_remove", "C")
326        self.assertEqual(self.d.getVar("TEST"), " A B")
327
328    def test_remove_preserve_whitespace2(self):
329        # When the removal is active preserve the whitespace
330        self.d.setVar("TEST", " A B")
331        self.d.setVar("TEST_remove", "B")
332        self.assertEqual(self.d.getVar("TEST"), " A ")
333
334class TestOverrides(unittest.TestCase):
335    def setUp(self):
336        self.d = bb.data.init()
337        self.d.setVar("OVERRIDES", "foo:bar:local")
338        self.d.setVar("TEST", "testvalue")
339
340    def test_no_override(self):
341        self.assertEqual(self.d.getVar("TEST"), "testvalue")
342
343    def test_one_override(self):
344        self.d.setVar("TEST_bar", "testvalue2")
345        self.assertEqual(self.d.getVar("TEST"), "testvalue2")
346
347    def test_one_override_unset(self):
348        self.d.setVar("TEST2_bar", "testvalue2")
349
350        self.assertEqual(self.d.getVar("TEST2"), "testvalue2")
351        self.assertCountEqual(list(self.d.keys()), ['TEST', 'TEST2', 'OVERRIDES', 'TEST2_bar'])
352
353    def test_multiple_override(self):
354        self.d.setVar("TEST_bar", "testvalue2")
355        self.d.setVar("TEST_local", "testvalue3")
356        self.d.setVar("TEST_foo", "testvalue4")
357        self.assertEqual(self.d.getVar("TEST"), "testvalue3")
358        self.assertCountEqual(list(self.d.keys()), ['TEST', 'TEST_foo', 'OVERRIDES', 'TEST_bar', 'TEST_local'])
359
360    def test_multiple_combined_overrides(self):
361        self.d.setVar("TEST_local_foo_bar", "testvalue3")
362        self.assertEqual(self.d.getVar("TEST"), "testvalue3")
363
364    def test_multiple_overrides_unset(self):
365        self.d.setVar("TEST2_local_foo_bar", "testvalue3")
366        self.assertEqual(self.d.getVar("TEST2"), "testvalue3")
367
368    def test_keyexpansion_override(self):
369        self.d.setVar("LOCAL", "local")
370        self.d.setVar("TEST_bar", "testvalue2")
371        self.d.setVar("TEST_${LOCAL}", "testvalue3")
372        self.d.setVar("TEST_foo", "testvalue4")
373        bb.data.expandKeys(self.d)
374        self.assertEqual(self.d.getVar("TEST"), "testvalue3")
375
376    def test_rename_override(self):
377        self.d.setVar("ALTERNATIVE_ncurses-tools_class-target", "a")
378        self.d.setVar("OVERRIDES", "class-target")
379        self.d.renameVar("ALTERNATIVE_ncurses-tools", "ALTERNATIVE_lib32-ncurses-tools")
380        self.assertEqual(self.d.getVar("ALTERNATIVE_lib32-ncurses-tools"), "a")
381
382    def test_underscore_override(self):
383        self.d.setVar("TEST_bar", "testvalue2")
384        self.d.setVar("TEST_some_val", "testvalue3")
385        self.d.setVar("TEST_foo", "testvalue4")
386        self.d.setVar("OVERRIDES", "foo:bar:some_val")
387        self.assertEqual(self.d.getVar("TEST"), "testvalue3")
388
389    def test_remove_with_override(self):
390        self.d.setVar("TEST_bar", "testvalue2")
391        self.d.setVar("TEST_some_val", "testvalue3 testvalue5")
392        self.d.setVar("TEST_some_val_remove", "testvalue3")
393        self.d.setVar("TEST_foo", "testvalue4")
394        self.d.setVar("OVERRIDES", "foo:bar:some_val")
395        self.assertEqual(self.d.getVar("TEST"), " testvalue5")
396
397
398class TestKeyExpansion(unittest.TestCase):
399    def setUp(self):
400        self.d = bb.data.init()
401        self.d.setVar("FOO", "foo")
402        self.d.setVar("BAR", "foo")
403
404    def test_keyexpand(self):
405        self.d.setVar("VAL_${FOO}", "A")
406        self.d.setVar("VAL_${BAR}", "B")
407        with LogRecord() as logs:
408            bb.data.expandKeys(self.d)
409            self.assertTrue(logContains("Variable key VAL_${FOO} (A) replaces original key VAL_foo (B)", logs))
410        self.assertEqual(self.d.getVar("VAL_foo"), "A")
411
412class TestFlags(unittest.TestCase):
413    def setUp(self):
414        self.d = bb.data.init()
415        self.d.setVar("foo", "value of foo")
416        self.d.setVarFlag("foo", "flag1", "value of flag1")
417        self.d.setVarFlag("foo", "flag2", "value of flag2")
418
419    def test_setflag(self):
420        self.assertEqual(self.d.getVarFlag("foo", "flag1", False), "value of flag1")
421        self.assertEqual(self.d.getVarFlag("foo", "flag2", False), "value of flag2")
422
423    def test_delflag(self):
424        self.d.delVarFlag("foo", "flag2")
425        self.assertEqual(self.d.getVarFlag("foo", "flag1", False), "value of flag1")
426        self.assertEqual(self.d.getVarFlag("foo", "flag2", False), None)
427
428
429class Contains(unittest.TestCase):
430    def setUp(self):
431        self.d = bb.data.init()
432        self.d.setVar("SOMEFLAG", "a b c")
433
434    def test_contains(self):
435        self.assertTrue(bb.utils.contains("SOMEFLAG", "a", True, False, self.d))
436        self.assertTrue(bb.utils.contains("SOMEFLAG", "b", True, False, self.d))
437        self.assertTrue(bb.utils.contains("SOMEFLAG", "c", True, False, self.d))
438
439        self.assertTrue(bb.utils.contains("SOMEFLAG", "a b", True, False, self.d))
440        self.assertTrue(bb.utils.contains("SOMEFLAG", "b c", True, False, self.d))
441        self.assertTrue(bb.utils.contains("SOMEFLAG", "c a", True, False, self.d))
442
443        self.assertTrue(bb.utils.contains("SOMEFLAG", "a b c", True, False, self.d))
444        self.assertTrue(bb.utils.contains("SOMEFLAG", "c b a", True, False, self.d))
445
446        self.assertFalse(bb.utils.contains("SOMEFLAG", "x", True, False, self.d))
447        self.assertFalse(bb.utils.contains("SOMEFLAG", "a x", True, False, self.d))
448        self.assertFalse(bb.utils.contains("SOMEFLAG", "x c b", True, False, self.d))
449        self.assertFalse(bb.utils.contains("SOMEFLAG", "x c b a", True, False, self.d))
450
451    def test_contains_any(self):
452        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "a", True, False, self.d))
453        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "b", True, False, self.d))
454        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "c", True, False, self.d))
455
456        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "a b", True, False, self.d))
457        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "b c", True, False, self.d))
458        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "c a", True, False, self.d))
459
460        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "a x", True, False, self.d))
461        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "x c", True, False, self.d))
462
463        self.assertFalse(bb.utils.contains_any("SOMEFLAG", "x", True, False, self.d))
464        self.assertFalse(bb.utils.contains_any("SOMEFLAG", "x y z", True, False, self.d))
465
466
467class TaskHash(unittest.TestCase):
468    def test_taskhashes(self):
469        def gettask_bashhash(taskname, d):
470            tasklist, gendeps, lookupcache = bb.data.generate_dependencies(d)
471            taskdeps, basehash = bb.data.generate_dependency_hash(tasklist, gendeps, lookupcache, set(), "somefile")
472            bb.warn(str(lookupcache))
473            return basehash["somefile." + taskname]
474
475        d = bb.data.init()
476        d.setVar("__BBTASKS", ["mytask"])
477        d.setVar("__exportlist", [])
478        d.setVar("mytask", "${MYCOMMAND}")
479        d.setVar("MYCOMMAND", "${VAR}; foo; bar; exit 0")
480        d.setVar("VAR", "val")
481        orighash = gettask_bashhash("mytask", d)
482
483        # Changing a variable should change the hash
484        d.setVar("VAR", "val2")
485        nexthash = gettask_bashhash("mytask", d)
486        self.assertNotEqual(orighash, nexthash)
487
488        d.setVar("VAR", "val")
489        # Adding an inactive removal shouldn't change the hash
490        d.setVar("BAR", "notbar")
491        d.setVar("MYCOMMAND_remove", "${BAR}")
492        nexthash = gettask_bashhash("mytask", d)
493        self.assertEqual(orighash, nexthash)
494
495        # Adding an active removal should change the hash
496        d.setVar("BAR", "bar;")
497        nexthash = gettask_bashhash("mytask", d)
498        self.assertNotEqual(orighash, nexthash)
499
500        # Setup an inactive contains()
501        d.setVar("VAR", "${@bb.utils.contains('VAR2', 'A', 'val', '', d)}")
502        orighash = gettask_bashhash("mytask", d)
503
504        # Activate the contains() and the hash should change
505        d.setVar("VAR2", "A")
506        nexthash = gettask_bashhash("mytask", d)
507        self.assertNotEqual(orighash, nexthash)
508
509        # The contains should be inactive but even though VAR2 has a
510        # different value the hash should match the original
511        d.setVar("VAR2", "B")
512        nexthash = gettask_bashhash("mytask", d)
513        self.assertEqual(orighash, nexthash)
514
515class Serialize(unittest.TestCase):
516
517    def test_serialize(self):
518        import tempfile
519        import pickle
520        d = bb.data.init()
521        d.enableTracking()
522        d.setVar('HELLO', 'world')
523        d.setVarFlag('HELLO', 'other', 'planet')
524        with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
525            tmpfilename = tmpfile.name
526            pickle.dump(d, tmpfile)
527
528        with open(tmpfilename, 'rb') as f:
529            newd = pickle.load(f)
530
531        os.remove(tmpfilename)
532
533        self.assertEqual(d, newd)
534        self.assertEqual(newd.getVar('HELLO'), 'world')
535        self.assertEqual(newd.getVarFlag('HELLO', 'other'), 'planet')
536
537
538# Remote datastore tests
539# These really only test the interface, since in actual usage we have a
540# tinfoil connector that does everything over RPC, and this doesn't test
541# that.
542
543class TestConnector:
544    d = None
545    def __init__(self, d):
546        self.d = d
547    def getVar(self, name):
548        return self.d._findVar(name)
549    def getKeys(self):
550        return set(self.d.keys())
551    def getVarHistory(self, name):
552        return self.d.varhistory.variable(name)
553    def expandPythonRef(self, varname, expr, d):
554        localdata = self.d.createCopy()
555        for key in d.localkeys():
556            localdata.setVar(d.getVar(key))
557        varparse = bb.data_smart.VariableParse(varname, localdata)
558        return varparse.python_sub(expr)
559    def setVar(self, name, value):
560        self.d.setVar(name, value)
561    def setVarFlag(self, name, flag, value):
562        self.d.setVarFlag(name, flag, value)
563    def delVar(self, name):
564        self.d.delVar(name)
565        return False
566    def delVarFlag(self, name, flag):
567        self.d.delVarFlag(name, flag)
568        return False
569    def renameVar(self, name, newname):
570        self.d.renameVar(name, newname)
571        return False
572
573class Remote(unittest.TestCase):
574    def test_remote(self):
575
576        d1 = bb.data.init()
577        d1.enableTracking()
578        d2 = bb.data.init()
579        d2.enableTracking()
580        connector = TestConnector(d1)
581
582        d2.setVar('_remote_data', connector)
583
584        d1.setVar('HELLO', 'world')
585        d1.setVarFlag('OTHER', 'flagname', 'flagvalue')
586        self.assertEqual(d2.getVar('HELLO'), 'world')
587        self.assertEqual(d2.expand('${HELLO}'), 'world')
588        self.assertEqual(d2.expand('${@d.getVar("HELLO")}'), 'world')
589        self.assertIn('flagname', d2.getVarFlags('OTHER'))
590        self.assertEqual(d2.getVarFlag('OTHER', 'flagname'), 'flagvalue')
591        self.assertEqual(d1.varhistory.variable('HELLO'), d2.varhistory.variable('HELLO'))
592        # Test setVar on client side affects server
593        d2.setVar('HELLO', 'other-world')
594        self.assertEqual(d1.getVar('HELLO'), 'other-world')
595        # Test setVarFlag on client side affects server
596        d2.setVarFlag('HELLO', 'flagname', 'flagvalue')
597        self.assertEqual(d1.getVarFlag('HELLO', 'flagname'), 'flagvalue')
598        # Test client side data is incorporated in python expansion (which is done on server)
599        d2.setVar('FOO', 'bar')
600        self.assertEqual(d2.expand('${@d.getVar("FOO")}'), 'bar')
601        # Test overrides work
602        d1.setVar('FOO_test', 'baz')
603        d1.appendVar('OVERRIDES', ':test')
604        self.assertEqual(d2.getVar('FOO'), 'baz')
605
606
607# Remote equivalents of local test classes
608# Note that these aren't perfect since we only test in one direction
609
610class RemoteDataExpansions(DataExpansions):
611    def setUp(self):
612        self.d1 = bb.data.init()
613        self.d = bb.data.init()
614        self.d1["foo"] = "value_of_foo"
615        self.d1["bar"] = "value_of_bar"
616        self.d1["value_of_foo"] = "value_of_'value_of_foo'"
617        connector = TestConnector(self.d1)
618        self.d.setVar('_remote_data', connector)
619
620class TestRemoteNestedExpansions(TestNestedExpansions):
621    def setUp(self):
622        self.d1 = bb.data.init()
623        self.d = bb.data.init()
624        self.d1["foo"] = "foo"
625        self.d1["bar"] = "bar"
626        self.d1["value_of_foobar"] = "187"
627        connector = TestConnector(self.d1)
628        self.d.setVar('_remote_data', connector)
629
630class TestRemoteConcat(TestConcat):
631    def setUp(self):
632        self.d1 = bb.data.init()
633        self.d = bb.data.init()
634        self.d1.setVar("FOO", "foo")
635        self.d1.setVar("VAL", "val")
636        self.d1.setVar("BAR", "bar")
637        connector = TestConnector(self.d1)
638        self.d.setVar('_remote_data', connector)
639
640class TestRemoteConcatOverride(TestConcatOverride):
641    def setUp(self):
642        self.d1 = bb.data.init()
643        self.d = bb.data.init()
644        self.d1.setVar("FOO", "foo")
645        self.d1.setVar("VAL", "val")
646        self.d1.setVar("BAR", "bar")
647        connector = TestConnector(self.d1)
648        self.d.setVar('_remote_data', connector)
649
650class TestRemoteOverrides(TestOverrides):
651    def setUp(self):
652        self.d1 = bb.data.init()
653        self.d = bb.data.init()
654        self.d1.setVar("OVERRIDES", "foo:bar:local")
655        self.d1.setVar("TEST", "testvalue")
656        connector = TestConnector(self.d1)
657        self.d.setVar('_remote_data', connector)
658
659class TestRemoteKeyExpansion(TestKeyExpansion):
660    def setUp(self):
661        self.d1 = bb.data.init()
662        self.d = bb.data.init()
663        self.d1.setVar("FOO", "foo")
664        self.d1.setVar("BAR", "foo")
665        connector = TestConnector(self.d1)
666        self.d.setVar('_remote_data', connector)
667
668class TestRemoteFlags(TestFlags):
669    def setUp(self):
670        self.d1 = bb.data.init()
671        self.d = bb.data.init()
672        self.d1.setVar("foo", "value of foo")
673        self.d1.setVarFlag("foo", "flag1", "value of flag1")
674        self.d1.setVarFlag("foo", "flag2", "value of flag2")
675        connector = TestConnector(self.d1)
676        self.d.setVar('_remote_data', connector)
677