| OLD | NEW |
| 1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
| 2 # Copyright 2014 Google Inc. All Rights Reserved. | 2 # Copyright 2014 Google Inc. All Rights Reserved. |
| 3 # | 3 # |
| 4 # Licensed under the Apache License, Version 2.0 (the "License"); | 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 # 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. |
| 6 # You may obtain a copy of the License at | 6 # You may obtain a copy of the License at |
| 7 # | 7 # |
| 8 # http://www.apache.org/licenses/LICENSE-2.0 | 8 # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 # | 9 # |
| 10 # Unless required by applicable law or agreed to in writing, software | 10 # Unless required by applicable law or agreed to in writing, software |
| 11 # distributed under the License is distributed on an "AS IS" BASIS, | 11 # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 # See the License for the specific language governing permissions and | 13 # See the License for the specific language governing permissions and |
| 14 # limitations under the License. | 14 # limitations under the License. |
| 15 """Integration tests for rsync command.""" | 15 """Integration tests for rsync command.""" |
| 16 | 16 |
| 17 import os | 17 import os |
| 18 | 18 |
| 19 import crcmod | 19 import crcmod |
| 20 | 20 |
| 21 import gslib.tests.testcase as testcase | 21 import gslib.tests.testcase as testcase |
| 22 from gslib.tests.testcase.integration_testcase import SkipForS3 | 22 from gslib.tests.testcase.integration_testcase import SkipForS3 |
| 23 from gslib.tests.util import ObjectToURI as suri | 23 from gslib.tests.util import ObjectToURI as suri |
| 24 from gslib.tests.util import PerformsFileToObjectUpload | 24 from gslib.tests.util import SequentialAndParallelTransfer |
| 25 from gslib.tests.util import SetBotoConfigForTest | 25 from gslib.tests.util import SetBotoConfigForTest |
| 26 from gslib.tests.util import unittest | 26 from gslib.tests.util import unittest |
| 27 from gslib.util import IS_WINDOWS | 27 from gslib.util import IS_WINDOWS |
| 28 from gslib.util import Retry | 28 from gslib.util import Retry |
| 29 from gslib.util import UsingCrcmodExtension | 29 from gslib.util import UsingCrcmodExtension |
| 30 | 30 |
| 31 NO_CHANGES = 'Building synchronization state...\nStarting synchronization\n' | 31 NO_CHANGES = 'Building synchronization state...\nStarting synchronization\n' |
| 32 | 32 |
| 33 | 33 |
| 34 def _TailSet(start_point, listing): | 34 def _TailSet(start_point, listing): |
| 35 """Returns set of object name tails. | 35 """Returns set of object name tails. |
| 36 | 36 |
| 37 Tails can be compared between source and dest, past the point at which rsync | 37 Tails can be compared between source and dest, past the point at which rsync |
| 38 was done. For example if test ran rsync gs://bucket1/dir gs://bucket2/dir2, | 38 was done. For example if test ran rsync gs://bucket1/dir gs://bucket2/dir2, |
| 39 the tails for listings from bucket1 would start after "dir", while the tails | 39 the tails for listings from bucket1 would start after "dir", while the tails |
| 40 for listings from bucket2 would start after "dir2". | 40 for listings from bucket2 would start after "dir2". |
| 41 | 41 |
| 42 Args: | 42 Args: |
| 43 start_point: The target of the rsync command, e.g., for the above command it | 43 start_point: The target of the rsync command, e.g., for the above command it |
| 44 would be gs://bucket1/dir for the bucket1 listing results and | 44 would be gs://bucket1/dir for the bucket1 listing results and |
| 45 gs://bucket2/dir2 for the bucket2 listing results. | 45 gs://bucket2/dir2 for the bucket2 listing results. |
| 46 listing: The listing over which to compute tail. | 46 listing: The listing over which to compute tail. |
| 47 | 47 |
| 48 Returns: | 48 Returns: |
| 49 Object name tails. | 49 Object name tails. |
| 50 """ | 50 """ |
| 51 return set(l[len(start_point):] for l in listing.strip().split('\n')) | 51 return set(l[len(start_point):] for l in listing.strip().split('\n')) |
| 52 | 52 |
| 53 |
| 53 # TODO: Add inspection to the retry wrappers in this test suite where the state | 54 # TODO: Add inspection to the retry wrappers in this test suite where the state |
| 54 # at the end of a retry block is depended upon by subsequent tests (since | 55 # at the end of a retry block is depended upon by subsequent tests (since |
| 55 # listing content can vary depending on which backend server is reached until | 56 # listing content can vary depending on which backend server is reached until |
| 56 # eventual consistency is reached). | 57 # eventual consistency is reached). |
| 57 # TODO: Remove retry wrappers and AssertNObjectsInBucket calls if GCS ever | 58 # TODO: Remove retry wrappers and AssertNObjectsInBucket calls if GCS ever |
| 58 # supports strong listing consistency. | 59 # supports strong listing consistency. |
| 59 class TestRsync(testcase.GsUtilIntegrationTestCase): | 60 class TestRsync(testcase.GsUtilIntegrationTestCase): |
| 60 """Integration tests for rsync command.""" | 61 """Integration tests for rsync command.""" |
| 61 | 62 |
| 62 @staticmethod | 63 @staticmethod |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 # Note: The tests below exercise the cases | 106 # Note: The tests below exercise the cases |
| 106 # {src_dir, src_bucket} X {dst_dir, dst_bucket}. We use gsutil rsync -d for | 107 # {src_dir, src_bucket} X {dst_dir, dst_bucket}. We use gsutil rsync -d for |
| 107 # all the cases but then have just one test without -d (test_bucket_to_bucket) | 108 # all the cases but then have just one test without -d (test_bucket_to_bucket) |
| 108 # as representative of handling without the -d option. This provides | 109 # as representative of handling without the -d option. This provides |
| 109 # reasonable test coverage because the -d handling it src/dest URI-type | 110 # reasonable test coverage because the -d handling it src/dest URI-type |
| 110 # independent, and keeps the test case combinations more manageable. | 111 # independent, and keeps the test case combinations more manageable. |
| 111 | 112 |
| 112 def test_bucket_to_bucket(self): | 113 def test_bucket_to_bucket(self): |
| 113 """Tests that flat and recursive rsync between 2 buckets works correctly.""" | 114 """Tests that flat and recursive rsync between 2 buckets works correctly.""" |
| 114 # Create 2 buckets with 1 overlapping object, 1 extra object at root level | 115 # Create 2 buckets with 1 overlapping object, 1 extra object at root level |
| 115 # in each, and 1 extra object 1 level down in each. Make the overlapping | 116 # in each, and 1 extra object 1 level down in each, where one of the objects |
| 116 # objects named the same but with different content, to test that we detect | 117 # starts with "." to test that we don't skip those objects. Make the |
| 117 # and properly copy in that case. | 118 # overlapping objects named the same but with different content, to test |
| 119 # that we detect and properly copy in that case. |
| 118 bucket1_uri = self.CreateBucket() | 120 bucket1_uri = self.CreateBucket() |
| 119 bucket2_uri = self.CreateBucket() | 121 bucket2_uri = self.CreateBucket() |
| 120 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj1', | 122 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj1', |
| 121 contents='obj1') | 123 contents='obj1') |
| 122 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj2', | 124 self.CreateObject(bucket_uri=bucket1_uri, object_name='.obj2', |
| 123 contents='obj2') | 125 contents='.obj2') |
| 124 self.CreateObject(bucket_uri=bucket1_uri, object_name='subdir/obj3', | 126 self.CreateObject(bucket_uri=bucket1_uri, object_name='subdir/obj3', |
| 125 contents='subdir/obj3') | 127 contents='subdir/obj3') |
| 126 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj2', | 128 self.CreateObject(bucket_uri=bucket2_uri, object_name='.obj2', |
| 127 contents='OBJ2') | 129 contents='.OBJ2') |
| 128 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj4', | 130 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj4', |
| 129 contents='obj4') | 131 contents='obj4') |
| 130 self.CreateObject(bucket_uri=bucket2_uri, object_name='subdir/obj5', | 132 self.CreateObject(bucket_uri=bucket2_uri, object_name='subdir/obj5', |
| 131 contents='subdir/obj5') | 133 contents='subdir/obj5') |
| 132 | 134 |
| 133 # Use @Retry as hedge against bucket listing eventual consistency. | 135 # Use @Retry as hedge against bucket listing eventual consistency. |
| 134 @Retry(AssertionError, tries=3, timeout_secs=1) | 136 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 135 def _Check1(): | 137 def _Check1(): |
| 136 """Tests rsync works as expected.""" | 138 """Tests rsync works as expected.""" |
| 137 self.RunGsUtil(['rsync', suri(bucket1_uri), suri(bucket2_uri)]) | 139 self.RunGsUtil(['rsync', suri(bucket1_uri), suri(bucket2_uri)]) |
| 138 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) | 140 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) |
| 139 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) | 141 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) |
| 140 # First bucket should have un-altered content. | 142 # First bucket should have un-altered content. |
| 141 self.assertEquals(listing1, set(['/obj1', '/obj2', '/subdir/obj3'])) | 143 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/subdir/obj3'])) |
| 142 # Second bucket should have new objects added from source bucket (without | 144 # Second bucket should have new objects added from source bucket (without |
| 143 # removing extraneeous object found in dest bucket), and without the | 145 # removing extraneeous object found in dest bucket), and without the |
| 144 # subdir objects synchronized. | 146 # subdir objects synchronized. |
| 145 self.assertEquals(listing2, | 147 self.assertEquals(listing2, |
| 146 set(['/obj1', '/obj2', '/obj4', '/subdir/obj5'])) | 148 set(['/obj1', '/.obj2', '/obj4', '/subdir/obj5'])) |
| 147 # Assert that the src/dest objects that had same length but different | 149 # Assert that the src/dest objects that had same length but different |
| 148 # content were correctly synchronized (bucket to bucket sync uses | 150 # content were correctly synchronized (bucket to bucket sync uses |
| 149 # checksums). | 151 # checksums). |
| 150 self.assertEquals('obj2', self.RunGsUtil( | 152 self.assertEquals('.obj2', self.RunGsUtil( |
| 151 ['cat', suri(bucket1_uri, 'obj2')], return_stdout=True)) | 153 ['cat', suri(bucket1_uri, '.obj2')], return_stdout=True)) |
| 152 self.assertEquals('obj2', self.RunGsUtil( | 154 self.assertEquals('.obj2', self.RunGsUtil( |
| 153 ['cat', suri(bucket2_uri, 'obj2')], return_stdout=True)) | 155 ['cat', suri(bucket2_uri, '.obj2')], return_stdout=True)) |
| 154 _Check1() | 156 _Check1() |
| 155 | 157 |
| 156 # Use @Retry as hedge against bucket listing eventual consistency. | 158 # Use @Retry as hedge against bucket listing eventual consistency. |
| 157 @Retry(AssertionError, tries=3, timeout_secs=1) | 159 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 158 def _Check2(): | 160 def _Check2(): |
| 159 # Check that re-running the same rsync command causes no more changes. | 161 # Check that re-running the same rsync command causes no more changes. |
| 160 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 162 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 161 ['rsync', suri(bucket1_uri), suri(bucket2_uri)], return_stderr=True)) | 163 ['rsync', suri(bucket1_uri), suri(bucket2_uri)], return_stderr=True)) |
| 162 _Check2() | 164 _Check2() |
| 163 | 165 |
| 164 # Now add and remove some objects in each bucket and test rsync -r. | 166 # Now add and remove some objects in each bucket and test rsync -r. |
| 165 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj6', | 167 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj6', |
| 166 contents='obj6') | 168 contents='obj6') |
| 167 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj7', | 169 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj7', |
| 168 contents='obj7') | 170 contents='obj7') |
| 169 self.RunGsUtil(['rm', suri(bucket1_uri, 'obj1')]) | 171 self.RunGsUtil(['rm', suri(bucket1_uri, 'obj1')]) |
| 170 self.RunGsUtil(['rm', suri(bucket2_uri, 'obj2')]) | 172 self.RunGsUtil(['rm', suri(bucket2_uri, '.obj2')]) |
| 171 | 173 |
| 172 # Use @Retry as hedge against bucket listing eventual consistency. | 174 # Use @Retry as hedge against bucket listing eventual consistency. |
| 173 @Retry(AssertionError, tries=3, timeout_secs=1) | 175 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 174 def _Check3(): | 176 def _Check3(): |
| 175 self.RunGsUtil(['rsync', '-r', suri(bucket1_uri), suri(bucket2_uri)]) | 177 self.RunGsUtil(['rsync', '-r', suri(bucket1_uri), suri(bucket2_uri)]) |
| 176 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) | 178 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) |
| 177 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) | 179 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) |
| 178 # First bucket should have un-altered content. | 180 # First bucket should have un-altered content. |
| 179 self.assertEquals(listing1, set(['/obj2', '/obj6', '/subdir/obj3'])) | 181 self.assertEquals(listing1, set(['/.obj2', '/obj6', '/subdir/obj3'])) |
| 180 # Second bucket should have objects tha were newly added to first bucket | 182 # Second bucket should have objects tha were newly added to first bucket |
| 181 # (wihout removing extraneous dest bucket objects), and without the | 183 # (wihout removing extraneous dest bucket objects), and without the |
| 182 # subdir objects synchronized. | 184 # subdir objects synchronized. |
| 183 self.assertEquals(listing2, set(['/obj1', '/obj2', '/obj4', '/obj6', | 185 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/obj4', '/obj6', |
| 184 '/obj7', '/subdir/obj3', | 186 '/obj7', '/subdir/obj3', |
| 185 '/subdir/obj5'])) | 187 '/subdir/obj5'])) |
| 186 _Check3() | 188 _Check3() |
| 187 | 189 |
| 188 # Use @Retry as hedge against bucket listing eventual consistency. | 190 # Use @Retry as hedge against bucket listing eventual consistency. |
| 189 @Retry(AssertionError, tries=3, timeout_secs=1) | 191 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 190 def _Check4(): | 192 def _Check4(): |
| 191 # Check that re-running the same rsync command causes no more changes. | 193 # Check that re-running the same rsync command causes no more changes. |
| 192 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 194 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 193 ['rsync', '-r', suri(bucket1_uri), suri(bucket2_uri)], | 195 ['rsync', '-r', suri(bucket1_uri), suri(bucket2_uri)], |
| 194 return_stderr=True)) | 196 return_stderr=True)) |
| 195 _Check4() | 197 _Check4() |
| 196 | 198 |
| 197 def test_bucket_to_bucket_minus_d(self): | 199 def test_bucket_to_bucket_minus_d(self): |
| 198 """Tests that flat and recursive rsync between 2 buckets works correctly.""" | 200 """Tests that flat and recursive rsync between 2 buckets works correctly.""" |
| 199 # Create 2 buckets with 1 overlapping object, 1 extra object at root level | 201 # Create 2 buckets with 1 overlapping object, 1 extra object at root level |
| 200 # in each, and 1 extra object 1 level down in each. Make the overlapping | 202 # in each, and 1 extra object 1 level down in each, where one of the objects |
| 201 # objects named the same but with different content, to test that we detect | 203 # starts with "." to test that we don't skip those objects. Make the |
| 202 # and properly copy in that case. | 204 # overlapping objects named the same but with different content, to test |
| 205 # that we detect and properly copy in that case. |
| 203 bucket1_uri = self.CreateBucket() | 206 bucket1_uri = self.CreateBucket() |
| 204 bucket2_uri = self.CreateBucket() | 207 bucket2_uri = self.CreateBucket() |
| 205 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj1', | 208 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj1', |
| 206 contents='obj1') | 209 contents='obj1') |
| 207 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj2', | 210 self.CreateObject(bucket_uri=bucket1_uri, object_name='.obj2', |
| 208 contents='obj2') | 211 contents='.obj2') |
| 209 self.CreateObject(bucket_uri=bucket1_uri, object_name='subdir/obj3', | 212 self.CreateObject(bucket_uri=bucket1_uri, object_name='subdir/obj3', |
| 210 contents='subdir/obj3') | 213 contents='subdir/obj3') |
| 211 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj2', | 214 self.CreateObject(bucket_uri=bucket2_uri, object_name='.obj2', |
| 212 contents='OBJ2') | 215 contents='.OBJ2') |
| 213 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj4', | 216 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj4', |
| 214 contents='obj4') | 217 contents='obj4') |
| 215 self.CreateObject(bucket_uri=bucket2_uri, object_name='subdir/obj5', | 218 self.CreateObject(bucket_uri=bucket2_uri, object_name='subdir/obj5', |
| 216 contents='subdir/obj5') | 219 contents='subdir/obj5') |
| 217 | 220 |
| 218 # Use @Retry as hedge against bucket listing eventual consistency. | 221 # Use @Retry as hedge against bucket listing eventual consistency. |
| 219 @Retry(AssertionError, tries=3, timeout_secs=1) | 222 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 220 def _Check1(): | 223 def _Check1(): |
| 221 """Tests rsync works as expected.""" | 224 """Tests rsync works as expected.""" |
| 222 self.RunGsUtil(['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)]) | 225 self.RunGsUtil(['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)]) |
| 223 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) | 226 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) |
| 224 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) | 227 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) |
| 225 # First bucket should have un-altered content. | 228 # First bucket should have un-altered content. |
| 226 self.assertEquals(listing1, set(['/obj1', '/obj2', '/subdir/obj3'])) | 229 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/subdir/obj3'])) |
| 227 # Second bucket should have content like first bucket but without the | 230 # Second bucket should have content like first bucket but without the |
| 228 # subdir objects synchronized. | 231 # subdir objects synchronized. |
| 229 self.assertEquals(listing2, set(['/obj1', '/obj2', '/subdir/obj5'])) | 232 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/subdir/obj5'])) |
| 230 # Assert that the src/dest objects that had same length but different | 233 # Assert that the src/dest objects that had same length but different |
| 231 # content were correctly synchronized (bucket to bucket sync uses | 234 # content were correctly synchronized (bucket to bucket sync uses |
| 232 # checksums). | 235 # checksums). |
| 233 self.assertEquals('obj2', self.RunGsUtil( | 236 self.assertEquals('.obj2', self.RunGsUtil( |
| 234 ['cat', suri(bucket1_uri, 'obj2')], return_stdout=True)) | 237 ['cat', suri(bucket1_uri, '.obj2')], return_stdout=True)) |
| 235 self.assertEquals('obj2', self.RunGsUtil( | 238 self.assertEquals('.obj2', self.RunGsUtil( |
| 236 ['cat', suri(bucket2_uri, 'obj2')], return_stdout=True)) | 239 ['cat', suri(bucket2_uri, '.obj2')], return_stdout=True)) |
| 237 _Check1() | 240 _Check1() |
| 238 | 241 |
| 239 # Use @Retry as hedge against bucket listing eventual consistency. | 242 # Use @Retry as hedge against bucket listing eventual consistency. |
| 240 @Retry(AssertionError, tries=3, timeout_secs=1) | 243 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 241 def _Check2(): | 244 def _Check2(): |
| 242 # Check that re-running the same rsync command causes no more changes. | 245 # Check that re-running the same rsync command causes no more changes. |
| 243 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 246 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 244 ['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)], | 247 ['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)], |
| 245 return_stderr=True)) | 248 return_stderr=True)) |
| 246 _Check2() | 249 _Check2() |
| 247 | 250 |
| 248 # Now add and remove some objects in each bucket and test rsync -r. | 251 # Now add and remove some objects in each bucket and test rsync -r. |
| 249 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj6', | 252 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj6', |
| 250 contents='obj6') | 253 contents='obj6') |
| 251 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj7', | 254 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj7', |
| 252 contents='obj7') | 255 contents='obj7') |
| 253 self.RunGsUtil(['rm', suri(bucket1_uri, 'obj1')]) | 256 self.RunGsUtil(['rm', suri(bucket1_uri, 'obj1')]) |
| 254 self.RunGsUtil(['rm', suri(bucket2_uri, 'obj2')]) | 257 self.RunGsUtil(['rm', suri(bucket2_uri, '.obj2')]) |
| 255 | 258 |
| 256 # Use @Retry as hedge against bucket listing eventual consistency. | 259 # Use @Retry as hedge against bucket listing eventual consistency. |
| 257 @Retry(AssertionError, tries=3, timeout_secs=1) | 260 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 258 def _Check3(): | 261 def _Check3(): |
| 259 self.RunGsUtil(['rsync', '-d', '-r', | 262 self.RunGsUtil(['rsync', '-d', '-r', |
| 260 suri(bucket1_uri), suri(bucket2_uri)]) | 263 suri(bucket1_uri), suri(bucket2_uri)]) |
| 261 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) | 264 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) |
| 262 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) | 265 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) |
| 263 # First bucket should have un-altered content. | 266 # First bucket should have un-altered content. |
| 264 self.assertEquals(listing1, set(['/obj2', '/obj6', '/subdir/obj3'])) | 267 self.assertEquals(listing1, set(['/.obj2', '/obj6', '/subdir/obj3'])) |
| 265 # Second bucket should have content like first bucket but without the | 268 # Second bucket should have content like first bucket but without the |
| 266 # subdir objects synchronized. | 269 # subdir objects synchronized. |
| 267 self.assertEquals(listing2, set(['/obj2', '/obj6', '/subdir/obj3'])) | 270 self.assertEquals(listing2, set(['/.obj2', '/obj6', '/subdir/obj3'])) |
| 268 _Check3() | 271 _Check3() |
| 269 | 272 |
| 270 # Use @Retry as hedge against bucket listing eventual consistency. | 273 # Use @Retry as hedge against bucket listing eventual consistency. |
| 271 @Retry(AssertionError, tries=3, timeout_secs=1) | 274 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 272 def _Check4(): | 275 def _Check4(): |
| 273 # Check that re-running the same rsync command causes no more changes. | 276 # Check that re-running the same rsync command causes no more changes. |
| 274 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 277 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 275 ['rsync', '-d', '-r', suri(bucket1_uri), suri(bucket2_uri)], | 278 ['rsync', '-d', '-r', suri(bucket1_uri), suri(bucket2_uri)], |
| 276 return_stderr=True)) | 279 return_stderr=True)) |
| 277 _Check4() | 280 _Check4() |
| 278 | 281 |
| 279 # Test sequential upload as well as parallel composite upload case. | 282 # Test sequential upload as well as parallel composite upload case. |
| 280 @PerformsFileToObjectUpload | 283 @SequentialAndParallelTransfer |
| 281 @unittest.skipUnless(UsingCrcmodExtension(crcmod), | 284 @unittest.skipUnless(UsingCrcmodExtension(crcmod), |
| 282 'Test requires fast crcmod.') | 285 'Test requires fast crcmod.') |
| 283 def test_dir_to_bucket_minus_d(self): | 286 def test_dir_to_bucket_minus_d(self): |
| 284 """Tests that flat and recursive rsync dir to bucket works correctly.""" | 287 """Tests that flat and recursive rsync dir to bucket works correctly.""" |
| 285 # Create dir and bucket with 1 overlapping object, 1 extra object at root | 288 # Create dir and bucket with 1 overlapping object, 1 extra object at root |
| 286 # level in each, and 1 extra object 1 level down in each. Make the | 289 # level in each, and 1 extra object 1 level down in each, where one of the |
| 290 # objects starts with "." to test that we don't skip those objects. Make the |
| 287 # overlapping objects named the same but with different content, to test | 291 # overlapping objects named the same but with different content, to test |
| 288 # that we detect and properly copy in that case. | 292 # that we detect and properly copy in that case. |
| 289 tmpdir = self.CreateTempDir() | 293 tmpdir = self.CreateTempDir() |
| 290 subdir = os.path.join(tmpdir, 'subdir') | 294 subdir = os.path.join(tmpdir, 'subdir') |
| 291 os.mkdir(subdir) | 295 os.mkdir(subdir) |
| 292 bucket_uri = self.CreateBucket() | 296 bucket_uri = self.CreateBucket() |
| 293 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') | 297 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') |
| 294 self.CreateTempFile(tmpdir=tmpdir, file_name='obj2', contents='obj2') | 298 self.CreateTempFile(tmpdir=tmpdir, file_name='.obj2', contents='.obj2') |
| 295 self.CreateTempFile(tmpdir=subdir, file_name='obj3', contents='subdir/obj3') | 299 self.CreateTempFile(tmpdir=subdir, file_name='obj3', contents='subdir/obj3') |
| 296 self.CreateObject(bucket_uri=bucket_uri, object_name='obj2', | 300 self.CreateObject(bucket_uri=bucket_uri, object_name='.obj2', |
| 297 contents='OBJ2') | 301 contents='.OBJ2') |
| 298 self.CreateObject(bucket_uri=bucket_uri, object_name='obj4', | 302 self.CreateObject(bucket_uri=bucket_uri, object_name='obj4', |
| 299 contents='obj4') | 303 contents='obj4') |
| 300 self.CreateObject(bucket_uri=bucket_uri, object_name='subdir/obj5', | 304 self.CreateObject(bucket_uri=bucket_uri, object_name='subdir/obj5', |
| 301 contents='subdir/obj5') | 305 contents='subdir/obj5') |
| 302 | 306 |
| 303 # Need to make sure the bucket listing is caught-up, otherwise the | 307 # Need to make sure the bucket listing is caught-up, otherwise the |
| 304 # first rsync may not see obj2 and overwrite it. | 308 # first rsync may not see .obj2 and overwrite it. |
| 305 self.AssertNObjectsInBucket(bucket_uri, 3) | 309 self.AssertNObjectsInBucket(bucket_uri, 3) |
| 306 | 310 |
| 307 # Use @Retry as hedge against bucket listing eventual consistency. | 311 # Use @Retry as hedge against bucket listing eventual consistency. |
| 308 @Retry(AssertionError, tries=3, timeout_secs=1) | 312 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 309 def _Check1(): | 313 def _Check1(): |
| 310 """Tests rsync works as expected.""" | 314 """Tests rsync works as expected.""" |
| 311 self.RunGsUtil(['rsync', '-d', tmpdir, suri(bucket_uri)]) | 315 self.RunGsUtil(['rsync', '-d', tmpdir, suri(bucket_uri)]) |
| 312 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 316 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 313 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 317 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 314 # Dir should have un-altered content. | 318 # Dir should have un-altered content. |
| 315 self.assertEquals(listing1, set(['/obj1', '/obj2', '/subdir/obj3'])) | 319 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/subdir/obj3'])) |
| 316 # Bucket should have content like dir but without the subdir objects | 320 # Bucket should have content like dir but without the subdir objects |
| 317 # synchronized. | 321 # synchronized. |
| 318 self.assertEquals(listing2, set(['/obj1', '/obj2', '/subdir/obj5'])) | 322 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/subdir/obj5'])) |
| 319 # Assert that the src/dest objects that had same length but different | 323 # Assert that the src/dest objects that had same length but different |
| 320 # content were not synchronized (dir to bucket sync doesn't use checksums | 324 # content were not synchronized (dir to bucket sync doesn't use checksums |
| 321 # unless you specify -c). | 325 # unless you specify -c). |
| 322 with open(os.path.join(tmpdir, 'obj2')) as f: | 326 with open(os.path.join(tmpdir, '.obj2')) as f: |
| 323 self.assertEquals('obj2', '\n'.join(f.readlines())) | 327 self.assertEquals('.obj2', '\n'.join(f.readlines())) |
| 324 self.assertEquals('OBJ2', self.RunGsUtil( | 328 self.assertEquals('.OBJ2', self.RunGsUtil( |
| 325 ['cat', suri(bucket_uri, 'obj2')], return_stdout=True)) | 329 ['cat', suri(bucket_uri, '.obj2')], return_stdout=True)) |
| 326 _Check1() | 330 _Check1() |
| 327 | 331 |
| 328 # Use @Retry as hedge against bucket listing eventual consistency. | 332 # Use @Retry as hedge against bucket listing eventual consistency. |
| 329 @Retry(AssertionError, tries=3, timeout_secs=1) | 333 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 330 def _Check2(): | 334 def _Check2(): |
| 331 # Check that re-running the same rsync command causes no more changes. | 335 # Check that re-running the same rsync command causes no more changes. |
| 332 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 336 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 333 ['rsync', '-d', tmpdir, suri(bucket_uri)], return_stderr=True)) | 337 ['rsync', '-d', tmpdir, suri(bucket_uri)], return_stderr=True)) |
| 334 _Check2() | 338 _Check2() |
| 335 | 339 |
| 336 # Now rerun the sync with the -c option. | 340 # Now rerun the sync with the -c option. |
| 337 # Use @Retry as hedge against bucket listing eventual consistency. | 341 # Use @Retry as hedge against bucket listing eventual consistency. |
| 338 @Retry(AssertionError, tries=3, timeout_secs=1) | 342 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 339 def _Check3(): | 343 def _Check3(): |
| 340 """Tests rsync -c works as expected.""" | 344 """Tests rsync -c works as expected.""" |
| 341 self.RunGsUtil(['rsync', '-d', '-c', tmpdir, suri(bucket_uri)]) | 345 self.RunGsUtil(['rsync', '-d', '-c', tmpdir, suri(bucket_uri)]) |
| 342 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 346 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 343 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 347 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 344 # Dir should have un-altered content. | 348 # Dir should have un-altered content. |
| 345 self.assertEquals(listing1, set(['/obj1', '/obj2', '/subdir/obj3'])) | 349 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/subdir/obj3'])) |
| 346 # Bucket should have content like dir but without the subdir objects | 350 # Bucket should have content like dir but without the subdir objects |
| 347 # synchronized. | 351 # synchronized. |
| 348 self.assertEquals(listing2, set(['/obj1', '/obj2', '/subdir/obj5'])) | 352 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/subdir/obj5'])) |
| 349 # Assert that the src/dest objects that had same length but different | 353 # Assert that the src/dest objects that had same length but different |
| 350 # content were synchronized (dir to bucket sync with -c uses checksums). | 354 # content were synchronized (dir to bucket sync with -c uses checksums). |
| 351 with open(os.path.join(tmpdir, 'obj2')) as f: | 355 with open(os.path.join(tmpdir, '.obj2')) as f: |
| 352 self.assertEquals('obj2', '\n'.join(f.readlines())) | 356 self.assertEquals('.obj2', '\n'.join(f.readlines())) |
| 353 self.assertEquals('obj2', self.RunGsUtil( | 357 self.assertEquals('.obj2', self.RunGsUtil( |
| 354 ['cat', suri(bucket_uri, 'obj2')], return_stdout=True)) | 358 ['cat', suri(bucket_uri, '.obj2')], return_stdout=True)) |
| 355 _Check3() | 359 _Check3() |
| 356 | 360 |
| 357 # Use @Retry as hedge against bucket listing eventual consistency. | 361 # Use @Retry as hedge against bucket listing eventual consistency. |
| 358 @Retry(AssertionError, tries=3, timeout_secs=1) | 362 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 359 def _Check4(): | 363 def _Check4(): |
| 360 # Check that re-running the same rsync command causes no more changes. | 364 # Check that re-running the same rsync command causes no more changes. |
| 361 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 365 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 362 ['rsync', '-d', '-c', tmpdir, suri(bucket_uri)], return_stderr=True)) | 366 ['rsync', '-d', '-c', tmpdir, suri(bucket_uri)], return_stderr=True)) |
| 363 _Check4() | 367 _Check4() |
| 364 | 368 |
| 365 # Now add and remove some objects in dir and bucket and test rsync -r. | 369 # Now add and remove some objects in dir and bucket and test rsync -r. |
| 366 self.CreateTempFile(tmpdir=tmpdir, file_name='obj6', contents='obj6') | 370 self.CreateTempFile(tmpdir=tmpdir, file_name='obj6', contents='obj6') |
| 367 self.CreateObject(bucket_uri=bucket_uri, object_name='obj7', | 371 self.CreateObject(bucket_uri=bucket_uri, object_name='obj7', |
| 368 contents='obj7') | 372 contents='obj7') |
| 369 os.unlink(os.path.join(tmpdir, 'obj1')) | 373 os.unlink(os.path.join(tmpdir, 'obj1')) |
| 370 self.RunGsUtil(['rm', suri(bucket_uri, 'obj2')]) | 374 self.RunGsUtil(['rm', suri(bucket_uri, '.obj2')]) |
| 371 | 375 |
| 372 # Use @Retry as hedge against bucket listing eventual consistency. | 376 # Use @Retry as hedge against bucket listing eventual consistency. |
| 373 @Retry(AssertionError, tries=3, timeout_secs=1) | 377 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 374 def _Check5(): | 378 def _Check5(): |
| 375 self.RunGsUtil(['rsync', '-d', '-r', tmpdir, suri(bucket_uri)]) | 379 self.RunGsUtil(['rsync', '-d', '-r', tmpdir, suri(bucket_uri)]) |
| 376 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 380 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 377 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 381 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 378 # Dir should have un-altered content. | 382 # Dir should have un-altered content. |
| 379 self.assertEquals(listing1, set(['/obj2', '/obj6', '/subdir/obj3'])) | 383 self.assertEquals(listing1, set(['/.obj2', '/obj6', '/subdir/obj3'])) |
| 380 # Bucket should have content like dir but without the subdir objects | 384 # Bucket should have content like dir but without the subdir objects |
| 381 # synchronized. | 385 # synchronized. |
| 382 self.assertEquals(listing2, set(['/obj2', '/obj6', '/subdir/obj3'])) | 386 self.assertEquals(listing2, set(['/.obj2', '/obj6', '/subdir/obj3'])) |
| 383 _Check5() | 387 _Check5() |
| 384 | 388 |
| 385 # Use @Retry as hedge against bucket listing eventual consistency. | 389 # Use @Retry as hedge against bucket listing eventual consistency. |
| 386 @Retry(AssertionError, tries=3, timeout_secs=1) | 390 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 387 def _Check6(): | 391 def _Check6(): |
| 388 # Check that re-running the same rsync command causes no more changes. | 392 # Check that re-running the same rsync command causes no more changes. |
| 389 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 393 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 390 ['rsync', '-d', '-r', tmpdir, suri(bucket_uri)], return_stderr=True)) | 394 ['rsync', '-d', '-r', tmpdir, suri(bucket_uri)], return_stderr=True)) |
| 391 _Check6() | 395 _Check6() |
| 392 | 396 |
| 393 @unittest.skipUnless(UsingCrcmodExtension(crcmod), | 397 @unittest.skipUnless(UsingCrcmodExtension(crcmod), |
| 394 'Test requires fast crcmod.') | 398 'Test requires fast crcmod.') |
| 395 def test_dir_to_dir_minus_d(self): | 399 def test_dir_to_dir_minus_d(self): |
| 396 """Tests that flat and recursive rsync dir to dir works correctly.""" | 400 """Tests that flat and recursive rsync dir to dir works correctly.""" |
| 397 # Create 2 dirs with 1 overlapping file, 1 extra file at root | 401 # Create 2 dirs with 1 overlapping file, 1 extra file at root |
| 398 # level in each, and 1 extra file 1 level down in each. Make the | 402 # level in each, and 1 extra file 1 level down in each, where one of the |
| 403 # objects starts with "." to test that we don't skip those objects. Make the |
| 399 # overlapping files named the same but with different content, to test | 404 # overlapping files named the same but with different content, to test |
| 400 # that we detect and properly copy in that case. | 405 # that we detect and properly copy in that case. |
| 401 tmpdir1 = self.CreateTempDir() | 406 tmpdir1 = self.CreateTempDir() |
| 402 tmpdir2 = self.CreateTempDir() | 407 tmpdir2 = self.CreateTempDir() |
| 403 subdir1 = os.path.join(tmpdir1, 'subdir1') | 408 subdir1 = os.path.join(tmpdir1, 'subdir1') |
| 404 subdir2 = os.path.join(tmpdir2, 'subdir2') | 409 subdir2 = os.path.join(tmpdir2, 'subdir2') |
| 405 os.mkdir(subdir1) | 410 os.mkdir(subdir1) |
| 406 os.mkdir(subdir2) | 411 os.mkdir(subdir2) |
| 407 self.CreateTempFile(tmpdir=tmpdir1, file_name='obj1', contents='obj1') | 412 self.CreateTempFile(tmpdir=tmpdir1, file_name='obj1', contents='obj1') |
| 408 self.CreateTempFile(tmpdir=tmpdir1, file_name='obj2', contents='obj2') | 413 self.CreateTempFile(tmpdir=tmpdir1, file_name='.obj2', contents='.obj2') |
| 409 self.CreateTempFile( | 414 self.CreateTempFile( |
| 410 tmpdir=subdir1, file_name='obj3', contents='subdir1/obj3') | 415 tmpdir=subdir1, file_name='obj3', contents='subdir1/obj3') |
| 411 self.CreateTempFile(tmpdir=tmpdir2, file_name='obj2', contents='OBJ2') | 416 self.CreateTempFile(tmpdir=tmpdir2, file_name='.obj2', contents='.OBJ2') |
| 412 self.CreateTempFile(tmpdir=tmpdir2, file_name='obj4', contents='obj4') | 417 self.CreateTempFile(tmpdir=tmpdir2, file_name='obj4', contents='obj4') |
| 413 self.CreateTempFile( | 418 self.CreateTempFile( |
| 414 tmpdir=subdir2, file_name='obj5', contents='subdir2/obj5') | 419 tmpdir=subdir2, file_name='obj5', contents='subdir2/obj5') |
| 415 | 420 |
| 416 self.RunGsUtil(['rsync', '-d', tmpdir1, tmpdir2]) | 421 self.RunGsUtil(['rsync', '-d', tmpdir1, tmpdir2]) |
| 417 listing1 = _TailSet(tmpdir1, self._FlatListDir(tmpdir1)) | 422 listing1 = _TailSet(tmpdir1, self._FlatListDir(tmpdir1)) |
| 418 listing2 = _TailSet(tmpdir2, self._FlatListDir(tmpdir2)) | 423 listing2 = _TailSet(tmpdir2, self._FlatListDir(tmpdir2)) |
| 419 # dir1 should have un-altered content. | 424 # dir1 should have un-altered content. |
| 420 self.assertEquals(listing1, set(['/obj1', '/obj2', '/subdir1/obj3'])) | 425 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/subdir1/obj3'])) |
| 421 # dir2 should have content like dir1 but without the subdir1 objects | 426 # dir2 should have content like dir1 but without the subdir1 objects |
| 422 # synchronized. | 427 # synchronized. |
| 423 self.assertEquals(listing2, set(['/obj1', '/obj2', '/subdir2/obj5'])) | 428 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/subdir2/obj5'])) |
| 424 # Assert that the src/dest objects that had same length but different | 429 # Assert that the src/dest objects that had same length but different |
| 425 # checksums were not synchronized (dir to dir sync doesn't use checksums | 430 # checksums were not synchronized (dir to dir sync doesn't use checksums |
| 426 # unless you specify -c). | 431 # unless you specify -c). |
| 427 with open(os.path.join(tmpdir1, 'obj2')) as f: | 432 with open(os.path.join(tmpdir1, '.obj2')) as f: |
| 428 self.assertEquals('obj2', '\n'.join(f.readlines())) | 433 self.assertEquals('.obj2', '\n'.join(f.readlines())) |
| 429 with open(os.path.join(tmpdir2, 'obj2')) as f: | 434 with open(os.path.join(tmpdir2, '.obj2')) as f: |
| 430 self.assertEquals('OBJ2', '\n'.join(f.readlines())) | 435 self.assertEquals('.OBJ2', '\n'.join(f.readlines())) |
| 431 | 436 |
| 432 # Use @Retry as hedge against bucket listing eventual consistency. | 437 # Use @Retry as hedge against bucket listing eventual consistency. |
| 433 @Retry(AssertionError, tries=3, timeout_secs=1) | 438 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 434 def _Check1(): | 439 def _Check1(): |
| 435 # Check that re-running the same rsync command causes no more changes. | 440 # Check that re-running the same rsync command causes no more changes. |
| 436 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 441 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 437 ['rsync', '-d', tmpdir1, tmpdir2], return_stderr=True)) | 442 ['rsync', '-d', tmpdir1, tmpdir2], return_stderr=True)) |
| 438 _Check1() | 443 _Check1() |
| 439 | 444 |
| 440 # Now rerun the sync with the -c option. | 445 # Now rerun the sync with the -c option. |
| 441 self.RunGsUtil(['rsync', '-d', '-c', tmpdir1, tmpdir2]) | 446 self.RunGsUtil(['rsync', '-d', '-c', tmpdir1, tmpdir2]) |
| 442 listing1 = _TailSet(tmpdir1, self._FlatListDir(tmpdir1)) | 447 listing1 = _TailSet(tmpdir1, self._FlatListDir(tmpdir1)) |
| 443 listing2 = _TailSet(tmpdir2, self._FlatListDir(tmpdir2)) | 448 listing2 = _TailSet(tmpdir2, self._FlatListDir(tmpdir2)) |
| 444 # dir1 should have un-altered content. | 449 # dir1 should have un-altered content. |
| 445 self.assertEquals(listing1, set(['/obj1', '/obj2', '/subdir1/obj3'])) | 450 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/subdir1/obj3'])) |
| 446 # dir2 should have content like dir but without the subdir objects | 451 # dir2 should have content like dir but without the subdir objects |
| 447 # synchronized. | 452 # synchronized. |
| 448 self.assertEquals(listing2, set(['/obj1', '/obj2', '/subdir2/obj5'])) | 453 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/subdir2/obj5'])) |
| 449 # Assert that the src/dest objects that had same length but different | 454 # Assert that the src/dest objects that had same length but different |
| 450 # content were synchronized (dir to dir sync with -c uses checksums). | 455 # content were synchronized (dir to dir sync with -c uses checksums). |
| 451 with open(os.path.join(tmpdir1, 'obj2')) as f: | 456 with open(os.path.join(tmpdir1, '.obj2')) as f: |
| 452 self.assertEquals('obj2', '\n'.join(f.readlines())) | 457 self.assertEquals('.obj2', '\n'.join(f.readlines())) |
| 453 with open(os.path.join(tmpdir1, 'obj2')) as f: | 458 with open(os.path.join(tmpdir1, '.obj2')) as f: |
| 454 self.assertEquals('obj2', '\n'.join(f.readlines())) | 459 self.assertEquals('.obj2', '\n'.join(f.readlines())) |
| 455 | 460 |
| 456 # Use @Retry as hedge against bucket listing eventual consistency. | 461 # Use @Retry as hedge against bucket listing eventual consistency. |
| 457 @Retry(AssertionError, tries=3, timeout_secs=1) | 462 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 458 def _Check2(): | 463 def _Check2(): |
| 459 # Check that re-running the same rsync command causes no more changes. | 464 # Check that re-running the same rsync command causes no more changes. |
| 460 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 465 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 461 ['rsync', '-d', '-c', tmpdir1, tmpdir2], return_stderr=True)) | 466 ['rsync', '-d', '-c', tmpdir1, tmpdir2], return_stderr=True)) |
| 462 _Check2() | 467 _Check2() |
| 463 | 468 |
| 464 # Now add and remove some objects in both dirs and test rsync -r. | 469 # Now add and remove some objects in both dirs and test rsync -r. |
| 465 self.CreateTempFile(tmpdir=tmpdir1, file_name='obj6', contents='obj6') | 470 self.CreateTempFile(tmpdir=tmpdir1, file_name='obj6', contents='obj6') |
| 466 self.CreateTempFile(tmpdir=tmpdir2, file_name='obj7', contents='obj7') | 471 self.CreateTempFile(tmpdir=tmpdir2, file_name='obj7', contents='obj7') |
| 467 os.unlink(os.path.join(tmpdir1, 'obj1')) | 472 os.unlink(os.path.join(tmpdir1, 'obj1')) |
| 468 os.unlink(os.path.join(tmpdir2, 'obj2')) | 473 os.unlink(os.path.join(tmpdir2, '.obj2')) |
| 469 | 474 |
| 470 self.RunGsUtil(['rsync', '-d', '-r', tmpdir1, tmpdir2]) | 475 self.RunGsUtil(['rsync', '-d', '-r', tmpdir1, tmpdir2]) |
| 471 listing1 = _TailSet(tmpdir1, self._FlatListDir(tmpdir1)) | 476 listing1 = _TailSet(tmpdir1, self._FlatListDir(tmpdir1)) |
| 472 listing2 = _TailSet(tmpdir2, self._FlatListDir(tmpdir2)) | 477 listing2 = _TailSet(tmpdir2, self._FlatListDir(tmpdir2)) |
| 473 # dir1 should have un-altered content. | 478 # dir1 should have un-altered content. |
| 474 self.assertEquals(listing1, set(['/obj2', '/obj6', '/subdir1/obj3'])) | 479 self.assertEquals(listing1, set(['/.obj2', '/obj6', '/subdir1/obj3'])) |
| 475 # dir2 should have content like dir but without the subdir objects | 480 # dir2 should have content like dir but without the subdir objects |
| 476 # synchronized. | 481 # synchronized. |
| 477 self.assertEquals(listing2, set(['/obj2', '/obj6', '/subdir1/obj3'])) | 482 self.assertEquals(listing2, set(['/.obj2', '/obj6', '/subdir1/obj3'])) |
| 478 | 483 |
| 479 # Use @Retry as hedge against bucket listing eventual consistency. | 484 # Use @Retry as hedge against bucket listing eventual consistency. |
| 480 @Retry(AssertionError, tries=3, timeout_secs=1) | 485 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 481 def _Check3(): | 486 def _Check3(): |
| 482 # Check that re-running the same rsync command causes no more changes. | 487 # Check that re-running the same rsync command causes no more changes. |
| 483 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 488 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 484 ['rsync', '-d', '-r', tmpdir1, tmpdir2], return_stderr=True)) | 489 ['rsync', '-d', '-r', tmpdir1, tmpdir2], return_stderr=True)) |
| 485 _Check3() | 490 _Check3() |
| 486 | 491 |
| 487 def test_dir_to_dir_minus_d_more_files_than_bufsize(self): | 492 def test_dir_to_dir_minus_d_more_files_than_bufsize(self): |
| (...skipping 23 matching lines...) Expand all Loading... |
| 511 # Check that re-running the same rsync command causes no more changes. | 516 # Check that re-running the same rsync command causes no more changes. |
| 512 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 517 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 513 ['rsync', '-d', tmpdir1, tmpdir2], return_stderr=True)) | 518 ['rsync', '-d', tmpdir1, tmpdir2], return_stderr=True)) |
| 514 _Check() | 519 _Check() |
| 515 | 520 |
| 516 @unittest.skipUnless(UsingCrcmodExtension(crcmod), | 521 @unittest.skipUnless(UsingCrcmodExtension(crcmod), |
| 517 'Test requires fast crcmod.') | 522 'Test requires fast crcmod.') |
| 518 def test_bucket_to_dir_minus_d(self): | 523 def test_bucket_to_dir_minus_d(self): |
| 519 """Tests that flat and recursive rsync bucket to dir works correctly.""" | 524 """Tests that flat and recursive rsync bucket to dir works correctly.""" |
| 520 # Create bucket and dir with 1 overlapping object, 1 extra object at root | 525 # Create bucket and dir with 1 overlapping object, 1 extra object at root |
| 521 # level in each, and 1 extra object 1 level down in each. Make the | 526 # level in each, and 1 extra object 1 level down in each, where one of the |
| 527 # objects starts with "." to test that we don't skip those objects. Make the |
| 522 # overlapping objects named the same but with different content, to test | 528 # overlapping objects named the same but with different content, to test |
| 523 # that we detect and properly copy in that case. | 529 # that we detect and properly copy in that case. |
| 524 bucket_uri = self.CreateBucket() | 530 bucket_uri = self.CreateBucket() |
| 525 tmpdir = self.CreateTempDir() | 531 tmpdir = self.CreateTempDir() |
| 526 subdir = os.path.join(tmpdir, 'subdir') | 532 subdir = os.path.join(tmpdir, 'subdir') |
| 527 os.mkdir(subdir) | 533 os.mkdir(subdir) |
| 528 self.CreateObject(bucket_uri=bucket_uri, object_name='obj1', | 534 self.CreateObject(bucket_uri=bucket_uri, object_name='obj1', |
| 529 contents='obj1') | 535 contents='obj1') |
| 530 self.CreateObject(bucket_uri=bucket_uri, object_name='obj2', | 536 self.CreateObject(bucket_uri=bucket_uri, object_name='.obj2', |
| 531 contents='obj2') | 537 contents='.obj2') |
| 532 self.CreateObject(bucket_uri=bucket_uri, object_name='subdir/obj3', | 538 self.CreateObject(bucket_uri=bucket_uri, object_name='subdir/obj3', |
| 533 contents='subdir/obj3') | 539 contents='subdir/obj3') |
| 534 self.CreateTempFile(tmpdir=tmpdir, file_name='obj2', contents='OBJ2') | 540 self.CreateTempFile(tmpdir=tmpdir, file_name='.obj2', contents='.OBJ2') |
| 535 self.CreateTempFile(tmpdir=tmpdir, file_name='obj4', contents='obj4') | 541 self.CreateTempFile(tmpdir=tmpdir, file_name='obj4', contents='obj4') |
| 536 self.CreateTempFile(tmpdir=subdir, file_name='obj5', contents='subdir/obj5') | 542 self.CreateTempFile(tmpdir=subdir, file_name='obj5', contents='subdir/obj5') |
| 537 | 543 |
| 538 # Use @Retry as hedge against bucket listing eventual consistency. | 544 # Use @Retry as hedge against bucket listing eventual consistency. |
| 539 @Retry(AssertionError, tries=3, timeout_secs=1) | 545 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 540 def _Check1(): | 546 def _Check1(): |
| 541 """Tests rsync works as expected.""" | 547 """Tests rsync works as expected.""" |
| 542 self.RunGsUtil(['rsync', '-d', suri(bucket_uri), tmpdir]) | 548 self.RunGsUtil(['rsync', '-d', suri(bucket_uri), tmpdir]) |
| 543 listing1 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 549 listing1 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 544 listing2 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 550 listing2 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 545 # Bucket should have un-altered content. | 551 # Bucket should have un-altered content. |
| 546 self.assertEquals(listing1, set(['/obj1', '/obj2', '/subdir/obj3'])) | 552 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/subdir/obj3'])) |
| 547 # Dir should have content like bucket but without the subdir objects | 553 # Dir should have content like bucket but without the subdir objects |
| 548 # synchronized. | 554 # synchronized. |
| 549 self.assertEquals(listing2, set(['/obj1', '/obj2', '/subdir/obj5'])) | 555 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/subdir/obj5'])) |
| 550 # Assert that the src/dest objects that had same length but different | 556 # Assert that the src/dest objects that had same length but different |
| 551 # content were not synchronized (bucket to dir sync doesn't use checksums | 557 # content were not synchronized (bucket to dir sync doesn't use checksums |
| 552 # unless you specify -c). | 558 # unless you specify -c). |
| 553 self.assertEquals('obj2', self.RunGsUtil( | 559 self.assertEquals('.obj2', self.RunGsUtil( |
| 554 ['cat', suri(bucket_uri, 'obj2')], return_stdout=True)) | 560 ['cat', suri(bucket_uri, '.obj2')], return_stdout=True)) |
| 555 with open(os.path.join(tmpdir, 'obj2')) as f: | 561 with open(os.path.join(tmpdir, '.obj2')) as f: |
| 556 self.assertEquals('OBJ2', '\n'.join(f.readlines())) | 562 self.assertEquals('.OBJ2', '\n'.join(f.readlines())) |
| 557 _Check1() | 563 _Check1() |
| 558 | 564 |
| 559 # Use @Retry as hedge against bucket listing eventual consistency. | 565 # Use @Retry as hedge against bucket listing eventual consistency. |
| 560 @Retry(AssertionError, tries=3, timeout_secs=1) | 566 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 561 def _Check2(): | 567 def _Check2(): |
| 562 # Check that re-running the same rsync command causes no more changes. | 568 # Check that re-running the same rsync command causes no more changes. |
| 563 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 569 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 564 ['rsync', '-d', suri(bucket_uri), tmpdir], return_stderr=True)) | 570 ['rsync', '-d', suri(bucket_uri), tmpdir], return_stderr=True)) |
| 565 _Check2() | 571 _Check2() |
| 566 | 572 |
| 567 # Now rerun the sync with the -c option. | 573 # Now rerun the sync with the -c option. |
| 568 # Use @Retry as hedge against bucket listing eventual consistency. | 574 # Use @Retry as hedge against bucket listing eventual consistency. |
| 569 @Retry(AssertionError, tries=3, timeout_secs=1) | 575 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 570 def _Check3(): | 576 def _Check3(): |
| 571 """Tests rsync -c works as expected.""" | 577 """Tests rsync -c works as expected.""" |
| 572 self.RunGsUtil(['rsync', '-d', '-c', suri(bucket_uri), tmpdir]) | 578 self.RunGsUtil(['rsync', '-d', '-c', suri(bucket_uri), tmpdir]) |
| 573 listing1 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 579 listing1 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 574 listing2 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 580 listing2 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 575 # Bucket should have un-altered content. | 581 # Bucket should have un-altered content. |
| 576 self.assertEquals(listing1, set(['/obj1', '/obj2', '/subdir/obj3'])) | 582 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/subdir/obj3'])) |
| 577 # Dir should have content like bucket but without the subdir objects | 583 # Dir should have content like bucket but without the subdir objects |
| 578 # synchronized. | 584 # synchronized. |
| 579 self.assertEquals(listing2, set(['/obj1', '/obj2', '/subdir/obj5'])) | 585 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/subdir/obj5'])) |
| 580 # Assert that the src/dest objects that had same length but different | 586 # Assert that the src/dest objects that had same length but different |
| 581 # content were synchronized (bucket to dir sync with -c uses checksums). | 587 # content were synchronized (bucket to dir sync with -c uses checksums). |
| 582 self.assertEquals('obj2', self.RunGsUtil( | 588 self.assertEquals('.obj2', self.RunGsUtil( |
| 583 ['cat', suri(bucket_uri, 'obj2')], return_stdout=True)) | 589 ['cat', suri(bucket_uri, '.obj2')], return_stdout=True)) |
| 584 with open(os.path.join(tmpdir, 'obj2')) as f: | 590 with open(os.path.join(tmpdir, '.obj2')) as f: |
| 585 self.assertEquals('obj2', '\n'.join(f.readlines())) | 591 self.assertEquals('.obj2', '\n'.join(f.readlines())) |
| 586 _Check3() | 592 _Check3() |
| 587 | 593 |
| 588 # Use @Retry as hedge against bucket listing eventual consistency. | 594 # Use @Retry as hedge against bucket listing eventual consistency. |
| 589 @Retry(AssertionError, tries=3, timeout_secs=1) | 595 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 590 def _Check4(): | 596 def _Check4(): |
| 591 # Check that re-running the same rsync command causes no more changes. | 597 # Check that re-running the same rsync command causes no more changes. |
| 592 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 598 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 593 ['rsync', '-d', '-c', suri(bucket_uri), tmpdir], return_stderr=True)) | 599 ['rsync', '-d', '-c', suri(bucket_uri), tmpdir], return_stderr=True)) |
| 594 _Check4() | 600 _Check4() |
| 595 | 601 |
| 596 # Now add and remove some objects in dir and bucket and test rsync -r. | 602 # Now add and remove some objects in dir and bucket and test rsync -r. |
| 597 self.CreateObject(bucket_uri=bucket_uri, object_name='obj6', | 603 self.CreateObject(bucket_uri=bucket_uri, object_name='obj6', |
| 598 contents='obj6') | 604 contents='obj6') |
| 599 self.CreateTempFile(tmpdir=tmpdir, file_name='obj7', contents='obj7') | 605 self.CreateTempFile(tmpdir=tmpdir, file_name='obj7', contents='obj7') |
| 600 self.RunGsUtil(['rm', suri(bucket_uri, 'obj1')]) | 606 self.RunGsUtil(['rm', suri(bucket_uri, 'obj1')]) |
| 601 os.unlink(os.path.join(tmpdir, 'obj2')) | 607 os.unlink(os.path.join(tmpdir, '.obj2')) |
| 602 | 608 |
| 603 # Use @Retry as hedge against bucket listing eventual consistency. | 609 # Use @Retry as hedge against bucket listing eventual consistency. |
| 604 @Retry(AssertionError, tries=3, timeout_secs=1) | 610 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 605 def _Check5(): | 611 def _Check5(): |
| 606 self.RunGsUtil(['rsync', '-d', '-r', suri(bucket_uri), tmpdir]) | 612 self.RunGsUtil(['rsync', '-d', '-r', suri(bucket_uri), tmpdir]) |
| 607 listing1 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 613 listing1 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 608 listing2 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 614 listing2 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 609 # Bucket should have un-altered content. | 615 # Bucket should have un-altered content. |
| 610 self.assertEquals(listing1, set(['/obj2', '/obj6', '/subdir/obj3'])) | 616 self.assertEquals(listing1, set(['/.obj2', '/obj6', '/subdir/obj3'])) |
| 611 # Dir should have content like bucket but without the subdir objects | 617 # Dir should have content like bucket but without the subdir objects |
| 612 # synchronized. | 618 # synchronized. |
| 613 self.assertEquals(listing2, set(['/obj2', '/obj6', '/subdir/obj3'])) | 619 self.assertEquals(listing2, set(['/.obj2', '/obj6', '/subdir/obj3'])) |
| 614 _Check5() | 620 _Check5() |
| 615 | 621 |
| 616 # Use @Retry as hedge against bucket listing eventual consistency. | 622 # Use @Retry as hedge against bucket listing eventual consistency. |
| 617 @Retry(AssertionError, tries=3, timeout_secs=1) | 623 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 618 def _Check6(): | 624 def _Check6(): |
| 619 # Check that re-running the same rsync command causes no more changes. | 625 # Check that re-running the same rsync command causes no more changes. |
| 620 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 626 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 621 ['rsync', '-d', '-r', suri(bucket_uri), tmpdir], return_stderr=True)) | 627 ['rsync', '-d', '-r', suri(bucket_uri), tmpdir], return_stderr=True)) |
| 622 _Check6() | 628 _Check6() |
| 623 | 629 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 def _Check1(): | 682 def _Check1(): |
| 677 """Tests rsync works as expected.""" | 683 """Tests rsync works as expected.""" |
| 678 output = self.RunGsUtil( | 684 output = self.RunGsUtil( |
| 679 ['rsync', '-d', '-r', suri(bucket_uri), tmpdir], return_stderr=True) | 685 ['rsync', '-d', '-r', suri(bucket_uri), tmpdir], return_stderr=True) |
| 680 listing1 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 686 listing1 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 681 listing2 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 687 listing2 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 682 # Bucket should have un-altered content. | 688 # Bucket should have un-altered content. |
| 683 self.assertEquals(listing1, set(['/obj1', '//'])) | 689 self.assertEquals(listing1, set(['/obj1', '//'])) |
| 684 # Bucket should not have the placeholder object. | 690 # Bucket should not have the placeholder object. |
| 685 self.assertEquals(listing2, set(['/obj1'])) | 691 self.assertEquals(listing2, set(['/obj1'])) |
| 686 # Stdout should report what happened. | |
| 687 self.assertRegexpMatches(output, r'.*Skipping cloud sub-directory.*') | |
| 688 _Check1() | 692 _Check1() |
| 689 | 693 |
| 690 @unittest.skipIf(IS_WINDOWS, 'os.symlink() is not available on Windows.') | 694 @unittest.skipIf(IS_WINDOWS, 'os.symlink() is not available on Windows.') |
| 691 def test_rsync_minus_d_minus_e(self): | 695 def test_rsync_minus_d_minus_e(self): |
| 692 """Tests that rsync -e ignores symlinks.""" | 696 """Tests that rsync -e ignores symlinks.""" |
| 693 tmpdir = self.CreateTempDir() | 697 tmpdir = self.CreateTempDir() |
| 694 subdir = os.path.join(tmpdir, 'subdir') | 698 subdir = os.path.join(tmpdir, 'subdir') |
| 695 os.mkdir(subdir) | 699 os.mkdir(subdir) |
| 696 bucket_uri = self.CreateBucket() | 700 bucket_uri = self.CreateBucket() |
| 697 fpath1 = self.CreateTempFile( | 701 fpath1 = self.CreateTempFile( |
| 698 tmpdir=tmpdir, file_name='obj1', contents='obj1') | 702 tmpdir=tmpdir, file_name='obj1', contents='obj1') |
| 699 self.CreateTempFile(tmpdir=tmpdir, file_name='obj2', contents='obj2') | 703 self.CreateTempFile(tmpdir=tmpdir, file_name='.obj2', contents='.obj2') |
| 700 self.CreateTempFile(tmpdir=subdir, file_name='obj3', contents='subdir/obj3') | 704 self.CreateTempFile(tmpdir=subdir, file_name='obj3', contents='subdir/obj3') |
| 701 good_symlink_path = os.path.join(tmpdir, 'symlink1') | 705 good_symlink_path = os.path.join(tmpdir, 'symlink1') |
| 702 os.symlink(fpath1, good_symlink_path) | 706 os.symlink(fpath1, good_symlink_path) |
| 703 # Make a symlink that points to a non-existent path to test that -e also | 707 # Make a symlink that points to a non-existent path to test that -e also |
| 704 # handles that case. | 708 # handles that case. |
| 705 bad_symlink_path = os.path.join(tmpdir, 'symlink2') | 709 bad_symlink_path = os.path.join(tmpdir, 'symlink2') |
| 706 os.symlink(os.path.join('/', 'non-existent'), bad_symlink_path) | 710 os.symlink(os.path.join('/', 'non-existent'), bad_symlink_path) |
| 707 self.CreateObject(bucket_uri=bucket_uri, object_name='obj2', | 711 self.CreateObject(bucket_uri=bucket_uri, object_name='.obj2', |
| 708 contents='OBJ2') | 712 contents='.OBJ2') |
| 709 self.CreateObject(bucket_uri=bucket_uri, object_name='obj4', | 713 self.CreateObject(bucket_uri=bucket_uri, object_name='obj4', |
| 710 contents='obj4') | 714 contents='obj4') |
| 711 self.CreateObject(bucket_uri=bucket_uri, object_name='subdir/obj5', | 715 self.CreateObject(bucket_uri=bucket_uri, object_name='subdir/obj5', |
| 712 contents='subdir/obj5') | 716 contents='subdir/obj5') |
| 713 | 717 |
| 714 # Use @Retry as hedge against bucket listing eventual consistency. | 718 # Use @Retry as hedge against bucket listing eventual consistency. |
| 715 @Retry(AssertionError, tries=3, timeout_secs=1) | 719 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 716 def _Check1(): | 720 def _Check1(): |
| 717 """Ensure listings match the commented expectations.""" | 721 """Ensure listings match the commented expectations.""" |
| 718 self.RunGsUtil(['rsync', '-d', '-e', tmpdir, suri(bucket_uri)]) | 722 self.RunGsUtil(['rsync', '-d', '-e', tmpdir, suri(bucket_uri)]) |
| 719 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 723 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 720 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 724 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 721 # Dir should have un-altered content. | 725 # Dir should have un-altered content. |
| 722 self.assertEquals( | 726 self.assertEquals( |
| 723 listing1, | 727 listing1, |
| 724 set(['/obj1', '/obj2', '/subdir/obj3', '/symlink1', '/symlink2'])) | 728 set(['/obj1', '/.obj2', '/subdir/obj3', '/symlink1', '/symlink2'])) |
| 725 # Bucket should have content like dir but without the symlink, and | 729 # Bucket should have content like dir but without the symlink, and |
| 726 # without subdir objects synchronized. | 730 # without subdir objects synchronized. |
| 727 self.assertEquals(listing2, set(['/obj1', '/obj2', '/subdir/obj5'])) | 731 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/subdir/obj5'])) |
| 728 _Check1() | 732 _Check1() |
| 729 | 733 |
| 730 # Now remove invalid symlink and run without -e, and see that symlink gets | 734 # Now remove invalid symlink and run without -e, and see that symlink gets |
| 731 # copied (as file to which it points). Use @Retry as hedge against bucket | 735 # copied (as file to which it points). Use @Retry as hedge against bucket |
| 732 # listing eventual consistency. | 736 # listing eventual consistency. |
| 733 os.unlink(bad_symlink_path) | 737 os.unlink(bad_symlink_path) |
| 734 @Retry(AssertionError, tries=3, timeout_secs=1) | 738 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 735 def _Check2(): | 739 def _Check2(): |
| 736 """Tests rsync works as expected.""" | 740 """Tests rsync works as expected.""" |
| 737 self.RunGsUtil(['rsync', '-d', tmpdir, suri(bucket_uri)]) | 741 self.RunGsUtil(['rsync', '-d', tmpdir, suri(bucket_uri)]) |
| 738 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 742 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 739 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 743 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 740 # Dir should have un-altered content. | 744 # Dir should have un-altered content. |
| 741 self.assertEquals( | 745 self.assertEquals( |
| 742 listing1, set(['/obj1', '/obj2', '/subdir/obj3', '/symlink1'])) | 746 listing1, set(['/obj1', '/.obj2', '/subdir/obj3', '/symlink1'])) |
| 743 # Bucket should have content like dir but without the symlink, and | 747 # Bucket should have content like dir but without the symlink, and |
| 744 # without subdir objects synchronized. | 748 # without subdir objects synchronized. |
| 745 self.assertEquals( | 749 self.assertEquals( |
| 746 listing2, set(['/obj1', '/obj2', '/subdir/obj5', '/symlink1'])) | 750 listing2, set(['/obj1', '/.obj2', '/subdir/obj5', '/symlink1'])) |
| 747 self.assertEquals('obj1', self.RunGsUtil( | 751 self.assertEquals('obj1', self.RunGsUtil( |
| 748 ['cat', suri(bucket_uri, 'symlink1')], return_stdout=True)) | 752 ['cat', suri(bucket_uri, 'symlink1')], return_stdout=True)) |
| 749 _Check2() | 753 _Check2() |
| 750 | 754 |
| 751 # Use @Retry as hedge against bucket listing eventual consistency. | 755 # Use @Retry as hedge against bucket listing eventual consistency. |
| 752 @Retry(AssertionError, tries=3, timeout_secs=1) | 756 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 753 def _Check3(): | 757 def _Check3(): |
| 754 # Check that re-running the same rsync command causes no more changes. | 758 # Check that re-running the same rsync command causes no more changes. |
| 755 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 759 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 756 ['rsync', '-d', tmpdir, suri(bucket_uri)], return_stderr=True)) | 760 ['rsync', '-d', tmpdir, suri(bucket_uri)], return_stderr=True)) |
| 757 _Check3() | 761 _Check3() |
| 758 | 762 |
| 759 @SkipForS3('S3 does not support composite objects') | 763 @SkipForS3('S3 does not support composite objects') |
| 760 def test_bucket_to_bucket_minus_d_with_composites(self): | 764 def test_bucket_to_bucket_minus_d_with_composites(self): |
| 761 """Tests that rsync works with composite objects (which don't have MD5s).""" | 765 """Tests that rsync works with composite objects (which don't have MD5s).""" |
| 762 bucket1_uri = self.CreateBucket() | 766 bucket1_uri = self.CreateBucket() |
| 763 bucket2_uri = self.CreateBucket() | 767 bucket2_uri = self.CreateBucket() |
| 764 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj1', | 768 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj1', |
| 765 contents='obj1') | 769 contents='obj1') |
| 766 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj2', | 770 self.CreateObject(bucket_uri=bucket1_uri, object_name='.obj2', |
| 767 contents='obj2') | 771 contents='.obj2') |
| 768 self.RunGsUtil( | 772 self.RunGsUtil( |
| 769 ['compose', suri(bucket1_uri, 'obj1'), suri(bucket1_uri, 'obj2'), | 773 ['compose', suri(bucket1_uri, 'obj1'), suri(bucket1_uri, '.obj2'), |
| 770 suri(bucket1_uri, 'obj3')]) | 774 suri(bucket1_uri, 'obj3')]) |
| 771 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj2', | 775 self.CreateObject(bucket_uri=bucket2_uri, object_name='.obj2', |
| 772 contents='OBJ2') | 776 contents='.OBJ2') |
| 773 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj4', | 777 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj4', |
| 774 contents='obj4') | 778 contents='obj4') |
| 775 | 779 |
| 776 # Use @Retry as hedge against bucket listing eventual consistency. | 780 # Use @Retry as hedge against bucket listing eventual consistency. |
| 777 @Retry(AssertionError, tries=3, timeout_secs=1) | 781 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 778 def _Check1(): | 782 def _Check1(): |
| 779 self.RunGsUtil(['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)]) | 783 self.RunGsUtil(['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)]) |
| 780 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) | 784 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) |
| 781 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) | 785 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) |
| 782 # First bucket should have un-altered content. | 786 # First bucket should have un-altered content. |
| 783 self.assertEquals(listing1, set(['/obj1', '/obj2', '/obj3'])) | 787 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/obj3'])) |
| 784 # Second bucket should have content like first bucket but without the | 788 # Second bucket should have content like first bucket but without the |
| 785 # subdir objects synchronized. | 789 # subdir objects synchronized. |
| 786 self.assertEquals(listing2, set(['/obj1', '/obj2', '/obj3'])) | 790 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/obj3'])) |
| 787 _Check1() | 791 _Check1() |
| 788 | 792 |
| 789 # Use @Retry as hedge against bucket listing eventual consistency. | 793 # Use @Retry as hedge against bucket listing eventual consistency. |
| 790 @Retry(AssertionError, tries=3, timeout_secs=1) | 794 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 791 def _Check2(): | 795 def _Check2(): |
| 792 # Check that re-running the same rsync command causes no more changes. | 796 # Check that re-running the same rsync command causes no more changes. |
| 793 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 797 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 794 ['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)], | 798 ['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)], |
| 795 return_stderr=True)) | 799 return_stderr=True)) |
| 796 _Check2() | 800 _Check2() |
| 797 | 801 |
| 798 def test_bucket_to_bucket_minus_d_empty_dest(self): | 802 def test_bucket_to_bucket_minus_d_empty_dest(self): |
| 799 """Tests working with empty dest bucket (iter runs out before src iter).""" | 803 """Tests working with empty dest bucket (iter runs out before src iter).""" |
| 800 bucket1_uri = self.CreateBucket() | 804 bucket1_uri = self.CreateBucket() |
| 801 bucket2_uri = self.CreateBucket() | 805 bucket2_uri = self.CreateBucket() |
| 802 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj1', | 806 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj1', |
| 803 contents='obj1') | 807 contents='obj1') |
| 804 self.CreateObject(bucket_uri=bucket1_uri, object_name='obj2', | 808 self.CreateObject(bucket_uri=bucket1_uri, object_name='.obj2', |
| 805 contents='obj2') | 809 contents='.obj2') |
| 806 | 810 |
| 807 # Use @Retry as hedge against bucket listing eventual consistency. | 811 # Use @Retry as hedge against bucket listing eventual consistency. |
| 808 @Retry(AssertionError, tries=3, timeout_secs=1) | 812 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 809 def _Check1(): | 813 def _Check1(): |
| 810 self.RunGsUtil(['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)]) | 814 self.RunGsUtil(['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)]) |
| 811 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) | 815 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) |
| 812 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) | 816 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) |
| 813 self.assertEquals(listing1, set(['/obj1', '/obj2'])) | 817 self.assertEquals(listing1, set(['/obj1', '/.obj2'])) |
| 814 self.assertEquals(listing2, set(['/obj1', '/obj2'])) | 818 self.assertEquals(listing2, set(['/obj1', '/.obj2'])) |
| 815 _Check1() | 819 _Check1() |
| 816 | 820 |
| 817 # Use @Retry as hedge against bucket listing eventual consistency. | 821 # Use @Retry as hedge against bucket listing eventual consistency. |
| 818 @Retry(AssertionError, tries=3, timeout_secs=1) | 822 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 819 def _Check2(): | 823 def _Check2(): |
| 820 # Check that re-running the same rsync command causes no more changes. | 824 # Check that re-running the same rsync command causes no more changes. |
| 821 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 825 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 822 ['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)], | 826 ['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)], |
| 823 return_stderr=True)) | 827 return_stderr=True)) |
| 824 _Check2() | 828 _Check2() |
| 825 | 829 |
| 826 def test_bucket_to_bucket_minus_d_empty_src(self): | 830 def test_bucket_to_bucket_minus_d_empty_src(self): |
| 827 """Tests working with empty src bucket (iter runs out before dst iter).""" | 831 """Tests working with empty src bucket (iter runs out before dst iter).""" |
| 828 bucket1_uri = self.CreateBucket() | 832 bucket1_uri = self.CreateBucket() |
| 829 bucket2_uri = self.CreateBucket() | 833 bucket2_uri = self.CreateBucket() |
| 830 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj1', | 834 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj1', |
| 831 contents='obj1') | 835 contents='obj1') |
| 832 self.CreateObject(bucket_uri=bucket2_uri, object_name='obj2', | 836 self.CreateObject(bucket_uri=bucket2_uri, object_name='.obj2', |
| 833 contents='obj2') | 837 contents='.obj2') |
| 834 | 838 |
| 835 # Use @Retry as hedge against bucket listing eventual consistency. | 839 # Use @Retry as hedge against bucket listing eventual consistency. |
| 836 @Retry(AssertionError, tries=3, timeout_secs=1) | 840 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 837 def _Check1(): | 841 def _Check1(): |
| 838 self.RunGsUtil(['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)]) | 842 self.RunGsUtil(['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)]) |
| 839 stderr = self.RunGsUtil(['ls', suri(bucket1_uri, '**')], | 843 stderr = self.RunGsUtil(['ls', suri(bucket1_uri, '**')], |
| 840 expected_status=1, return_stderr=True) | 844 expected_status=1, return_stderr=True) |
| 841 self.assertIn('One or more URLs matched no objects', stderr) | 845 self.assertIn('One or more URLs matched no objects', stderr) |
| 842 stderr = self.RunGsUtil(['ls', suri(bucket2_uri, '**')], | 846 stderr = self.RunGsUtil(['ls', suri(bucket2_uri, '**')], |
| 843 expected_status=1, return_stderr=True) | 847 expected_status=1, return_stderr=True) |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 889 _Check2() | 893 _Check2() |
| 890 | 894 |
| 891 def test_rsync_to_nonexistent_bucket_subdir(self): | 895 def test_rsync_to_nonexistent_bucket_subdir(self): |
| 892 """Tests that rsync to non-existent bucket subdir works.""" | 896 """Tests that rsync to non-existent bucket subdir works.""" |
| 893 # Create dir with some objects and empty bucket. | 897 # Create dir with some objects and empty bucket. |
| 894 tmpdir = self.CreateTempDir() | 898 tmpdir = self.CreateTempDir() |
| 895 subdir = os.path.join(tmpdir, 'subdir') | 899 subdir = os.path.join(tmpdir, 'subdir') |
| 896 os.mkdir(subdir) | 900 os.mkdir(subdir) |
| 897 bucket_url = self.CreateBucket() | 901 bucket_url = self.CreateBucket() |
| 898 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') | 902 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') |
| 899 self.CreateTempFile(tmpdir=tmpdir, file_name='obj2', contents='obj2') | 903 self.CreateTempFile(tmpdir=tmpdir, file_name='.obj2', contents='.obj2') |
| 900 self.CreateTempFile(tmpdir=subdir, file_name='obj3', contents='subdir/obj3') | 904 self.CreateTempFile(tmpdir=subdir, file_name='obj3', contents='subdir/obj3') |
| 901 | 905 |
| 902 # Use @Retry as hedge against bucket listing eventual consistency. | 906 # Use @Retry as hedge against bucket listing eventual consistency. |
| 903 @Retry(AssertionError, tries=3, timeout_secs=1) | 907 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 904 def _Check1(): | 908 def _Check1(): |
| 905 """Tests rsync works as expected.""" | 909 """Tests rsync works as expected.""" |
| 906 self.RunGsUtil(['rsync', '-r', tmpdir, suri(bucket_url, 'subdir')]) | 910 self.RunGsUtil(['rsync', '-r', tmpdir, suri(bucket_url, 'subdir')]) |
| 907 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 911 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 908 listing2 = _TailSet( | 912 listing2 = _TailSet( |
| 909 suri(bucket_url, 'subdir'), | 913 suri(bucket_url, 'subdir'), |
| 910 self._FlatListBucket(bucket_url.clone_replace_name('subdir'))) | 914 self._FlatListBucket(bucket_url.clone_replace_name('subdir'))) |
| 911 # Dir should have un-altered content. | 915 # Dir should have un-altered content. |
| 912 self.assertEquals(listing1, set(['/obj1', '/obj2', '/subdir/obj3'])) | 916 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/subdir/obj3'])) |
| 913 # Bucket subdir should have content like dir. | 917 # Bucket subdir should have content like dir. |
| 914 self.assertEquals(listing2, set(['/obj1', '/obj2', '/subdir/obj3'])) | 918 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/subdir/obj3'])) |
| 915 _Check1() | 919 _Check1() |
| 916 | 920 |
| 917 # Use @Retry as hedge against bucket listing eventual consistency. | 921 # Use @Retry as hedge against bucket listing eventual consistency. |
| 918 @Retry(AssertionError, tries=3, timeout_secs=1) | 922 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 919 def _Check2(): | 923 def _Check2(): |
| 920 # Check that re-running the same rsync command causes no more changes. | 924 # Check that re-running the same rsync command causes no more changes. |
| 921 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 925 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 922 ['rsync', '-r', tmpdir, suri(bucket_url, 'subdir')], | 926 ['rsync', '-r', tmpdir, suri(bucket_url, 'subdir')], |
| 923 return_stderr=True)) | 927 return_stderr=True)) |
| 924 _Check2() | 928 _Check2() |
| 925 | 929 |
| 926 def test_rsync_from_nonexistent_bucket(self): | 930 def test_rsync_from_nonexistent_bucket(self): |
| 927 """Tests that rsync from a non-existent bucket subdir fails gracefully.""" | 931 """Tests that rsync from a non-existent bucket subdir fails gracefully.""" |
| 928 tmpdir = self.CreateTempDir() | 932 tmpdir = self.CreateTempDir() |
| 929 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') | 933 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') |
| 930 self.CreateTempFile(tmpdir=tmpdir, file_name='obj2', contents='obj2') | 934 self.CreateTempFile(tmpdir=tmpdir, file_name='.obj2', contents='.obj2') |
| 931 bucket_url_str = '%s://%s' % ( | 935 bucket_url_str = '%s://%s' % ( |
| 932 self.default_provider, self.nonexistent_bucket_name) | 936 self.default_provider, self.nonexistent_bucket_name) |
| 933 stderr = self.RunGsUtil(['rsync', '-d', bucket_url_str, tmpdir], | 937 stderr = self.RunGsUtil(['rsync', '-d', bucket_url_str, tmpdir], |
| 934 expected_status=1, return_stderr=True) | 938 expected_status=1, return_stderr=True) |
| 935 self.assertIn('Caught non-retryable exception', stderr) | 939 self.assertIn('Caught non-retryable exception', stderr) |
| 936 listing = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 940 listing = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 937 # Dir should have un-altered content. | 941 # Dir should have un-altered content. |
| 938 self.assertEquals(listing, set(['/obj1', '/obj2'])) | 942 self.assertEquals(listing, set(['/obj1', '/.obj2'])) |
| 939 | 943 |
| 940 def test_rsync_to_nonexistent_bucket(self): | 944 def test_rsync_to_nonexistent_bucket(self): |
| 941 """Tests that rsync from a non-existent bucket subdir fails gracefully.""" | 945 """Tests that rsync from a non-existent bucket subdir fails gracefully.""" |
| 942 tmpdir = self.CreateTempDir() | 946 tmpdir = self.CreateTempDir() |
| 943 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') | 947 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') |
| 944 self.CreateTempFile(tmpdir=tmpdir, file_name='obj2', contents='obj2') | 948 self.CreateTempFile(tmpdir=tmpdir, file_name='.obj2', contents='.obj2') |
| 945 bucket_url_str = '%s://%s' % ( | 949 bucket_url_str = '%s://%s' % ( |
| 946 self.default_provider, self.nonexistent_bucket_name) | 950 self.default_provider, self.nonexistent_bucket_name) |
| 947 stderr = self.RunGsUtil(['rsync', '-d', bucket_url_str, tmpdir], | 951 stderr = self.RunGsUtil(['rsync', '-d', bucket_url_str, tmpdir], |
| 948 expected_status=1, return_stderr=True) | 952 expected_status=1, return_stderr=True) |
| 949 self.assertIn('Caught non-retryable exception', stderr) | 953 self.assertIn('Caught non-retryable exception', stderr) |
| 950 listing = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 954 listing = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 951 # Dir should have un-altered content. | 955 # Dir should have un-altered content. |
| 952 self.assertEquals(listing, set(['/obj1', '/obj2'])) | 956 self.assertEquals(listing, set(['/obj1', '/.obj2'])) |
| 953 | 957 |
| 954 def test_bucket_to_bucket_minus_d_with_overwrite_and_punc_chars(self): | 958 def test_bucket_to_bucket_minus_d_with_overwrite_and_punc_chars(self): |
| 955 """Tests that punc chars in filenames don't confuse sort order.""" | 959 """Tests that punc chars in filenames don't confuse sort order.""" |
| 956 bucket1_uri = self.CreateBucket() | 960 bucket1_uri = self.CreateBucket() |
| 957 bucket2_uri = self.CreateBucket() | 961 bucket2_uri = self.CreateBucket() |
| 958 # Create 2 objects in each bucket, with one overwritten with a name that's | 962 # Create 2 objects in each bucket, with one overwritten with a name that's |
| 959 # less than the next name in destination bucket when encoded, but not when | 963 # less than the next name in destination bucket when encoded, but not when |
| 960 # compared without encoding. | 964 # compared without encoding. |
| 961 self.CreateObject(bucket_uri=bucket1_uri, object_name='e/obj1', | 965 self.CreateObject(bucket_uri=bucket1_uri, object_name='e/obj1', |
| 962 contents='obj1') | 966 contents='obj1') |
| 963 self.CreateObject(bucket_uri=bucket1_uri, object_name='e-1/obj2', | 967 self.CreateObject(bucket_uri=bucket1_uri, object_name='e-1/.obj2', |
| 964 contents='obj2') | 968 contents='.obj2') |
| 965 self.CreateObject(bucket_uri=bucket2_uri, object_name='e/obj1', | 969 self.CreateObject(bucket_uri=bucket2_uri, object_name='e/obj1', |
| 966 contents='OBJ1') | 970 contents='OBJ1') |
| 967 self.CreateObject(bucket_uri=bucket2_uri, object_name='e-1/obj2', | 971 self.CreateObject(bucket_uri=bucket2_uri, object_name='e-1/.obj2', |
| 968 contents='obj2') | 972 contents='.obj2') |
| 969 # Need to make sure the bucket listings are caught-up, otherwise the | 973 # Need to make sure the bucket listings are caught-up, otherwise the |
| 970 # rsync may not see all objects and fail to synchronize correctly. | 974 # rsync may not see all objects and fail to synchronize correctly. |
| 971 self.AssertNObjectsInBucket(bucket1_uri, 2) | 975 self.AssertNObjectsInBucket(bucket1_uri, 2) |
| 972 self.AssertNObjectsInBucket(bucket2_uri, 2) | 976 self.AssertNObjectsInBucket(bucket2_uri, 2) |
| 973 | 977 |
| 974 # Use @Retry as hedge against bucket listing eventual consistency. | 978 # Use @Retry as hedge against bucket listing eventual consistency. |
| 975 @Retry(AssertionError, tries=3, timeout_secs=1) | 979 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 976 def _Check1(): | 980 def _Check1(): |
| 977 """Tests rsync works as expected.""" | 981 """Tests rsync works as expected.""" |
| 978 self.RunGsUtil(['rsync', '-rd', suri(bucket1_uri), suri(bucket2_uri)]) | 982 self.RunGsUtil(['rsync', '-rd', suri(bucket1_uri), suri(bucket2_uri)]) |
| 979 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) | 983 listing1 = _TailSet(suri(bucket1_uri), self._FlatListBucket(bucket1_uri)) |
| 980 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) | 984 listing2 = _TailSet(suri(bucket2_uri), self._FlatListBucket(bucket2_uri)) |
| 981 # First bucket should have un-altered content. | 985 # First bucket should have un-altered content. |
| 982 self.assertEquals(listing1, set(['/e/obj1', '/e-1/obj2'])) | 986 self.assertEquals(listing1, set(['/e/obj1', '/e-1/.obj2'])) |
| 983 self.assertEquals(listing2, set(['/e/obj1', '/e-1/obj2'])) | 987 self.assertEquals(listing2, set(['/e/obj1', '/e-1/.obj2'])) |
| 984 # Assert correct contents. | 988 # Assert correct contents. |
| 985 self.assertEquals('obj1', self.RunGsUtil( | 989 self.assertEquals('obj1', self.RunGsUtil( |
| 986 ['cat', suri(bucket2_uri, 'e/obj1')], return_stdout=True)) | 990 ['cat', suri(bucket2_uri, 'e/obj1')], return_stdout=True)) |
| 987 self.assertEquals('obj2', self.RunGsUtil( | 991 self.assertEquals('.obj2', self.RunGsUtil( |
| 988 ['cat', suri(bucket2_uri, 'e-1/obj2')], return_stdout=True)) | 992 ['cat', suri(bucket2_uri, 'e-1/.obj2')], return_stdout=True)) |
| 989 _Check1() | 993 _Check1() |
| 990 | 994 |
| 991 # Use @Retry as hedge against bucket listing eventual consistency. | 995 # Use @Retry as hedge against bucket listing eventual consistency. |
| 992 @Retry(AssertionError, tries=3, timeout_secs=1) | 996 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 993 def _Check2(): | 997 def _Check2(): |
| 994 # Check that re-running the same rsync command causes no more changes. | 998 # Check that re-running the same rsync command causes no more changes. |
| 995 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 999 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 996 ['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)], | 1000 ['rsync', '-d', suri(bucket1_uri), suri(bucket2_uri)], |
| 997 return_stderr=True)) | 1001 return_stderr=True)) |
| 998 _Check2() | 1002 _Check2() |
| 999 | 1003 |
| 1000 def test_dir_to_bucket_minus_x(self): | 1004 def test_dir_to_bucket_minus_x(self): |
| 1001 """Tests that rsync -x option works correctly.""" | 1005 """Tests that rsync -x option works correctly.""" |
| 1002 # Create dir and bucket with 1 overlapping and 2 extra objects in each. | 1006 # Create dir and bucket with 1 overlapping and 2 extra objects in each. |
| 1003 tmpdir = self.CreateTempDir() | 1007 tmpdir = self.CreateTempDir() |
| 1004 bucket_uri = self.CreateBucket() | 1008 bucket_uri = self.CreateBucket() |
| 1005 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') | 1009 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') |
| 1006 self.CreateTempFile(tmpdir=tmpdir, file_name='obj2', contents='obj2') | 1010 self.CreateTempFile(tmpdir=tmpdir, file_name='.obj2', contents='.obj2') |
| 1007 self.CreateTempFile(tmpdir=tmpdir, file_name='obj3', contents='obj3') | 1011 self.CreateTempFile(tmpdir=tmpdir, file_name='obj3', contents='obj3') |
| 1008 self.CreateObject(bucket_uri=bucket_uri, object_name='obj2', | 1012 self.CreateObject(bucket_uri=bucket_uri, object_name='.obj2', |
| 1009 contents='obj2') | 1013 contents='.obj2') |
| 1010 self.CreateObject(bucket_uri=bucket_uri, object_name='obj4', | 1014 self.CreateObject(bucket_uri=bucket_uri, object_name='obj4', |
| 1011 contents='obj4') | 1015 contents='obj4') |
| 1012 self.CreateObject(bucket_uri=bucket_uri, object_name='obj5', | 1016 self.CreateObject(bucket_uri=bucket_uri, object_name='obj5', |
| 1013 contents='obj5') | 1017 contents='obj5') |
| 1014 | 1018 |
| 1015 # Need to make sure the bucket listing is caught-up, otherwise the | 1019 # Need to make sure the bucket listing is caught-up, otherwise the |
| 1016 # first rsync may not see obj2 and overwrite it. | 1020 # first rsync may not see .obj2 and overwrite it. |
| 1017 self.AssertNObjectsInBucket(bucket_uri, 3) | 1021 self.AssertNObjectsInBucket(bucket_uri, 3) |
| 1018 | 1022 |
| 1019 # Use @Retry as hedge against bucket listing eventual consistency. | 1023 # Use @Retry as hedge against bucket listing eventual consistency. |
| 1020 @Retry(AssertionError, tries=3, timeout_secs=1) | 1024 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 1021 def _Check1(): | 1025 def _Check1(): |
| 1022 """Tests rsync works as expected.""" | 1026 """Tests rsync works as expected.""" |
| 1023 self.RunGsUtil(['rsync', '-d', '-x', 'obj[34]', tmpdir, suri(bucket_uri)]) | 1027 self.RunGsUtil(['rsync', '-d', '-x', 'obj[34]', tmpdir, suri(bucket_uri)]) |
| 1024 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) | 1028 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 1025 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) | 1029 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 1026 # Dir should have un-altered content. | 1030 # Dir should have un-altered content. |
| 1027 self.assertEquals(listing1, set(['/obj1', '/obj2', '/obj3'])) | 1031 self.assertEquals(listing1, set(['/obj1', '/.obj2', '/obj3'])) |
| 1028 # Bucket should have content like dir but ignoring obj3 from dir and not | 1032 # Bucket should have content like dir but ignoring obj3 from dir and not |
| 1029 # deleting obj4 from bucket (per exclude regex). | 1033 # deleting obj4 from bucket (per exclude regex). |
| 1030 self.assertEquals(listing2, set(['/obj1', '/obj2', '/obj4'])) | 1034 self.assertEquals(listing2, set(['/obj1', '/.obj2', '/obj4'])) |
| 1031 _Check1() | 1035 _Check1() |
| 1032 | 1036 |
| 1033 # Use @Retry as hedge against bucket listing eventual consistency. | 1037 # Use @Retry as hedge against bucket listing eventual consistency. |
| 1034 @Retry(AssertionError, tries=3, timeout_secs=1) | 1038 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 1035 def _Check2(): | 1039 def _Check2(): |
| 1036 # Check that re-running the same rsync command causes no more changes. | 1040 # Check that re-running the same rsync command causes no more changes. |
| 1037 self.assertEquals(NO_CHANGES, self.RunGsUtil( | 1041 self.assertEquals(NO_CHANGES, self.RunGsUtil( |
| 1038 ['rsync', '-d', '-x', 'obj[34]', tmpdir, suri(bucket_uri)], | 1042 ['rsync', '-d', '-x', 'obj[34]', tmpdir, suri(bucket_uri)], |
| 1039 return_stderr=True)) | 1043 return_stderr=True)) |
| 1040 _Check2() | 1044 _Check2() |
| 1045 |
| 1046 @unittest.skipIf(IS_WINDOWS, |
| 1047 "os.chmod() won't make file unreadable on Windows.") |
| 1048 def test_dir_to_bucket_minus_C(self): |
| 1049 """Tests that rsync -C option works correctly.""" |
| 1050 # Create dir with 3 objects, the middle of which is unreadable. |
| 1051 tmpdir = self.CreateTempDir() |
| 1052 bucket_uri = self.CreateBucket() |
| 1053 self.CreateTempFile(tmpdir=tmpdir, file_name='obj1', contents='obj1') |
| 1054 path = self.CreateTempFile(tmpdir=tmpdir, file_name='obj2', contents='obj2') |
| 1055 os.chmod(path, 0) |
| 1056 self.CreateTempFile(tmpdir=tmpdir, file_name='obj3', contents='obj3') |
| 1057 |
| 1058 # Use @Retry as hedge against bucket listing eventual consistency. |
| 1059 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 1060 def _Check(): |
| 1061 """Tests rsync works as expected.""" |
| 1062 stderr = self.RunGsUtil(['rsync', '-C', tmpdir, suri(bucket_uri)], |
| 1063 expected_status=1, return_stderr=True) |
| 1064 self.assertIn('1 files/objects could not be copied/removed.', stderr) |
| 1065 listing1 = _TailSet(tmpdir, self._FlatListDir(tmpdir)) |
| 1066 listing2 = _TailSet(suri(bucket_uri), self._FlatListBucket(bucket_uri)) |
| 1067 # Dir should have un-altered content. |
| 1068 self.assertEquals(listing1, set(['/obj1', '/obj2', '/obj3'])) |
| 1069 # Bucket should have obj1 and obj3 even though obj2 was unreadable. |
| 1070 self.assertEquals(listing2, set(['/obj1', '/obj3'])) |
| 1071 _Check() |
| OLD | NEW |