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
4 # found in the LICENSE file.
17 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
18 sys.path.insert(0, ROOT_DIR)
25 FILE_NAME = u'test.isolated'
27 TEST_NAME = u'unit_tests'
28 STDOUT_FOR_TRIGGER_LEN = 180
32 '[----------] 2 tests from StaticCookiePolicyTest\n'
33 '[ RUN ] StaticCookiePolicyTest.AllowAllCookiesTest\n'
34 '[ OK ] StaticCookiePolicyTest.AllowAllCookiesTest (0 ms)\n'
35 '[ RUN ] StaticCookiePolicyTest.BlockAllCookiesTest\n'
36 '[ OK ] StaticCookiePolicyTest.BlockAllCookiesTest (0 ms)\n'
37 '[----------] 2 tests from StaticCookiePolicyTest (0 ms total)\n'
39 '[----------] 1 test from TCPListenSocketTest\n'
40 '[ RUN ] TCPListenSocketTest.ServerSend\n'
41 '[ OK ] TCPListenSocketTest.ServerSend (1 ms)\n'
42 '[----------] 1 test from TCPListenSocketTest (1 ms total)\n')
46 '[----------] 2 tests from StaticCookiePolicyTest\n'
47 '[ RUN ] StaticCookiePolicyTest.AllowAllCookiesTest\n'
48 '[ OK ] StaticCookiePolicyTest.AllowAllCookiesTest (0 ms)\n'
49 '[ RUN ] StaticCookiePolicyTest.BlockAllCookiesTest\n'
50 'C:\\win\\build\\src\\chrome\\test.cc: error: Value of: result()\n'
53 '[ FAILED ] StaticCookiePolicyTest.BlockAllCookiesTest (0 ms)\n'
54 '[----------] 2 tests from StaticCookiePolicyTest (0 ms total)\n'
56 '[----------] 1 test from TCPListenSocketTest\n'
57 '[ RUN ] TCPListenSocketTest.ServerSend\n'
58 '[ OK ] TCPListenSocketTest.ServerSend (1 ms)\n'
59 '[----------] 1 test from TCPListenSocketTest (1 ms total)\n')
62 SWARM_OUTPUT_SUCCESS = (
63 '[ RUN ] unittests.Run Test\n' +
65 '[ OK ] unittests.Run Test (2549 ms)\n'
66 '[ RUN ] unittests.Clean Up\n'
68 '[ OK ] unittests.Clean Up (6 ms)\n'
70 '[----------] unittests summary\n'
71 '[==========] 2 tests ran. (2556 ms total)\n')
74 SWARM_OUTPUT_FAILURE = (
75 '[ RUN ] unittests.Run Test\n' +
77 '[ OK ] unittests.Run Test (2549 ms)\n'
78 '[ RUN ] unittests.Clean Up\n'
80 '[ OK ] unittests.Clean Up (6 ms)\n'
82 '[----------] unittests summary\n'
83 '[==========] 2 tests ran. (2556 ms total)\n')
86 SWARM_OUTPUT_WITH_NO_TEST_OUTPUT = (
88 'Unable to connection to swarm machine.\n')
91 TEST_SHARD_1 = 'Note: This is test shard 1 of 3.'
92 TEST_SHARD_2 = 'Note: This is test shard 2 of 3.'
93 TEST_SHARD_3 = 'Note: This is test shard 3 of 3.'
96 SWARM_SHARD_OUTPUT = (
97 '[ RUN ] unittests.Run Test\n'
99 '[ OK ] unittests.Run Test (2549 ms)\n'
100 '[ RUN ] unittests.Clean Up\n'
102 '[ OK ] unittests.Clean Up (6 ms)\n'
104 '[----------] unittests summary\n'
105 '[==========] 2 tests ran. (2556 ms total)\n')
108 TEST_SHARD_OUTPUT_1 = SWARM_SHARD_OUTPUT % TEST_SHARD_1
109 TEST_SHARD_OUTPUT_2 = SWARM_SHARD_OUTPUT % TEST_SHARD_2
110 TEST_SHARD_OUTPUT_3 = SWARM_SHARD_OUTPUT % TEST_SHARD_3
113 def gen_data(index, shard_output, exit_codes):
115 u'config_instance_index': index,
116 u'exit_codes': unicode(exit_codes),
117 u'machine_id': u'host',
118 u'machine_tag': u'localhost',
119 u'output': unicode(shard_output),
123 def gen_yielded_data(index, shard_output, exit_codes):
124 """Returns an entry as it would be yielded by yield_results()."""
125 return index, gen_data(index, shard_output, exit_codes)
128 def generate_url_response(index, shard_output, exit_codes):
129 return net.HttpResponse.get_fake_response(
130 json.dumps(gen_data(index, shard_output, exit_codes)), 'mocked_url')
133 def get_swarm_results(keys):
134 """Simplifies the call to yield_results().
136 The timeout is hard-coded to 10 seconds.
138 return list(swarming.yield_results('http://host:9001', keys, 10., None))
141 class TestCase(auto_stub.TestCase):
142 """Base class that defines the url_open mock."""
144 super(TestCase, self).setUp()
145 self._lock = threading.Lock()
147 self.mock(swarming.net, 'url_open', self._url_open)
151 if not self.has_failed():
152 self.assertEqual([], self.requests)
154 super(TestCase, self).tearDown()
156 def _url_open(self, url, **kwargs):
157 logging.info('url_open(%s)', url)
159 # Ignore 'stream' argument, it's not important for these tests.
161 # Since the client is multi-threaded, requests can be processed out of
163 for index, r in enumerate(self.requests):
164 if r[0] == url and r[1] == kwargs:
165 _, _, returned = self.requests.pop(index)
168 self.fail('Failed to find url %s' % url)
172 class TestGetTestKeys(TestCase):
173 def test_no_keys(self):
174 self.mock(swarming.time, 'sleep', lambda x: x)
177 'http://host:9001/get_matching_test_cases?name=my_test',
179 StringIO.StringIO('No matching Test Cases'),
180 ) for _ in range(net.URL_OPEN_MAX_ATTEMPTS)
183 swarming.get_test_keys('http://host:9001', 'my_test')
185 except swarming.Failure as e:
187 'Error: Unable to find any tests with the name, my_test, on swarm '
189 self.assertEqual(msg, e.args[0])
191 def test_no_keys_on_first_attempt(self):
192 self.mock(swarming.time, 'sleep', lambda x: x)
193 keys = ['key_1', 'key_2']
196 'http://host:9001/get_matching_test_cases?name=my_test',
198 StringIO.StringIO('No matching Test Cases'),
201 'http://host:9001/get_matching_test_cases?name=my_test',
203 StringIO.StringIO(json.dumps(keys)),
206 actual = swarming.get_test_keys('http://host:9001', 'my_test')
207 self.assertEqual(keys, actual)
209 def test_find_keys(self):
210 keys = ['key_1', 'key_2']
213 'http://host:9001/get_matching_test_cases?name=my_test',
215 StringIO.StringIO(json.dumps(keys)),
218 actual = swarming.get_test_keys('http://host:9001', 'my_test')
219 self.assertEqual(keys, actual)
222 class TestGetSwarmResults(TestCase):
223 def test_success(self):
226 'http://host:9001/get_result?r=key1',
227 {'retry_404': False, 'retry_50x': False},
228 generate_url_response(0, SWARM_OUTPUT_SUCCESS, '0, 0'),
231 expected = [gen_yielded_data(0, SWARM_OUTPUT_SUCCESS, '0, 0')]
232 actual = get_swarm_results(['key1'])
233 self.assertEqual(expected, actual)
235 def test_failure(self):
238 'http://host:9001/get_result?r=key1',
239 {'retry_404': False, 'retry_50x': False},
240 generate_url_response(0, SWARM_OUTPUT_FAILURE, '0, 1'),
243 expected = [gen_yielded_data(0, SWARM_OUTPUT_FAILURE, '0, 1')]
244 actual = get_swarm_results(['key1'])
245 self.assertEqual(expected, actual)
247 def test_no_test_output(self):
250 'http://host:9001/get_result?r=key1',
251 {'retry_404': False, 'retry_50x': False},
252 generate_url_response(0, SWARM_OUTPUT_WITH_NO_TEST_OUTPUT, '0, 0'),
255 expected = [gen_yielded_data(0, SWARM_OUTPUT_WITH_NO_TEST_OUTPUT, '0, 0')]
256 actual = get_swarm_results(['key1'])
257 self.assertEqual(expected, actual)
259 def test_no_keys(self):
260 actual = get_swarm_results([])
261 self.assertEqual([], actual)
263 def test_url_errors(self):
264 self.mock(logging, 'error', lambda *_: None)
265 # NOTE: get_swarm_results() hardcodes timeout=10. range(12) is because of an
266 # additional time.time() call deep in net.url_open().
268 lock = threading.Lock()
270 t = threading.current_thread()
272 return now.setdefault(t, range(12)).pop(0)
273 self.mock(swarming.net, 'sleep_before_retry', lambda _x, _y: None)
274 self.mock(swarming, 'now', get_now)
275 # The actual number of requests here depends on 'now' progressing to 10
276 # seconds. It's called twice per loop.
279 'http://host:9001/get_result?r=key1',
280 {'retry_404': False, 'retry_50x': False},
284 'http://host:9001/get_result?r=key1',
285 {'retry_404': False, 'retry_50x': False},
289 'http://host:9001/get_result?r=key1',
290 {'retry_404': False, 'retry_50x': False},
294 'http://host:9001/get_result?r=key1',
295 {'retry_404': False, 'retry_50x': False},
299 'http://host:9001/get_result?r=key1',
300 {'retry_404': False, 'retry_50x': False},
304 actual = get_swarm_results(['key1'])
305 self.assertEqual([], actual)
306 self.assertTrue(all(not v for v in now.itervalues()), now)
308 def test_shard_repeated(self):
311 'http://host:9001/get_result?r=key1',
312 {'retry_404': False, 'retry_50x': False},
313 generate_url_response(0, SWARM_OUTPUT_SUCCESS, '0, 0'),
316 'http://host:9001/get_result?r=key1-repeat',
317 {'retry_404': False, 'retry_50x': False},
318 generate_url_response(0, SWARM_OUTPUT_SUCCESS, '0, 0'),
321 expected = [gen_yielded_data(0, SWARM_OUTPUT_SUCCESS, '0, 0')]
322 actual = get_swarm_results(['key1', 'key1-repeat'])
323 self.assertEqual(expected, actual)
325 def test_one_shard_repeated(self):
326 """Have shard 1 repeated twice, then shard 2 and 3."""
329 'http://host:9001/get_result?r=key1',
330 {'retry_404': False, 'retry_50x': False},
331 generate_url_response(0, TEST_SHARD_OUTPUT_1, '0, 0'),
334 'http://host:9001/get_result?r=key1-repeat',
335 {'retry_404': False, 'retry_50x': False},
336 generate_url_response(0, TEST_SHARD_OUTPUT_1, '0, 0'),
339 'http://host:9001/get_result?r=key2',
340 {'retry_404': False, 'retry_50x': False},
341 generate_url_response(1, TEST_SHARD_OUTPUT_2, '0, 0'),
344 'http://host:9001/get_result?r=key3',
345 {'retry_404': False, 'retry_50x': False},
346 generate_url_response(2, TEST_SHARD_OUTPUT_3, '0, 0'),
350 gen_yielded_data(0, TEST_SHARD_OUTPUT_1, '0, 0'),
351 gen_yielded_data(1, TEST_SHARD_OUTPUT_2, '0, 0'),
352 gen_yielded_data(2, TEST_SHARD_OUTPUT_3, '0, 0'),
354 actual = get_swarm_results(['key1', 'key1-repeat', 'key2', 'key3'])
355 self.assertEqual(expected, sorted(actual))
357 def test_collect_nothing(self):
358 self.mock(swarming, 'get_test_keys', lambda *_: [1, 2])
359 self.mock(swarming, 'yield_results', lambda *_: [])
361 1, swarming.collect('url', 'test_name', 'timeout', 'decorate'))
363 def test_collect_success(self):
364 self.mock(swarming, 'get_test_keys', lambda *_: [1, 2])
365 self.mock(sys, 'stdout', StringIO.StringIO())
367 'config_instance_index': 0,
372 self.mock(swarming, 'yield_results', lambda *_: [(0, data)])
374 0, swarming.collect('url', 'test_name', 'timeout', 'decorate'))
376 def test_collect_fail(self):
377 self.mock(swarming, 'get_test_keys', lambda *_: [1, 2])
378 self.mock(sys, 'stdout', StringIO.StringIO())
380 'config_instance_index': 0,
385 self.mock(swarming, 'yield_results', lambda *_: [(0, data)])
387 8, swarming.collect('url', 'test_name', 'timeout', 'decorate'))
390 def chromium_tasks(retrieval_url):
394 u'python', u'run_isolated.zip',
395 u'--hash', FILE_HASH,
396 u'--isolate-server', retrieval_url,
398 u'decorate_output': False,
399 u'test_name': u'Run Test',
404 u'python', u'swarm_cleanup.py',
406 u'decorate_output': False,
407 u'test_name': u'Clean Up',
413 def generate_expected_json(
419 os_value = unicode(swarming.PLATFORM_MAPPING_SWARMING[slave_os])
424 u'config_name': os_value,
428 u'min_instances': shards,
434 u'restart_on_failure': True,
435 u'test_case_name': TEST_NAME,
436 u'tests': chromium_tasks(isolate_server),
437 u'working_dir': unicode(working_dir),
440 expected[u'env_vars'][u'GTEST_SHARD_INDEX'] = u'%(instance_index)s'
441 expected[u'env_vars'][u'GTEST_TOTAL_SHARDS'] = u'%(num_instances)s'
443 expected[u'tests'][0][u'action'].append(u'--verbose')
447 class MockedStorage(object):
448 def __init__(self, warm_cache):
449 self._warm_cache = warm_cache
451 def upload_items(self, items):
452 return [] if self._warm_cache else items
454 def get_fetch_url(self, _digest): # pylint: disable=R0201
455 return 'http://localhost:8081/fetch_url'
458 class ManifestTest(auto_stub.TestCase):
460 self.mock(swarming.time, 'sleep', lambda x: None)
461 self.mock(sys, 'stdout', StringIO.StringIO())
462 self.mock(sys, 'stderr', StringIO.StringIO())
465 if not self.has_failed():
466 self._check_output('', '')
467 super(ManifestTest, self).tearDown()
469 def _check_output(self, out, err):
470 self.assertEqual(out, sys.stdout.getvalue())
471 self.assertEqual(err, sys.stderr.getvalue())
473 # Flush their content by mocking them again.
474 self.mock(sys, 'stdout', StringIO.StringIO())
475 self.mock(sys, 'stderr', StringIO.StringIO())
477 def test_basic_manifest(self):
478 manifest = swarming.Manifest(
479 isolated_hash=FILE_HASH,
484 working_dir='swarm_tests',
485 isolate_server='http://localhost:8081',
491 swarming.chromium_setup(manifest)
492 manifest_json = json.loads(manifest.to_json())
494 expected = generate_expected_json(
497 working_dir='swarm_tests',
498 isolate_server=u'http://localhost:8081',
500 self.assertEqual(expected, manifest_json)
502 def test_basic_linux(self):
503 """A basic linux manifest test to ensure that windows specific values
506 manifest = swarming.Manifest(
507 isolated_hash=FILE_HASH,
512 working_dir='swarm_tests',
513 isolate_server='http://localhost:8081',
519 swarming.chromium_setup(manifest)
520 manifest_json = json.loads(manifest.to_json())
522 expected = generate_expected_json(
525 working_dir='swarm_tests',
526 isolate_server=u'http://localhost:8081',
528 self.assertEqual(expected, manifest_json)
530 def test_basic_linux_profile(self):
531 manifest = swarming.Manifest(
532 isolated_hash=FILE_HASH,
537 working_dir='swarm_tests',
538 isolate_server='http://localhost:8081',
544 swarming.chromium_setup(manifest)
545 manifest_json = json.loads(manifest.to_json())
547 expected = generate_expected_json(
550 working_dir='swarm_tests',
551 isolate_server=u'http://localhost:8081',
553 self.assertEqual(expected, manifest_json)
555 def test_process_manifest_success(self):
556 self.mock(swarming.net, 'url_read', lambda url, data=None: '{}')
557 self.mock(swarming.isolateserver, 'get_storage',
558 lambda *_: MockedStorage(warm_cache=False))
560 result = swarming.process_manifest(
561 file_hash_or_isolated=FILE_HASH,
566 working_dir='swarm_tests',
567 isolate_server='http://localhost:8081',
568 swarming='http://localhost:8082',
573 self.assertEqual(0, result)
575 # Just assert it printed enough, since it contains variable output.
576 out = sys.stdout.getvalue()
578 len(out) > STDOUT_FOR_TRIGGER_LEN,
579 (out, sys.stderr.getvalue()))
580 self.assertTrue('Upload complete' in out)
581 self.mock(sys, 'stdout', StringIO.StringIO())
583 def test_process_manifest_success_zip_already_uploaded(self):
584 self.mock(swarming.net, 'url_read', lambda url, data=None: '{}')
585 self.mock(swarming.isolateserver, 'get_storage',
586 lambda *_: MockedStorage(warm_cache=True))
588 result = swarming.process_manifest(
589 file_hash_or_isolated=FILE_HASH,
594 working_dir='swarm_tests',
595 isolate_server='http://localhost:8081',
596 swarming='http://localhost:8082',
601 self.assertEqual(0, result)
603 # Just assert it printed enough, since it contains variable output.
604 out = sys.stdout.getvalue()
605 self.assertTrue(len(out) > STDOUT_FOR_TRIGGER_LEN)
606 self.assertTrue('Zip file already on server' in out)
607 self.mock(sys, 'stdout', StringIO.StringIO())
609 def test_no_request(self):
612 'trigger', '--swarming', 'https://example.com',
613 '--isolate-server', 'https://example.com'])
615 except SystemExit as e:
616 self.assertEqual(2, e.code)
619 'Usage: swarming.py trigger [options]\n\n'
620 'swarming.py: error: At least one --task is required.\n')
623 if __name__ == '__main__':
625 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)
627 unittest.TestCase.maxDiff = None