1
# -*- coding: utf-8 -*-
3
# Copyright 2014 Canonical Ltd.
5
# This program is free software: you can redistribute it and/or modify it
6
# under the terms of the GNU Affero General Public License version 3, as
7
# published by the Free Software Foundation.
9
# This program is distributed in the hope that it will be useful, but
10
# WITHOUT ANY WARRANTY; without even the implied warranties of
11
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12
# PURPOSE. See the GNU Affero General Public License for more details.
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
"""Swift datastore sandbox mixin tests."""
17
from __future__ import unicode_literals
19
from datetime import datetime
20
from mock import patch
22
from testtools import TestCase
24
from gatekeeper.datastore.tests import FakeOptions
25
from gatekeeper.datastore.sandbox import (
29
SupervisedSandboxesMixin,
31
from gatekeeper.datastore.tempurl import (
37
def patch_it(context, name):
38
"""Nested patcher helper."""
40
thing = patcher.start()
41
context.addCleanup(patcher.stop)
45
class TestSandboxObject(TestCase):
46
"""Tests for `SandboxObject`."""
49
# Creates a sample `SandboxObject`.
50
super(TestSandboxObject, self).setUp()
54
'content_type': 'text/plain',
56
self.object = SandboxObject(**contents)
59
# `SandboxObject` implements 'title'.
61
'foo.txt (11 bytes, text/plain)', self.object.title)
64
class TestSandboxContainer(TestCase):
65
"""Tests for `SandboxObject`."""
68
# Creates a sample `SandboxContainer`.
69
super(TestSandboxContainer, self).setUp()
71
'name': 'sandbox-02c5fc18-ca73-11e3-88d9-001c4229f9ac',
75
self.url = 'http://fake.com/AUTH_1234'
77
self.options = FakeOptions()
78
self.sandbox = SandboxContainer(
79
self.url, self.token, self.options, **contents)
81
def test_prefix(self):
82
# `SandboxContainer` implements 'PREFIX' class attribute.
84
'sandbox-', SandboxContainer.PREFIX)
86
def test_representation(self):
87
# `SandboxContainer` representation.
89
'02c5fc18-ca73-11e3-88d9-001c4229f9ac (17 bytes, 1 objects)',
90
unicode(self.sandbox))
93
# `SandboxContainer` implements 'title'.
95
'02c5fc18-ca73-11e3-88d9-001c4229f9ac (17 bytes, 1 objects)',
98
def test_identifier(self):
99
# `SandboxContainer` implements 'identifier'.
101
'02c5fc18-ca73-11e3-88d9-001c4229f9ac',
102
self.sandbox.identifier)
105
# `SandboxContainer` implements 'age'.
106
with patch.object(self.sandbox, '_now') as mock_now:
107
mock_now.return_value = datetime(2014, 04, 23, tzinfo=pytz.utc)
108
age = self.sandbox.age
109
self.assertEquals('0:51:33.217380', str(age))
111
def test_objects(self):
112
# `SandboxContainer` contained objects iterator.
113
with patch('swiftclient.client.get_container') as mock_container:
114
mock_container.return_value = (
116
[{'name': 'one', 'bytes': 1, 'content_type': 'um'},
117
{'name': 'two', 'bytes': 2, 'content_type': 'dois'}])
118
sandbox_objects = self.sandbox.objects
121
['one (1 bytes, um)',
122
'two (2 bytes, dois)'],
123
[o.title for o in sandbox_objects])
126
# `SandboxContainer` drop method delete the sandbox and its contents.
127
mock_gc = patch_it(self, 'swiftclient.client.get_container')
128
mock_do = patch_it(self, 'swiftclient.client.delete_object')
129
mock_dc = patch_it(self, 'swiftclient.client.delete_container')
130
# Simulates a sandbox with a single object.
131
mock_gc.return_value = (
132
'ignored', [{'name': 'one', 'bytes': 1, 'content_type': 'um'}])
134
# 'delete_object' is called once for the contained object.
135
mock_do.assert_called_once_with(
136
self.url, self.token, self.sandbox.name, 'one')
137
# 'delete_container' is called once for the sandbox container.
138
mock_dc.assert_called_once_with(
139
self.url, self.token, self.sandbox.name)
141
def test_get_tempurl_provider_os(self):
142
# `SandboxContainer` uses appropriate tempurl provider for OS.
143
self.assertIsInstance(
144
self.sandbox._get_tempurl_provider(), OSTempUrlProvider)
146
def test_get_tempurl_provider_hp(self):
147
# `SandboxContainer` uses appropriate tempurl provider for HP
148
hp_options = FakeOptions(
149
auth_url='http://hpcloud.com', secret_key=b'secret')
150
hp_sandbox = SandboxContainer(self.url, self.token, hp_options)
151
self.assertIsInstance(
152
hp_sandbox._get_tempurl_provider(), HPTempUrlProvider)
154
def test_get_temp_url(self):
155
# `SandboxContainer` wraps the tempurl provider.
156
# Constant tempurl key.
159
'gatekeeper.datastore.sandbox.SandboxContainer._get_tempurl_key')
160
mock_key.return_value = b'02c5fc18-ca73-11e3-88d9-001c4229f9ac'
161
# Known expiration time.
162
mock_time = patch_it(self, 'time.time')
163
mock_time.return_value = 1397702769
164
# Suppress external access.
165
patch_it(self, 'swiftclient.client.post_account')
166
# And finaly builds a predictable tempurl.
168
'http://fake.com/v1/AUTH_1234/'
169
'sandbox-02c5fc18-ca73-11e3-88d9-001c4229f9ac/a_object?'
170
'temp_url_sig=a218db1ec606995f4912c0e3193b059926fb451d&'
171
'temp_url_expires=1397702829',
172
self.sandbox.get_temp_url('a_object'))
175
class TestSupervisedSandboxesMixin(TestCase):
176
"""Tests for `SupervisedSandboxesMixin`."""
179
# Creates a sample `SupervisedSandboxesMixin`.
180
super(TestSupervisedSandboxesMixin, self).setUp()
181
self.mixin = SupervisedSandboxesMixin()
182
self.mixin.url = 'http://a-url'
183
self.mixin.token = 'a-token'
184
self.mixin.options = FakeOptions()
186
def test_get_container_name(self):
187
# `SandboxContainer.PREFIX` is used to build container names.
189
'sandbox-foo', self.mixin._get_container_name('foo'))
191
def test_sandboxes(self):
192
# `SupervisedSandboxesMixin` implements a sandbox iterator.
193
with patch('swiftclient.client.get_account') as mock_account:
194
mock_account.return_value = (
196
[{'name': 'one', 'bytes': 1, 'count': 1},
197
{'name': 'two', 'bytes': 2, 'count': 2}])
198
sandboxes = self.mixin.sandboxes
200
['one (1 bytes, 1 objects)',
201
'two (2 bytes, 2 objects)'],
202
[s.title for s in sandboxes])
204
def test_get_sandbox(self):
205
# `SupervisedSandboxesMixin` implements a sandbox getter.
206
mock_account = patch_it(self, 'swiftclient.client.get_account')
207
mock_account.return_value = (
208
'ignored', [{'name': 'new', 'bytes': 0, 'count': 0}])
209
# Fetch an existing sandbox.
210
sandbox = self.mixin.get_sandbox('new')
211
mock_account.assert_called_once_with(
212
self.mixin.url, self.mixin.token, prefix='sandbox-new')
213
self.assertIsInstance(sandbox, SandboxContainer)
214
self.assertEquals('new', sandbox.name)
215
self.assertEquals(0, sandbox.size)
216
self.assertEquals(0, sandbox.count)
218
def test_get_sandbox_missing(self):
219
# `SupervisedSandboxesMixin.get_sandbox` raises `SandboxNotFound`
220
# on missing sandboxes.
221
mock_account = patch_it(self, 'swiftclient.client.get_account')
222
mock_account.return_value = ('ignored', [])
223
# Try to fetch a missing sandbox.
225
SandboxNotFound, self.mixin.get_sandbox, 'missing')
226
mock_account.assert_called_once_with(
227
self.mixin.url, self.mixin.token, prefix='sandbox-missing')
229
def test_get_sandbox_empty_identifier(self):
230
# `SupervisedSandboxesMixin.get_sandbox` raises `SandboxNotFound`
231
# when called with empty identifier, swift is not even consulted.
232
mock_account = patch_it(self, 'swiftclient.client.get_account')
233
self.assertRaises(SandboxNotFound, self.mixin.get_sandbox, '')
234
mock_account.assert_not_called()
236
def test_create_sandbox(self):
237
# `SupervisedSandboxesMixin` implements a sandbox creator.
238
a_uuid = '02c5fc18-ca73-11e3-88d9-001c4229f9ac'
239
mock_uuid = patch_it(self, 'uuid.uuid1')
240
mock_uuid.return_value = a_uuid
241
patch_it(self, 'swiftclient.client.put_container')
242
mock_account = patch_it(self, 'swiftclient.client.get_account')
243
container_name = self.mixin._get_container_name(a_uuid)
244
mock_account.return_value = (
246
[{'name': container_name, 'bytes': 0, 'count': 0}])
247
# Create a new sandbox.
248
sandbox = self.mixin.create_sandbox()
249
self.assertIsInstance(sandbox, SandboxContainer)
250
self.assertEquals(container_name, sandbox.name)
251
self.assertEquals(a_uuid, sandbox.identifier)
252
self.assertEquals(0, sandbox.size)
253
self.assertEquals(0, sandbox.count)