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