Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(135)

Side by Side Diff: gslib/tests/testcase/unit_testcase.py

Issue 698893003: Update checked in version of gsutil to version 4.6 (Closed) Base URL: http://dart.googlecode.com/svn/third_party/gsutil/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « gslib/tests/testcase/integration_testcase.py ('k') | gslib/tests/util.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # -*- coding: utf-8 -*-
1 # Copyright 2013 Google Inc. All Rights Reserved. 2 # Copyright 2013 Google Inc. All Rights Reserved.
2 # 3 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License. 5 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at 6 # You may obtain a copy of the License at
6 # 7 #
7 # http://www.apache.org/licenses/LICENSE-2.0 8 # http://www.apache.org/licenses/LICENSE-2.0
8 # 9 #
9 # Unless required by applicable law or agreed to in writing, software 10 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and 13 # See the License for the specific language governing permissions and
13 # limitations under the License. 14 # limitations under the License.
14
15 """Contains gsutil base unit test case class.""" 15 """Contains gsutil base unit test case class."""
16 16
17 from __future__ import absolute_import
18
19 import logging
17 import os 20 import os
18 import sys 21 import sys
19 import tempfile 22 import tempfile
20 23
21 import boto 24 import boto
22
23 from gslib import wildcard_iterator 25 from gslib import wildcard_iterator
26 from gslib.boto_translation import BotoTranslation
27 from gslib.cloud_api_delegator import CloudApiDelegator
24 from gslib.command_runner import CommandRunner 28 from gslib.command_runner import CommandRunner
25 from gslib.project_id import ProjectIdHandler 29 from gslib.cs_api_map import ApiMapConstants
30 from gslib.cs_api_map import ApiSelector
31 from gslib.tests.mock_logging_handler import MockLoggingHandler
32 from gslib.tests.testcase import base
26 import gslib.tests.util as util 33 import gslib.tests.util as util
27 from gslib.tests.util import unittest 34 from gslib.tests.util import unittest
28 import base
29
30 # The mock storage service comes from the Boto library, but it is not
31 # distributed with Boto when installed as a package. To get around this, we
32 # copy the file to gslib/tests/mock_storage_service.py when building the gsutil
33 # package. Try and import from several places here to find it.
34 try:
35 from gslib.tests import mock_storage_service
36 except ImportError:
37 try:
38 from boto.tests.integration.s3 import mock_storage_service
39 except ImportError:
40 try:
41 from tests.integration.s3 import mock_storage_service
42 except ImportError:
43 import mock_storage_service
44 35
45 36
46 class GSMockConnection(mock_storage_service.MockConnection): 37 class GsutilApiUnitTestClassMapFactory(object):
38 """Class map factory for use in unit tests.
47 39
48 def __init__(self, *args, **kwargs): 40 BotoTranslation is used for all cases so that GSMockBucketStorageUri can
49 kwargs['provider'] = 'gs' 41 be used to communicate with the mock XML service.
50 super(GSMockConnection, self).__init__(*args, **kwargs) 42 """
51 43
52 mock_connection = GSMockConnection() 44 @classmethod
45 def GetClassMap(cls):
46 """Returns a class map for use in unit tests."""
47 gs_class_map = {
48 ApiSelector.XML: BotoTranslation,
49 ApiSelector.JSON: BotoTranslation
50 }
51 s3_class_map = {
52 ApiSelector.XML: BotoTranslation
53 }
54 class_map = {
55 'gs': gs_class_map,
56 's3': s3_class_map
57 }
58 return class_map
53 59
54 60
55 class GSMockBucketStorageUri(mock_storage_service.MockBucketStorageUri):
56
57 def connect(self, access_key_id=None, secret_access_key=None):
58 return mock_connection
59
60 def compose(self, components, headers=None):
61 """Dummy implementation to allow parallel uploads with tests."""
62 return self.new_key()
63
64 @unittest.skipUnless(util.RUN_UNIT_TESTS, 61 @unittest.skipUnless(util.RUN_UNIT_TESTS,
65 'Not running integration tests.') 62 'Not running integration tests.')
66 class GsUtilUnitTestCase(base.GsUtilTestCase): 63 class GsUtilUnitTestCase(base.GsUtilTestCase):
67 """Base class for gsutil unit tests.""" 64 """Base class for gsutil unit tests."""
68 65
69 @classmethod 66 @classmethod
70 def setUpClass(cls): 67 def setUpClass(cls):
71 base.GsUtilTestCase.setUpClass() 68 base.GsUtilTestCase.setUpClass()
72 cls.mock_bucket_storage_uri = GSMockBucketStorageUri 69 cls.mock_bucket_storage_uri = util.GSMockBucketStorageUri
73 cls.proj_id_handler = ProjectIdHandler() 70 cls.mock_gsutil_api_class_map_factory = GsutilApiUnitTestClassMapFactory
74 config_file_list = boto.pyami.config.BotoConfigLocations 71 cls.logger = logging.getLogger()
75 # Use "gsutil_test_commands" as a fake UserAgent. This value will never be 72 cls.command_runner = CommandRunner(
76 # sent via HTTP because we're using MockStorageService here. 73 bucket_storage_uri_class=cls.mock_bucket_storage_uri,
77 cls.command_runner = CommandRunner(config_file_list, 74 gsutil_api_class_map_factory=cls.mock_gsutil_api_class_map_factory)
78 cls.mock_bucket_storage_uri)
79 75
80 def setUp(self): 76 def setUp(self):
81 super(GsUtilUnitTestCase, self).setUp() 77 super(GsUtilUnitTestCase, self).setUp()
82 self.bucket_uris = [] 78 self.bucket_uris = []
79 self.stdout_save = sys.stdout
80 self.stderr_save = sys.stderr
81 fd, self.stdout_file = tempfile.mkstemp()
82 sys.stdout = os.fdopen(fd, 'w+')
83 fd, self.stderr_file = tempfile.mkstemp()
84 sys.stderr = os.fdopen(fd, 'w+')
85 self.accumulated_stdout = []
86 self.accumulated_stderr = []
87
88 self.root_logger = logging.getLogger()
89 self.is_debugging = self.root_logger.isEnabledFor(logging.DEBUG)
90 self.log_handlers_save = self.root_logger.handlers
91 fd, self.log_handler_file = tempfile.mkstemp()
92 self.log_handler_stream = os.fdopen(fd, 'w+')
93 self.temp_log_handler = logging.StreamHandler(self.log_handler_stream)
94 self.root_logger.handlers = [self.temp_log_handler]
95
96 def tearDown(self):
97 super(GsUtilUnitTestCase, self).tearDown()
98
99 self.root_logger.handlers = self.log_handlers_save
100 self.temp_log_handler.flush()
101 self.log_handler_stream.seek(0)
102 log_output = self.log_handler_stream.read()
103 self.log_handler_stream.close()
104 os.unlink(self.log_handler_file)
105
106 sys.stdout.seek(0)
107 sys.stderr.seek(0)
108 stdout = sys.stdout.read()
109 stderr = sys.stderr.read()
110 stdout += ''.join(self.accumulated_stdout)
111 stderr += ''.join(self.accumulated_stderr)
112 sys.stdout.close()
113 sys.stderr.close()
114 sys.stdout = self.stdout_save
115 sys.stderr = self.stderr_save
116 os.unlink(self.stdout_file)
117 os.unlink(self.stderr_file)
118
119 if self.is_debugging and stdout:
120 sys.stderr.write('==== stdout %s ====\n' % self.id())
121 sys.stderr.write(stdout)
122 sys.stderr.write('==== end stdout ====\n')
123 if self.is_debugging and stderr:
124 sys.stderr.write('==== stderr %s ====\n' % self.id())
125 sys.stderr.write(stderr)
126 sys.stderr.write('==== end stderr ====\n')
127 if self.is_debugging and log_output:
128 sys.stderr.write('==== log output %s ====\n' % self.id())
129 sys.stderr.write(log_output)
130 sys.stderr.write('==== end log output ====\n')
83 131
84 def RunCommand(self, command_name, args=None, headers=None, debug=0, 132 def RunCommand(self, command_name, args=None, headers=None, debug=0,
85 test_method=None, return_stdout=False, cwd=None): 133 test_method=None, return_stdout=False, return_stderr=False,
86 """ 134 return_log_handler=False, cwd=None):
87 Method for calling gslib.command_runner.CommandRunner, passing 135 """Method for calling gslib.command_runner.CommandRunner.
88 parallel_operations=False for all tests, optionally saving/returning stdout 136
89 output. We run all tests multi-threaded, to exercise those more complicated 137 Passes parallel_operations=False for all tests, optionally saving/returning
90 code paths. 138 stdout output. We run all tests multi-threaded, to exercise those more
91 TODO: change to run with parallel_operations=True for all tests. At 139 complicated code paths.
140 TODO: Change to run with parallel_operations=True for all tests. At
92 present when you do this it causes many test failures. 141 present when you do this it causes many test failures.
93 142
94 Args: 143 Args:
95 command_name: The name of the command being run. 144 command_name: The name of the command being run.
96 args: Command-line args (arg0 = actual arg, not command name ala bash). 145 args: Command-line args (arg0 = actual arg, not command name ala bash).
97 headers: Dictionary containing optional HTTP headers to pass to boto. 146 headers: Dictionary containing optional HTTP headers to pass to boto.
98 debug: Debug level to pass in to boto connection (range 0..3). 147 debug: Debug level to pass in to boto connection (range 0..3).
99 parallel_operations: Should command operations be executed in parallel?
100 test_method: Optional general purpose method for testing purposes. 148 test_method: Optional general purpose method for testing purposes.
101 Application and semantics of this method will vary by 149 Application and semantics of this method will vary by
102 command and test type. 150 command and test type.
151 return_stdout: If True, will save and return stdout produced by command.
152 return_stderr: If True, will save and return stderr produced by command.
153 return_log_handler: If True, will return a MockLoggingHandler instance
154 that was attached to the command's logger while running.
103 cwd: The working directory that should be switched to before running the 155 cwd: The working directory that should be switched to before running the
104 command. The working directory will be reset back to its original 156 command. The working directory will be reset back to its original
105 value after running the command. If not specified, the working 157 value after running the command. If not specified, the working
106 directory is left unchanged. 158 directory is left unchanged.
107 return_stdout: If true will save and return stdout produced by command. 159
160 Returns:
161 One or a tuple of requested return values, depending on whether
162 return_stdout, return_stderr, and/or return_log_handler were specified.
108 """ 163 """
109 if util.VERBOSE_OUTPUT: 164 args = args or []
110 sys.stderr.write('\nRunning test of %s %s\n' %
111 (command_name, ' '.join(args)))
112 if return_stdout:
113 # Redirect stdout temporarily, to save output to a file.
114 fh, outfile = tempfile.mkstemp()
115 os.close(fh)
116 elif not util.VERBOSE_OUTPUT:
117 outfile = os.devnull
118 else:
119 outfile = None
120 165
121 stdout_sav = sys.stdout 166 command_line = ' '.join([command_name] + args)
122 output = None 167 if self.is_debugging:
168 self.stderr_save.write('\nRunCommand of %s\n' % command_line)
169
170 # Save and truncate stdout and stderr for the lifetime of RunCommand. This
171 # way, we can return just the stdout and stderr that was output during the
172 # RunNamedCommand call below.
173 sys.stdout.seek(0)
174 sys.stderr.seek(0)
175 stdout = sys.stdout.read()
176 stderr = sys.stderr.read()
177 if stdout:
178 self.accumulated_stdout.append(stdout)
179 if stderr:
180 self.accumulated_stderr.append(stderr)
181 sys.stdout.seek(0)
182 sys.stderr.seek(0)
183 sys.stdout.truncate()
184 sys.stderr.truncate()
185
123 cwd_sav = None 186 cwd_sav = None
124 try: 187 try:
125 cwd_sav = os.getcwd() 188 cwd_sav = os.getcwd()
126 except OSError: 189 except OSError:
127 # This can happen if the current working directory no longer exists. 190 # This can happen if the current working directory no longer exists.
128 pass 191 pass
192
193 mock_log_handler = MockLoggingHandler()
194 logging.getLogger(command_name).addHandler(mock_log_handler)
195
129 try: 196 try:
130 if outfile:
131 fp = open(outfile, 'w')
132 sys.stdout = fp
133 if cwd: 197 if cwd:
134 os.chdir(cwd) 198 os.chdir(cwd)
135 self.command_runner.RunNamedCommand( 199 self.command_runner.RunNamedCommand(
136 command_name, args=args, headers=headers, debug=debug, 200 command_name, args=args, headers=headers, debug=debug,
137 parallel_operations=False, test_method=test_method) 201 parallel_operations=False, test_method=test_method, do_shutdown=False)
138 finally: 202 finally:
139 if cwd and cwd_sav: 203 if cwd and cwd_sav:
140 os.chdir(cwd_sav) 204 os.chdir(cwd_sav)
141 if outfile:
142 fp.close()
143 sys.stdout = stdout_sav
144 with open(outfile, 'r') as f:
145 output = f.read()
146 if return_stdout:
147 os.unlink(outfile)
148 205
149 if output is not None and return_stdout: 206 sys.stdout.seek(0)
150 return output 207 stdout = sys.stdout.read()
208 sys.stderr.seek(0)
209 stderr = sys.stderr.read()
210 logging.getLogger(command_name).removeHandler(mock_log_handler)
211
212 log_output = '\n'.join(
213 '%s:\n ' % level + '\n '.join(records)
214 for level, records in mock_log_handler.messages.iteritems()
215 if records)
216 if self.is_debugging and log_output:
217 self.stderr_save.write(
218 '==== logging RunCommand %s %s ====\n' % (self.id(), command_line))
219 self.stderr_save.write(log_output)
220 self.stderr_save.write('\n==== end logging ====\n')
221 if self.is_debugging and stdout:
222 self.stderr_save.write(
223 '==== stdout RunCommand %s %s ====\n' % (self.id(), command_line))
224 self.stderr_save.write(stdout)
225 self.stderr_save.write('==== end stdout ====\n')
226 if self.is_debugging and stderr:
227 self.stderr_save.write(
228 '==== stderr RunCommand %s %s ====\n' % (self.id(), command_line))
229 self.stderr_save.write(stderr)
230 self.stderr_save.write('==== end stderr ====\n')
231
232 # Reset stdout and stderr files, so that we won't print them out again
233 # in tearDown if debugging is enabled.
234 sys.stdout.seek(0)
235 sys.stderr.seek(0)
236 sys.stdout.truncate()
237 sys.stderr.truncate()
238
239 to_return = []
240 if return_stdout:
241 to_return.append(stdout)
242 if return_stderr:
243 to_return.append(stderr)
244 if return_log_handler:
245 to_return.append(mock_log_handler)
246 if len(to_return) == 1:
247 return to_return[0]
248 return tuple(to_return)
151 249
152 @classmethod 250 @classmethod
153 def _test_wildcard_iterator(cls, uri_or_str, debug=0): 251 def _test_wildcard_iterator(cls, uri_or_str, debug=0):
154 """ 252 """Convenience method for instantiating a test instance of WildcardIterator.
155 Convenience method for instantiating a testing instance of 253
156 WildCardIterator, without having to specify all the params of that class 254 This makes it unnecessary to specify all the params of that class
157 (like bucket_storage_uri_class=mock_storage_service.MockBucketStorageUri). 255 (like bucket_storage_uri_class=mock_storage_service.MockBucketStorageUri).
158 Also naming the factory method this way makes it clearer in the test code 256 Also, naming the factory method this way makes it clearer in the test code
159 that WildcardIterator needs to be set up for testing. 257 that WildcardIterator needs to be set up for testing.
160 258
161 Args are same as for wildcard_iterator.wildcard_iterator(), except there's 259 Args are same as for wildcard_iterator.wildcard_iterator(), except
162 no bucket_storage_uri_class arg. 260 there are no class args for bucket_storage_uri_class or gsutil_api_class.
261
262 Args:
263 uri_or_str: StorageUri or string representing the wildcard string.
264 debug: debug level to pass to the underlying connection (0..3)
163 265
164 Returns: 266 Returns:
165 WildcardIterator.IterUris(), over which caller can iterate. 267 WildcardIterator, over which caller can iterate.
166 """ 268 """
167 return wildcard_iterator.wildcard_iterator( 269 # TODO: Remove when tests no longer pass StorageUri arguments.
168 uri_or_str, cls.proj_id_handler, cls.mock_bucket_storage_uri, 270 uri_string = uri_or_str
271 if hasattr(uri_or_str, 'uri'):
272 uri_string = uri_or_str.uri
273
274 cls.gsutil_api_map = {
275 ApiMapConstants.API_MAP: (
276 cls.mock_gsutil_api_class_map_factory.GetClassMap()),
277 ApiMapConstants.SUPPORT_MAP: {
278 'gs': [ApiSelector.XML, ApiSelector.JSON],
279 's3': [ApiSelector.XML]
280 },
281 ApiMapConstants.DEFAULT_MAP: {
282 'gs': ApiSelector.JSON,
283 's3': ApiSelector.XML
284 }
285 }
286
287 cls.gsutil_api = CloudApiDelegator(
288 cls.mock_bucket_storage_uri, cls.gsutil_api_map, cls.logger,
169 debug=debug) 289 debug=debug)
170 290
291 return wildcard_iterator.CreateWildcardIterator(uri_string, cls.gsutil_api)
292
171 @staticmethod 293 @staticmethod
172 def _test_storage_uri(uri_str, default_scheme='file', debug=0, 294 def _test_storage_uri(uri_str, default_scheme='file', debug=0,
173 validate=True): 295 validate=True):
174 """ 296 """Convenience method for instantiating a testing instance of StorageUri.
175 Convenience method for instantiating a testing 297
176 instance of StorageUri, without having to specify 298 This makes it unnecessary to specify
177 bucket_storage_uri_class=mock_storage_service.MockBucketStorageUri. 299 bucket_storage_uri_class=mock_storage_service.MockBucketStorageUri.
178 Also naming the factory method this way makes it clearer in the test 300 Also naming the factory method this way makes it clearer in the test
179 code that StorageUri needs to be set up for testing. 301 code that StorageUri needs to be set up for testing.
180 302
181 Args, Returns, and Raises are same as for boto.storage_uri(), except there's 303 Args, Returns, and Raises are same as for boto.storage_uri(), except there's
182 no bucket_storage_uri_class arg. 304 no bucket_storage_uri_class arg.
305
306 Args:
307 uri_str: Uri string to create StorageUri for.
308 default_scheme: Default scheme for the StorageUri
309 debug: debug level to pass to the underlying connection (0..3)
310 validate: If True, validate the resource that the StorageUri refers to.
311
312 Returns:
313 StorageUri based on the arguments.
183 """ 314 """
184 return boto.storage_uri(uri_str, default_scheme, debug, validate, 315 return boto.storage_uri(uri_str, default_scheme, debug, validate,
185 GSMockBucketStorageUri) 316 util.GSMockBucketStorageUri)
186 317
187 def CreateBucket(self, bucket_name=None, test_objects=0, storage_class=None): 318 def CreateBucket(self, bucket_name=None, test_objects=0, storage_class=None,
319 provider='gs'):
188 """Creates a test bucket. 320 """Creates a test bucket.
189 321
190 The bucket and all of its contents will be deleted after the test. 322 The bucket and all of its contents will be deleted after the test.
191 323
192 Args: 324 Args:
193 bucket_name: Create the bucket with this name. If not provided, a 325 bucket_name: Create the bucket with this name. If not provided, a
194 temporary test bucket name is constructed. 326 temporary test bucket name is constructed.
195 test_objects: The number of objects that should be placed in the bucket or 327 test_objects: The number of objects that should be placed in the bucket or
196 a list of object names to place in the bucket. Defaults to 328 a list of object names to place in the bucket. Defaults to
197 0. 329 0.
198 storage_class: storage class to use. If not provided we us standard. 330 storage_class: storage class to use. If not provided we us standard.
331 provider: string provider to use, default gs.
199 332
200 Returns: 333 Returns:
201 StorageUri for the created bucket. 334 StorageUri for the created bucket.
202 """ 335 """
203 bucket_name = bucket_name or self.MakeTempName('bucket') 336 bucket_name = bucket_name or self.MakeTempName('bucket')
204 bucket_uri = boto.storage_uri( 337 bucket_uri = boto.storage_uri(
205 'gs://%s' % bucket_name.lower(), 338 '%s://%s' % (provider, bucket_name.lower()),
206 suppress_consec_slashes=False, 339 suppress_consec_slashes=False,
207 bucket_storage_uri_class=GSMockBucketStorageUri) 340 bucket_storage_uri_class=util.GSMockBucketStorageUri)
208 bucket_uri.create_bucket(storage_class=storage_class) 341 bucket_uri.create_bucket(storage_class=storage_class)
209 self.bucket_uris.append(bucket_uri) 342 self.bucket_uris.append(bucket_uri)
210 try: 343 try:
211 iter(test_objects) 344 iter(test_objects)
212 except TypeError: 345 except TypeError:
213 test_objects = [self.MakeTempName('obj') for _ in range(test_objects)] 346 test_objects = [self.MakeTempName('obj') for _ in range(test_objects)]
214 for i, name in enumerate(test_objects): 347 for i, name in enumerate(test_objects):
215 self.CreateObject(bucket_uri=bucket_uri, object_name=name, 348 self.CreateObject(bucket_uri=bucket_uri, object_name=name,
216 contents='test %d' % i) 349 contents='test %d' % i)
217 return bucket_uri 350 return bucket_uri
218 351
219 def CreateObject(self, bucket_uri=None, object_name=None, contents=None): 352 def CreateObject(self, bucket_uri=None, object_name=None, contents=None):
220 """Creates a test object. 353 """Creates a test object.
221 354
222 Args: 355 Args:
223 bucket: The URI of the bucket to place the object in. If not specified, a 356 bucket_uri: The URI of the bucket to place the object in. If not
224 new temporary bucket is created. 357 specified, a new temporary bucket is created.
225 object_name: The name to use for the object. If not specified, a temporary 358 object_name: The name to use for the object. If not specified, a temporary
226 test object name is constructed. 359 test object name is constructed.
227 contents: The contents to write to the object. If not specified, the key 360 contents: The contents to write to the object. If not specified, the key
228 is not written to, which means that it isn't actually created 361 is not written to, which means that it isn't actually created
229 yet on the server. 362 yet on the server.
230 363
231 Returns: 364 Returns:
232 A StorageUri for the created object. 365 A StorageUri for the created object.
233 """ 366 """
234 bucket_uri = bucket_uri or self.CreateBucket() 367 bucket_uri = bucket_uri or self.CreateBucket()
235 object_name = object_name or self.MakeTempName('obj') 368 object_name = object_name or self.MakeTempName('obj')
236 key_uri = bucket_uri.clone_replace_name(object_name) 369 key_uri = bucket_uri.clone_replace_name(object_name)
237 if contents is not None: 370 if contents is not None:
238 key_uri.set_contents_from_string(contents) 371 key_uri.set_contents_from_string(contents)
239 return key_uri 372 return key_uri
OLDNEW
« no previous file with comments | « gslib/tests/testcase/integration_testcase.py ('k') | gslib/tests/util.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698