OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # Copyright 2013 Google Inc. All Rights Reserved. |
| 3 # |
| 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 # you may not use this file except in compliance with the License. |
| 6 # You may obtain a copy of the License at |
| 7 # |
| 8 # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 # |
| 10 # Unless required by applicable law or agreed to in writing, software |
| 11 # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 # See the License for the specific language governing permissions and |
| 14 # limitations under the License. |
| 15 """Integration tests for cors command.""" |
| 16 |
| 17 from __future__ import absolute_import |
| 18 |
| 19 import json |
| 20 import posixpath |
| 21 from xml.dom.minidom import parseString |
| 22 |
| 23 import gslib.tests.testcase as testcase |
| 24 from gslib.tests.testcase.integration_testcase import SkipForS3 |
| 25 from gslib.tests.util import ObjectToURI as suri |
| 26 from gslib.translation_helper import CorsTranslation |
| 27 from gslib.util import Retry |
| 28 |
| 29 |
| 30 @SkipForS3('CORS command is only supported for gs:// URLs') |
| 31 class TestCors(testcase.GsUtilIntegrationTestCase): |
| 32 """Integration tests for cors command.""" |
| 33 |
| 34 _set_cmd_prefix = ['cors', 'set'] |
| 35 _get_cmd_prefix = ['cors', 'get'] |
| 36 |
| 37 empty_doc1 = '[]' |
| 38 empty_doc2 = '[ {} ]' |
| 39 |
| 40 cors_bad = ( |
| 41 '[{"origin": ["http://origin1.example.com", ' |
| 42 '"http://origin2.example.com"], ' |
| 43 '"responseHeader": ["foo", "bar"], "badmethod": ["GET", "PUT", "POST"], ' |
| 44 '"maxAgeSeconds": 3600},' |
| 45 '{"origin": ["http://origin3.example.com"], ' |
| 46 '"responseHeader": ["foo2", "bar2"], "method": ["GET", "DELETE"]}])' |
| 47 ) |
| 48 |
| 49 no_cors = 'has no CORS configuration' |
| 50 |
| 51 xml_cors_doc = parseString( |
| 52 '<CorsConfig><Cors><Origins>' |
| 53 '<Origin>http://origin1.example.com</Origin>' |
| 54 '<Origin>http://origin2.example.com</Origin>' |
| 55 '</Origins><Methods><Method>GET</Method>' |
| 56 '<Method>PUT</Method><Method>POST</Method></Methods>' |
| 57 '<ResponseHeaders><ResponseHeader>foo</ResponseHeader>' |
| 58 '<ResponseHeader>bar</ResponseHeader></ResponseHeaders>' |
| 59 '<MaxAgeSec>3600</MaxAgeSec></Cors>' |
| 60 '<Cors><Origins><Origin>http://origin3.example.com</Origin></Origins>' |
| 61 '<Methods><Method>GET</Method><Method>DELETE</Method></Methods>' |
| 62 '<ResponseHeaders><ResponseHeader>foo2</ResponseHeader>' |
| 63 '<ResponseHeader>bar2</ResponseHeader></ResponseHeaders>' |
| 64 '</Cors></CorsConfig>').toprettyxml(indent=' ') |
| 65 |
| 66 cors_doc = ( |
| 67 '[{"origin": ["http://origin1.example.com", ' |
| 68 '"http://origin2.example.com"], ' |
| 69 '"responseHeader": ["foo", "bar"], "method": ["GET", "PUT", "POST"], ' |
| 70 '"maxAgeSeconds": 3600},' |
| 71 '{"origin": ["http://origin3.example.com"], ' |
| 72 '"responseHeader": ["foo2", "bar2"], "method": ["GET", "DELETE"]}]\n') |
| 73 cors_json_obj = json.loads(cors_doc) |
| 74 |
| 75 cors_doc2 = ( |
| 76 '[{"origin": ["http://origin1.example.com", ' |
| 77 '"http://origin2.example.com"], ' |
| 78 '"responseHeader": ["foo", "bar"], "method": ["GET", "PUT", "POST"]}]\n') |
| 79 cors_json_obj2 = json.loads(cors_doc2) |
| 80 |
| 81 def test_cors_translation(self): |
| 82 """Tests cors translation for various formats.""" |
| 83 json_text = self.cors_doc |
| 84 entries_list = CorsTranslation.JsonCorsToMessageEntries(json_text) |
| 85 boto_cors = CorsTranslation.BotoCorsFromMessage(entries_list) |
| 86 converted_entries_list = CorsTranslation.BotoCorsToMessage(boto_cors) |
| 87 converted_json_text = CorsTranslation.MessageEntriesToJson( |
| 88 converted_entries_list) |
| 89 self.assertEqual(json.loads(json_text), json.loads(converted_json_text)) |
| 90 |
| 91 def test_default_cors(self): |
| 92 bucket_uri = self.CreateBucket() |
| 93 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket_uri)], |
| 94 return_stdout=True) |
| 95 self.assertIn(self.no_cors, stdout) |
| 96 |
| 97 def test_set_empty_cors1(self): |
| 98 bucket_uri = self.CreateBucket() |
| 99 fpath = self.CreateTempFile(contents=self.empty_doc1) |
| 100 self.RunGsUtil(self._set_cmd_prefix + [fpath, suri(bucket_uri)]) |
| 101 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket_uri)], |
| 102 return_stdout=True) |
| 103 self.assertIn(self.no_cors, stdout) |
| 104 |
| 105 def test_set_empty_cors2(self): |
| 106 bucket_uri = self.CreateBucket() |
| 107 fpath = self.CreateTempFile(contents=self.empty_doc2) |
| 108 self.RunGsUtil(self._set_cmd_prefix + [fpath, suri(bucket_uri)]) |
| 109 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket_uri)], |
| 110 return_stdout=True) |
| 111 self.assertIn(self.no_cors, stdout) |
| 112 |
| 113 def test_non_null_cors(self): |
| 114 bucket_uri = self.CreateBucket() |
| 115 fpath = self.CreateTempFile(contents=self.cors_doc) |
| 116 self.RunGsUtil(self._set_cmd_prefix + [fpath, suri(bucket_uri)]) |
| 117 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket_uri)], |
| 118 return_stdout=True) |
| 119 self.assertEqual(json.loads(stdout), self.cors_json_obj) |
| 120 |
| 121 def test_bad_cors_xml(self): |
| 122 bucket_uri = self.CreateBucket() |
| 123 fpath = self.CreateTempFile(contents=self.xml_cors_doc) |
| 124 stderr = self.RunGsUtil(self._set_cmd_prefix + [fpath, suri(bucket_uri)], |
| 125 expected_status=1, return_stderr=True) |
| 126 self.assertIn('XML CORS data provided', stderr) |
| 127 |
| 128 def test_bad_cors(self): |
| 129 bucket_uri = self.CreateBucket() |
| 130 fpath = self.CreateTempFile(contents=self.cors_bad) |
| 131 stderr = self.RunGsUtil(self._set_cmd_prefix + [fpath, suri(bucket_uri)], |
| 132 expected_status=1, return_stderr=True) |
| 133 self.assertNotIn('XML CORS data provided', stderr) |
| 134 |
| 135 def set_cors_and_reset(self): |
| 136 """Tests setting CORS then removing it.""" |
| 137 bucket_uri = self.CreateBucket() |
| 138 tmpdir = self.CreateTempDir() |
| 139 fpath = self.CreateTempFile(tmpdir=tmpdir, contents=self.cors_doc) |
| 140 self.RunGsUtil(self._set_cmd_prefix + [fpath, suri(bucket_uri)]) |
| 141 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket_uri)], |
| 142 return_stdout=True) |
| 143 self.assertEqual(json.loads(stdout), self.valid_cors_obj) |
| 144 |
| 145 fpath = self.CreateTempFile(tmpdir=tmpdir, contents=self.empty_doc1) |
| 146 self.RunGsUtil(self._set_cmd_prefix + [fpath, suri(bucket_uri)]) |
| 147 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket_uri)], |
| 148 return_stdout=True) |
| 149 self.assertIn(self.no_cors, stdout) |
| 150 |
| 151 def set_partial_cors_and_reset(self): |
| 152 """Tests setting CORS without maxAgeSeconds, then removing it.""" |
| 153 bucket_uri = self.CreateBucket() |
| 154 tmpdir = self.CreateTempDir() |
| 155 fpath = self.CreateTempFile(tmpdir=tmpdir, contents=self.cors_doc2) |
| 156 self.RunGsUtil(self._set_cmd_prefix + [fpath, suri(bucket_uri)]) |
| 157 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket_uri)], |
| 158 return_stdout=True) |
| 159 self.assertEqual(json.loads(stdout), self.cors_json_obj2) |
| 160 |
| 161 fpath = self.CreateTempFile(tmpdir=tmpdir, contents=self.empty_doc1) |
| 162 self.RunGsUtil(self._set_cmd_prefix + [fpath, suri(bucket_uri)]) |
| 163 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket_uri)], |
| 164 return_stdout=True) |
| 165 self.assertIn(self.no_cors, stdout) |
| 166 |
| 167 def set_multi_non_null_cors(self): |
| 168 """Tests setting different CORS configurations.""" |
| 169 bucket1_uri = self.CreateBucket() |
| 170 bucket2_uri = self.CreateBucket() |
| 171 fpath = self.CreateTempFile(contents=self.cors_doc) |
| 172 self.RunGsUtil( |
| 173 self._set_cmd_prefix + [fpath, suri(bucket1_uri), suri(bucket2_uri)]) |
| 174 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket1_uri)], |
| 175 return_stdout=True) |
| 176 self.assertEqual(json.loads(stdout), self.cors_json_obj) |
| 177 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket2_uri)], |
| 178 return_stdout=True) |
| 179 self.assertEqual(json.loads(stdout), self.cors_json_obj) |
| 180 |
| 181 def test_set_wildcard_non_null_cors(self): |
| 182 """Tests setting CORS on a wildcarded bucket URI.""" |
| 183 random_prefix = self.MakeRandomTestString() |
| 184 bucket1_name = self.MakeTempName('bucket', prefix=random_prefix) |
| 185 bucket2_name = self.MakeTempName('bucket', prefix=random_prefix) |
| 186 bucket1_uri = self.CreateBucket(bucket_name=bucket1_name) |
| 187 bucket2_uri = self.CreateBucket(bucket_name=bucket2_name) |
| 188 # This just double checks that the common prefix of the two buckets is what |
| 189 # we think it should be (based on implementation detail of CreateBucket). |
| 190 # We want to be careful when setting a wildcard on buckets to make sure we |
| 191 # don't step outside the test buckets to affect other buckets. |
| 192 common_prefix = posixpath.commonprefix([suri(bucket1_uri), |
| 193 suri(bucket2_uri)]) |
| 194 self.assertTrue(common_prefix.startswith( |
| 195 'gs://%sgsutil-test-test_set_wildcard_non_null_cors-' % random_prefix)) |
| 196 wildcard = '%s*' % common_prefix |
| 197 |
| 198 fpath = self.CreateTempFile(contents=self.cors_doc) |
| 199 |
| 200 # Use @Retry as hedge against bucket listing eventual consistency. |
| 201 expected = set(['Setting CORS on %s/...' % suri(bucket1_uri), |
| 202 'Setting CORS on %s/...' % suri(bucket2_uri)]) |
| 203 actual = set() |
| 204 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 205 def _Check1(): |
| 206 """Ensures expect set lines are present in command output.""" |
| 207 stderr = self.RunGsUtil(self._set_cmd_prefix + [fpath, wildcard], |
| 208 return_stderr=True) |
| 209 outlines = stderr.splitlines() |
| 210 for line in outlines: |
| 211 # Ignore the deprecation warnings from running the old cors command. |
| 212 if ('You are using a deprecated alias' in line or |
| 213 'gsutil help cors' in line or |
| 214 'Please use "cors" with the appropriate sub-command' in line): |
| 215 continue |
| 216 actual.add(line) |
| 217 for line in expected: |
| 218 self.assertIn(line, actual) |
| 219 self.assertEqual(stderr.count('Setting CORS'), 2) |
| 220 _Check1() |
| 221 |
| 222 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket1_uri)], |
| 223 return_stdout=True) |
| 224 self.assertEqual(json.loads(stdout), self.cors_json_obj) |
| 225 stdout = self.RunGsUtil(self._get_cmd_prefix + [suri(bucket2_uri)], |
| 226 return_stdout=True) |
| 227 self.assertEqual(json.loads(stdout), self.cors_json_obj) |
| 228 |
| 229 def testTooFewArgumentsFails(self): |
| 230 """Ensures CORS commands fail with too few arguments.""" |
| 231 # No arguments for get, but valid subcommand. |
| 232 stderr = self.RunGsUtil(self._get_cmd_prefix, return_stderr=True, |
| 233 expected_status=1) |
| 234 self.assertIn('command requires at least', stderr) |
| 235 |
| 236 # No arguments for set, but valid subcommand. |
| 237 stderr = self.RunGsUtil(self._set_cmd_prefix, return_stderr=True, |
| 238 expected_status=1) |
| 239 self.assertIn('command requires at least', stderr) |
| 240 |
| 241 # Neither arguments nor subcommand. |
| 242 stderr = self.RunGsUtil(['cors'], return_stderr=True, expected_status=1) |
| 243 self.assertIn('command requires at least', stderr) |
| 244 |
| 245 |
| 246 class TestCorsOldAlias(TestCors): |
| 247 _set_cmd_prefix = ['setcors'] |
| 248 _get_cmd_prefix = ['getcors'] |
OLD | NEW |