Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Side by Side Diff: third_party/gsutil/boto/tests/unit/glacier/test_layer2.py

Issue 12317103: Added gsutil to depot tools (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: added readme Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # -*- coding: utf-8 -*-
2 # Copyright (c) 2012 Thomas Parslow http://almostobsolete.net/
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining a
5 # copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish, dis-
8 # tribute, sublicense, and/or sell copies of the Software, and to permit
9 # persons to whom the Software is furnished to do so, subject to the fol-
10 # lowing conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 # IN THE SOFTWARE.
22 #
23
24 from tests.unit import unittest
25
26 from mock import call, Mock, patch, sentinel
27
28 from boto.glacier.layer1 import Layer1
29 from boto.glacier.layer2 import Layer2
30 import boto.glacier.vault
31 from boto.glacier.vault import Vault
32 from boto.glacier.vault import Job
33
34 from StringIO import StringIO
35
36 # Some fixture data from the Glacier docs
37 FIXTURE_VAULT = {
38 "CreationDate" : "2012-02-20T17:01:45.198Z",
39 "LastInventoryDate" : "2012-03-20T17:03:43.221Z",
40 "NumberOfArchives" : 192,
41 "SizeInBytes" : 78088912,
42 "VaultARN" : "arn:aws:glacier:us-east-1:012345678901:vaults/examplevault",
43 "VaultName" : "examplevault"
44 }
45
46 FIXTURE_ARCHIVE_JOB = {
47 "Action": "ArchiveRetrieval",
48 "ArchiveId": ("NkbByEejwEggmBz2fTHgJrg0XBoDfjP4q6iu87-TjhqG6eGoOY9Z8i1_AUyUs"
49 "uhPAdTqLHy8pTl5nfCFJmDl2yEZONi5L26Omw12vcs01MNGntHEQL8MBfGlqr"
50 "EXAMPLEArchiveId"),
51 "ArchiveSizeInBytes": 16777216,
52 "Completed": False,
53 "CreationDate": "2012-05-15T17:21:39.339Z",
54 "CompletionDate": "2012-05-15T17:21:43.561Z",
55 "InventorySizeInBytes": None,
56 "JobDescription": "My ArchiveRetrieval Job",
57 "JobId": ("HkF9p6o7yjhFx-K3CGl6fuSm6VzW9T7esGQfco8nUXVYwS0jlb5gq1JZ55yHgt5v"
58 "P54ZShjoQzQVVh7vEXAMPLEjobID"),
59 "SHA256TreeHash": ("beb0fe31a1c7ca8c6c04d574ea906e3f97b31fdca7571defb5b44dc"
60 "a89b5af60"),
61 "SNSTopic": "arn:aws:sns:us-east-1:012345678901:mytopic",
62 "StatusCode": "InProgress",
63 "StatusMessage": "Operation in progress.",
64 "VaultARN": "arn:aws:glacier:us-east-1:012345678901:vaults/examplevault"
65 }
66
67 EXAMPLE_PART_LIST_RESULT_PAGE_1 = {
68 "ArchiveDescription": "archive description 1",
69 "CreationDate": "2012-03-20T17:03:43.221Z",
70 "Marker": "MfgsKHVjbQ6EldVl72bn3_n5h2TaGZQUO-Qb3B9j3TITf7WajQ",
71 "MultipartUploadId": "OW2fM5iVylEpFEMM9_HpKowRapC3vn5sSL39_396UW9zLFUWVrnRHa PjUJddQ5OxSHVXjYtrN47NBZ-khxOjyEXAMPLE",
72 "PartSizeInBytes": 4194304,
73 "Parts":
74 [ {
75 "RangeInBytes": "4194304-8388607",
76 "SHA256TreeHash": "01d34dabf7be316472c93b1ef80721f5d4"
77 }],
78 "VaultARN": "arn:aws:glacier:us-east-1:012345678901:vaults/demo1-vault"
79 }
80
81 # The documentation doesn't say whether the non-Parts fields are defined in
82 # future pages, so assume they are not.
83 EXAMPLE_PART_LIST_RESULT_PAGE_2 = {
84 "ArchiveDescription": None,
85 "CreationDate": None,
86 "Marker": None,
87 "MultipartUploadId": None,
88 "PartSizeInBytes": None,
89 "Parts":
90 [ {
91 "RangeInBytes": "0-4194303",
92 "SHA256TreeHash": "01d34dabf7be316472c93b1ef80721f5d4"
93 }],
94 "VaultARN": None
95 }
96
97 EXAMPLE_PART_LIST_COMPLETE = {
98 "ArchiveDescription": "archive description 1",
99 "CreationDate": "2012-03-20T17:03:43.221Z",
100 "Marker": None,
101 "MultipartUploadId": "OW2fM5iVylEpFEMM9_HpKowRapC3vn5sSL39_396UW9zLFUWVrnRHa PjUJddQ5OxSHVXjYtrN47NBZ-khxOjyEXAMPLE",
102 "PartSizeInBytes": 4194304,
103 "Parts":
104 [ {
105 "RangeInBytes": "4194304-8388607",
106 "SHA256TreeHash": "01d34dabf7be316472c93b1ef80721f5d4"
107 }, {
108 "RangeInBytes": "0-4194303",
109 "SHA256TreeHash": "01d34dabf7be316472c93b1ef80721f5d4"
110 }],
111 "VaultARN": "arn:aws:glacier:us-east-1:012345678901:vaults/demo1-vault"
112 }
113
114
115 class GlacierLayer2Base(unittest.TestCase):
116 def setUp(self):
117 self.mock_layer1 = Mock(spec=Layer1)
118
119
120 class TestGlacierLayer2Connection(GlacierLayer2Base):
121 def setUp(self):
122 GlacierLayer2Base.setUp(self)
123 self.layer2 = Layer2(layer1=self.mock_layer1)
124
125 def test_create_vault(self):
126 self.mock_layer1.describe_vault.return_value = FIXTURE_VAULT
127 self.layer2.create_vault("My Vault")
128 self.mock_layer1.create_vault.assert_called_with("My Vault")
129
130 def test_get_vault(self):
131 self.mock_layer1.describe_vault.return_value = FIXTURE_VAULT
132 vault = self.layer2.get_vault("examplevault")
133 self.assertEqual(vault.layer1, self.mock_layer1)
134 self.assertEqual(vault.name, "examplevault")
135 self.assertEqual(vault.size, 78088912)
136 self.assertEqual(vault.number_of_archives, 192)
137
138 def list_vaults(self):
139 self.mock_layer1.list_vaults.return_value = [FIXTURE_VAULT]
140 vaults = self.layer2.list_vaults()
141 self.assertEqual(vaults[0].name, "examplevault")
142
143
144 class TestVault(GlacierLayer2Base):
145 def setUp(self):
146 GlacierLayer2Base.setUp(self)
147 self.vault = Vault(self.mock_layer1, FIXTURE_VAULT)
148
149 # TODO: Tests for the other methods of uploading
150
151 def test_create_archive_writer(self):
152 self.mock_layer1.initiate_multipart_upload.return_value = {
153 "UploadId": "UPLOADID"}
154 writer = self.vault.create_archive_writer(description="stuff")
155 self.mock_layer1.initiate_multipart_upload.assert_called_with(
156 "examplevault", self.vault.DefaultPartSize, "stuff")
157 self.assertEqual(writer.vault, self.vault)
158 self.assertEqual(writer.upload_id, "UPLOADID")
159
160 def test_delete_vault(self):
161 self.vault.delete_archive("archive")
162 self.mock_layer1.delete_archive.assert_called_with("examplevault",
163 "archive")
164
165 def test_get_job(self):
166 self.mock_layer1.describe_job.return_value = FIXTURE_ARCHIVE_JOB
167 job = self.vault.get_job(
168 "NkbByEejwEggmBz2fTHgJrg0XBoDfjP4q6iu87-TjhqG6eGoOY9Z8i1_AUyUsuhPA"
169 "dTqLHy8pTl5nfCFJmDl2yEZONi5L26Omw12vcs01MNGntHEQL8MBfGlqrEXAMPLEA"
170 "rchiveId")
171 self.assertEqual(job.action, "ArchiveRetrieval")
172
173 def test_list_jobs(self):
174 self.mock_layer1.list_jobs.return_value = {
175 "JobList": [FIXTURE_ARCHIVE_JOB]}
176 jobs = self.vault.list_jobs(False, "InProgress")
177 self.mock_layer1.list_jobs.assert_called_with("examplevault",
178 False, "InProgress")
179 self.assertEqual(jobs[0].archive_id,
180 "NkbByEejwEggmBz2fTHgJrg0XBoDfjP4q6iu87-TjhqG6eGoOY9Z"
181 "8i1_AUyUsuhPAdTqLHy8pTl5nfCFJmDl2yEZONi5L26Omw12vcs0"
182 "1MNGntHEQL8MBfGlqrEXAMPLEArchiveId")
183
184 def test_list_all_parts_one_page(self):
185 self.mock_layer1.list_parts.return_value = (
186 dict(EXAMPLE_PART_LIST_COMPLETE)) # take a copy
187 parts_result = self.vault.list_all_parts(sentinel.upload_id)
188 expected = [call('examplevault', sentinel.upload_id)]
189 self.assertEquals(expected, self.mock_layer1.list_parts.call_args_list)
190 self.assertEquals(EXAMPLE_PART_LIST_COMPLETE, parts_result)
191
192 def test_list_all_parts_two_pages(self):
193 self.mock_layer1.list_parts.side_effect = [
194 # take copies
195 dict(EXAMPLE_PART_LIST_RESULT_PAGE_1),
196 dict(EXAMPLE_PART_LIST_RESULT_PAGE_2)
197 ]
198 parts_result = self.vault.list_all_parts(sentinel.upload_id)
199 expected = [call('examplevault', sentinel.upload_id),
200 call('examplevault', sentinel.upload_id,
201 marker=EXAMPLE_PART_LIST_RESULT_PAGE_1['Marker'])]
202 self.assertEquals(expected, self.mock_layer1.list_parts.call_args_list)
203 self.assertEquals(EXAMPLE_PART_LIST_COMPLETE, parts_result)
204
205 @patch('boto.glacier.vault.resume_file_upload')
206 def test_resume_archive_from_file(self, mock_resume_file_upload):
207 part_size = 4
208 mock_list_parts = Mock()
209 mock_list_parts.return_value = {
210 'PartSizeInBytes': part_size,
211 'Parts': [{
212 'RangeInBytes': '0-3',
213 'SHA256TreeHash': '12',
214 }, {
215 'RangeInBytes': '4-6',
216 'SHA256TreeHash': '34',
217 },
218 ]}
219
220 self.vault.list_all_parts = mock_list_parts
221 self.vault.resume_archive_from_file(
222 sentinel.upload_id, file_obj=sentinel.file_obj)
223 mock_resume_file_upload.assert_called_once_with(
224 self.vault, sentinel.upload_id, part_size, sentinel.file_obj,
225 {0: '12'.decode('hex'), 1: '34'.decode('hex')})
226
227
228 class TestJob(GlacierLayer2Base):
229 def setUp(self):
230 GlacierLayer2Base.setUp(self)
231 self.vault = Vault(self.mock_layer1, FIXTURE_VAULT)
232 self.job = Job(self.vault, FIXTURE_ARCHIVE_JOB)
233
234 def test_get_job_output(self):
235 self.mock_layer1.get_job_output.return_value = "TEST_OUTPUT"
236 self.job.get_output((0,100))
237 self.mock_layer1.get_job_output.assert_called_with(
238 "examplevault",
239 "HkF9p6o7yjhFx-K3CGl6fuSm6VzW9T7esGQfco8nUXVYwS0jlb5gq1JZ55yHgt5vP"
240 "54ZShjoQzQVVh7vEXAMPLEjobID", (0,100))
241
242 class TestRangeStringParsing(unittest.TestCase):
243 def test_simple_range(self):
244 self.assertEquals(
245 Vault._range_string_to_part_index('0-3', 4), 0)
246
247 def test_range_one_too_big(self):
248 # Off-by-one bug in Amazon's Glacier implementation
249 # See: https://forums.aws.amazon.com/thread.jspa?threadID=106866&tstart= 0
250 # Workaround is to assume that if a (start, end] range appears to be
251 # returned then that is what it is.
252 self.assertEquals(
253 Vault._range_string_to_part_index('0-4', 4), 0)
254
255 def test_range_too_big(self):
256 self.assertRaises(
257 AssertionError, Vault._range_string_to_part_index, '0-5', 4)
258
259 def test_range_start_mismatch(self):
260 self.assertRaises(
261 AssertionError, Vault._range_string_to_part_index, '1-3', 4)
262
263 def test_range_end_mismatch(self):
264 # End mismatch is OK, since the last part might be short
265 self.assertEquals(
266 Vault._range_string_to_part_index('0-2', 4), 0)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698