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 lifecycle command.""" | |
16 | |
17 from __future__ import absolute_import | |
18 | |
19 import json | |
20 import posixpath | |
21 from xml.dom.minidom import parseString | |
22 | |
23 from gslib.cs_api_map import ApiSelector | |
24 import gslib.tests.testcase as testcase | |
25 from gslib.tests.testcase.integration_testcase import SkipForS3 | |
26 from gslib.tests.util import ObjectToURI as suri | |
27 from gslib.tests.util import unittest | |
28 from gslib.translation_helper import LifecycleTranslation | |
29 from gslib.util import Retry | |
30 | |
31 | |
32 @SkipForS3('Lifecycle command is only supported for gs:// URLs') | |
33 class TestSetLifecycle(testcase.GsUtilIntegrationTestCase): | |
34 """Integration tests for lifecycle command.""" | |
35 | |
36 empty_doc1 = '{}' | |
37 | |
38 xml_doc = parseString( | |
39 '<LifecycleConfiguration><Rule>' | |
40 '<Action><Delete/></Action>' | |
41 '<Condition><Age>365</Age></Condition>' | |
42 '</Rule></LifecycleConfiguration>').toprettyxml(indent=' ') | |
43 | |
44 bad_doc = ( | |
45 '{"rule": [{"action": {"type": "Add"}, "condition": {"age": 365}}]}\n') | |
46 | |
47 lifecycle_doc = ( | |
48 '{"rule": [{"action": {"type": "Delete"}, "condition": {"age": 365}}]}\n') | |
49 lifecycle_json_obj = json.loads(lifecycle_doc) | |
50 | |
51 lifecycle_doc_bucket_style = ( | |
52 '{"lifecycle": {"rule": [{"action": {"type": "Delete"}, "condition": ' | |
53 '{"age": 365}}]}}\n') | |
54 | |
55 lifecycle_created_before_doc = ( | |
56 '{"rule": [{"action": {"type": "Delete"}, "condition": ' | |
57 '{"createdBefore": "2014-10-01"}}]}\n') | |
58 lifecycle_created_before_json_obj = json.loads(lifecycle_created_before_doc) | |
59 | |
60 no_lifecycle_config = 'has no lifecycle configuration.' | |
61 | |
62 def test_lifecycle_translation(self): | |
63 """Tests lifecycle translation for various formats.""" | |
64 json_text = self.lifecycle_doc | |
65 entries_list = LifecycleTranslation.JsonLifecycleToMessage(json_text) | |
66 boto_lifecycle = LifecycleTranslation.BotoLifecycleFromMessage(entries_list) | |
67 converted_entries_list = LifecycleTranslation.BotoLifecycleToMessage( | |
68 boto_lifecycle) | |
69 converted_json_text = LifecycleTranslation.JsonLifecycleFromMessage( | |
70 converted_entries_list) | |
71 self.assertEqual(json.loads(json_text), json.loads(converted_json_text)) | |
72 | |
73 def test_default_lifecycle(self): | |
74 bucket_uri = self.CreateBucket() | |
75 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket_uri)], | |
76 return_stdout=True) | |
77 self.assertIn(self.no_lifecycle_config, stdout) | |
78 | |
79 def test_set_empty_lifecycle1(self): | |
80 bucket_uri = self.CreateBucket() | |
81 fpath = self.CreateTempFile(contents=self.empty_doc1) | |
82 self.RunGsUtil(['lifecycle', 'set', fpath, suri(bucket_uri)]) | |
83 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket_uri)], | |
84 return_stdout=True) | |
85 self.assertIn(self.no_lifecycle_config, stdout) | |
86 | |
87 def test_valid_lifecycle(self): | |
88 bucket_uri = self.CreateBucket() | |
89 fpath = self.CreateTempFile(contents=self.lifecycle_doc) | |
90 self.RunGsUtil(['lifecycle', 'set', fpath, suri(bucket_uri)]) | |
91 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket_uri)], | |
92 return_stdout=True) | |
93 self.assertEqual(json.loads(stdout), self.lifecycle_json_obj) | |
94 | |
95 def test_valid_lifecycle_bucket_style(self): | |
96 bucket_uri = self.CreateBucket() | |
97 fpath = self.CreateTempFile(contents=self.lifecycle_doc_bucket_style) | |
98 self.RunGsUtil(['lifecycle', 'set', fpath, suri(bucket_uri)]) | |
99 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket_uri)], | |
100 return_stdout=True) | |
101 self.assertEqual(json.loads(stdout), self.lifecycle_json_obj) | |
102 | |
103 def test_created_before_lifecycle(self): | |
104 bucket_uri = self.CreateBucket() | |
105 fpath = self.CreateTempFile(contents=self.lifecycle_created_before_doc) | |
106 self.RunGsUtil(['lifecycle', 'set', fpath, suri(bucket_uri)]) | |
107 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket_uri)], | |
108 return_stdout=True) | |
109 self.assertEqual(json.loads(stdout), self.lifecycle_created_before_json_obj) | |
110 | |
111 def test_bad_lifecycle(self): | |
112 bucket_uri = self.CreateBucket() | |
113 fpath = self.CreateTempFile(contents=self.bad_doc) | |
114 stderr = self.RunGsUtil(['lifecycle', 'set', fpath, suri(bucket_uri)], | |
115 expected_status=1, return_stderr=True) | |
116 self.assertNotIn('XML lifecycle data provided', stderr) | |
117 | |
118 def test_bad_xml_lifecycle(self): | |
119 bucket_uri = self.CreateBucket() | |
120 fpath = self.CreateTempFile(contents=self.xml_doc) | |
121 stderr = self.RunGsUtil(['lifecycle', 'set', fpath, suri(bucket_uri)], | |
122 expected_status=1, return_stderr=True) | |
123 self.assertIn('XML lifecycle data provided', stderr) | |
124 | |
125 def test_set_lifecycle_and_reset(self): | |
126 """Tests setting and turning off lifecycle configuration.""" | |
127 bucket_uri = self.CreateBucket() | |
128 tmpdir = self.CreateTempDir() | |
129 fpath = self.CreateTempFile(tmpdir=tmpdir, contents=self.lifecycle_doc) | |
130 self.RunGsUtil(['lifecycle', 'set', fpath, suri(bucket_uri)]) | |
131 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket_uri)], | |
132 return_stdout=True) | |
133 self.assertEqual(json.loads(stdout), self.lifecycle_json_obj) | |
134 | |
135 fpath = self.CreateTempFile(tmpdir=tmpdir, contents=self.empty_doc1) | |
136 self.RunGsUtil(['lifecycle', 'set', fpath, suri(bucket_uri)]) | |
137 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket_uri)], | |
138 return_stdout=True) | |
139 self.assertIn(self.no_lifecycle_config, stdout) | |
140 | |
141 def test_set_lifecycle_multi_buckets(self): | |
142 """Tests setting lifecycle configuration on multiple buckets.""" | |
143 bucket1_uri = self.CreateBucket() | |
144 bucket2_uri = self.CreateBucket() | |
145 fpath = self.CreateTempFile(contents=self.lifecycle_doc) | |
146 self.RunGsUtil( | |
147 ['lifecycle', 'set', fpath, suri(bucket1_uri), suri(bucket2_uri)]) | |
148 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket1_uri)], | |
149 return_stdout=True) | |
150 self.assertEqual(json.loads(stdout), self.lifecycle_json_obj) | |
151 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket2_uri)], | |
152 return_stdout=True) | |
153 self.assertEqual(json.loads(stdout), self.lifecycle_json_obj) | |
154 | |
155 def test_set_lifecycle_wildcard(self): | |
156 """Tests setting lifecycle with a wildcarded bucket URI.""" | |
157 if self.test_api == ApiSelector.XML: | |
158 # This test lists buckets with wildcards, but it is possible that another | |
159 # test being run in parallel (in the same project) deletes a bucket after | |
160 # it is listed in this test. This causes the subsequent XML metadata get | |
161 # for the lifecycle configuration to fail on that just-deleted bucket, | |
162 # even though that bucket is not used directly in this test. | |
163 return unittest.skip('XML wildcard behavior can cause test to flake ' | |
164 'if a bucket in the same project is deleted ' | |
165 'during execution.') | |
166 | |
167 random_prefix = self.MakeRandomTestString() | |
168 bucket1_name = self.MakeTempName('bucket', prefix=random_prefix) | |
169 bucket2_name = self.MakeTempName('bucket', prefix=random_prefix) | |
170 bucket1_uri = self.CreateBucket(bucket_name=bucket1_name) | |
171 bucket2_uri = self.CreateBucket(bucket_name=bucket2_name) | |
172 # This just double checks that the common prefix of the two buckets is what | |
173 # we think it should be (based on implementation detail of CreateBucket). | |
174 # We want to be careful when setting a wildcard on buckets to make sure we | |
175 # don't step outside the test buckets to affect other buckets. | |
176 common_prefix = posixpath.commonprefix([suri(bucket1_uri), | |
177 suri(bucket2_uri)]) | |
178 self.assertTrue(common_prefix.startswith( | |
179 'gs://%sgsutil-test-test_set_lifecycle_wildcard-' % random_prefix)) | |
180 wildcard = '%s*' % common_prefix | |
181 | |
182 fpath = self.CreateTempFile(contents=self.lifecycle_doc) | |
183 | |
184 # Use @Retry as hedge against bucket listing eventual consistency. | |
185 expected = set([ | |
186 'Setting lifecycle configuration on %s/...' % suri(bucket1_uri), | |
187 'Setting lifecycle configuration on %s/...' % suri(bucket2_uri)]) | |
188 actual = set() | |
189 @Retry(AssertionError, tries=3, timeout_secs=1) | |
190 def _Check1(): | |
191 stderr = self.RunGsUtil(['lifecycle', 'set', fpath, wildcard], | |
192 return_stderr=True) | |
193 actual.update(stderr.splitlines()) | |
194 self.assertEqual(expected, actual) | |
195 self.assertEqual(stderr.count('Setting lifecycle configuration'), 2) | |
196 _Check1() | |
197 | |
198 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket1_uri)], | |
199 return_stdout=True) | |
200 self.assertEqual(json.loads(stdout), self.lifecycle_json_obj) | |
201 stdout = self.RunGsUtil(['lifecycle', 'get', suri(bucket2_uri)], | |
202 return_stdout=True) | |
203 self.assertEqual(json.loads(stdout), self.lifecycle_json_obj) | |
OLD | NEW |