| 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 |