def test_download_isolated_simple(self): # Test downloading an isolated tree. server = 'http://example.com' files = { os.path.join('a', 'foo'): 'Content', 'b': 'More content', } isolated = { 'command': ['Absurb', 'command'], 'relative_cwd': 'a', 'files': { os.path.join('a', 'foo'): { 'h': isolateserver_mock.hash_content('Content'), 's': len('Content'), 'm': 0700, }, 'b': { 'h': isolateserver_mock.hash_content('More content'), 's': len('More content'), 'm': 0600, }, 'c': { 'l': 'a/foo', }, }, 'read_only': 1, 'version': isolated_format.ISOLATED_FILE_VERSION, }
def test_download_isolated_simple(self): # Test downloading an isolated tree. actual = {} def putfile_mock( srcfileobj, dstpath, file_mode=None, size=-1, use_symlink=False): actual[dstpath] = srcfileobj.read() self.mock(isolateserver, 'putfile', putfile_mock) self.mock(os, 'makedirs', lambda _: None) server = 'http://example.com' files = { os.path.join('a', 'foo'): 'Content', 'b': 'More content', } isolated = { 'command': ['Absurb', 'command'], 'relative_cwd': 'a', 'files': dict( (k, {'h': isolateserver_mock.hash_content(v), 's': len(v)}) for k, v in files.iteritems()), 'version': isolated_format.ISOLATED_FILE_VERSION, } isolated_data = json.dumps(isolated, sort_keys=True, separators=(',',':')) isolated_hash = isolateserver_mock.hash_content(isolated_data) requests = [(v['h'], files[k]) for k, v in isolated['files'].iteritems()] requests.append((isolated_hash, isolated_data)) requests = [ ( server + '/api/isolateservice/v1/retrieve', { 'data': { 'digest': h.encode('utf-8'), 'namespace': { 'namespace': 'default-gzip', 'digest_hash': 'sha-1', 'compression': 'flate', }, 'offset': 0, }, 'read_timeout': 60, }, {'content': base64.b64encode(zlib.compress(v))}, ) for h, v in requests ] cmd = [ 'download', '--isolate-server', server, '--target', self.tempdir, '--isolated', isolated_hash, ] self.expected_requests(requests) self.assertEqual(0, isolateserver.main(cmd)) expected = dict( (os.path.join(self.tempdir, k), v) for k, v in files.iteritems()) self.assertEqual(expected, actual) expected_stdout = ( 'To run this test please run from the directory %s:\n Absurb command\n' % os.path.join(self.tempdir, 'a')) self.checkOutput(expected_stdout, '')
def test_download_isolated(self): # Test downloading an isolated tree. actual = {} def file_write_mock(key, generator): actual[key] = ''.join(generator) self.mock(isolateserver, 'file_write', file_write_mock) self.mock(os, 'makedirs', lambda _: None) server = 'http://example.com' files = { os.path.join('a', 'foo'): 'Content', 'b': 'More content', } isolated = { 'command': ['Absurb', 'command'], 'relative_cwd': 'a', 'files': dict( (k, {'h': isolateserver_mock.hash_content(v), 's': len(v)}) for k, v in files.iteritems()), 'version': isolated_format.ISOLATED_FILE_VERSION, } isolated_data = json.dumps(isolated, sort_keys=True, separators=(',',':')) isolated_hash = isolateserver_mock.hash_content(isolated_data) requests = [(v['h'], files[k]) for k, v in isolated['files'].iteritems()] requests.append((isolated_hash, isolated_data)) requests = [ ( server + '/_ah/api/isolateservice/v1/retrieve', { 'data': { 'digest': h.encode('utf-8'), 'namespace': { 'namespace': 'default-gzip', 'digest_hash': 'sha-1', 'compression': 'flate', }, 'offset': 0, }, 'read_timeout': 60, }, {'content': base64.b64encode(zlib.compress(v))}, ) for h, v in requests ] cmd = [ 'download', '--isolate-server', server, '--target', self.tempdir, '--isolated', isolated_hash, ] self.expected_requests(requests) self.assertEqual(0, isolateserver.main(cmd)) expected = dict( (os.path.join(self.tempdir, k), v) for k, v in files.iteritems()) self.assertEqual(expected, actual) expected_stdout = ( 'To run this test please run from the directory %s:\n Absurb command\n' % os.path.join(self.tempdir, 'a')) self.checkOutput(expected_stdout, '')
class RunIsolatedTestOutputFiles(RunIsolatedTestBase): def _run_test(self, isolated, command): # Starts a full isolate server mock and have run_tha_test() uploads results # back after the task completed. server = isolateserver_mock.MockIsolateServer() try: script = ('import sys\n' 'open(sys.argv[1], "w").write("bar")\n' 'open(sys.argv[2], "w").write("baz")\n') script_hash = isolateserver_mock.hash_content(script) isolated['files']['cmd.py'] = { 'h': script_hash, 'm': 0700, 's': len(script), } if sys.platform == 'win32': isolated['files']['cmd.py'].pop('m') isolated_data = json_dumps(isolated) isolated_hash = isolateserver_mock.hash_content(isolated_data) server.add_content('default-store', script) server.add_content('default-store', isolated_data) store = isolateserver.get_storage(server.url, 'default-store') self.mock(sys, 'stdout', StringIO.StringIO()) ret = run_isolated.run_tha_test(command, isolated_hash, store, isolateserver.MemoryCache(), ['foo', 'foodir/foo2'], init_named_caches_stub, False, None, None, None, None, None, run_isolated.noop_install_packages, False) self.assertEqual(0, ret) # It uploaded back. Assert the store has a new item containing foo. hashes = {isolated_hash, script_hash} foo_output_hash = isolateserver_mock.hash_content('bar') foo2_output_hash = isolateserver_mock.hash_content('baz') hashes.add(foo_output_hash) hashes.add(foo2_output_hash) isolated = { 'algo': 'sha-1', 'files': { 'foo': { 'h': foo_output_hash, # TODO(maruel): Handle umask. 'm': 0640, 's': 3, }, 'foodir/foo2': { 'h': foo2_output_hash, # TODO(maruel): Handle umask. 'm': 0640, 's': 3, }, }, 'version': isolated_format.ISOLATED_FILE_VERSION, }
def test_main_json(self): # Instruct the Popen mock to write a file in ISOLATED_OUTDIR so it will be # archived back on termination. self.mock(tools, 'disable_buffering', lambda: None) sub_cmd = [ self.ir_dir(u'foo.exe'), u'cmd with space', '${ISOLATED_OUTDIR}/out.txt', ] isolated_in_json = json_dumps({'command': sub_cmd}) isolated_in_hash = isolateserver_mock.hash_content(isolated_in_json) def get_storage(_isolate_server, _namespace): return StorageFake({isolated_in_hash: isolated_in_json}) self.mock(isolateserver, 'get_storage', get_storage) out = os.path.join(self.tempdir, 'res.json') cmd = [ '--no-log', '--isolated', isolated_in_hash, '--cache', os.path.join(self.tempdir, 'isolated_cache'), '--isolate-server', 'https://localhost:1', '--named-cache-root', os.path.join(self.tempdir, 'named_cache'), '--json', out, '--root-dir', self.tempdir, ] ret = run_isolated.main(cmd) self.assertEqual(0, ret) # Replace ${ISOLATED_OUTDIR} with the temporary directory. sub_cmd[2] = self.popen_calls[0][0][2] self.assertNotIn('ISOLATED_OUTDIR', sub_cmd[2]) self.assertEqual([(sub_cmd, { 'cwd': self.ir_dir(), 'detached': True })], self.popen_calls) isolated_out = { 'algo': 'sha-1', 'files': { 'out.txt': { 'h': isolateserver_mock.hash_content('generated data\n'), 's': 15, 'm': 0640, }, }, 'version': isolated_format.ISOLATED_FILE_VERSION, }
def _run_test(self, isolated, command): # Starts a full isolate server mock and have run_tha_test() uploads results # back after the task completed. server = isolateserver_mock.MockIsolateServer() try: # Output two files. If we're on Linux, we'll try to make one of them a # symlink to ensure that we correctly follow symlinks. Note that this only # tests file symlinks, not directory symlinks. # TODO(aludwin): follow directory symlinks script = ( 'import os\n' 'import sys\n' 'open(sys.argv[1], "w").write("bar")\n' 'if sys.platform.startswith("linux"):\n' ' realpath = os.path.abspath("contents_of_symlink")\n' ' open(realpath, "w").write("baz")\n' ' os.symlink(realpath, sys.argv[2])\n' 'else:\n' ' open(sys.argv[2], "w").write("baz")\n') script_hash = isolateserver_mock.hash_content(script) isolated['files']['cmd.py'] = { 'h': script_hash, 'm': 0700, 's': len(script), } if sys.platform == 'win32':
def test_main_args(self): self.mock(tools, 'disable_buffering', lambda: None) isolated = json_dumps({'command': ['foo.exe', 'cmd w/ space']}) isolated_hash = isolateserver_mock.hash_content(isolated) def get_storage(_isolate_server, _namespace): return StorageFake({isolated_hash: isolated}) self.mock(isolateserver, 'get_storage', get_storage) cmd = [ '--no-log', '--isolated', isolated_hash, '--cache', self.tempdir, '--isolate-server', 'https://localhost', '--', '--extraargs', 'bar', ] ret = run_isolated.main(cmd) self.assertEqual(0, ret) self.assertEqual([ ([ self.temp_join(u'foo.exe'), u'cmd w/ space', '--extraargs', 'bar' ], { 'detached': True }), ], self.popen_calls)
def test_main_naked(self): self.mock(on_error, 'report', lambda _: None) # The most naked .isolated file that can exist. self.mock(tools, 'disable_buffering', lambda: None) isolated = json_dumps({'command': ['invalid', 'command']}) isolated_hash = isolateserver_mock.hash_content(isolated) def get_storage(_isolate_server, _namespace): return StorageFake({isolated_hash:isolated}) self.mock(isolateserver, 'get_storage', get_storage) def r(self, args, **kwargs): old_init(self, args, **kwargs) raise OSError('Unknown') old_init = self.mock(subprocess42.Popen, '__init__', r) cmd = [ '--no-log', '--isolated', isolated_hash, '--cache', self.tempdir, '--isolate-server', 'https://localhost', ] ret = run_isolated.main(cmd) self.assertEqual(1, ret) self.assertEqual(1, len(self.popen_calls)) self.assertEqual( [([self.temp_join(u'invalid'), u'command'], {'detached': True})], self.popen_calls)
def test_main_naked(self): self.mock(on_error, 'report', lambda _: None) # The most naked .isolated file that can exist. self.mock(tools, 'disable_buffering', lambda: None) isolated = json_dumps({'command': ['invalid', 'command']}) isolated_hash = isolateserver_mock.hash_content(isolated) def get_storage(_isolate_server, _namespace): return StorageFake({isolated_hash: isolated}) self.mock(isolateserver, 'get_storage', get_storage) def r(self, args, **kwargs): old_init(self, args, **kwargs) raise OSError('Unknown') old_init = self.mock(subprocess42.Popen, '__init__', r) cmd = [ '--no-log', '--isolated', isolated_hash, '--cache', self.tempdir, '--isolate-server', 'https://localhost', ] ret = run_isolated.main(cmd) self.assertEqual(1, ret) self.assertEqual(1, len(self.popen_calls)) self.assertEqual([([self.temp_join(u'invalid'), u'command'], { 'detached': True })], self.popen_calls)
def test_main_args(self): self.mock(tools, 'disable_buffering', lambda: None) isolated = json_dumps({'command': ['foo.exe', 'cmd w/ space']}) isolated_hash = isolateserver_mock.hash_content(isolated) def get_storage(_isolate_server, _namespace): return StorageFake({isolated_hash:isolated}) self.mock(isolateserver, 'get_storage', get_storage) cmd = [ '--no-log', '--isolated', isolated_hash, '--cache', self.tempdir, '--isolate-server', 'https://localhost', '--', '--extraargs', 'bar', ] ret = run_isolated.main(cmd) self.assertEqual(0, ret) self.assertEqual( [ ([self.temp_join(u'foo.exe'), u'cmd w/ space', '--extraargs', 'bar'], {'detached': True}), ], self.popen_calls)
def test_main(self): self.mock(tools, 'disable_buffering', lambda: None) isolated = json_dumps({ 'command': ['foo.exe', 'cmd with space'], }) isolated_hash = isolateserver_mock.hash_content(isolated) def get_storage(_isolate_server, _namespace): return StorageFake({isolated_hash: isolated}) self.mock(isolateserver, 'get_storage', get_storage) cmd = [ '--no-log', '--isolated', isolated_hash, '--cache', os.path.join(self.tempdir, 'isolated_cache'), '--named-cache-root', os.path.join(self.tempdir, 'named_cache'), '--isolate-server', 'https://localhost', '--root-dir', self.tempdir, ] ret = run_isolated.main(cmd) self.assertEqual(0, ret) self.assertEqual([ ([self.ir_dir(u'foo.exe'), u'cmd with space'], { 'cwd': self.ir_dir(), 'detached': True }), ], self.popen_calls)
def _run_test(self, isolated, command, extra_args): # Starts a full isolate server mock and have run_tha_test() uploads results # back after the task completed. server = isolateserver_mock.MockIsolateServer() try: # Output the following structure: # # foo1 # foodir --> foo2_sl (symlink to "foo2_content" file) # bardir --> bar1 # # Create the symlinks only on Linux. script = ('import os\n' 'import sys\n' 'open(sys.argv[1], "w").write("foo1")\n' 'bar1_path = os.path.join(sys.argv[3], "bar1")\n' 'open(bar1_path, "w").write("bar1")\n' 'if sys.platform.startswith("linux"):\n' ' foo_realpath = os.path.abspath("foo2_content")\n' ' open(foo_realpath, "w").write("foo2")\n' ' os.symlink(foo_realpath, sys.argv[2])\n' 'else:\n' ' open(sys.argv[2], "w").write("foo2")\n') script_hash = isolateserver_mock.hash_content(script) isolated['files']['cmd.py'] = { 'h': script_hash, 'm': 0700, 's': len(script), } if sys.platform == 'win32':
def test_fetch_offset_bad_header(self): server = 'http://example.com' namespace = 'default' data = ''.join(str(x) for x in xrange(1000)) item = isolateserver_mock.hash_content(data) offset = 200 size = len(data) bad_content_range_headers = [ # Missing header. None, '', # Bad format. 'not bytes %d-%d/%d' % (offset, size - 1, size), 'bytes %d-%d' % (offset, size - 1), # Bad offset. 'bytes %d-%d/%d' % (offset - 1, size - 1, size), # Incomplete chunk. 'bytes %d-%d/%d' % (offset, offset + 10, size), ] for content_range_header in bad_content_range_headers: self.expected_requests([ self.mock_fetch_request( server, namespace, item, offset=offset), self.mock_gs_request( server, namespace, item, data, offset=offset, request_headers={'Range': 'bytes=%d-' % offset}, response_headers={'Content-Range': content_range_header}), ]) storage = isolate_storage.IsolateServer(server, namespace) with self.assertRaises(IOError): _ = ''.join(storage.fetch(item, offset))
def test_fetch_offset_bad_header(self): server = 'http://example.com' namespace = 'default' data = ''.join(str(x) for x in xrange(1000)) item = isolateserver_mock.hash_content(data) offset = 200 size = len(data) bad_content_range_headers = [ # Missing header. None, '', # Bad format. 'not bytes %d-%d/%d' % (offset, size - 1, size), 'bytes %d-%d' % (offset, size - 1), # Bad offset. 'bytes %d-%d/%d' % (offset - 1, size - 1, size), # Incomplete chunk. 'bytes %d-%d/%d' % (offset, offset + 10, size), ] for content_range_header in bad_content_range_headers: self.expected_requests([ self.mock_fetch_request( server, namespace, item, offset=offset), self.mock_gs_request( server, namespace, item, data, offset=offset, request_headers={'Range': 'bytes=%d-' % offset}, response_headers={'Content-Range': content_range_header}), ]) storage = isolateserver.IsolateServer(server, namespace) with self.assertRaises(IOError): _ = ''.join(storage.fetch(item, offset))
def test_main_naked(self): self.mock_popen_with_oserr() self.mock(on_error, 'report', lambda _: None) # The most naked .isolated file that can exist. self.mock(tools, 'disable_buffering', lambda: None) isolated = json_dumps({'command': ['invalid', 'command']}) isolated_hash = isolateserver_mock.hash_content(isolated) def get_storage(_isolate_server, _namespace): return StorageFake({isolated_hash: isolated}) self.mock(isolateserver, 'get_storage', get_storage) cmd = [ '--no-log', '--isolated', isolated_hash, '--cache', os.path.join(self.tempdir, 'isolated_cache'), '--isolate-server', 'https://localhost', '--named-cache-root', os.path.join(self.tempdir, 'named_cache'), '--root-dir', self.tempdir, ] ret = run_isolated.main(cmd) self.assertEqual(1, ret) self.assertEqual(1, len(self.popen_calls)) self.assertEqual([ ([self.ir_dir(u'invalid'), u'command'], { 'cwd': self.ir_dir(), 'detached': True }), ], self.popen_calls)
def test_fetch_failure(self): server = 'http://example.com' namespace = 'default' item = isolateserver_mock.hash_content('something') self.expected_requests( [self.mock_fetch_request(server, namespace, item)[:-1] + (None, )]) storage = isolateserver.IsolateServer(server, namespace) with self.assertRaises(IOError): _ = ''.join(storage.fetch(item))
def test_fetch_failure(self): server = 'http://example.com' namespace = 'default' item = isolateserver_mock.hash_content('something') self.expected_requests( [self.mock_fetch_request(server, namespace, item)[:-1] + (None,)]) storage = isolateserver.IsolateServer(server, namespace) with self.assertRaises(IOError): _ = ''.join(storage.fetch(item))
def test_fetch_success(self): server = 'http://example.com' namespace = 'default' data = ''.join(str(x) for x in xrange(1000)) item = isolateserver_mock.hash_content(data) self.expected_requests( [self.mock_fetch_request(server, namespace, item, data)]) storage = isolateserver.IsolateServer(server, namespace) fetched = ''.join(storage.fetch(item)) self.assertEqual(data, fetched)
def test_modified_cwd(self): isolated = json_dumps({ 'command': ['../out/some.exe', 'arg'], 'relative_cwd': 'some', }) isolated_hash = isolateserver_mock.hash_content(isolated) files = {isolated_hash:isolated} _ = self._run_tha_test(isolated_hash, files) self.assertEqual(1, len(self.popen_calls)) self.assertEqual( [([self.temp_join(u'out', u'some.exe'), 'arg'], {'detached': True})], self.popen_calls)
def test_run_tha_test_naked(self): isolated = json_dumps({'command': ['invalid', 'command']}) isolated_hash = isolateserver_mock.hash_content(isolated) files = {isolated_hash:isolated} make_tree_call = self._run_tha_test(isolated_hash, files) self.assertEqual( ['make_tree_writeable', 'make_tree_deleteable', 'make_tree_deleteable'], make_tree_call) self.assertEqual(1, len(self.popen_calls)) self.assertEqual( [([self.temp_join(u'invalid'), u'command'], {'detached': True})], self.popen_calls)
def test_main_json(self): # Instruct the Popen mock to write a file in ISOLATED_OUTDIR so it will be # archived back on termination. self.mock(tools, 'disable_buffering', lambda: None) sub_cmd = [ self.temp_join(u'foo.exe'), u'cmd with space', '${ISOLATED_OUTDIR}/out.txt', ] isolated_in_json = json_dumps({'command': sub_cmd}) isolated_in_hash = isolateserver_mock.hash_content(isolated_in_json) def get_storage(_isolate_server, _namespace): return StorageFake({isolated_in_hash:isolated_in_json}) self.mock(isolateserver, 'get_storage', get_storage) out = os.path.join(self.tempdir, 'res.json') cmd = [ '--no-log', '--isolated', isolated_in_hash, '--cache', self.tempdir, '--isolate-server', 'https://localhost:1', '--json', out, ] ret = run_isolated.main(cmd) self.assertEqual(0, ret) # Replace ${ISOLATED_OUTDIR} with the temporary directory. sub_cmd[2] = self.popen_calls[0][0][2] self.assertNotIn('ISOLATED_OUTDIR', sub_cmd[2]) self.assertEqual([(sub_cmd, {'detached': True})], self.popen_calls) isolated_out = { 'algo': 'sha-1', 'files': { 'out.txt': { 'h': isolateserver_mock.hash_content('generated data\n'), 's': 15, 'm': 0640, }, }, 'version': isolated_format.ISOLATED_FILE_VERSION, }
def help_test_archive(self, cmd_line_prefix): self.mock(isolateserver, 'get_storage', get_storage) self.make_tree(CONTENTS) isolateserver.main(cmd_line_prefix + [self.tempdir]) # If you modify isolated_format.ISOLATED_FILE_VERSION, you'll have to update # the hash below. Sorry about that but this ensures the .isolated format is # stable. isolated = { 'algo': 'sha-1', 'files': {}, 'version': isolated_format.ISOLATED_FILE_VERSION, } for k, v in CONTENTS.iteritems(): isolated['files'][k] = { 'h': isolateserver_mock.hash_content(v), 's': len(v), } if sys.platform != 'win32': isolated['files'][k]['m'] = 0600 isolated_data = json.dumps(isolated, sort_keys=True, separators=(',', ':')) isolated_hash = isolateserver_mock.hash_content(isolated_data) self.checkOutput('%s %s\n' % (isolated_hash, self.tempdir), '')
def help_test_archive(self, cmd_line_prefix): self.mock(isolateserver, 'get_storage', get_storage) self.make_tree(CONTENTS) isolateserver.main(cmd_line_prefix + [self.tempdir]) # If you modify isolated_format.ISOLATED_FILE_VERSION, you'll have to update # the hash below. Sorry about that but this ensures the .isolated format is # stable. isolated = { 'algo': 'sha-1', 'files': {}, 'version': isolated_format.ISOLATED_FILE_VERSION, } for k, v in CONTENTS.iteritems(): isolated['files'][k] = { 'h': isolateserver_mock.hash_content(v), 's': len(v), } if sys.platform != 'win32': isolated['files'][k]['m'] = 0600 isolated_data = json.dumps(isolated, sort_keys=True, separators=(',',':')) isolated_hash = isolateserver_mock.hash_content(isolated_data) self.checkOutput( '%s %s\n' % (isolated_hash, self.tempdir), '')
def _run_test(self, isolated, command): # Starts a full isolate server mock and have run_tha_test() uploads results # back after the task completed. server = isolateserver_mock.MockIsolateServer() try: script = ('import sys\n' 'open(sys.argv[1], "w").write("bar")\n' 'open(sys.argv[2], "w").write("baz")\n') script_hash = isolateserver_mock.hash_content(script) isolated['files']['cmd.py'] = { 'h': script_hash, 'm': 0700, 's': len(script), } if sys.platform == 'win32':
def test_python_cmd(self): isolated = json_dumps({ 'command': ['../out/cmd.py', 'arg'], 'relative_cwd': 'some', }) isolated_hash = isolateserver_mock.hash_content(isolated) files = {isolated_hash:isolated} _ = self._run_tha_test(isolated_hash, files) self.assertEqual(1, len(self.popen_calls)) # Injects sys.executable. self.assertEqual( [ ([sys.executable, os.path.join(u'..', 'out', 'cmd.py'), u'arg'], {'detached': True}), ], self.popen_calls)
def test_python_cmd(self): isolated = json_dumps({ 'command': ['../out/cmd.py', 'arg'], 'relative_cwd': 'some', }) isolated_hash = isolateserver_mock.hash_content(isolated) files = {isolated_hash: isolated} _ = self._run_tha_test(isolated_hash, files) # Injects sys.executable. self.assertEqual([ ([sys.executable, os.path.join(u'..', 'out', 'cmd.py'), u'arg'], { 'cwd': self.ir_dir('some'), 'detached': True }), ], self.popen_calls)
def test_fetch_offset_success(self): server = 'http://example.com' namespace = 'default' data = ''.join(str(x) for x in xrange(1000)) item = isolateserver_mock.hash_content(data) offset = 200 size = len(data) good_content_range_headers = [ 'bytes %d-%d/%d' % (offset, size - 1, size), 'bytes %d-%d/*' % (offset, size - 1), ] for _content_range_header in good_content_range_headers: self.expected_requests([self.mock_fetch_request( server, namespace, item, data, offset=offset)]) storage = isolateserver.IsolateServer(server, namespace) fetched = ''.join(storage.fetch(item, offset)) self.assertEqual(data[offset:], fetched)
def test_fetch_offset_success(self): server = 'http://example.com' namespace = 'default' data = ''.join(str(x) for x in xrange(1000)) item = isolateserver_mock.hash_content(data) offset = 200 size = len(data) good_content_range_headers = [ 'bytes %d-%d/%d' % (offset, size - 1, size), 'bytes %d-%d/*' % (offset, size - 1), ] for _content_range_header in good_content_range_headers: self.expected_requests([self.mock_fetch_request( server, namespace, item, data, offset=offset)]) storage = isolate_storage.IsolateServer(server, namespace) fetched = ''.join(storage.fetch(item, offset)) self.assertEqual(data[offset:], fetched)
def test_run_tha_test_naked_read_only_2(self): isolated = json_dumps({ 'command': ['invalid', 'command'], 'read_only': 2, }) isolated_hash = isolateserver_mock.hash_content(isolated) files = {isolated_hash: isolated} make_tree_call = self._run_tha_test(isolated_hash, files) self.assertEqual([ 'make_tree_read_only', 'make_tree_deleteable', 'make_tree_deleteable', 'make_tree_deleteable', ], make_tree_call) self.assertEqual([ ([self.ir_dir(u'invalid'), u'command'], { 'cwd': self.ir_dir(), 'detached': True }), ], self.popen_calls)
def test_output(self): # Starts a full isolate server mock and have run_tha_test() uploads results # back after the task completed. server = isolateserver_mock.MockIsolateServer() try: script = ('import sys\n' 'open(sys.argv[1], "w").write("bar")\n') script_hash = isolateserver_mock.hash_content(script) isolated = { u'algo': u'sha-1', u'command': [u'cmd.py', u'${ISOLATED_OUTDIR}/foo'], u'files': { u'cmd.py': { u'h': script_hash, u'm': 0700, u's': len(script), }, }, u'version': isolated_format.ISOLATED_FILE_VERSION, } if sys.platform == 'win32':
def test_output(self): # Starts a full isolate server mock and have run_tha_test() uploads results # back after the task completed. server = isolateserver_mock.MockIsolateServer() try: script = ( 'import sys\n' 'open(sys.argv[1], "w").write("bar")\n') script_hash = isolateserver_mock.hash_content(script) isolated = { 'algo': 'sha-1', 'command': ['cmd.py', '${ISOLATED_OUTDIR}/foo'], 'files': { 'cmd.py': { 'h': script_hash, 'm': 0700, 's': len(script), }, }, 'version': isolated_format.ISOLATED_FILE_VERSION, } if sys.platform == 'win32':
def test_main_json(self): # Instruct the Popen mock to write a file in ISOLATED_OUTDIR so it will be # archived back on termination. self.mock(tools, 'disable_buffering', lambda: None) sub_cmd = [ self.temp_join(u'foo.exe'), u'cmd with space', '${ISOLATED_OUTDIR}/out.txt', ] isolated = json_dumps({'command': sub_cmd}) isolated_hash = isolateserver_mock.hash_content(isolated) def get_storage(_isolate_server, _namespace): return StorageFake({isolated_hash:isolated}) self.mock(isolateserver, 'get_storage', get_storage) out = os.path.join(self.tempdir, 'res.json') cmd = [ '--no-log', '--isolated', isolated_hash, '--cache', self.tempdir, '--isolate-server', 'https://localhost:1', '--json', out, ] ret = run_isolated.main(cmd) self.assertEqual(0, ret) # Replace ${ISOLATED_OUTDIR} with the temporary directory. sub_cmd[2] = self.popen_calls[0][0][2] self.assertNotIn('ISOLATED_OUTDIR', sub_cmd[2]) self.assertEqual([(sub_cmd, {'detached': True})], self.popen_calls) expected = { u'exit_code': 0, u'internal_failure': None, u'outputs_ref': { u'isolated': u'e0a0fffa0910dd09e7ef4c89496116f60317e6c4', u'isolatedserver': u'http://localhost:1', u'namespace': u'default-gzip', }, u'version': 1, } self.assertEqual(expected, tools.read_json(out))
def test_run_isolated_upload_and_json(self): # pylint: disable=unused-argument write_json_calls = [] self.mock(tools, "write_json", lambda *args: write_json_calls.append(args)) subprocess_calls = [] self.mock(subprocess, "call", lambda *c: subprocess_calls.append(c)) self.mock(swarming, "now", lambda: 123456) isolated = os.path.join(self.tempdir, "zaz.isolated") content = "{}" with open(isolated, "wb") as f: f.write(content) isolated_hash = isolateserver_mock.hash_content(content) request = gen_request_data( properties={ "command": None, "idempotent": True, "inputs_ref": { "isolated": isolated_hash, "isolatedserver": "https://*****:*****@localhost", "--tags", "taga", "--tags", "tagb", "--hard-timeout", "60", "--io-timeout", "60", "--idempotent", "--task-name", "unit_tests", "--dump-json", "foo.json", isolated, "--", "--some-arg", "123", ] ) actual = sys.stdout.getvalue() self.assertEqual(0, ret, (actual, sys.stderr.getvalue())) self.assertEqual([], subprocess_calls) self._check_output( "Triggered task: unit_tests\n" "To collect results, use:\n" " swarming.py collect -S https://localhost:1 --json foo.json\n" "Or visit:\n" " https://localhost:1/user/task/12300\n", "", ) expected = [ ( "foo.json", { "base_task_name": "unit_tests", "tasks": { "unit_tests": { "shard_index": 0, "task_id": "12300", "view_url": "https://localhost:1/user/task/12300", } }, }, True, ) ] self.assertEqual(expected, write_json_calls)
{ 'command': [ 'python', '-V' ], 'files': {'file1.txt': file_meta('file1.txt')}, 'read_only': 1, }) CONTENTS['manifest1.isolated'] = json.dumps( {'files': {'file1.txt': file_meta('file1.txt')}}) CONTENTS['manifest2.isolated'] = json.dumps( { 'files': {'file2.txt': file_meta('file2.txt')}, 'includes': [ isolateserver_mock.hash_content(CONTENTS['manifest1.isolated']), ], }) CONTENTS['max_path.isolated'] = json.dumps( { 'command': ['python', 'max_path.py'], 'files': { 'a' * 200 + '/' + 'b' * 200: file_meta('file1.txt'), 'max_path.py': file_meta('max_path.py'), }, }) CONTENTS['repeated_files.isolated'] = json.dumps(
isolated = { 'algo': 'sha-1', 'files': { 'foo': { 'h': output_hash, # TODO(maruel): Handle umask. 'm': 0640, 's': 3, }, }, 'version': isolated_format.ISOLATED_FILE_VERSION, } if sys.platform == 'win32': isolated['files']['foo'].pop('m') uploaded = json_dumps(isolated) uploaded_hash = isolateserver_mock.hash_content(uploaded) hashes.add(uploaded_hash) self.assertEqual(hashes, set(server.contents['default-store'])) expected = ''.join([ '[run_isolated_out_hack]', '{"hash":"%s","namespace":"default-store","storage":%s}' % ( uploaded_hash, json.dumps(server.url)), '[/run_isolated_out_hack]' ]) + '\n' self.assertEqual(expected, sys.stdout.getvalue()) finally: server.close() class RunIsolatedJsonTest(RunIsolatedTestBase):
def __init__(self, data, high_priority=False): super(FakeItem, self).__init__( isolateserver_mock.hash_content(data), len(data), high_priority) self.data = data
isolated = { 'algo': 'sha-1', 'files': { 'foo': { 'h': output_hash, # TODO(maruel): Handle umask. 'm': 0640, 's': 3, }, }, 'version': isolated_format.ISOLATED_FILE_VERSION, } if sys.platform == 'win32': isolated['files']['foo'].pop('m') uploaded = json_dumps(isolated) uploaded_hash = isolateserver_mock.hash_content(uploaded) hashes.add(uploaded_hash) self.assertEqual(hashes, set(server.contents['default-store'])) expected = ''.join([ '[run_isolated_out_hack]', '{"hash":"%s","namespace":"default-store","storage":%s}' % ( uploaded_hash, json.dumps(server.url)), '[/run_isolated_out_hack]' ]) + '\n' self.assertEqual(expected, sys.stdout.getvalue()) finally: server.close() if __name__ == '__main__':
def file_meta(filename): return { 'h': isolateserver_mock.hash_content(CONTENTS[filename]), 's': len(CONTENTS[filename]), }
def test_run_isolated_upload_and_json(self): # pylint: disable=unused-argument write_json_calls = [] self.mock(tools, 'write_json', lambda *args: write_json_calls.append(args)) subprocess_calls = [] self.mock(subprocess, 'call', lambda *c: subprocess_calls.append(c)) self.mock(swarming, 'now', lambda: 123456) isolated = os.path.join(self.tempdir, 'zaz.isolated') content = '{}' with open(isolated, 'wb') as f: f.write(content) isolated_hash = isolateserver_mock.hash_content(content) request = gen_request_data( properties={ 'command': None, 'idempotent': True, 'inputs_ref': { 'isolated': isolated_hash, 'isolatedserver': 'https://*****:*****@localhost', '--tags', 'tag:a', '--tags', 'tag:b', '--hard-timeout', '60', '--io-timeout', '60', '--idempotent', '--task-name', 'unit_tests', '--dump-json', 'foo.json', isolated, '--', '--some-arg', '123', ]) actual = sys.stdout.getvalue() self.assertEqual(0, ret, (actual, sys.stderr.getvalue())) self.assertEqual([], subprocess_calls) self._check_output( 'Triggered task: unit_tests\n' 'To collect results, use:\n' ' swarming.py collect -S https://localhost:1 --json foo.json\n' 'Or visit:\n' ' https://localhost:1/user/task/12300\n', '') expected = [ ( u'foo.json', { 'base_task_name': 'unit_tests', 'tasks': { 'unit_tests': { 'shard_index': 0, 'task_id': '12300', 'view_url': 'https://localhost:1/user/task/12300', } }, 'request': { 'expiration_secs': 3600, 'name': 'unit_tests', 'parent_task_id': '', 'priority': 101, 'properties': { 'cipd_input': None, 'command': None, 'dimensions': [ {'key': 'foo', 'value': 'bar'}, {'key': 'os', 'value': 'Mac'}, ], 'env': [], 'execution_timeout_secs': 60, 'extra_args': ['--some-arg', '123'], 'grace_period_secs': 30, 'idempotent': True, 'inputs_ref': { 'isolated': isolated_hash, 'isolatedserver': 'https://localhost:2', 'namespace': 'default-gzip', }, 'io_timeout_secs': 60, }, 'tags': ['tag:a', 'tag:b'], 'user': '******', }, }, True, ), ] self.assertEqual(expected, write_json_calls)
def __init__(self, data, high_priority=False): super(FakeItem, self).__init__(isolateserver_mock.hash_content(data), len(data), high_priority) self.data = data
class RunIsolatedTestOutputFiles(RunIsolatedTestBase): # Like RunIsolatedTestRun, but ensures that specific output files # (as opposed to anything in $(ISOLATED_OUTDIR)) are returned. def _run_test(self, isolated, command, extra_args): # Starts a full isolate server mock and have run_tha_test() uploads results # back after the task completed. server = isolateserver_mock.MockIsolateServer() try: # Output the following structure: # # foo1 # foodir --> foo2_sl (symlink to "foo2_content" file) # bardir --> bar1 # # Create the symlinks only on Linux. script = ('import os\n' 'import sys\n' 'open(sys.argv[1], "w").write("foo1")\n' 'bar1_path = os.path.join(sys.argv[3], "bar1")\n' 'open(bar1_path, "w").write("bar1")\n' 'if sys.platform.startswith("linux"):\n' ' foo_realpath = os.path.abspath("foo2_content")\n' ' open(foo_realpath, "w").write("foo2")\n' ' os.symlink(foo_realpath, sys.argv[2])\n' 'else:\n' ' open(sys.argv[2], "w").write("foo2")\n') script_hash = isolateserver_mock.hash_content(script) isolated['files']['cmd.py'] = { 'h': script_hash, 'm': 0700, 's': len(script), } if sys.platform == 'win32': isolated['files']['cmd.py'].pop('m') isolated_data = json_dumps(isolated) isolated_hash = isolateserver_mock.hash_content(isolated_data) server.add_content('default-store', script) server.add_content('default-store', isolated_data) store = isolateserver.get_storage(server.url, 'default-store') self.mock(sys, 'stdout', StringIO.StringIO()) data = run_isolated.TaskData( command=command, relative_cwd=None, extra_args=extra_args, isolated_hash=isolated_hash, storage=store, isolate_cache=local_caching.MemoryContentAddressedCache(), outputs=['foo1', 'foodir/foo2_sl', 'bardir/'], install_named_caches=init_named_caches_stub, leak_temp_dir=False, root_dir=None, hard_timeout=60, grace_period=30, bot_file=None, switch_to_account=False, install_packages_fn=run_isolated.noop_install_packages, use_symlinks=False, env={}, env_prefix={}) ret = run_isolated.run_tha_test(data, None) self.assertEqual(0, ret) # It uploaded back. Assert the store has a new item containing foo. hashes = {isolated_hash, script_hash} foo1_output_hash = isolateserver_mock.hash_content('foo1') foo2_output_hash = isolateserver_mock.hash_content('foo2') bar1_output_hash = isolateserver_mock.hash_content('bar1') hashes.add(foo1_output_hash) hashes.add(foo2_output_hash) hashes.add(bar1_output_hash) isolated = { u'algo': u'sha-1', u'files': { u'foo1': { u'h': foo1_output_hash, # TODO(maruel): Handle umask. u'm': 0640, u's': 4, }, u'foodir/foo2_sl': { u'h': foo2_output_hash, # TODO(maruel): Handle umask. u'm': 0640, u's': 4, }, u'bardir/bar1': { u'h': bar1_output_hash, # TODO(maruel): Handle umask. u'm': 0640, u's': 4, }, }, u'version': isolated_format.ISOLATED_FILE_VERSION, }
'file1.txt': file_meta('file1.txt') }, 'read_only': 1, }) CONTENTS['manifest1.isolated'] = json.dumps( {'files': { 'file1.txt': file_meta('file1.txt') }}) CONTENTS['manifest2.isolated'] = json.dumps({ 'files': { 'file2.txt': file_meta('file2.txt') }, 'includes': [ isolateserver_mock.hash_content(CONTENTS['manifest1.isolated']), ], }) CONTENTS['max_path.isolated'] = json.dumps({ 'command': ['python', 'max_path.py'], 'files': { 'a' * 200 + '/' + 'b' * 200: file_meta('file1.txt'), 'max_path.py': file_meta('max_path.py'), }, }) CONTENTS['repeated_files.isolated'] = json.dumps({ 'command': ['python', 'repeated_files.py'], 'files': { 'file1.txt': file_meta('file1.txt'),
def test_run_isolated_upload_and_json(self): # pylint: disable=unused-argument write_json_calls = [] self.mock(tools, 'write_json', lambda *args: write_json_calls.append(args)) subprocess_calls = [] self.mock(subprocess, 'call', lambda *c: subprocess_calls.append(c)) self.mock(swarming, 'now', lambda: 123456) isolated = os.path.join(self.tempdir, 'zaz.isolated') content = '{}' with open(isolated, 'wb') as f: f.write(content) isolated_hash = isolateserver_mock.hash_content(content) request = gen_request_data( properties={ 'command': None, 'idempotent': True, 'inputs_ref': { 'isolated': isolated_hash, 'isolatedserver': 'https://*****:*****@localhost', '--tags', 'taga', '--tags', 'tagb', '--hard-timeout', '60', '--io-timeout', '60', '--idempotent', '--task-name', 'unit_tests', '--dump-json', 'foo.json', isolated, '--', '--some-arg', '123', ]) actual = sys.stdout.getvalue() self.assertEqual(0, ret, (actual, sys.stderr.getvalue())) self.assertEqual([], subprocess_calls) self._check_output( 'Triggered task: unit_tests\n' 'To collect results, use:\n' ' swarming.py collect -S https://localhost:1 --json foo.json\n' 'Or visit:\n' ' https://localhost:1/user/task/12300\n', '') expected = [ ( 'foo.json', { 'base_task_name': 'unit_tests', 'tasks': { 'unit_tests': { 'shard_index': 0, 'task_id': '12300', 'view_url': 'https://localhost:1/user/task/12300', } }, }, True, ), ] self.assertEqual(expected, write_json_calls)
class RunIsolatedTestRun(RunIsolatedTestBase): # Runs the actual command requested. def test_output(self): # Starts a full isolate server mock and have run_tha_test() uploads results # back after the task completed. server = isolateserver_mock.MockIsolateServer() try: script = ('import sys\n' 'open(sys.argv[1], "w").write("bar")\n') script_hash = isolateserver_mock.hash_content(script) isolated = { u'algo': u'sha-1', u'command': [u'cmd.py', u'${ISOLATED_OUTDIR}/foo'], u'files': { u'cmd.py': { u'h': script_hash, u'm': 0700, u's': len(script), }, }, u'version': isolated_format.ISOLATED_FILE_VERSION, } if sys.platform == 'win32': isolated[u'files'][u'cmd.py'].pop(u'm') isolated_data = json_dumps(isolated) isolated_hash = isolateserver_mock.hash_content(isolated_data) server.add_content('default-store', script) server.add_content('default-store', isolated_data) store = isolateserver.get_storage(server.url, 'default-store') self.mock(sys, 'stdout', StringIO.StringIO()) data = run_isolated.TaskData( command=[], relative_cwd=None, extra_args=[], isolated_hash=isolated_hash, storage=store, isolate_cache=local_caching.MemoryContentAddressedCache(), outputs=None, install_named_caches=init_named_caches_stub, leak_temp_dir=False, root_dir=None, hard_timeout=60, grace_period=30, bot_file=None, switch_to_account=False, install_packages_fn=run_isolated.noop_install_packages, use_symlinks=False, env={}, env_prefix={}) ret = run_isolated.run_tha_test(data, None) self.assertEqual(0, ret) # It uploaded back. Assert the store has a new item containing foo. hashes = {isolated_hash, script_hash} output_hash = isolateserver_mock.hash_content('bar') hashes.add(output_hash) isolated = { u'algo': u'sha-1', u'files': { u'foo': { u'h': output_hash, # TODO(maruel): Handle umask. u'm': 0640, u's': 3, }, }, u'version': isolated_format.ISOLATED_FILE_VERSION, }
'file1.txt': file_meta('file1.txt') }, 'read_only': 1, }) CONTENTS['manifest1.isolated'] = json.dumps( {'files': { 'file1.txt': file_meta('file1.txt') }}) CONTENTS['manifest2.isolated'] = json.dumps({ 'files': { 'file2.txt': file_meta('file2.txt') }, 'includes': [ isolateserver_mock.hash_content(CONTENTS['manifest1.isolated']), ], }) CONTENTS['tar_archive.isolated'] = json.dumps({ 'command': ['python', 'archive_files.py'], 'files': { 'archive': { 'h': isolateserver_mock.hash_content(CONTENTS['tar_archive']), 's': len(CONTENTS['tar_archive']), 't': 'tar', }, 'archive_files.py': file_meta('archive_files.py'), }, })
def test_run_isolated_upload_and_json(self): # pylint: disable=unused-argument write_json_calls = [] self.mock(tools, "write_json", lambda *args: write_json_calls.append(args)) def isolated_upload_zip_bundle(isolate_server, bundle): return "https://*****:*****@localhost", "--tags", "taga", "--tags", "tagb", "--hard-timeout", "60", "--io-timeout", "60", "--idempotent", "--task-name", "unit_tests", "--dump-json", "foo.json", isolated, "--", "--some-arg", "123", ] ) actual = sys.stdout.getvalue() self.assertEqual(0, ret, (actual, sys.stderr.getvalue())) expected = [ ( [ sys.executable, os.path.join(swarming.ROOT_DIR, "isolate.py"), "archive", "--isolate-server", "https://localhost:2", "--namespace", "default-gzip", "--isolated", isolated, ], 0, ) ] self.assertEqual(expected, subprocess_calls) self._check_output( "Archiving: %s\n" "Triggered task: unit_tests\n" "To collect results, use:\n" " swarming.py collect -S https://localhost:1 --json foo.json\n" "Or visit:\n" " https://localhost:1/user/task/12300\n" % isolated, "", ) expected = [ ( "foo.json", { "base_task_name": "unit_tests", "tasks": { "unit_tests": { "shard_index": 0, "task_id": "12300", "view_url": "https://localhost:1/user/task/12300", } }, }, True, ) ] self.assertEqual(expected, write_json_calls)
isolated = { u'algo': u'sha-1', u'files': { u'foo': { u'h': output_hash, # TODO(maruel): Handle umask. u'm': 0640, u's': 3, }, }, u'version': isolated_format.ISOLATED_FILE_VERSION, } if sys.platform == 'win32': isolated[u'files'][u'foo'].pop(u'm') uploaded = json_dumps(isolated) uploaded_hash = isolateserver_mock.hash_content(uploaded) hashes.add(uploaded_hash) self.assertEqual(hashes, set(server.contents['default-store'])) expected = ''.join([ '[run_isolated_out_hack]', '{"hash":"%s","namespace":"default-store","storage":%s}' % (uploaded_hash, json.dumps(server.url)), '[/run_isolated_out_hack]' ]) + '\n' self.assertEqual(expected, sys.stdout.getvalue()) finally: server.close() FILE, LINK, RELATIVE_LINK, DIR = range(4)