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