~vila/uci-engine/enable-nova-and-swift

« back to all changes in this revision

Viewing changes to gatekeeper/gatekeeper/datastore/tests/test_sandbox.py

  • Committer: Ubuntu CI Bot
  • Author(s): Celso Providelo, Vincent Ladeuil
  • Date: 2014-04-29 21:24:01 UTC
  • mfrom: (450.1.21 uci-engine-gatekeeper)
  • Revision ID: ubuntu_ci_bot-20140429212401-vxmww51nzgpyajds
[r=PS Jenkins bot, Andy Doan, Vincent Ladeuil] Initial implementation of the Gatekeeper (Swift Sandbox/TempUrl manager) component.  from Celso Providelo

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
# Ubuntu CI Engine
 
3
# Copyright 2014 Canonical Ltd.
 
4
 
 
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.
 
8
 
 
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.
 
13
 
 
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
 
18
 
 
19
from datetime import datetime
 
20
from mock import patch
 
21
import pytz
 
22
from testtools import TestCase
 
23
 
 
24
from gatekeeper.datastore.tests import FakeOptions
 
25
from gatekeeper.datastore.sandbox import (
 
26
    SandboxContainer,
 
27
    SandboxNotFound,
 
28
    SandboxObject,
 
29
    SupervisedSandboxesMixin,
 
30
)
 
31
from gatekeeper.datastore.tempurl import (
 
32
    OSTempUrlProvider,
 
33
    HPTempUrlProvider,
 
34
)
 
35
 
 
36
 
 
37
def patch_it(context, name):
 
38
    """Nested patcher helper."""
 
39
    patcher = patch(name)
 
40
    thing = patcher.start()
 
41
    context.addCleanup(patcher.stop)
 
42
    return thing
 
43
 
 
44
 
 
45
class TestSandboxObject(TestCase):
 
46
    """Tests for `SandboxObject`."""
 
47
 
 
48
    def setUp(self):
 
49
        # Creates a sample `SandboxObject`.
 
50
        super(TestSandboxObject, self).setUp()
 
51
        contents = {
 
52
            'name': 'foo.txt',
 
53
            'bytes': 11,
 
54
            'content_type': 'text/plain',
 
55
        }
 
56
        self.object = SandboxObject(**contents)
 
57
 
 
58
    def test_title(self):
 
59
        # `SandboxObject` implements 'title'.
 
60
        self.assertEquals(
 
61
            'foo.txt (11 bytes, text/plain)', self.object.title)
 
62
 
 
63
 
 
64
class TestSandboxContainer(TestCase):
 
65
    """Tests for `SandboxObject`."""
 
66
 
 
67
    def setUp(self):
 
68
        # Creates a sample `SandboxContainer`.
 
69
        super(TestSandboxContainer, self).setUp()
 
70
        contents = {
 
71
            'name': 'sandbox-02c5fc18-ca73-11e3-88d9-001c4229f9ac',
 
72
            'bytes': 17,
 
73
            'count': 1,
 
74
        }
 
75
        self.url = 'http://fake.com/AUTH_1234'
 
76
        self.token = '4321'
 
77
        self.options = FakeOptions()
 
78
        self.sandbox = SandboxContainer(
 
79
            self.url, self.token, self.options, **contents)
 
80
 
 
81
    def test_prefix(self):
 
82
        # `SandboxContainer` implements 'PREFIX' class attribute.
 
83
        self.assertEquals(
 
84
            'sandbox-', SandboxContainer.PREFIX)
 
85
 
 
86
    def test_representation(self):
 
87
        # `SandboxContainer` representation.
 
88
        self.assertEquals(
 
89
            '02c5fc18-ca73-11e3-88d9-001c4229f9ac (17 bytes, 1 objects)',
 
90
            unicode(self.sandbox))
 
91
 
 
92
    def test_title(self):
 
93
        # `SandboxContainer` implements 'title'.
 
94
        self.assertEquals(
 
95
            '02c5fc18-ca73-11e3-88d9-001c4229f9ac (17 bytes, 1 objects)',
 
96
            self.sandbox.title)
 
97
 
 
98
    def test_identifier(self):
 
99
        # `SandboxContainer` implements 'identifier'.
 
100
        self.assertEquals(
 
101
            '02c5fc18-ca73-11e3-88d9-001c4229f9ac',
 
102
            self.sandbox.identifier)
 
103
 
 
104
    def test_age(self):
 
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))
 
110
 
 
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 = (
 
115
                'ignored',
 
116
                [{'name': 'one', 'bytes': 1, 'content_type': 'um'},
 
117
                 {'name': 'two', 'bytes': 2, 'content_type': 'dois'}])
 
118
            sandbox_objects = self.sandbox.objects
 
119
 
 
120
        self.assertEquals(
 
121
            ['one (1 bytes, um)',
 
122
             'two (2 bytes, dois)'],
 
123
            [o.title for o in sandbox_objects])
 
124
 
 
125
    def test_drop(self):
 
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'}])
 
133
        self.sandbox.drop()
 
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)
 
140
 
 
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)
 
145
 
 
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)
 
153
 
 
154
    def test_get_temp_url(self):
 
155
        # `SandboxContainer` wraps the tempurl provider.
 
156
        # Constant tempurl key.
 
157
        mock_key = patch_it(
 
158
            self,
 
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.
 
167
        self.assertEquals(
 
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'))
 
173
 
 
174
 
 
175
class TestSupervisedSandboxesMixin(TestCase):
 
176
    """Tests for `SupervisedSandboxesMixin`."""
 
177
 
 
178
    def setUp(self):
 
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()
 
185
 
 
186
    def test_get_container_name(self):
 
187
        # `SandboxContainer.PREFIX` is used to build container names.
 
188
        self.assertEquals(
 
189
            'sandbox-foo', self.mixin._get_container_name('foo'))
 
190
 
 
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 = (
 
195
                'ignored',
 
196
                [{'name': 'one', 'bytes': 1, 'count': 1},
 
197
                 {'name': 'two', 'bytes': 2, 'count': 2}])
 
198
            sandboxes = self.mixin.sandboxes
 
199
        self.assertEquals(
 
200
            ['one (1 bytes, 1 objects)',
 
201
             'two (2 bytes, 2 objects)'],
 
202
            [s.title for s in sandboxes])
 
203
 
 
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)
 
217
 
 
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.
 
224
        self.assertRaises(
 
225
            SandboxNotFound, self.mixin.get_sandbox, 'missing')
 
226
        mock_account.assert_called_once_with(
 
227
            self.mixin.url, self.mixin.token, prefix='sandbox-missing')
 
228
 
 
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()
 
235
 
 
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 = (
 
245
            'ignored',
 
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)