Index: third_party/gsutil/gslib/tests/testcase/unit_testcase.py |
diff --git a/third_party/gsutil/gslib/tests/testcase/unit_testcase.py b/third_party/gsutil/gslib/tests/testcase/unit_testcase.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..daac0365e1b90f0bbf881bd6672729664deb90b7 |
--- /dev/null |
+++ b/third_party/gsutil/gslib/tests/testcase/unit_testcase.py |
@@ -0,0 +1,230 @@ |
+# Copyright 2013 Google Inc. All Rights Reserved. |
+# |
+# Licensed under the Apache License, Version 2.0 (the "License"); |
+# you may not use this file except in compliance with the License. |
+# You may obtain a copy of the License at |
+# |
+# http://www.apache.org/licenses/LICENSE-2.0 |
+# |
+# Unless required by applicable law or agreed to in writing, software |
+# distributed under the License is distributed on an "AS IS" BASIS, |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+# See the License for the specific language governing permissions and |
+# limitations under the License. |
+ |
+"""Contains gsutil base unit test case class.""" |
+ |
+import os.path |
+import sys |
+import tempfile |
+ |
+import boto |
+ |
+from gslib import wildcard_iterator |
+from gslib.command_runner import CommandRunner |
+from gslib.project_id import ProjectIdHandler |
+import gslib.tests.util as util |
+from gslib.tests.util import unittest |
+from tests.integration.s3 import mock_storage_service |
+import base |
+ |
+ |
+CURDIR = os.path.abspath(os.path.dirname(__file__)) |
+TESTS_DIR = os.path.split(CURDIR)[0] |
+GSLIB_DIR = os.path.split(TESTS_DIR)[0] |
+GSUTIL_DIR = os.path.split(GSLIB_DIR)[0] |
+BOTO_DIR = os.path.join(GSUTIL_DIR, 'boto') |
+ |
+ |
+class GSMockConnection(mock_storage_service.MockConnection): |
+ |
+ def __init__(self, *args, **kwargs): |
+ kwargs['provider'] = 'gs' |
+ super(GSMockConnection, self).__init__(*args, **kwargs) |
+ |
+mock_connection = GSMockConnection() |
+ |
+ |
+class GSMockBucketStorageUri(mock_storage_service.MockBucketStorageUri): |
+ |
+ def connect(self, access_key_id=None, secret_access_key=None): |
+ return mock_connection |
+ |
+ |
+@unittest.skipUnless(util.RUN_UNIT_TESTS, |
+ 'Not running integration tests.') |
+class GsUtilUnitTestCase(base.GsUtilTestCase): |
+ """Base class for gsutil unit tests.""" |
+ |
+ @classmethod |
+ def setUpClass(cls): |
+ base.GsUtilTestCase.setUpClass() |
+ cls.mock_bucket_storage_uri = GSMockBucketStorageUri |
+ cls.proj_id_handler = ProjectIdHandler() |
+ config_file_list = boto.pyami.config.BotoConfigLocations |
+ # Use "gsutil_test_commands" as a fake UserAgent. This value will never be |
+ # sent via HTTP because we're using MockStorageService here. |
+ cls.command_runner = CommandRunner(GSUTIL_DIR, BOTO_DIR, |
+ config_file_list, 'gsutil_test_commands', |
+ cls.mock_bucket_storage_uri) |
+ |
+ def setUp(self): |
+ super(GsUtilUnitTestCase, self).setUp() |
+ self.bucket_uris = [] |
+ |
+ def RunCommand(self, command_name, args=None, headers=None, debug=0, |
+ test_method=None, return_stdout=False, cwd=None): |
+ """ |
+ Method for calling gslib.command_runner.CommandRunner, passing |
+ parallel_operations=False for all tests, optionally saving/returning stdout |
+ output. We run all tests multi-threaded, to exercise those more complicated |
+ code paths. |
+ TODO: change to run with parallel_operations=True for all tests. At |
+ present when you do this it causes many test failures. |
+ |
+ Args: |
+ command_name: The name of the command being run. |
+ args: Command-line args (arg0 = actual arg, not command name ala bash). |
+ headers: Dictionary containing optional HTTP headers to pass to boto. |
+ debug: Debug level to pass in to boto connection (range 0..3). |
+ parallel_operations: Should command operations be executed in parallel? |
+ test_method: Optional general purpose method for testing purposes. |
+ Application and semantics of this method will vary by |
+ command and test type. |
+ cwd: The working directory that should be switched to before running the |
+ command. The working directory will be reset back to its original |
+ value after running the command. If not specified, the working |
+ directory is left unchanged. |
+ return_stdout: If true will save and return stdout produced by command. |
+ """ |
+ if util.VERBOSE_OUTPUT: |
+ sys.stderr.write('\nRunning test of %s %s\n' % |
+ (command_name, ' '.join(args))) |
+ if return_stdout: |
+ # Redirect stdout temporarily, to save output to a file. |
+ fh, outfile = tempfile.mkstemp() |
+ os.close(fh) |
+ elif not util.VERBOSE_OUTPUT: |
+ outfile = os.devnull |
+ else: |
+ outfile = None |
+ |
+ stdout_sav = sys.stdout |
+ output = None |
+ cwd_sav = None |
+ try: |
+ cwd_sav = os.getcwd() |
+ except OSError: |
+ # This can happen if the current working directory no longer exists. |
+ pass |
+ try: |
+ if outfile: |
+ fp = open(outfile, 'w') |
+ sys.stdout = fp |
+ if cwd: |
+ os.chdir(cwd) |
+ self.command_runner.RunNamedCommand( |
+ command_name, args=args, headers=headers, debug=debug, |
+ parallel_operations=False, test_method=test_method) |
+ finally: |
+ if cwd and cwd_sav: |
+ os.chdir(cwd_sav) |
+ if outfile: |
+ fp.close() |
+ sys.stdout = stdout_sav |
+ with open(outfile, 'r') as f: |
+ output = f.read() |
+ if return_stdout: |
+ os.unlink(outfile) |
+ |
+ if output is not None and return_stdout: |
+ return output |
+ |
+ @classmethod |
+ def _test_wildcard_iterator(cls, uri_or_str, debug=0): |
+ """ |
+ Convenience method for instantiating a testing instance of |
+ WildCardIterator, without having to specify all the params of that class |
+ (like bucket_storage_uri_class=mock_storage_service.MockBucketStorageUri). |
+ Also naming the factory method this way makes it clearer in the test code |
+ that WildcardIterator needs to be set up for testing. |
+ |
+ Args are same as for wildcard_iterator.wildcard_iterator(), except there's |
+ no bucket_storage_uri_class arg. |
+ |
+ Returns: |
+ WildcardIterator.IterUris(), over which caller can iterate. |
+ """ |
+ return wildcard_iterator.wildcard_iterator( |
+ uri_or_str, cls.proj_id_handler, cls.mock_bucket_storage_uri, |
+ debug=debug) |
+ |
+ @staticmethod |
+ def _test_storage_uri(uri_str, default_scheme='file', debug=0, |
+ validate=True): |
+ """ |
+ Convenience method for instantiating a testing |
+ instance of StorageUri, without having to specify |
+ bucket_storage_uri_class=mock_storage_service.MockBucketStorageUri. |
+ Also naming the factory method this way makes it clearer in the test |
+ code that StorageUri needs to be set up for testing. |
+ |
+ Args, Returns, and Raises are same as for boto.storage_uri(), except there's |
+ no bucket_storage_uri_class arg. |
+ """ |
+ return boto.storage_uri(uri_str, default_scheme, debug, validate, |
+ GSMockBucketStorageUri) |
+ |
+ def CreateBucket(self, bucket_name=None, test_objects=0, storage_class=None): |
+ """Creates a test bucket. |
+ |
+ The bucket and all of its contents will be deleted after the test. |
+ |
+ Args: |
+ bucket_name: Create the bucket with this name. If not provided, a |
+ temporary test bucket name is constructed. |
+ test_objects: The number of objects that should be placed in the bucket or |
+ a list of object names to place in the bucket. Defaults to |
+ 0. |
+ storage_class: storage class to use. If not provided we us standard. |
+ |
+ Returns: |
+ StorageUri for the created bucket. |
+ """ |
+ bucket_name = bucket_name or self.MakeTempName('bucket') |
+ bucket_uri = boto.storage_uri( |
+ 'gs://%s' % bucket_name.lower(), |
+ suppress_consec_slashes=False, |
+ bucket_storage_uri_class=GSMockBucketStorageUri) |
+ bucket_uri.create_bucket(storage_class=storage_class) |
+ self.bucket_uris.append(bucket_uri) |
+ try: |
+ iter(test_objects) |
+ except TypeError: |
+ test_objects = [self.MakeTempName('obj') for _ in range(test_objects)] |
+ for i, name in enumerate(test_objects): |
+ self.CreateObject(bucket_uri=bucket_uri, object_name=name, |
+ contents='test %d' % i) |
+ return bucket_uri |
+ |
+ def CreateObject(self, bucket_uri=None, object_name=None, contents=None): |
+ """Creates a test object. |
+ |
+ Args: |
+ bucket: The URI of the bucket to place the object in. If not specified, a |
+ new temporary bucket is created. |
+ object_name: The name to use for the object. If not specified, a temporary |
+ test object name is constructed. |
+ contents: The contents to write to the object. If not specified, the key |
+ is not written to, which means that it isn't actually created |
+ yet on the server. |
+ |
+ Returns: |
+ A StorageUri for the created object. |
+ """ |
+ bucket_uri = bucket_uri or self.CreateBucket() |
+ object_name = object_name or self.MakeTempName('obj') |
+ key_uri = bucket_uri.clone_replace_name(object_name) |
+ if contents is not None: |
+ key_uri.set_contents_from_string(contents) |
+ return key_uri |