| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import json | 6 import json |
| 7 import logging | 7 import logging |
| 8 import os | 8 import os |
| 9 import StringIO | 9 import StringIO |
| 10 import sys | 10 import sys |
| 11 import threading | 11 import threading |
| 12 import unittest | 12 import unittest |
| 13 import urllib2 | 13 import urllib2 |
| 14 | 14 |
| 15 import auto_stub | 15 import auto_stub |
| 16 | 16 |
| 17 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | 17 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 18 sys.path.insert(0, ROOT_DIR) | 18 sys.path.insert(0, ROOT_DIR) |
| 19 | 19 |
| 20 import run_isolated | |
| 21 import swarming | 20 import swarming |
| 21 from utils import net |
| 22 | 22 |
| 23 | 23 |
| 24 FILE_NAME = u'test.isolated' | 24 FILE_NAME = u'test.isolated' |
| 25 FILE_HASH = u'1' * 40 | 25 FILE_HASH = u'1' * 40 |
| 26 TEST_NAME = u'unit_tests' | 26 TEST_NAME = u'unit_tests' |
| 27 STDOUT_FOR_TRIGGER_LEN = 188 | 27 STDOUT_FOR_TRIGGER_LEN = 188 |
| 28 | 28 |
| 29 | 29 |
| 30 TEST_CASE_SUCCESS = ( | 30 TEST_CASE_SUCCESS = ( |
| 31 '[----------] 2 tests from StaticCookiePolicyTest\n' | 31 '[----------] 2 tests from StaticCookiePolicyTest\n' |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 """ | 141 """ |
| 142 return list(swarming.yield_results('http://host:9001', keys, 10., None)) | 142 return list(swarming.yield_results('http://host:9001', keys, 10., None)) |
| 143 | 143 |
| 144 | 144 |
| 145 class TestCase(auto_stub.TestCase): | 145 class TestCase(auto_stub.TestCase): |
| 146 """Base class that defines the url_open mock.""" | 146 """Base class that defines the url_open mock.""" |
| 147 def setUp(self): | 147 def setUp(self): |
| 148 super(TestCase, self).setUp() | 148 super(TestCase, self).setUp() |
| 149 self._lock = threading.Lock() | 149 self._lock = threading.Lock() |
| 150 self.requests = [] | 150 self.requests = [] |
| 151 self.mock(swarming.run_isolated, 'url_open', self._url_open) | 151 self.mock(swarming.net, 'url_open', self._url_open) |
| 152 | 152 |
| 153 def tearDown(self): | 153 def tearDown(self): |
| 154 try: | 154 try: |
| 155 if not self.has_failed(): | 155 if not self.has_failed(): |
| 156 self.assertEqual([], self.requests) | 156 self.assertEqual([], self.requests) |
| 157 finally: | 157 finally: |
| 158 super(TestCase, self).tearDown() | 158 super(TestCase, self).tearDown() |
| 159 | 159 |
| 160 def _url_open(self, url, **kwargs): | 160 def _url_open(self, url, **kwargs): |
| 161 logging.info('url_open(%s)', url) | 161 logging.info('url_open(%s)', url) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 172 | 172 |
| 173 | 173 |
| 174 class TestGetTestKeys(TestCase): | 174 class TestGetTestKeys(TestCase): |
| 175 def test_no_keys(self): | 175 def test_no_keys(self): |
| 176 self.mock(swarming.time, 'sleep', lambda x: x) | 176 self.mock(swarming.time, 'sleep', lambda x: x) |
| 177 self.requests = [ | 177 self.requests = [ |
| 178 ( | 178 ( |
| 179 'http://host:9001/get_matching_test_cases?name=my_test', | 179 'http://host:9001/get_matching_test_cases?name=my_test', |
| 180 {'retry_404': True}, | 180 {'retry_404': True}, |
| 181 StringIO.StringIO('No matching Test Cases'), | 181 StringIO.StringIO('No matching Test Cases'), |
| 182 ) for _ in range(run_isolated.URL_OPEN_MAX_ATTEMPTS) | 182 ) for _ in range(net.URL_OPEN_MAX_ATTEMPTS) |
| 183 ] | 183 ] |
| 184 try: | 184 try: |
| 185 swarming.get_test_keys('http://host:9001', 'my_test') | 185 swarming.get_test_keys('http://host:9001', 'my_test') |
| 186 self.fail() | 186 self.fail() |
| 187 except swarming.Failure as e: | 187 except swarming.Failure as e: |
| 188 msg = ( | 188 msg = ( |
| 189 'Error: Unable to find any tests with the name, my_test, on swarm ' | 189 'Error: Unable to find any tests with the name, my_test, on swarm ' |
| 190 'server') | 190 'server') |
| 191 self.assertEqual(msg, e.args[0]) | 191 self.assertEqual(msg, e.args[0]) |
| 192 | 192 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 expected = [gen_yielded_data(0, SWARM_OUTPUT_WITH_NO_TEST_OUTPUT, '0, 0')] | 257 expected = [gen_yielded_data(0, SWARM_OUTPUT_WITH_NO_TEST_OUTPUT, '0, 0')] |
| 258 actual = get_swarm_results(['key1']) | 258 actual = get_swarm_results(['key1']) |
| 259 self.assertEqual(expected, actual) | 259 self.assertEqual(expected, actual) |
| 260 | 260 |
| 261 def test_no_keys(self): | 261 def test_no_keys(self): |
| 262 actual = get_swarm_results([]) | 262 actual = get_swarm_results([]) |
| 263 self.assertEqual([], actual) | 263 self.assertEqual([], actual) |
| 264 | 264 |
| 265 def test_url_errors(self): | 265 def test_url_errors(self): |
| 266 # NOTE: get_swarm_results() hardcodes timeout=10. range(12) is because of an | 266 # NOTE: get_swarm_results() hardcodes timeout=10. range(12) is because of an |
| 267 # additional time.time() call deep in run_isolated.url_open(). | 267 # additional time.time() call deep in net.url_open(). |
| 268 now = {} | 268 now = {} |
| 269 lock = threading.Lock() | 269 lock = threading.Lock() |
| 270 def get_now(): | 270 def get_now(): |
| 271 t = threading.current_thread() | 271 t = threading.current_thread() |
| 272 with lock: | 272 with lock: |
| 273 return now.setdefault(t, range(12)).pop(0) | 273 return now.setdefault(t, range(12)).pop(0) |
| 274 self.mock( | 274 self.mock( |
| 275 swarming.run_isolated.HttpService, | 275 swarming.net.HttpService, |
| 276 'sleep_before_retry', | 276 'sleep_before_retry', |
| 277 staticmethod(lambda _x, _y: None)) | 277 staticmethod(lambda _x, _y: None)) |
| 278 self.mock(swarming, 'now', get_now) | 278 self.mock(swarming, 'now', get_now) |
| 279 # The actual number of requests here depends on 'now' progressing to 10 | 279 # The actual number of requests here depends on 'now' progressing to 10 |
| 280 # seconds. It's called twice per loop. | 280 # seconds. It's called twice per loop. |
| 281 self.requests = [ | 281 self.requests = [ |
| 282 ( | 282 ( |
| 283 'http://host:9001/get_result?r=key1', | 283 'http://host:9001/get_result?r=key1', |
| 284 {'retry_404': False, 'retry_50x': False}, | 284 {'retry_404': False, 'retry_50x': False}, |
| 285 None, | 285 None, |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 gen_yielded_data(2, TEST_SHARD_OUTPUT_3, '0, 0'), | 356 gen_yielded_data(2, TEST_SHARD_OUTPUT_3, '0, 0'), |
| 357 ] | 357 ] |
| 358 actual = get_swarm_results(['key1', 'key1-repeat', 'key2', 'key3']) | 358 actual = get_swarm_results(['key1', 'key1-repeat', 'key2', 'key3']) |
| 359 self.assertEqual(expected, sorted(actual)) | 359 self.assertEqual(expected, sorted(actual)) |
| 360 | 360 |
| 361 | 361 |
| 362 def chromium_tasks(retrieval_url): | 362 def chromium_tasks(retrieval_url): |
| 363 return [ | 363 return [ |
| 364 { | 364 { |
| 365 u'action': [ | 365 u'action': [ |
| 366 u'python', u'run_isolated.py', | 366 u'python', u'run_isolated.zip', |
| 367 u'--hash', FILE_HASH, | 367 u'--hash', FILE_HASH, |
| 368 u'--remote', retrieval_url + u'default-gzip/', | 368 u'--remote', retrieval_url + u'default-gzip/', |
| 369 ], | 369 ], |
| 370 u'decorate_output': False, | 370 u'decorate_output': False, |
| 371 u'test_name': u'Run Test', | 371 u'test_name': u'Run Test', |
| 372 u'time_out': 600, | 372 u'time_out': 600, |
| 373 }, | 373 }, |
| 374 { | 374 { |
| 375 u'action' : [ | 375 u'action' : [ |
| 376 u'python', u'swarm_cleanup.py', | 376 u'python', u'swarm_cleanup.py', |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 u'priority': 101, | 410 u'priority': 101, |
| 411 } | 411 } |
| 412 if shards > 1: | 412 if shards > 1: |
| 413 expected[u'env_vars'][u'GTEST_SHARD_INDEX'] = u'%(instance_index)s' | 413 expected[u'env_vars'][u'GTEST_SHARD_INDEX'] = u'%(instance_index)s' |
| 414 expected[u'env_vars'][u'GTEST_TOTAL_SHARDS'] = u'%(num_instances)s' | 414 expected[u'env_vars'][u'GTEST_TOTAL_SHARDS'] = u'%(num_instances)s' |
| 415 if profile: | 415 if profile: |
| 416 expected[u'tests'][0][u'action'].append(u'--verbose') | 416 expected[u'tests'][0][u'action'].append(u'--verbose') |
| 417 return expected | 417 return expected |
| 418 | 418 |
| 419 | 419 |
| 420 class MockZipFile(object): | |
| 421 def __init__(self, filename, mode): | |
| 422 pass | |
| 423 | |
| 424 def write(self, source, dest=None): | |
| 425 pass | |
| 426 | |
| 427 def close(self): | |
| 428 pass | |
| 429 | |
| 430 | |
| 431 def MockUrlOpen(url, _data, has_return_value): | 420 def MockUrlOpen(url, _data, has_return_value): |
| 432 if '/content/contains' in url: | 421 if '/content/contains' in url: |
| 433 return StringIO.StringIO(has_return_value) | 422 return StringIO.StringIO(has_return_value) |
| 434 return StringIO.StringIO('{}') | 423 return StringIO.StringIO('{}') |
| 435 | 424 |
| 436 | 425 |
| 437 def MockUrlOpenHasZip(url, data=None, content_type=None): | 426 def MockUrlOpenHasZip(url, data=None, content_type=None): |
| 438 assert content_type in (None, 'application/json', 'application/octet-stream') | 427 assert content_type in (None, 'application/json', 'application/octet-stream') |
| 439 return MockUrlOpen(url, data, has_return_value=chr(1)) | 428 return MockUrlOpen(url, data, has_return_value=chr(1)) |
| 440 | 429 |
| 441 | 430 |
| 442 def MockUrlOpenNoZip(url, data=None, content_type=None): | 431 def MockUrlOpenNoZip(url, data=None, content_type=None): |
| 443 assert content_type in (None, 'application/json', 'application/octet-stream') | 432 assert content_type in (None, 'application/json', 'application/octet-stream') |
| 444 return MockUrlOpen(url, data, has_return_value=chr(0)) | 433 return MockUrlOpen(url, data, has_return_value=chr(0)) |
| 445 | 434 |
| 446 | 435 |
| 447 class ManifestTest(auto_stub.TestCase): | 436 class ManifestTest(auto_stub.TestCase): |
| 448 def setUp(self): | 437 def setUp(self): |
| 449 self.mock(swarming.time, 'sleep', lambda x: None) | 438 self.mock(swarming.time, 'sleep', lambda x: None) |
| 450 self.mock(swarming.zipfile, 'ZipFile', MockZipFile) | |
| 451 self.mock(sys, 'stdout', StringIO.StringIO()) | 439 self.mock(sys, 'stdout', StringIO.StringIO()) |
| 452 self.mock(sys, 'stderr', StringIO.StringIO()) | 440 self.mock(sys, 'stderr', StringIO.StringIO()) |
| 453 | 441 |
| 454 def tearDown(self): | 442 def tearDown(self): |
| 455 if not self.has_failed(): | 443 if not self.has_failed(): |
| 456 self._check_output('', '') | 444 self._check_output('', '') |
| 457 super(ManifestTest, self).tearDown() | 445 super(ManifestTest, self).tearDown() |
| 458 | 446 |
| 459 def _check_output(self, out, err): | 447 def _check_output(self, out, err): |
| 460 self.assertEqual(out, sys.stdout.getvalue()) | 448 self.assertEqual(out, sys.stdout.getvalue()) |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 533 | 521 |
| 534 expected = generate_expected_json( | 522 expected = generate_expected_json( |
| 535 shards=1, | 523 shards=1, |
| 536 slave_os='linux2', | 524 slave_os='linux2', |
| 537 working_dir='swarm_tests', | 525 working_dir='swarm_tests', |
| 538 isolate_server='http://localhost:8081', | 526 isolate_server='http://localhost:8081', |
| 539 profile=True) | 527 profile=True) |
| 540 self.assertEqual(expected, manifest_json) | 528 self.assertEqual(expected, manifest_json) |
| 541 | 529 |
| 542 def test_process_manifest_success(self): | 530 def test_process_manifest_success(self): |
| 543 self.mock(swarming.run_isolated, 'url_open', MockUrlOpenNoZip) | 531 self.mock(swarming.net, 'url_open', MockUrlOpenNoZip) |
| 544 | 532 |
| 545 result = swarming.process_manifest( | 533 result = swarming.process_manifest( |
| 546 file_sha1_or_isolated=FILE_HASH, | 534 file_sha1_or_isolated=FILE_HASH, |
| 547 test_name=TEST_NAME, | 535 test_name=TEST_NAME, |
| 548 shards=1, | 536 shards=1, |
| 549 test_filter='*', | 537 test_filter='*', |
| 550 slave_os='linux2', | 538 slave_os='linux2', |
| 551 working_dir='swarm_tests', | 539 working_dir='swarm_tests', |
| 552 isolate_server='http://localhost:8081', | 540 isolate_server='http://localhost:8081', |
| 553 swarming='http://localhost:8082', | 541 swarming='http://localhost:8082', |
| 554 verbose=False, | 542 verbose=False, |
| 555 profile=False, | 543 profile=False, |
| 556 priority=101) | 544 priority=101) |
| 557 self.assertEqual(0, result) | 545 self.assertEqual(0, result) |
| 558 | 546 |
| 559 # Just assert it printed enough, since it contains variable output. | 547 # Just assert it printed enough, since it contains variable output. |
| 560 out = sys.stdout.getvalue() | 548 out = sys.stdout.getvalue() |
| 561 self.assertTrue( | 549 self.assertTrue( |
| 562 len(out) > STDOUT_FOR_TRIGGER_LEN, | 550 len(out) > STDOUT_FOR_TRIGGER_LEN, |
| 563 (out, sys.stderr.getvalue())) | 551 (out, sys.stderr.getvalue())) |
| 564 self.assertTrue('Zip file not on server, starting uploading.' in out) | 552 self.assertTrue('Zip file not on server, starting uploading.' in out) |
| 565 self.mock(sys, 'stdout', StringIO.StringIO()) | 553 self.mock(sys, 'stdout', StringIO.StringIO()) |
| 566 | 554 |
| 567 def test_process_manifest_success_zip_already_uploaded(self): | 555 def test_process_manifest_success_zip_already_uploaded(self): |
| 568 self.mock(swarming.run_isolated, 'url_open', MockUrlOpenHasZip) | 556 self.mock(swarming.net, 'url_open', MockUrlOpenHasZip) |
| 569 | 557 |
| 570 result = swarming.process_manifest( | 558 result = swarming.process_manifest( |
| 571 file_sha1_or_isolated=FILE_HASH, | 559 file_sha1_or_isolated=FILE_HASH, |
| 572 test_name=TEST_NAME, | 560 test_name=TEST_NAME, |
| 573 shards=1, | 561 shards=1, |
| 574 test_filter='*', | 562 test_filter='*', |
| 575 slave_os='linux2', | 563 slave_os='linux2', |
| 576 working_dir='swarm_tests', | 564 working_dir='swarm_tests', |
| 577 isolate_server='http://localhost:8081', | 565 isolate_server='http://localhost:8081', |
| 578 swarming='http://localhost:8082', | 566 swarming='http://localhost:8082', |
| (...skipping 19 matching lines...) Expand all Loading... |
| 598 'Usage: swarming.py trigger [options]\n\n' | 586 'Usage: swarming.py trigger [options]\n\n' |
| 599 'swarming.py: error: At least one --task is required.\n') | 587 'swarming.py: error: At least one --task is required.\n') |
| 600 | 588 |
| 601 | 589 |
| 602 if __name__ == '__main__': | 590 if __name__ == '__main__': |
| 603 logging.basicConfig( | 591 logging.basicConfig( |
| 604 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR) | 592 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR) |
| 605 if '-v' in sys.argv: | 593 if '-v' in sys.argv: |
| 606 unittest.TestCase.maxDiff = None | 594 unittest.TestCase.maxDiff = None |
| 607 unittest.main() | 595 unittest.main() |
| OLD | NEW |