1import grp 2import mock_flimflam 3import os 4import pwd 5import stat 6import time 7import utils 8 9from autotest_lib.client.bin import test 10from autotest_lib.client.common_lib import error 11 12class network_ShillInitScripts(test.test): 13 """ Test that shill init scripts perform as expected. Use the 14 real filesystem (doing a best effort to archive and restore 15 current state). The shill manager is stopped and a proxy 16 DBus entity is installed to accept DBus messages that are sent 17 via "dbus-send" in the shill startup scripts. However, the 18 "real" shill is still also started from time to time and we 19 check that it is run with the right command line arguments. 20 """ 21 version = 1 22 save_directories = [ '/var/cache/shill', 23 '/var/cache/flimflam', 24 '/var/run/shill', 25 '/var/run/state/logged-in', 26 '/var/run/dhcpcd', 27 '/var/lib/dhcpcd', 28 '/home/chronos/.disable_shill' ] 29 fake_user = 'not-a-real-user@chromium.org' 30 saved_config = '/tmp/network_ShillInitScripts_saved_config.tgz' 31 cryptohome_path_command = 'cryptohome-path' 32 guest_shill_user_profile_dir = '/var/run/shill/guest_user_profile/shill' 33 guest_shill_user_log_dir = '/var/run/shill/guest_user_profile/shill_logs' 34 magic_header = '# --- shill init file test magic header ---' 35 36 37 def start_shill(self): 38 """ Starts a shill instance. """ 39 utils.system('start shill') 40 41 42 def stop_shill(self): 43 """ Halt the running shill instance. """ 44 utils.system('stop shill', ignore_status=True) 45 46 for attempt in range(10): 47 if not self.find_pid('shill'): 48 break 49 time.sleep(1) 50 else: 51 raise error.TestFail('Shill process does not appear to be dying') 52 53 54 def login(self, user=None): 55 """ Simulate the login process. 56 57 Note: "start" blocks until the "script" block completes. 58 59 @param user string user name (email address) to log in. 60 61 """ 62 utils.system('start shill-start-user-session CHROMEOS_USER=%s' % 63 (user or self.fake_user)) 64 65 66 def login_guest(self): 67 """ Simulate guest login. 68 69 For guest login, session-manager passes an empty CHROMEOS_USER arg. 70 71 """ 72 self.login('""') 73 74 75 def logout(self): 76 """ Simulate user logout. 77 78 Note: "start" blocks until the "script" block completes. 79 80 """ 81 utils.system('start shill-stop-user-session') 82 83 84 def start_test(self): 85 """ Setup the start of the test. Stop shill and create test harness.""" 86 # Stop a system process on test duts for keeping connectivity up. 87 ret = utils.system('stop recover_duts', ignore_status=True) 88 self.recover_duts_stopped = (ret == 0); 89 90 self.stop_shill() 91 92 # Deduce the root cryptohome directory name for our fake user. 93 self.root_cryptohome_dir = utils.system_output( 94 '%s system %s' % (self.cryptohome_path_command, self.fake_user)) 95 96 # Deduce the user cryptohome directory name for our fake user. 97 self.user_cryptohome_dir = utils.system_output( 98 '%s user %s' % (self.cryptohome_path_command, self.fake_user)) 99 100 # Deduce the directory for memory log storage. 101 self.user_cryptohome_log_dir = ('%s/shill_logs' % 102 self.root_cryptohome_dir) 103 104 # The sanitized hash of the username is the basename of the cryptohome. 105 self.fake_user_hash = os.path.basename(self.root_cryptohome_dir) 106 107 # Just in case this hash actually exists, add these to the list of 108 # saved directories. 109 self.save_directories.append(self.root_cryptohome_dir) 110 self.save_directories.append(self.user_cryptohome_dir) 111 112 # Archive the system state we will be modifying, then remove them. 113 utils.system('tar zcvf %s --directory / --ignore-failed-read %s' 114 ' 2>/dev/null' % 115 (self.saved_config, ' '.join(self.save_directories))) 116 utils.system('rm -rf %s' % ' '.join(self.save_directories), 117 ignore_status=True) 118 119 # Create the fake user's system cryptohome directory. 120 os.mkdir(self.root_cryptohome_dir) 121 self.new_shill_user_profile_dir = ('%s/shill' % 122 self.root_cryptohome_dir) 123 self.new_shill_user_profile = ('%s/shill.profile' % 124 self.new_shill_user_profile_dir) 125 126 # Create the fake user's user cryptohome directory. 127 os.mkdir(self.user_cryptohome_dir) 128 self.flimflam_user_profile_dir = ('%s/flimflam' % 129 self.user_cryptohome_dir) 130 self.flimflam_user_profile = ('%s/flimflam.profile' % 131 self.flimflam_user_profile_dir) 132 self.old_shill_user_profile_dir = ('%s/shill' % 133 self.user_cryptohome_dir) 134 self.old_shill_user_profile = ('%s/shill.profile' % 135 self.old_shill_user_profile_dir) 136 self.mock_flimflam = None 137 138 139 def start_mock_flimflam(self): 140 """ Start a mock flimflam instance to accept and log DBus calls. """ 141 self.mock_flimflam = mock_flimflam.MockFlimflam() 142 self.mock_flimflam.start() 143 144 145 def erase_state(self): 146 """ Remove all the test harness files. """ 147 utils.system('rm -rf %s' % ' '.join(self.save_directories)) 148 os.mkdir(self.root_cryptohome_dir) 149 os.mkdir(self.user_cryptohome_dir) 150 151 152 def end_test(self): 153 """ Perform cleanup at the end of the test. """ 154 if self.mock_flimflam: 155 self.mock_flimflam.quit() 156 self.mock_flimflam.join() 157 self.erase_state() 158 utils.system('tar zxvf %s --directory /' % self.saved_config) 159 utils.system('rm -f %s' % self.saved_config) 160 self.restart_system_processes() 161 162 163 def restart_system_processes(self): 164 """ Restart vital system services at the end of the test. """ 165 utils.system('start shill', ignore_status=True) 166 if self.recover_duts_stopped: 167 utils.system('start recover_duts', ignore_status=True) 168 169 170 def assure(self, must_be_true, assertion_name): 171 """ Perform a named assertion. 172 173 @param must_be_true boolean parameter that must be true. 174 @param assertion_name string name of this assertion. 175 176 """ 177 if not must_be_true: 178 raise error.TestFail('%s: Assertion failed: %s' % 179 (self.test_name, assertion_name)) 180 181 182 def assure_path_owner(self, path, owner): 183 """ Assert that |path| is owned by |owner|. 184 185 @param path string pathname to test. 186 @param owner string user name that should own |path|. 187 188 """ 189 self.assure(pwd.getpwuid(os.stat(path).st_uid)[0] == owner, 190 'Path %s is owned by %s' % (path, owner)) 191 192 193 def assure_path_group(self, path, group): 194 """ Assert that |path| is owned by |group|. 195 196 @param path string pathname to test. 197 @param group string group name that should own |path|. 198 199 """ 200 self.assure(grp.getgrgid(os.stat(path).st_gid)[0] == group, 201 'Path %s is group-owned by %s' % (path, group)) 202 203 204 def assure_exists(self, path, path_friendly_name): 205 """ Assert that |path| exists. 206 207 @param path string pathname to test. 208 @param path_friendly_name string user-parsable description of |path|. 209 210 """ 211 self.assure(os.path.exists(path), '%s exists' % path_friendly_name) 212 213 214 def assure_is_dir(self, path, path_friendly_name): 215 """ Assert that |path| is a directory. 216 217 @param path string pathname to test. 218 @param path_friendly_name string user-parsable description of |path|. 219 220 """ 221 self.assure_exists(path, path_friendly_name) 222 self.assure(stat.S_ISDIR(os.lstat(path).st_mode), 223 '%s is a directory' % path_friendly_name) 224 225 226 def assure_is_link(self, path, path_friendly_name): 227 """ Assert that |path| is a symbolic link. 228 229 @param path string pathname to test. 230 @param path_friendly_name string user-parsable description of |path|. 231 232 """ 233 self.assure_exists(path, path_friendly_name) 234 self.assure(stat.S_ISLNK(os.lstat(path).st_mode), 235 '%s is a symbolic link' % path_friendly_name) 236 237 238 def assure_is_link_to(self, path, pointee, path_friendly_name): 239 """ Assert that |path| is a symbolic link to |pointee|. 240 241 @param path string pathname to test. 242 @param pointee string pathname that |path| should point to. 243 @param path_friendly_name string user-parsable description of |path|. 244 245 """ 246 self.assure_is_link(path, path_friendly_name) 247 self.assure(os.readlink(path) == pointee, 248 '%s is a symbolic link to %s' % 249 (path_friendly_name, pointee)) 250 251 252 def assure_method_calls(self, expected_method_calls, assertion_name): 253 """ Assert that |expected_method_calls| were executed on mock_flimflam. 254 255 @param expected_method_calls list of string-tuple pairs of method 256 name + tuple of arguments. 257 @param assertion_name string name to assign to the assertion. 258 259 """ 260 method_calls = self.mock_flimflam.get_method_calls() 261 if len(expected_method_calls) != len(method_calls): 262 self.assure(False, '%s: method call count does not match' % 263 assertion_name) 264 for expected, actual in zip(expected_method_calls, method_calls): 265 self.assure(actual.method == expected[0], 266 '%s: method %s matches expected %s' % 267 (assertion_name, actual.method, expected[0])) 268 self.assure(actual.argument == expected[1], 269 '%s: argument %s matches expected %s' % 270 (assertion_name, actual.argument, expected[1])) 271 272 273 def create_file_with_contents(self, filename, contents): 274 """ Create a file named |filename| that contains |contents|. 275 276 @param filename string name of file. 277 @param contents string contents of file. 278 279 """ 280 with open(filename, 'w') as f: 281 f.write(contents) 282 283 284 def touch(self, filename): 285 """ Create an empty file named |filename|. 286 287 @param filename string name of file. 288 289 """ 290 self.create_file_with_contents(filename, '') 291 292 293 def create_new_shill_user_profile(self, contents): 294 """ Create a fake new user profile with |contents|. 295 296 @param contents string contents of the new user profile. 297 298 """ 299 os.mkdir(self.new_shill_user_profile_dir) 300 self.create_file_with_contents(self.new_shill_user_profile, contents) 301 302 303 def create_old_shill_user_profile(self, contents): 304 """ Create a fake old-style user profile with |contents|. 305 306 @param contents string contents of the old user profile. 307 308 """ 309 os.mkdir(self.old_shill_user_profile_dir) 310 self.create_file_with_contents(self.old_shill_user_profile, contents) 311 312 313 def create_flimflam_user_profile(self, contents): 314 """ Create a legacy flimflam user profile with |contents|. 315 316 @param contents string contents of the flimflam user profile. 317 318 """ 319 os.mkdir(self.flimflam_user_profile_dir) 320 self.create_file_with_contents(self.flimflam_user_profile, contents) 321 322 323 def file_contents(self, filename): 324 """ Returns the contents of |filename|. 325 326 @param filename string name of file to read. 327 328 """ 329 with open(filename) as f: 330 return f.read() 331 332 333 def find_pid(self, process_name): 334 """ Returns the process id of |process_name|. 335 336 @param process_name string name of process to search for. 337 338 """ 339 return utils.system_output('pgrep %s' % process_name, 340 ignore_status=True).split('\n')[0] 341 342 343 def get_commandline(self): 344 """ Returns the command line of the current shill executable. """ 345 pid = self.find_pid('shill') 346 return file('/proc/%s/cmdline' % pid).read().split('\0') 347 348 349 def run_once(self): 350 """ Main test loop. """ 351 try: 352 self.start_test() 353 except: 354 self.restart_system_processes() 355 raise 356 357 try: 358 self.run_tests([ 359 self.test_start_shill, 360 self.test_start_logged_in, 361 self.test_start_port_flimflam_profile]) 362 363 # The tests above run a real instance of shill, whereas the tests 364 # below rely on a mock instance of shill. We must take care not 365 # to run the mock at the same time as a real shill instance. 366 self.start_mock_flimflam() 367 368 self.run_tests([ 369 self.test_login, 370 self.test_login_guest, 371 self.test_login_profile_exists, 372 self.test_login_old_shill_profile, 373 self.test_login_invalid_old_shill_profile, 374 self.test_login_ignore_old_shill_profile, 375 self.test_login_flimflam_profile, 376 self.test_login_ignore_flimflam_profile, 377 self.test_login_prefer_old_shill_profile, 378 self.test_login_multi_profile, 379 self.test_logout]) 380 finally: 381 # Stop any shill instances started during testing. 382 self.stop_shill() 383 self.end_test() 384 385 386 def run_tests(self, tests): 387 """ Executes each of the test subparts in sequence. 388 389 @param tests list of methods to run. 390 391 """ 392 for test in tests: 393 self.test_name = test.__name__ 394 test() 395 self.stop_shill() 396 self.erase_state() 397 398 399 def test_start_shill(self): 400 """ Test all created pathnames during shill startup. 401 402 Also ensure the push argument is not provided by default. 403 404 """ 405 self.touch('/home/chronos/.disable_shill') 406 self.start_shill() 407 self.assure_is_dir('/var/run/shill', 'Shill run directory') 408 self.assure_is_dir('/var/lib/dhcpcd', 'dhcpcd lib directory') 409 self.assure_path_owner('/var/lib/dhcpcd', 'dhcp') 410 self.assure_path_group('/var/lib/dhcpcd', 'dhcp') 411 self.assure_is_dir('/var/run/dhcpcd', 'dhcpcd run directory') 412 self.assure_path_owner('/var/run/dhcpcd', 'dhcp') 413 self.assure_path_group('/var/run/dhcpcd', 'dhcp') 414 self.assure(not os.path.exists('/home/chronos/.disable_shill'), 415 'Shill disable file does not exist') 416 self.assure('--push=~chronos/shill' not in self.get_commandline(), 417 'Shill command line does not contain push argument') 418 419 420 def test_start_logged_in(self): 421 """ Tests starting up shill while a user is already logged in. 422 423 The "--push" argument should not be added even though shill is started 424 while a user is logged in. 425 426 """ 427 os.mkdir('/var/run/shill') 428 os.mkdir('/var/run/shill/user_profiles') 429 self.create_new_shill_user_profile('') 430 os.symlink(self.new_shill_user_profile_dir, 431 '/var/run/shill/user_profiles/chronos') 432 self.touch('/var/run/state/logged-in') 433 self.start_shill() 434 self.assure('--push=~chronos/shill' not in self.get_commandline(), 435 'Shill command line does not contain push argument') 436 os.unlink('/var/run/state/logged-in') 437 438 439 def test_start_port_flimflam_profile(self): 440 """ Test that we can port a flimflam profile to a new shill profile. 441 442 Startup should move an old flimflam profile into place if a shill 443 profile does not already exist. 444 445 """ 446 os.mkdir('/var/cache/flimflam') 447 flimflam_profile = '/var/cache/flimflam/default.profile' 448 self.create_file_with_contents(flimflam_profile, self.magic_header) 449 shill_profile = '/var/cache/shill/default.profile' 450 self.start_shill() 451 self.assure(not os.path.exists(flimflam_profile), 452 'Flimflam profile no longer exists') 453 self.assure(os.path.exists(shill_profile), 454 'Shill profile exists') 455 self.assure(self.magic_header in self.file_contents(shill_profile), 456 'Shill default profile contains our magic header') 457 458 459 def test_start_ignore_flimflam_profile(self): 460 """ Test that we ignore a flimflam profile if a new profile exists. 461 462 Startup should ignore an old flimflam profile if a shill profile 463 already exists. 464 465 """ 466 os.mkdir('/var/cache/flimflam') 467 os.mkdir('/var/cache/shill') 468 flimflam_profile = '/var/cache/flimflam/default.profile' 469 self.create_file_with_contents(flimflam_profile, self.magic_header) 470 shill_profile = '/var/cache/shill/default.profile' 471 self.touch(shill_profile) 472 self.start_shill() 473 self.assure(os.path.exists(flimflam_profile), 474 'Flimflam profile still exists') 475 self.assure(self.magic_header not in self.file_contents(shill_profile), 476 'Shill default profile does not contain our magic header') 477 478 479 def test_login(self): 480 """ Test the login process. 481 482 Login should create a profile directory, then create and push 483 a user profile, given no previous state. 484 485 """ 486 os.mkdir('/var/run/shill') 487 self.login() 488 self.assure(not os.path.exists(self.flimflam_user_profile), 489 'Flimflam user profile does not exist') 490 self.assure(not os.path.exists(self.old_shill_user_profile), 491 'Old shill user profile does not exist') 492 self.assure(not os.path.exists(self.new_shill_user_profile), 493 'New shill user profile does not exist') 494 # The DBus "CreateProfile" method should have been handled 495 # by our mock_flimflam instance, so the profile directory 496 # should not have actually been created. 497 self.assure_is_dir(self.new_shill_user_profile_dir, 498 'New shill user profile directory') 499 self.assure_is_dir('/var/run/shill/user_profiles', 500 'Shill profile root') 501 self.assure_is_link_to('/var/run/shill/user_profiles/chronos', 502 self.new_shill_user_profile_dir, 503 'Shill profile link') 504 self.assure_is_dir(self.user_cryptohome_log_dir, 505 'shill user log directory') 506 self.assure_is_link_to('/var/run/shill/log', 507 self.user_cryptohome_log_dir, 508 'Shill logs link') 509 self.assure_method_calls([[ 'CreateProfile', '~chronos/shill' ], 510 [ 'InsertUserProfile', 511 ('~chronos/shill', self.fake_user_hash) ]], 512 'CreateProfile and InsertUserProfile ' 513 'are called') 514 515 516 def test_login_guest(self): 517 """ Tests the guest login process. 518 519 Login should create a temporary profile directory in /var/run, 520 instead of using one within the root directory for normal users. 521 522 """ 523 os.mkdir('/var/run/shill') 524 self.login_guest() 525 self.assure(not os.path.exists(self.flimflam_user_profile), 526 'Flimflam user profile does not exist') 527 self.assure(not os.path.exists(self.old_shill_user_profile), 528 'Old shill user profile does not exist') 529 self.assure(not os.path.exists(self.new_shill_user_profile), 530 'New shill user profile does not exist') 531 self.assure(not os.path.exists(self.new_shill_user_profile_dir), 532 'New shill user profile directory') 533 self.assure_is_dir(self.guest_shill_user_profile_dir, 534 'shill guest user profile directory') 535 self.assure_is_dir('/var/run/shill/user_profiles', 536 'Shill profile root') 537 self.assure_is_link_to('/var/run/shill/user_profiles/chronos', 538 self.guest_shill_user_profile_dir, 539 'Shill profile link') 540 self.assure_is_dir(self.guest_shill_user_log_dir, 541 'shill guest user log directory') 542 self.assure_is_link_to('/var/run/shill/log', 543 self.guest_shill_user_log_dir, 544 'Shill logs link') 545 self.assure_method_calls([[ 'CreateProfile', '~chronos/shill' ], 546 [ 'InsertUserProfile', 547 ('~chronos/shill', '') ]], 548 'CreateProfile and InsertUserProfile ' 549 'are called') 550 551 552 def test_login_profile_exists(self): 553 """ Test logging in a user whose profile already exists. 554 555 Login script should only push (and not create) the user profile 556 if a user profile already exists. 557 """ 558 os.mkdir('/var/run/shill') 559 os.mkdir(self.new_shill_user_profile_dir) 560 self.touch(self.new_shill_user_profile) 561 self.login() 562 self.assure_method_calls([[ 'InsertUserProfile', 563 ('~chronos/shill', self.fake_user_hash) ]], 564 'Only InsertUserProfile is called') 565 566 567 def test_login_old_shill_profile(self): 568 """ Test logging in a user with an old-style shill profile. 569 570 Login script should move an old shill user profile into place 571 if a new one does not exist. 572 """ 573 os.mkdir('/var/run/shill') 574 self.create_old_shill_user_profile(self.magic_header) 575 self.login() 576 self.assure(not os.path.exists(self.old_shill_user_profile), 577 'Old shill user profile no longer exists') 578 self.assure(not os.path.exists(self.old_shill_user_profile_dir), 579 'Old shill user profile directory no longer exists') 580 self.assure_exists(self.new_shill_user_profile, 581 'New shill profile') 582 self.assure(self.magic_header in 583 self.file_contents(self.new_shill_user_profile), 584 'Shill user profile contains our magic header') 585 self.assure_method_calls([[ 'InsertUserProfile', 586 ('~chronos/shill', self.fake_user_hash) ]], 587 'Only InsertUserProfile is called') 588 589 590 def make_symlink(self, path): 591 """ Create a symbolic link named |path|. 592 593 @param path string pathname of the symbolic link. 594 595 """ 596 os.symlink('/etc/hosts', path) 597 598 599 def make_special_file(self, path): 600 """ Create a special file named |path|. 601 602 @param path string pathname of the special file. 603 604 """ 605 os.mknod(path, stat.S_IFIFO) 606 607 608 def make_bad_owner(self, path): 609 """ Create a regular file with a strange ownership. 610 611 @param path string pathname of the file. 612 613 """ 614 self.touch(path) 615 os.lchown(path, 1000, 1000) 616 617 618 def test_login_invalid_old_shill_profile(self): 619 """ Test logging in with an invalid old-style shill profile. 620 621 Login script should ignore non-regular files or files not owned 622 by the correct user. The original file should be removed. 623 624 """ 625 os.mkdir('/var/run/shill') 626 for file_creation_method in (self.make_symlink, 627 self.make_special_file, 628 os.mkdir, 629 self.make_bad_owner): 630 os.mkdir(self.old_shill_user_profile_dir) 631 file_creation_method(self.old_shill_user_profile) 632 self.login() 633 self.assure(not os.path.exists(self.old_shill_user_profile), 634 'Old shill user profile no longer exists') 635 self.assure(not os.path.exists(self.old_shill_user_profile_dir), 636 'Old shill user profile directory no longer exists') 637 self.assure(not os.path.exists(self.new_shill_user_profile), 638 'New shill profile was not created') 639 self.assure_method_calls([[ 'CreateProfile', '~chronos/shill' ], 640 [ 'InsertUserProfile', 641 ('~chronos/shill', 642 self.fake_user_hash) ]], 643 'CreateProfile and InsertUserProfile ' 644 'are called') 645 os.unlink('/var/run/shill/user_profiles/chronos') 646 647 648 def test_login_ignore_old_shill_profile(self): 649 """ Test logging in with both an old and new profile present. 650 651 Login script should ignore an old shill user profile if a new one 652 exists. 653 654 """ 655 os.mkdir('/var/run/shill') 656 self.create_new_shill_user_profile('') 657 self.create_old_shill_user_profile(self.magic_header) 658 self.login() 659 self.assure(os.path.exists(self.old_shill_user_profile), 660 'Old shill user profile still exists') 661 self.assure_exists(self.new_shill_user_profile, 662 'New shill profile') 663 self.assure(self.magic_header not in 664 self.file_contents(self.new_shill_user_profile), 665 'Shill user profile does not contain our magic header') 666 self.assure_method_calls([[ 'InsertUserProfile', 667 ('~chronos/shill', self.fake_user_hash) ]], 668 'Only InsertUserProfile is called') 669 670 671 def test_login_flimflam_profile(self): 672 """ Test logging in with an old flimflam profile. 673 674 Login script should move a flimflam user profile into place 675 if a shill one does not exist. 676 677 """ 678 os.mkdir('/var/run/shill') 679 self.create_flimflam_user_profile(self.magic_header) 680 self.login() 681 self.assure(not os.path.exists(self.flimflam_user_profile), 682 'Flimflam user profile no longer exists') 683 self.assure(not os.path.exists(self.flimflam_user_profile_dir), 684 'Flimflam user profile directory no longer exists') 685 self.assure_exists(self.new_shill_user_profile, 686 'New shill profile') 687 self.assure(self.magic_header in 688 self.file_contents(self.new_shill_user_profile), 689 'Shill user profile contains our magic header') 690 self.assure_method_calls([[ 'InsertUserProfile', 691 ('~chronos/shill', self.fake_user_hash) ]], 692 'Only InsertUserProfile is called') 693 694 695 def test_login_ignore_flimflam_profile(self): 696 """ Test logging in with both a flimflam profile and a new profile. 697 698 Login script should ignore an old flimflam user profile if a new 699 one exists. 700 701 """ 702 os.mkdir('/var/run/shill') 703 self.create_flimflam_user_profile(self.magic_header) 704 self.create_new_shill_user_profile('') 705 self.login() 706 self.assure_exists(self.new_shill_user_profile, 707 'New shill profile') 708 self.assure(self.magic_header not in 709 self.file_contents(self.new_shill_user_profile), 710 'Shill user profile does not contain our magic header') 711 self.assure_method_calls([[ 'InsertUserProfile', 712 ('~chronos/shill', self.fake_user_hash) ]], 713 'Only InsertUserProfile is called') 714 715 716 def test_login_prefer_old_shill_profile(self): 717 """ Test logging in with both a flimflam and old-style shill profile. 718 719 Login script should use the old shill user profile in preference 720 to a flimflam user profile if the new user profile does not 721 exist. 722 723 """ 724 os.mkdir('/var/run/shill') 725 self.create_flimflam_user_profile('') 726 self.create_old_shill_user_profile(self.magic_header) 727 self.login() 728 self.assure(not os.path.exists(self.flimflam_user_profile), 729 'Flimflam user profile was removed') 730 self.assure(not os.path.exists(self.old_shill_user_profile), 731 'Old shill user profile no longer exists') 732 self.assure_exists(self.new_shill_user_profile, 733 'New shill profile') 734 self.assure(self.magic_header in 735 self.file_contents(self.new_shill_user_profile), 736 'Shill user profile contains our magic header') 737 self.assure_method_calls([[ 'InsertUserProfile', 738 ('~chronos/shill', self.fake_user_hash) ]], 739 'Only InsertUserProfile is called') 740 741 742 def test_login_multi_profile(self): 743 """ Test signalling shill about multiple logged-in users. 744 745 Login script should not create multiple profiles in parallel 746 if called more than once without an intervening logout. Only 747 the initial user profile should be created. 748 749 """ 750 os.mkdir('/var/run/shill') 751 self.create_new_shill_user_profile('') 752 753 # First logged-in user should create a profile (tested above). 754 self.login() 755 756 # Clear the mock method-call queue. 757 self.mock_flimflam.get_method_calls() 758 759 for attempt in range(5): 760 self.login() 761 self.assure_method_calls([], 'No more profiles are added to shill') 762 profile_links = os.listdir('/var/run/shill/user_profiles') 763 self.assure(len(profile_links) == 1, 'Only one profile exists') 764 self.assure(profile_links[0] == 'chronos', 765 'The profile link is for the chronos user') 766 self.assure_is_link_to('/var/run/shill/log', 767 self.user_cryptohome_log_dir, 768 'Shill log link for chronos') 769 770 771 def test_logout(self): 772 """ Test the logout process. """ 773 os.makedirs('/var/run/shill/user_profiles') 774 os.makedirs(self.guest_shill_user_profile_dir) 775 os.makedirs(self.guest_shill_user_log_dir) 776 self.touch('/var/run/state/logged-in') 777 self.logout() 778 self.assure(not os.path.exists('/var/run/shill/user_profiles'), 779 'User profile directory was removed') 780 self.assure(not os.path.exists(self.guest_shill_user_profile_dir), 781 'Guest user profile directory was removed') 782 self.assure(not os.path.exists(self.guest_shill_user_log_dir), 783 'Guest user log directory was removed') 784 self.assure_method_calls([[ 'PopAllUserProfiles', '' ]], 785 'PopAllUserProfiles is called') 786