| OLD | NEW |
| 1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
| 2 # Copyright 2013 Google Inc. All Rights Reserved. | 2 # Copyright 2013 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 setmeta command.""" |
| 16 |
| 17 from __future__ import absolute_import |
| 15 | 18 |
| 16 import gslib.tests.testcase as testcase | 19 import gslib.tests.testcase as testcase |
| 20 from gslib.tests.testcase.integration_testcase import SkipForS3 |
| 21 from gslib.tests.util import ObjectToURI as suri |
| 17 from gslib.util import Retry | 22 from gslib.util import Retry |
| 18 from gslib.tests.util import ObjectToURI as suri | 23 from gslib.util import UTF8 |
| 19 | 24 |
| 20 | 25 |
| 21 class TestSetMeta(testcase.GsUtilIntegrationTestCase): | 26 class TestSetMeta(testcase.GsUtilIntegrationTestCase): |
| 22 """Integration tests for setmeta command.""" | 27 """Integration tests for setmeta command.""" |
| 23 | 28 |
| 24 def test_initial_metadata(self): | 29 def test_initial_metadata(self): |
| 30 """Tests copying file to an object with metadata.""" |
| 25 objuri = suri(self.CreateObject(contents='foo')) | 31 objuri = suri(self.CreateObject(contents='foo')) |
| 26 inpath = self.CreateTempFile() | 32 inpath = self.CreateTempFile() |
| 27 ct = 'image/gif' | 33 ct = 'image/gif' |
| 28 self.RunGsUtil(['-h', 'x-goog-meta-xyz:abc', '-h', 'Content-Type:%s' % ct, | 34 self.RunGsUtil(['-h', 'x-%s-meta-xyz:abc' % self.provider_custom_meta, |
| 29 'cp', inpath, objuri]) | 35 '-h', 'Content-Type:%s' % ct, 'cp', inpath, objuri]) |
| 30 # Use @Retry as hedge against bucket listing eventual consistency. | 36 # Use @Retry as hedge against bucket listing eventual consistency. |
| 31 @Retry(AssertionError, tries=3, timeout_secs=1) | 37 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 32 def _Check1(): | 38 def _Check1(): |
| 33 stdout = self.RunGsUtil(['ls', '-L', objuri], return_stdout=True) | 39 stdout = self.RunGsUtil(['ls', '-L', objuri], return_stdout=True) |
| 34 self.assertRegexpMatches(stdout, 'Content-Type:\s+%s' % ct) | 40 self.assertRegexpMatches(stdout, r'Content-Type:\s+%s' % ct) |
| 35 self.assertRegexpMatches(stdout, 'x-goog-meta-xyz:\s+abc') | 41 self.assertRegexpMatches(stdout, r'xyz:\s+abc') |
| 36 _Check1() | 42 _Check1() |
| 37 | 43 |
| 38 def test_overwrite_existing(self): | 44 def test_overwrite_existing(self): |
| 45 """Tests overwriting an object's metadata.""" |
| 39 objuri = suri(self.CreateObject(contents='foo')) | 46 objuri = suri(self.CreateObject(contents='foo')) |
| 40 inpath = self.CreateTempFile() | 47 inpath = self.CreateTempFile() |
| 41 self.RunGsUtil(['-h', 'x-goog-meta-xyz:abc', '-h', 'Content-Type:image/gif', | 48 self.RunGsUtil(['-h', 'x-%s-meta-xyz:abc' % self.provider_custom_meta, |
| 42 'cp', inpath, objuri]) | 49 '-h', 'Content-Type:image/gif', 'cp', inpath, objuri]) |
| 43 self.RunGsUtil(['setmeta', '-n', '-h', 'Content-Type:text/html', '-h', | 50 self.RunGsUtil(['setmeta', '-n', '-h', 'Content-Type:text/html', '-h', |
| 44 'x-goog-meta-xyz', objuri]) | 51 'x-%s-meta-xyz' % self.provider_custom_meta, objuri]) |
| 45 # Use @Retry as hedge against bucket listing eventual consistency. | 52 # Use @Retry as hedge against bucket listing eventual consistency. |
| 46 @Retry(AssertionError, tries=3, timeout_secs=1) | 53 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 47 def _Check1(): | 54 def _Check1(): |
| 48 stdout = self.RunGsUtil(['ls', '-L', objuri], return_stdout=True) | 55 stdout = self.RunGsUtil(['ls', '-L', objuri], return_stdout=True) |
| 49 self.assertRegexpMatches(stdout, 'Content-Type:\s+text/html') | 56 self.assertRegexpMatches(stdout, r'Content-Type:\s+text/html') |
| 50 self.assertNotIn('xyz', stdout) | 57 self.assertNotIn('xyz', stdout) |
| 51 _Check1() | 58 _Check1() |
| 52 | 59 |
| 53 def test_duplicate_header_removal(self): | 60 def test_duplicate_header_removal(self): |
| 54 stderr = self.RunGsUtil( | 61 stderr = self.RunGsUtil( |
| 55 ['setmeta', '-h', 'Content-Type:text/html', '-h', 'Content-Type', | 62 ['setmeta', '-h', 'Content-Type:text/html', '-h', 'Content-Type', |
| 56 'gs://foo/bar'], expected_status=1, return_stderr=True) | 63 'gs://foo/bar'], expected_status=1, return_stderr=True) |
| 57 self.assertIn('Each header must appear at most once', stderr) | 64 self.assertIn('Each header must appear at most once', stderr) |
| 58 | 65 |
| 59 def test_duplicate_header(self): | 66 def test_duplicate_header(self): |
| 60 stderr = self.RunGsUtil( | 67 stderr = self.RunGsUtil( |
| 61 ['setmeta', '-h', 'Content-Type:text/html', '-h', 'Content-Type:foobar', | 68 ['setmeta', '-h', 'Content-Type:text/html', '-h', 'Content-Type:foobar', |
| 62 'gs://foo/bar'], expected_status=1, return_stderr=True) | 69 'gs://foo/bar'], expected_status=1, return_stderr=True) |
| 63 self.assertIn('Each header must appear at most once', stderr) | 70 self.assertIn('Each header must appear at most once', stderr) |
| 64 | 71 |
| 65 def test_recursion_works(self): | 72 def test_recursion_works(self): |
| 66 bucket_uri = self.CreateBucket() | 73 bucket_uri = self.CreateBucket() |
| 67 object1_uri = self.CreateObject(bucket_uri=bucket_uri, contents='foo') | 74 object1_uri = self.CreateObject(bucket_uri=bucket_uri, contents='foo') |
| 68 object2_uri = self.CreateObject(bucket_uri=bucket_uri, contents='foo') | 75 object2_uri = self.CreateObject(bucket_uri=bucket_uri, contents='foo') |
| 69 self.RunGsUtil(['setmeta', '-R', '-h', 'content-type:footype', | 76 self.RunGsUtil(['setmeta', '-R', '-h', 'content-type:footype', |
| 70 suri(bucket_uri)]) | 77 suri(bucket_uri)]) |
| 71 | 78 |
| 72 for obj_uri in [object1_uri, object2_uri]: | 79 for obj_uri in [object1_uri, object2_uri]: |
| 73 stdout = self.RunGsUtil(['stat', suri(obj_uri)], return_stdout=True) | 80 stdout = self.RunGsUtil(['stat', suri(obj_uri)], return_stdout=True) |
| 74 self.assertIn('footype', stdout) | 81 self.assertIn('footype', stdout) |
| 75 | 82 |
| 76 def test_invalid_non_ascii_custom_header(self): | 83 def test_invalid_non_ascii_custom_header(self): |
| 77 unicode_header = u'x-goog-meta-soufflé:5' | 84 unicode_header = u'x-%s-meta-soufflé:5' % self.provider_custom_meta |
| 78 unicode_header_bytes = unicode_header.encode('utf-8') | 85 unicode_header_bytes = unicode_header.encode(UTF8) |
| 79 stderr = self.RunGsUtil( | 86 stderr = self.RunGsUtil( |
| 80 ['setmeta', '-h', unicode_header_bytes, 'gs://foo/bar'], | 87 ['setmeta', '-h', unicode_header_bytes, 'gs://foo/bar'], |
| 81 expected_status=1, return_stderr=True) | 88 expected_status=1, return_stderr=True) |
| 82 self.assertIn('Invalid non-ASCII header', stderr) | 89 self.assertIn('Invalid non-ASCII header', stderr) |
| 83 | 90 |
| 91 @SkipForS3('Only ASCII characters are supported for x-amz-meta headers') |
| 84 def test_valid_non_ascii_custom_header(self): | 92 def test_valid_non_ascii_custom_header(self): |
| 93 """Tests setting custom metadata with a non-ASCII content.""" |
| 85 objuri = self.CreateObject(contents='foo') | 94 objuri = self.CreateObject(contents='foo') |
| 86 unicode_header = u'x-goog-meta-dessert:soufflé' | 95 unicode_header = u'x-%s-meta-dessert:soufflé' % self.provider_custom_meta |
| 87 unicode_header_bytes = unicode_header.encode('utf-8') | 96 unicode_header_bytes = unicode_header.encode(UTF8) |
| 88 self.RunGsUtil(['setmeta', '-h', unicode_header_bytes, suri(objuri)]) | 97 self.RunGsUtil(['setmeta', '-h', unicode_header_bytes, suri(objuri)]) |
| 89 # Use @Retry as hedge against bucket listing eventual consistency. | 98 # Use @Retry as hedge against bucket listing eventual consistency. |
| 90 @Retry(AssertionError, tries=3, timeout_secs=1) | 99 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 91 def _Check1(): | 100 def _Check1(): |
| 92 stdout = self.RunGsUtil(['ls', '-L', suri(objuri)], return_stdout=True) | 101 stdout = self.RunGsUtil(['ls', '-L', suri(objuri)], return_stdout=True) |
| 93 stdout = stdout.decode('utf-8') | 102 stdout = stdout.decode(UTF8) |
| 94 self.assertIn(u'x-goog-meta-dessert:\tsoufflé', stdout) | 103 self.assertIn(u'dessert:\t\tsoufflé', stdout) |
| 95 _Check1() | 104 _Check1() |
| 96 | 105 |
| 97 def test_disallowed_header(self): | 106 def test_disallowed_header(self): |
| 98 stderr = self.RunGsUtil( | 107 stderr = self.RunGsUtil( |
| 99 ['setmeta', '-h', 'Content-Length:5', 'gs://foo/bar'], | 108 ['setmeta', '-h', 'Content-Length:5', 'gs://foo/bar'], |
| 100 expected_status=1, return_stderr=True) | 109 expected_status=1, return_stderr=True) |
| 101 self.assertIn('Invalid or disallowed header', stderr) | 110 self.assertIn('Invalid or disallowed header', stderr) |
| 102 | 111 |
| 103 def test_setmeta_bucket(self): | 112 def test_setmeta_bucket(self): |
| 104 bucket_uri = self.CreateBucket() | 113 bucket_uri = self.CreateBucket() |
| 105 stderr = self.RunGsUtil( | 114 stderr = self.RunGsUtil( |
| 106 ['setmeta', '-h', 'x-goog-meta-foo:5', suri(bucket_uri)], | 115 ['setmeta', '-h', 'x-%s-meta-foo:5' % self.provider_custom_meta, |
| 107 expected_status=1, return_stderr=True) | 116 suri(bucket_uri)], expected_status=1, return_stderr=True) |
| 108 self.assertIn('must name an object', stderr) | 117 self.assertIn('must name an object', stderr) |
| 109 | 118 |
| 110 def test_setmeta_invalid_arg(self): | 119 def test_setmeta_invalid_arg(self): |
| 111 stderr = self.RunGsUtil( | 120 stderr = self.RunGsUtil( |
| 112 ['setmeta', '-h', 'foo:bar:baz', 'gs://foo/bar'], expected_status=1, | 121 ['setmeta', '-h', 'foo:bar:baz', 'gs://foo/bar'], expected_status=1, |
| 113 return_stderr=True) | 122 return_stderr=True) |
| 114 self.assertIn('must be either header or header:value', stderr) | 123 self.assertIn('must be either header or header:value', stderr) |
| 115 | 124 |
| 125 def test_setmeta_with_canned_acl(self): |
| 126 stderr = self.RunGsUtil( |
| 127 ['setmeta', '-h', 'x-%s-acl:public-read' % self.provider_custom_meta, |
| 128 'gs://foo/bar'], expected_status=1, return_stderr=True) |
| 129 self.assertIn('gsutil setmeta no longer allows canned ACLs', stderr) |
| 130 |
| 116 def test_invalid_non_ascii_header_value(self): | 131 def test_invalid_non_ascii_header_value(self): |
| 117 unicode_header = u'Content-Type:dessert/soufflé' | 132 unicode_header = u'Content-Type:dessert/soufflé' |
| 118 unicode_header_bytes = unicode_header.encode('utf-8') | 133 unicode_header_bytes = unicode_header.encode(UTF8) |
| 119 stderr = self.RunGsUtil( | 134 stderr = self.RunGsUtil( |
| 120 ['setmeta', '-h', unicode_header_bytes, 'gs://foo/bar'], | 135 ['setmeta', '-h', unicode_header_bytes, 'gs://foo/bar'], |
| 121 expected_status=1, return_stderr=True) | 136 expected_status=1, return_stderr=True) |
| 122 self.assertIn('Invalid non-ASCII header', stderr) | 137 self.assertIn('Invalid non-ASCII header', stderr) |
| OLD | NEW |