OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 The Swarming Authors. All rights reserved. | 2 # Copyright 2014 The Swarming Authors. All rights reserved. |
3 # Use of this source code is governed by the Apache v2.0 license that can be | 3 # Use of this source code is governed by the Apache v2.0 license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Integration test for the Swarming server, Swarming bot and Swarming client. | 6 """Integration test for the Swarming server, Swarming bot and Swarming client. |
7 | 7 |
8 It starts both a Swarming server and a Swarming bot and triggers tasks with the | 8 It starts both a Swarming server and a Swarming bot and triggers tasks with the |
9 Swarming client to ensure the system works end to end. | 9 Swarming client to ensure the system works end to end. |
10 """ | 10 """ |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 SIGNAL_TERM = -1073741510 if sys.platform == 'win32' else -signal.SIGTERM | 43 SIGNAL_TERM = -1073741510 if sys.platform == 'win32' else -signal.SIGTERM |
44 | 44 |
45 | 45 |
46 class SwarmingClient(object): | 46 class SwarmingClient(object): |
47 def __init__(self, swarming_server, isolate_server): | 47 def __init__(self, swarming_server, isolate_server): |
48 self._swarming_server = swarming_server | 48 self._swarming_server = swarming_server |
49 self._isolate_server = isolate_server | 49 self._isolate_server = isolate_server |
50 self._tmpdir = tempfile.mkdtemp(prefix='swarming_client') | 50 self._tmpdir = tempfile.mkdtemp(prefix='swarming_client') |
51 self._index = 0 | 51 self._index = 0 |
52 | 52 |
| 53 def isolate(self, isolate_path, isolated_path): |
| 54 cmd = [ |
| 55 sys.executable, 'isolate.py', 'archive', |
| 56 '-I', self._isolate_server, |
| 57 '--namespace', 'default-gzip', |
| 58 '-i', isolate_path, |
| 59 '-s', isolated_path, |
| 60 ] |
| 61 isolated_hash = subprocess.check_output(cmd, cwd=CLIENT_DIR).split()[0] |
| 62 logging.debug('%s = %s', isolated_path, isolated_hash) |
| 63 return isolated_hash |
| 64 |
53 def task_trigger_raw(self, args): | 65 def task_trigger_raw(self, args): |
54 """Triggers a task and return the task id.""" | 66 """Triggers a task and return the task id.""" |
55 h, tmp = tempfile.mkstemp(prefix='swarming_smoke_test', suffix='.json') | 67 h, tmp = tempfile.mkstemp(prefix='swarming_smoke_test', suffix='.json') |
56 os.close(h) | 68 os.close(h) |
57 try: | 69 try: |
58 cmd = [ | 70 cmd = [ |
59 '--user', 'joe@localhost', | 71 '--user', 'joe@localhost', |
60 '-d', 'cpu', 'x86', | 72 '-d', 'cpu', 'x86', |
61 '--dump-json', tmp, | 73 '--dump-json', tmp, |
62 '--raw-cmd', | 74 '--raw-cmd', |
63 ] | 75 ] |
64 cmd.extend(args) | 76 cmd.extend(args) |
65 assert not self._run('trigger', cmd), args | 77 assert not self._run('trigger', cmd), args |
66 with open(tmp, 'rb') as f: | 78 with open(tmp, 'rb') as f: |
67 data = json.load(f) | 79 data = json.load(f) |
68 task_id = data['tasks'].popitem()[1]['task_id'] | 80 task_id = data['tasks'].popitem()[1]['task_id'] |
69 logging.debug('task_id = %s', task_id) | 81 logging.debug('task_id = %s', task_id) |
70 return task_id | 82 return task_id |
71 finally: | 83 finally: |
72 os.remove(tmp) | 84 os.remove(tmp) |
73 | 85 |
| 86 def task_trigger_isolated(self, name, isolated_hash, extra=None): |
| 87 """Triggers a task and return the task id.""" |
| 88 h, tmp = tempfile.mkstemp(prefix='swarming_smoke_test', suffix='.json') |
| 89 os.close(h) |
| 90 try: |
| 91 cmd = [ |
| 92 '--user', 'joe@localhost', |
| 93 '-d', 'cpu', 'x86', |
| 94 '--dump-json', tmp, |
| 95 '--task-name', name, |
| 96 '-I', self._isolate_server, |
| 97 '--namespace', 'default-gzip', |
| 98 isolated_hash, |
| 99 ] |
| 100 if extra: |
| 101 cmd.extend(extra) |
| 102 assert not self._run('trigger', cmd) |
| 103 with open(tmp, 'rb') as f: |
| 104 data = json.load(f) |
| 105 task_id = data['tasks'].popitem()[1]['task_id'] |
| 106 logging.debug('task_id = %s', task_id) |
| 107 return task_id |
| 108 finally: |
| 109 os.remove(tmp) |
| 110 |
74 def task_collect(self, task_id): | 111 def task_collect(self, task_id): |
75 """Collects the results for a task.""" | 112 """Collects the results for a task.""" |
76 h, tmp = tempfile.mkstemp(prefix='swarming_smoke_test', suffix='.json') | 113 h, tmp = tempfile.mkstemp(prefix='swarming_smoke_test', suffix='.json') |
77 os.close(h) | 114 os.close(h) |
78 try: | 115 try: |
79 tmpdir = tempfile.mkdtemp(prefix='swarming_smoke_test') | 116 tmpdir = tempfile.mkdtemp(prefix='swarming_smoke_test') |
80 try: | 117 try: |
81 # swarming.py collect will return the exit code of the task. | 118 # swarming.py collect will return the exit code of the task. |
82 args = [ | 119 args = [ |
83 '--task-summary-json', tmp, task_id, '--task-output-dir', tmpdir, | 120 '--task-summary-json', tmp, task_id, '--task-output-dir', tmpdir, |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 # This will restart the bot. This ensures the update mechanism works. | 328 # This will restart the bot. This ensures the update mechanism works. |
292 # TODO(maruel): Convert to a real API. Can only be accessed by admin-level | 329 # TODO(maruel): Convert to a real API. Can only be accessed by admin-level |
293 # account. | 330 # account. |
294 res = self.servers.http_client.request( | 331 res = self.servers.http_client.request( |
295 '/restricted/upload/bot_config', | 332 '/restricted/upload/bot_config', |
296 body=urllib.urlencode({'script': bot_config_content})) | 333 body=urllib.urlencode({'script': bot_config_content})) |
297 self.assertEqual(200, res.http_code, res.body) | 334 self.assertEqual(200, res.http_code, res.body) |
298 bot_version2 = self.assertOneTask(args, summary, {}) | 335 bot_version2 = self.assertOneTask(args, summary, {}) |
299 self.assertNotEqual(bot_version1, bot_version2) | 336 self.assertNotEqual(bot_version1, bot_version2) |
300 | 337 |
| 338 def test_isolated(self): |
| 339 # Make an isolated file, archive it. |
| 340 isolate = { |
| 341 'variables': { |
| 342 'command': ['python', 'hello_world.py'], |
| 343 'files': ['hello_world.py'], |
| 344 }, |
| 345 } |
| 346 hello_world = '\n'.join(( |
| 347 'import os', |
| 348 'import sys', |
| 349 'print(\'hi\')', |
| 350 'with open(os.path.join(sys.argv[1], \'result.txt\'), \'wb\') as f:', |
| 351 ' f.write(\'hey\')')) |
| 352 expected_summary = self.gen_expected( |
| 353 name=u'yo', |
| 354 isolated_out={ |
| 355 u'isolated': u'f10f4c42b38ca01726610f9575ba695468c32108', |
| 356 u'isolatedserver': u'http://localhost:10050', |
| 357 u'namespace': u'default-gzip', |
| 358 u'view_url': |
| 359 u'http://localhost:10050/browse?namespace=default-gzip' |
| 360 '&hash=f10f4c42b38ca01726610f9575ba695468c32108', |
| 361 }, |
| 362 outputs=[ |
| 363 u'hi\n' |
| 364 ], |
| 365 outputs_ref={ |
| 366 u'isolated': u'f10f4c42b38ca01726610f9575ba695468c32108', |
| 367 u'isolatedserver': u'http://localhost:10050', |
| 368 u'namespace': u'default-gzip', |
| 369 u'view_url': |
| 370 u'http://localhost:10050/browse?namespace=default-gzip' |
| 371 '&hash=f10f4c42b38ca01726610f9575ba695468c32108', |
| 372 }) |
| 373 expected_files = {os.path.join('0', 'result.txt'): 'hey'} |
| 374 tmpdir = tempfile.mkdtemp(prefix='swarming_smoke') |
| 375 try: |
| 376 isolate_path = os.path.join(tmpdir, 'i.isolate') |
| 377 isolated_path = os.path.join(tmpdir, 'i.isolated') |
| 378 with open(isolate_path, 'wb') as f: |
| 379 json.dump(isolate, f) |
| 380 with open(os.path.join(tmpdir, 'hello_world.py'), 'wb') as f: |
| 381 f.write(hello_world) |
| 382 isolated_hash = self.client.isolate(isolate_path, isolated_path) |
| 383 task_id = self.client.task_trigger_isolated( |
| 384 'yo', isolated_hash, extra=['--', '${ISOLATED_OUTDIR}']) |
| 385 actual_summary, actual_files = self.client.task_collect(task_id) |
| 386 self.assertResults(expected_summary, actual_summary) |
| 387 actual_files.pop('summary.json') |
| 388 self.assertEqual(expected_files, actual_files) |
| 389 finally: |
| 390 shutil.rmtree(tmpdir) |
| 391 |
301 def assertResults(self, expected, result): | 392 def assertResults(self, expected, result): |
302 self.assertEqual(['shards'], result.keys()) | 393 self.assertEqual(['shards'], result.keys()) |
303 self.assertEqual(1, len(result['shards'])) | 394 self.assertEqual(1, len(result['shards'])) |
304 self.assertTrue(result['shards'][0]) | 395 self.assertTrue(result['shards'][0]) |
305 result = result['shards'][0].copy() | 396 result = result['shards'][0].copy() |
306 # These are not deterministic (or I'm too lazy to calculate the value). | 397 # These are not deterministic (or I'm too lazy to calculate the value). |
307 bot_version = result.pop('bot_version') | 398 bot_version = result.pop('bot_version') |
308 self.assertTrue(bot_version) | 399 self.assertTrue(bot_version) |
309 self.assertTrue(result.pop('costs_usd')) | 400 self.assertTrue(result.pop('costs_usd')) |
310 self.assertTrue(result.pop('created_ts')) | 401 self.assertTrue(result.pop('created_ts')) |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 print >> sys.stderr, '<Ctrl-C>' | 473 print >> sys.stderr, '<Ctrl-C>' |
383 if bot: | 474 if bot: |
384 bot.kill() | 475 bot.kill() |
385 finally: | 476 finally: |
386 cleanup(bot, client, servers, failed or verbose) | 477 cleanup(bot, client, servers, failed or verbose) |
387 return int(failed) | 478 return int(failed) |
388 | 479 |
389 | 480 |
390 if __name__ == '__main__': | 481 if __name__ == '__main__': |
391 sys.exit(main()) | 482 sys.exit(main()) |
OLD | NEW |