| OLD | NEW |
| (Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # Copyright 2014 Google Inc. All Rights Reserved. |
| 3 # |
| 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 # you may not use this file except in compliance with the License. |
| 6 # You may obtain a copy of the License at |
| 7 # |
| 8 # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 # |
| 10 # Unless required by applicable law or agreed to in writing, software |
| 11 # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 # See the License for the specific language governing permissions and |
| 14 # limitations under the License. |
| 15 """Implements a simple mock gsutil Cloud API for unit testing.""" |
| 16 |
| 17 from gslib.cloud_api import ServiceException |
| 18 from gslib.third_party.storage_apitools import storage_v1_messages as apitools_m
essages |
| 19 from gslib.translation_helper import CreateBucketNotFoundException |
| 20 from gslib.translation_helper import CreateObjectNotFoundException |
| 21 |
| 22 |
| 23 class MockObject(object): |
| 24 """Defines a mock cloud storage provider object.""" |
| 25 |
| 26 def __init__(self, root_object, contents=''): |
| 27 self.root_object = root_object |
| 28 self.contents = contents |
| 29 |
| 30 def __str__(self): |
| 31 return '%s/%s#%s' % (self.root_object.bucket, |
| 32 self.root_object.name, |
| 33 self.root_object.generation) |
| 34 |
| 35 def __repr__(self): |
| 36 return str(self) |
| 37 |
| 38 |
| 39 class MockBucket(object): |
| 40 """Defines a mock cloud storage provider bucket.""" |
| 41 |
| 42 def __init__(self, bucket_name, versioned=False): |
| 43 self.root_object = apitools_messages.Bucket( |
| 44 name=bucket_name, |
| 45 versioning=apitools_messages.Bucket.VersioningValue(enabled=versioned)) |
| 46 # Dict of object_name: (dict of 'live': MockObject |
| 47 # 'versioned': ordered list of MockObject). |
| 48 self.objects = {} |
| 49 |
| 50 def CreateObject(self, object_name, contents=''): |
| 51 return self.CreateObjectWithMetadata(MockObject( |
| 52 apitools_messages.Object(name=object_name, contents=contents))) |
| 53 |
| 54 def CreateObjectWithMetadata(self, apitools_object, contents=''): |
| 55 """Creates an object in the bucket according to the input metadata. |
| 56 |
| 57 This will create a new object version (ignoring the generation specified |
| 58 in the input object). |
| 59 |
| 60 Args: |
| 61 apitools_object: apitools Object. |
| 62 contents: optional object contents. |
| 63 |
| 64 Returns: |
| 65 apitools Object representing created object. |
| 66 """ |
| 67 # This modifies the apitools_object with a generation number. |
| 68 object_name = apitools_object.name |
| 69 if (self.root_object.versioning and self.root_object.versioning.enabled and |
| 70 apitools_object.name in self.objects): |
| 71 if 'live' in self.objects[object_name]: |
| 72 # Versioning enabled and object exists, create an object with a |
| 73 # generation 1 higher. |
| 74 apitools_object.generation = ( |
| 75 self.objects[object_name]['live'].root_object.generation + 1) |
| 76 # Move the live object to versioned. |
| 77 if 'versioned' not in self.objects[object_name]: |
| 78 self.objects[object_name]['versioned'] = [] |
| 79 self.objects[object_name]['versioned'].append( |
| 80 self.objects[object_name]['live']) |
| 81 elif ('versioned' in self.objects[object_name] and |
| 82 self.objects[object_name]['versioned']): |
| 83 # Versioning enabled but only archived objects exist, pick a generation |
| 84 # higher than the highest versioned object (which will be at the end). |
| 85 apitools_object.generation = ( |
| 86 self.objects[object_name]['versioned'][-1].root_object.generation |
| 87 + 1) |
| 88 else: |
| 89 # Versioning disabled or no objects exist yet with this name. |
| 90 apitools_object.generation = 1 |
| 91 self.objects[object_name] = {} |
| 92 new_object = MockObject(apitools_object, contents=contents) |
| 93 self.objects[object_name]['live'] = new_object |
| 94 return new_object |
| 95 |
| 96 |
| 97 class MockCloudApi(object): |
| 98 """Simple mock service for buckets/objects that implements Cloud API. |
| 99 |
| 100 Also includes some setup functions for tests. |
| 101 """ |
| 102 |
| 103 def __init__(self, provider='gs'): |
| 104 self.buckets = {} |
| 105 self.provider = provider |
| 106 |
| 107 def MockCreateBucket(self, bucket_name): |
| 108 """Creates a simple bucket without exercising the API directly.""" |
| 109 if bucket_name in self.buckets: |
| 110 raise ServiceException('Bucket %s already exists.' % bucket_name, |
| 111 status=409) |
| 112 self.buckets[bucket_name] = MockBucket(bucket_name) |
| 113 |
| 114 def MockCreateVersionedBucket(self, bucket_name): |
| 115 """Creates a simple bucket without exercising the API directly.""" |
| 116 if bucket_name in self.buckets: |
| 117 raise ServiceException('Bucket %s already exists.' % bucket_name, |
| 118 status=409) |
| 119 self.buckets[bucket_name] = MockBucket(bucket_name, versioned=True) |
| 120 |
| 121 def MockCreateObject(self, bucket_name, object_name, contents=''): |
| 122 """Creates an object without exercising the API directly.""" |
| 123 if bucket_name not in self.buckets: |
| 124 self.MockCreateBucket(bucket_name) |
| 125 self.buckets[bucket_name].CreateObject(object_name, contents=contents) |
| 126 |
| 127 def MockCreateObjectWithMetadata(self, apitools_object, contents=''): |
| 128 """Creates an object without exercising the API directly.""" |
| 129 assert apitools_object.bucket, 'No bucket specified for mock object' |
| 130 assert apitools_object.name, 'No object name specified for mock object' |
| 131 if apitools_object.bucket not in self.buckets: |
| 132 self.MockCreateBucket(apitools_object.bucket) |
| 133 return self.buckets[apitools_object.bucket].CreateObjectWithMetadata( |
| 134 apitools_object, contents=contents).root_object |
| 135 |
| 136 # pylint: disable=unused-argument |
| 137 def GetObjectMetadata(self, bucket_name, object_name, generation=None, |
| 138 provider=None, fields=None): |
| 139 """See CloudApi class for function doc strings.""" |
| 140 if generation: |
| 141 generation = long(generation) |
| 142 if bucket_name in self.buckets: |
| 143 bucket = self.buckets[bucket_name] |
| 144 if object_name in bucket.objects and bucket.objects[object_name]: |
| 145 if generation: |
| 146 if 'versioned' in bucket.objects[object_name]: |
| 147 for obj in bucket.objects[object_name]['versioned']: |
| 148 if obj.root_object.generation == generation: |
| 149 return obj.root_object |
| 150 if 'live' in bucket.objects[object_name]: |
| 151 if (bucket.objects[object_name]['live'].root_object.generation == |
| 152 generation): |
| 153 return bucket.objects[object_name]['live'].root_object |
| 154 else: |
| 155 # Return live object. |
| 156 if 'live' in bucket.objects[object_name]: |
| 157 return bucket.objects[object_name]['live'].root_object |
| 158 raise CreateObjectNotFoundException(404, self.provider, bucket_name, |
| 159 object_name) |
| 160 raise CreateBucketNotFoundException(404, self.provider, bucket_name) |
| OLD | NEW |