| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """This module runs a suite of Auto Update tests. | 7 """This module runs a suite of Auto Update tests. |
| 8 | 8 |
| 9 The tests can be run on either a virtual machine or actual device depending | 9 The tests can be run on either a virtual machine or actual device depending |
| 10 on parameters given. Specific tests can be run by invoking --test_prefix. | 10 on parameters given. Specific tests can be run by invoking --test_prefix. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 ] | 61 ] |
| 62 # Add actual args to command. | 62 # Add actual args to command. |
| 63 command.append('--image=%s' % cros_lib.ReinterpretPathForChroot(target)) | 63 command.append('--image=%s' % cros_lib.ReinterpretPathForChroot(target)) |
| 64 if src: command.append('--src_image=%s' % | 64 if src: command.append('--src_image=%s' % |
| 65 cros_lib.ReinterpretPathForChroot(src)) | 65 cros_lib.ReinterpretPathForChroot(src)) |
| 66 if options.type == 'vm': command.append('--for_vm') | 66 if options.type == 'vm': command.append('--for_vm') |
| 67 if private_key_path: | 67 if private_key_path: |
| 68 command.append('--private_key=%s' % | 68 command.append('--private_key=%s' % |
| 69 cros_lib.ReinterpretPathForChroot(private_key_path)) | 69 cros_lib.ReinterpretPathForChroot(private_key_path)) |
| 70 | 70 |
| 71 return cros_lib.RunCommand(command, enter_chroot=True, print_cmd=True, | 71 if src: |
| 72 debug_message = 'delta update payload from %s to %s' % (target, src) |
| 73 else: |
| 74 debug_message = 'full update payload to %s' % target |
| 75 |
| 76 if private_key_path: |
| 77 debug_message = 'Generating a signed ' + debug_message |
| 78 else: |
| 79 debug_message = 'Generating an unsigned ' + debug_message |
| 80 |
| 81 cros_lib.Info(debug_message) |
| 82 return cros_lib.RunCommand(command, enter_chroot=True, print_cmd=False, |
| 72 cwd=cros_lib.GetCrosUtilsPath(), | 83 cwd=cros_lib.GetCrosUtilsPath(), |
| 73 log_to_file=log_file, error_ok=True, | 84 log_to_file=log_file, error_ok=True, |
| 74 exit_code=True) | 85 exit_code=True) |
| 75 | 86 |
| 76 def _ProcessGeneratorOutputs(log_files, return_codes): | 87 def _ProcessGeneratorOutputs(log_files, return_codes): |
| 77 """Processes results from the log files of GenerateVMUpdate calls. | 88 """Processes results from the log files of GenerateVMUpdate calls. |
| 78 | 89 |
| 79 Returns an array of cache entries from the log files. | 90 Returns an array of cache entries from the log files. |
| 80 """ | 91 """ |
| 81 return_array = [] | 92 return_array = [] |
| (...skipping 17 matching lines...) Expand all Loading... |
| 99 path_to_update_gz = match.group(1).rstrip() | 110 path_to_update_gz = match.group(1).rstrip() |
| 100 (path_to_update_dir, _, _) = path_to_update_gz.rpartition( | 111 (path_to_update_dir, _, _) = path_to_update_gz.rpartition( |
| 101 '/update.gz') | 112 '/update.gz') |
| 102 return_array.append('/'.join(['update', path_to_update_dir])) | 113 return_array.append('/'.join(['update', path_to_update_dir])) |
| 103 | 114 |
| 104 assert len(return_array) == len(log_files), 'Return result size mismatch.' | 115 assert len(return_array) == len(log_files), 'Return result size mismatch.' |
| 105 return return_array | 116 return return_array |
| 106 | 117 |
| 107 # Use dummy class to mock out updates that would be run as part of a test. | 118 # Use dummy class to mock out updates that would be run as part of a test. |
| 108 test_suite = _PrepareTestSuite(options, use_dummy_worker=True) | 119 test_suite = _PrepareTestSuite(options, use_dummy_worker=True) |
| 109 test_result = unittest.TextTestRunner(verbosity=0).run(test_suite) | 120 test_result = unittest.TextTestRunner( |
| 121 stream=open(os.devnull, 'w')).run(test_suite) |
| 110 if not test_result.wasSuccessful(): | 122 if not test_result.wasSuccessful(): |
| 111 raise update_exception.UpdateException(1, | 123 raise update_exception.UpdateException(1, |
| 112 'Error finding updates to generate.') | 124 'Error finding updates to generate.') |
| 113 | |
| 114 cros_lib.Info('The following delta updates are required.') | |
| 115 update_ids = [] | 125 update_ids = [] |
| 116 jobs = [] | 126 jobs = [] |
| 117 args = [] | 127 args = [] |
| 118 log_files = [] | 128 log_files = [] |
| 119 modified_images = set() | 129 modified_images = set() |
| 120 for target, srcs in dummy_au_worker.DummyAUWorker.delta_list.items(): | 130 for target, srcs in dummy_au_worker.DummyAUWorker.delta_list.items(): |
| 121 modified_images.add(target) | 131 modified_images.add(target) |
| 122 for src_key in srcs: | 132 for src_key in srcs: |
| 123 log_file = tempfile.mktemp('GenerateVMUpdate') | 133 log_file = tempfile.mktemp('GenerateVMUpdate') |
| 124 (src, _ , key) = src_key.partition('+') | 134 (src, _ , key) = src_key.partition('+') |
| 125 if src: modified_images.add(src) | 135 if src: modified_images.add(src) |
| 126 # TODO(sosa): Add private key as part of caching name once devserver can | 136 # TODO(sosa): Add private key as part of caching name once devserver can |
| 127 # handle it its own cache. | 137 # handle it its own cache. |
| 128 update_id = dev_server_wrapper.GenerateUpdateId(target, src, key) | 138 update_id = dev_server_wrapper.GenerateUpdateId(target, src, key) |
| 129 print >> sys.stderr, 'AU: %s' % update_id | |
| 130 update_ids.append(update_id) | 139 update_ids.append(update_id) |
| 131 jobs.append(_GenerateVMUpdate) | 140 jobs.append(_GenerateVMUpdate) |
| 132 args.append((target, src, key, log_file)) | 141 args.append((target, src, key, log_file)) |
| 133 log_files.append(log_file) | 142 log_files.append(log_file) |
| 134 | 143 |
| 135 # Always add the base image path. This is only useful for non-delta updates. | 144 # Always add the base image path. This is only useful for non-delta updates. |
| 136 modified_images.add(options.base_image) | 145 modified_images.add(options.base_image) |
| 137 | 146 |
| 138 # Add public key to all images we are using. | 147 # Add public key to all images we are using. |
| 139 if options.public_key: | 148 if options.public_key: |
| 140 cros_lib.Info('Adding public keys to images for testing.') | 149 cros_lib.Info('Adding public keys to images for testing.') |
| 141 for image in modified_images: | 150 for image in modified_images: |
| 142 manager = public_key_manager.PublicKeyManager(image, options.public_key) | 151 manager = public_key_manager.PublicKeyManager(image, options.public_key) |
| 143 manager.AddKeyToImage() | 152 manager.AddKeyToImage() |
| 144 au_test.AUTest.public_key_managers.append(manager) | 153 au_test.AUTest.public_key_managers.append(manager) |
| 145 | 154 |
| 155 cros_lib.Info('Generating updates required for this test suite in parallel.') |
| 146 error_codes = parallel_test_job.RunParallelJobs(options.jobs, jobs, args) | 156 error_codes = parallel_test_job.RunParallelJobs(options.jobs, jobs, args) |
| 147 results = _ProcessGeneratorOutputs(log_files, error_codes) | 157 results = _ProcessGeneratorOutputs(log_files, error_codes) |
| 148 | 158 |
| 149 # Build the dictionary from our id's and returned cache paths. | 159 # Build the dictionary from our id's and returned cache paths. |
| 150 cache_dictionary = {} | 160 cache_dictionary = {} |
| 151 for index, id in enumerate(update_ids): | 161 for index, id in enumerate(update_ids): |
| 152 cache_dictionary[id] = results[index] | 162 cache_dictionary[id] = results[index] |
| 153 | 163 |
| 154 return cache_dictionary | 164 return cache_dictionary |
| 155 | 165 |
| 156 | 166 |
| 157 def _RunTestsInParallel(options): | 167 def _RunTestsInParallel(options): |
| 158 """Runs the tests given by the options in parallel.""" | 168 """Runs the tests given by the options in parallel.""" |
| 159 threads = [] | 169 threads = [] |
| 160 args = [] | 170 args = [] |
| 161 test_suite = _PrepareTestSuite(options) | 171 test_suite = _PrepareTestSuite(options) |
| 162 for test in test_suite: | 172 for test in test_suite: |
| 163 test_name = test.id() | 173 test_name = test.id() |
| 164 test_case = unittest.TestLoader().loadTestsFromName(test_name) | 174 test_case = unittest.TestLoader().loadTestsFromName(test_name) |
| 165 threads.append(unittest.TextTestRunner(verbosity=2).run) | 175 threads.append(unittest.TextTestRunner().run) |
| 166 args.append(test_case) | 176 args.append(test_case) |
| 167 | 177 |
| 178 cros_lib.Info('Running tests in test suite in parallel.') |
| 168 results = parallel_test_job.RunParallelJobs(options.jobs, threads, args) | 179 results = parallel_test_job.RunParallelJobs(options.jobs, threads, args) |
| 169 for test_result in results: | 180 for test_result in results: |
| 170 if not test_result.wasSuccessful(): | 181 if not test_result.wasSuccessful(): |
| 171 cros_lib.Die('Test harness was not successful') | 182 cros_lib.Die( |
| 183 'Test harness was not successful. See logs for details. ' |
| 184 'Note: Ignore max recursion depth errors crosbug.com/14274') |
| 172 | 185 |
| 173 | 186 |
| 174 def _CleanPreviousWork(options): | 187 def _CleanPreviousWork(options): |
| 175 """Cleans up previous work from the devserver cache and local image cache.""" | 188 """Cleans up previous work from the devserver cache and local image cache.""" |
| 176 cros_lib.Info('Cleaning up previous work.') | 189 cros_lib.Info('Cleaning up previous work.') |
| 177 # Wipe devserver cache. | 190 # Wipe devserver cache. |
| 178 cros_lib.RunCommandCaptureOutput( | 191 cros_lib.RunCommandCaptureOutput( |
| 179 ['sudo', 'start_devserver', '--clear_cache', '--exit', ], | 192 ['sudo', 'start_devserver', '--clear_cache', '--exit', ], |
| 180 enter_chroot=True, print_cmd=False, combine_stdout_stderr=True, | 193 enter_chroot=True, print_cmd=False, combine_stdout_stderr=True, |
| 181 cwd=cros_lib.GetCrosUtilsPath()) | 194 cwd=cros_lib.GetCrosUtilsPath()) |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 my_server = dev_server_wrapper.DevServerWrapper( | 275 my_server = dev_server_wrapper.DevServerWrapper( |
| 263 au_test.AUTest.test_results_root) | 276 au_test.AUTest.test_results_root) |
| 264 my_server.start() | 277 my_server.start() |
| 265 try: | 278 try: |
| 266 if options.type == 'vm': | 279 if options.type == 'vm': |
| 267 _RunTestsInParallel(options) | 280 _RunTestsInParallel(options) |
| 268 else: | 281 else: |
| 269 # TODO(sosa) - Take in a machine pool for a real test. | 282 # TODO(sosa) - Take in a machine pool for a real test. |
| 270 # Can't run in parallel with only one remote device. | 283 # Can't run in parallel with only one remote device. |
| 271 test_suite = _PrepareTestSuite(options) | 284 test_suite = _PrepareTestSuite(options) |
| 272 test_result = unittest.TextTestRunner(verbosity=2).run(test_suite) | 285 test_result = unittest.TextTestRunner().run(test_suite) |
| 273 if not test_result.wasSuccessful(): cros_lib.Die('Test harness failed.') | 286 if not test_result.wasSuccessful(): cros_lib.Die('Test harness failed.') |
| 274 | 287 |
| 275 finally: | 288 finally: |
| 276 my_server.Stop() | 289 my_server.Stop() |
| 277 | 290 |
| 278 finally: | 291 finally: |
| 279 # Un-modify any target images we modified. We don't need to un-modify | 292 # Un-modify any target images we modified. We don't need to un-modify |
| 280 # non-targets because they aren't important for archival steps. | 293 # non-targets because they aren't important for archival steps. |
| 281 if options.public_key: | 294 if options.public_key: |
| 282 cros_lib.Info('Cleaning up. Removing keys added as part of testing.') | 295 cros_lib.Info('Cleaning up. Removing keys added as part of testing.') |
| 283 target_directory = os.path.dirname(options.target_image) | 296 target_directory = os.path.dirname(options.target_image) |
| 284 for key_manager in au_test.AUTest.public_key_managers: | 297 for key_manager in au_test.AUTest.public_key_managers: |
| 285 if key_manager.image_path.startswith(target_directory): | 298 if key_manager.image_path.startswith(target_directory): |
| 286 key_manager.RemoveKeyFromImage() | 299 key_manager.RemoveKeyFromImage() |
| 287 | 300 |
| 288 | 301 |
| 289 if __name__ == '__main__': | 302 if __name__ == '__main__': |
| 290 main() | 303 main() |
| OLD | NEW |