Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / test / __init__.py @ 369a7b41

History | View | Annotate | Download (15.5 kB)

1 f3787696 Sofia Papagiannaki
#!/usr/bin/env python
2 f3787696 Sofia Papagiannaki
#coding=utf8
3 f3787696 Sofia Papagiannaki
4 f3787696 Sofia Papagiannaki
# Copyright 2011-2013 GRNET S.A. All rights reserved.
5 f3787696 Sofia Papagiannaki
#
6 f3787696 Sofia Papagiannaki
# Redistribution and use in source and binary forms, with or
7 f3787696 Sofia Papagiannaki
# without modification, are permitted provided that the following
8 f3787696 Sofia Papagiannaki
# conditions are met:
9 f3787696 Sofia Papagiannaki
#
10 f3787696 Sofia Papagiannaki
#   1. Redistributions of source code must retain the above
11 f3787696 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
12 f3787696 Sofia Papagiannaki
#      disclaimer.
13 f3787696 Sofia Papagiannaki
#
14 f3787696 Sofia Papagiannaki
#   2. Redistributions in binary form must reproduce the above
15 f3787696 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
16 f3787696 Sofia Papagiannaki
#      disclaimer in the documentation and/or other materials
17 f3787696 Sofia Papagiannaki
#      provided with the distribution.
18 f3787696 Sofia Papagiannaki
#
19 f3787696 Sofia Papagiannaki
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
20 f3787696 Sofia Papagiannaki
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 f3787696 Sofia Papagiannaki
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 f3787696 Sofia Papagiannaki
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
23 f3787696 Sofia Papagiannaki
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 f3787696 Sofia Papagiannaki
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 f3787696 Sofia Papagiannaki
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 f3787696 Sofia Papagiannaki
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 f3787696 Sofia Papagiannaki
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 f3787696 Sofia Papagiannaki
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 f3787696 Sofia Papagiannaki
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 f3787696 Sofia Papagiannaki
# POSSIBILITY OF SUCH DAMAGE.
31 f3787696 Sofia Papagiannaki
#
32 f3787696 Sofia Papagiannaki
# The views and conclusions contained in the software and
33 f3787696 Sofia Papagiannaki
# documentation are those of the authors and should not be
34 f3787696 Sofia Papagiannaki
# interpreted as representing official policies, either expressed
35 f3787696 Sofia Papagiannaki
# or implied, of GRNET S.A.
36 f3787696 Sofia Papagiannaki
37 f3787696 Sofia Papagiannaki
from urlparse import urlunsplit, urlsplit
38 f3787696 Sofia Papagiannaki
from xml.dom import minidom
39 f3787696 Sofia Papagiannaki
40 f3787696 Sofia Papagiannaki
from snf_django.utils.testing import with_settings, astakos_user
41 f3787696 Sofia Papagiannaki
42 f3787696 Sofia Papagiannaki
from pithos.backends.random_word import get_random_word
43 f3787696 Sofia Papagiannaki
from pithos.api import settings as pithos_settings
44 f3787696 Sofia Papagiannaki
45 d6a92fa0 Sofia Papagiannaki
from synnefo.lib.services import get_service_path
46 d6a92fa0 Sofia Papagiannaki
from synnefo.lib import join_urls
47 d6a92fa0 Sofia Papagiannaki
48 f3787696 Sofia Papagiannaki
from django.test import TestCase
49 f3787696 Sofia Papagiannaki
from django.utils.http import urlencode
50 f3787696 Sofia Papagiannaki
from django.conf import settings
51 f3787696 Sofia Papagiannaki
52 f3787696 Sofia Papagiannaki
import django.utils.simplejson as json
53 f3787696 Sofia Papagiannaki
54 f3787696 Sofia Papagiannaki
import re
55 f3787696 Sofia Papagiannaki
import random
56 f3787696 Sofia Papagiannaki
import threading
57 f3787696 Sofia Papagiannaki
import functools
58 f3787696 Sofia Papagiannaki
59 f3787696 Sofia Papagiannaki
pithos_test_settings = functools.partial(with_settings, pithos_settings)
60 f3787696 Sofia Papagiannaki
61 f3787696 Sofia Papagiannaki
DATE_FORMATS = ["%a %b %d %H:%M:%S %Y",
62 f3787696 Sofia Papagiannaki
                "%A, %d-%b-%y %H:%M:%S GMT",
63 f3787696 Sofia Papagiannaki
                "%a, %d %b %Y %H:%M:%S GMT"]
64 f3787696 Sofia Papagiannaki
65 f3787696 Sofia Papagiannaki
o_names = ['kate.jpg',
66 f3787696 Sofia Papagiannaki
           'kate_beckinsale.jpg',
67 f3787696 Sofia Papagiannaki
           'How To Win Friends And Influence People.pdf',
68 f3787696 Sofia Papagiannaki
           'moms_birthday.jpg',
69 f3787696 Sofia Papagiannaki
           'poodle_strut.mov',
70 f3787696 Sofia Papagiannaki
           'Disturbed - Down With The Sickness.mp3',
71 f3787696 Sofia Papagiannaki
           'army_of_darkness.avi',
72 f3787696 Sofia Papagiannaki
           'the_mad.avi',
73 f3787696 Sofia Papagiannaki
           'photos/animals/dogs/poodle.jpg',
74 f3787696 Sofia Papagiannaki
           'photos/animals/dogs/terrier.jpg',
75 f3787696 Sofia Papagiannaki
           'photos/animals/cats/persian.jpg',
76 f3787696 Sofia Papagiannaki
           'photos/animals/cats/siamese.jpg',
77 f3787696 Sofia Papagiannaki
           'photos/plants/fern.jpg',
78 f3787696 Sofia Papagiannaki
           'photos/plants/rose.jpg',
79 f3787696 Sofia Papagiannaki
           'photos/me.jpg']
80 f3787696 Sofia Papagiannaki
81 f3787696 Sofia Papagiannaki
details = {'container': ('name', 'count', 'bytes', 'last_modified',
82 f3787696 Sofia Papagiannaki
                         'x_container_policy'),
83 f3787696 Sofia Papagiannaki
           'object': ('name', 'hash', 'bytes', 'content_type',
84 f3787696 Sofia Papagiannaki
                      'content_encoding', 'last_modified',)}
85 f3787696 Sofia Papagiannaki
86 f3787696 Sofia Papagiannaki
return_codes = (400, 401, 403, 404, 503)
87 f3787696 Sofia Papagiannaki
88 f3787696 Sofia Papagiannaki
89 f3787696 Sofia Papagiannaki
class PithosAPITest(TestCase):
90 f3787696 Sofia Papagiannaki
    #TODO unauthorized request
91 f3787696 Sofia Papagiannaki
    def setUp(self):
92 f3787696 Sofia Papagiannaki
        pithos_settings.BACKEND_DB_MODULE = 'pithos.backends.lib.sqlalchemy'
93 d6a92fa0 Sofia Papagiannaki
        pithos_settings.BACKEND_DB_CONNECTION = django_to_sqlalchemy()
94 f3787696 Sofia Papagiannaki
        pithos_settings.BACKEND_POOL_SIZE = 1
95 369a7b41 Sofia Papagiannaki
96 369a7b41 Sofia Papagiannaki
        # Override default block size to spead up tests
97 369a7b41 Sofia Papagiannaki
        pithos_settings.BACKEND_BLOCK_SIZE = 1024
98 369a7b41 Sofia Papagiannaki
99 f3787696 Sofia Papagiannaki
        self.user = 'user'
100 d6a92fa0 Sofia Papagiannaki
        self.pithos_path = join_urls(get_service_path(
101 d6a92fa0 Sofia Papagiannaki
            pithos_settings.pithos_services, 'object-store'))
102 f3787696 Sofia Papagiannaki
103 f3787696 Sofia Papagiannaki
    def tearDown(self):
104 f3787696 Sofia Papagiannaki
        #delete additionally created metadata
105 f3787696 Sofia Papagiannaki
        meta = self.get_account_meta()
106 f3787696 Sofia Papagiannaki
        self.delete_account_meta(meta)
107 f3787696 Sofia Papagiannaki
108 f3787696 Sofia Papagiannaki
        #delete additionally created groups
109 f3787696 Sofia Papagiannaki
        groups = self.get_account_groups()
110 f3787696 Sofia Papagiannaki
        self.delete_account_groups(groups)
111 f3787696 Sofia Papagiannaki
112 f3787696 Sofia Papagiannaki
        self._clean_account()
113 f3787696 Sofia Papagiannaki
114 f3787696 Sofia Papagiannaki
    def head(self, url, user='user', *args, **kwargs):
115 f3787696 Sofia Papagiannaki
        with astakos_user(user):
116 f3787696 Sofia Papagiannaki
            response = self.client.head(url, *args, **kwargs)
117 f3787696 Sofia Papagiannaki
        return response
118 f3787696 Sofia Papagiannaki
119 f3787696 Sofia Papagiannaki
    def get(self, url, user='user', *args, **kwargs):
120 f3787696 Sofia Papagiannaki
        with astakos_user(user):
121 f3787696 Sofia Papagiannaki
            response = self.client.get(url, *args, **kwargs)
122 f3787696 Sofia Papagiannaki
        return response
123 f3787696 Sofia Papagiannaki
124 f3787696 Sofia Papagiannaki
    def delete(self, url, user='user', *args, **kwargs):
125 f3787696 Sofia Papagiannaki
        with astakos_user(user):
126 f3787696 Sofia Papagiannaki
            response = self.client.delete(url, *args, **kwargs)
127 f3787696 Sofia Papagiannaki
        return response
128 f3787696 Sofia Papagiannaki
129 f3787696 Sofia Papagiannaki
    def post(self, url, user='user', *args, **kwargs):
130 f3787696 Sofia Papagiannaki
        with astakos_user(user):
131 f3787696 Sofia Papagiannaki
            kwargs.setdefault('content_type', 'application/octet-stream')
132 f3787696 Sofia Papagiannaki
            response = self.client.post(url, *args, **kwargs)
133 f3787696 Sofia Papagiannaki
        return response
134 f3787696 Sofia Papagiannaki
135 f3787696 Sofia Papagiannaki
    def put(self, url, user='user', *args, **kwargs):
136 f3787696 Sofia Papagiannaki
        with astakos_user(user):
137 f3787696 Sofia Papagiannaki
            kwargs.setdefault('content_type', 'application/octet-stream')
138 f3787696 Sofia Papagiannaki
            response = self.client.put(url, *args, **kwargs)
139 f3787696 Sofia Papagiannaki
        return response
140 f3787696 Sofia Papagiannaki
141 f3787696 Sofia Papagiannaki
    def _clean_account(self):
142 f3787696 Sofia Papagiannaki
        for c in self.list_containers():
143 f3787696 Sofia Papagiannaki
            self.delete_container_content(c['name'])
144 f3787696 Sofia Papagiannaki
            self.delete_container(c['name'])
145 f3787696 Sofia Papagiannaki
146 f3787696 Sofia Papagiannaki
    def update_account_meta(self, meta):
147 f3787696 Sofia Papagiannaki
        kwargs = dict(
148 f3787696 Sofia Papagiannaki
            ('HTTP_X_ACCOUNT_META_%s' % k, str(v)) for k, v in meta.items())
149 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user)
150 d6a92fa0 Sofia Papagiannaki
        r = self.post('%s?update=' % url, **kwargs)
151 f3787696 Sofia Papagiannaki
        self.assertEqual(r.status_code, 202)
152 f3787696 Sofia Papagiannaki
        account_meta = self.get_account_meta()
153 f3787696 Sofia Papagiannaki
        (self.assertTrue('X-Account-Meta-%s' % k in account_meta) for
154 f3787696 Sofia Papagiannaki
            k in meta.keys())
155 f3787696 Sofia Papagiannaki
        (self.assertEqual(account_meta['X-Account-Meta-%s' % k], v) for
156 f3787696 Sofia Papagiannaki
            k, v in meta.items())
157 f3787696 Sofia Papagiannaki
158 f3787696 Sofia Papagiannaki
    def reset_account_meta(self, meta):
159 f3787696 Sofia Papagiannaki
        kwargs = dict(
160 f3787696 Sofia Papagiannaki
            ('HTTP_X_ACCOUNT_META_%s' % k, str(v)) for k, v in meta.items())
161 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user)
162 d6a92fa0 Sofia Papagiannaki
        r = self.post(url, **kwargs)
163 f3787696 Sofia Papagiannaki
        self.assertEqual(r.status_code, 202)
164 f3787696 Sofia Papagiannaki
        account_meta = self.get_account_meta()
165 f3787696 Sofia Papagiannaki
        (self.assertTrue('X-Account-Meta-%s' % k in account_meta) for
166 f3787696 Sofia Papagiannaki
            k in meta.keys())
167 f3787696 Sofia Papagiannaki
        (self.assertEqual(account_meta['X-Account-Meta-%s' % k], v) for
168 f3787696 Sofia Papagiannaki
            k, v in meta.items())
169 f3787696 Sofia Papagiannaki
170 f3787696 Sofia Papagiannaki
    def delete_account_meta(self, meta):
171 f3787696 Sofia Papagiannaki
        transform = lambda k: 'HTTP_%s' % k.replace('-', '_').upper()
172 f3787696 Sofia Papagiannaki
        kwargs = dict((transform(k), '') for k, v in meta.items())
173 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user)
174 d6a92fa0 Sofia Papagiannaki
        r = self.post('%s?update=' % url, **kwargs)
175 f3787696 Sofia Papagiannaki
        self.assertEqual(r.status_code, 202)
176 f3787696 Sofia Papagiannaki
        account_meta = self.get_account_meta()
177 f3787696 Sofia Papagiannaki
        (self.assertTrue('X-Account-Meta-%s' % k not in account_meta) for
178 f3787696 Sofia Papagiannaki
            k in meta.keys())
179 f3787696 Sofia Papagiannaki
        return r
180 f3787696 Sofia Papagiannaki
181 f3787696 Sofia Papagiannaki
    def delete_account_groups(self, groups):
182 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user)
183 d6a92fa0 Sofia Papagiannaki
        r = self.post('%s?update=' % url, **groups)
184 f3787696 Sofia Papagiannaki
        self.assertEqual(r.status_code, 202)
185 f3787696 Sofia Papagiannaki
        return r
186 f3787696 Sofia Papagiannaki
187 f3787696 Sofia Papagiannaki
    def get_account_info(self, until=None):
188 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user)
189 f3787696 Sofia Papagiannaki
        if until is not None:
190 f3787696 Sofia Papagiannaki
            parts = list(urlsplit(url))
191 f3787696 Sofia Papagiannaki
            parts[3] = urlencode({
192 f3787696 Sofia Papagiannaki
                'until': until
193 f3787696 Sofia Papagiannaki
            })
194 f3787696 Sofia Papagiannaki
            url = urlunsplit(parts)
195 f3787696 Sofia Papagiannaki
        r = self.head(url)
196 f3787696 Sofia Papagiannaki
        self.assertEqual(r.status_code, 204)
197 f3787696 Sofia Papagiannaki
        return r
198 f3787696 Sofia Papagiannaki
199 f3787696 Sofia Papagiannaki
    def get_account_meta(self, until=None):
200 f3787696 Sofia Papagiannaki
        r = self.get_account_info(until=until)
201 f3787696 Sofia Papagiannaki
        headers = dict(r._headers.values())
202 f3787696 Sofia Papagiannaki
        map(headers.pop,
203 f3787696 Sofia Papagiannaki
            [k for k in headers.keys()
204 f3787696 Sofia Papagiannaki
                if not k.startswith('X-Account-Meta-')])
205 f3787696 Sofia Papagiannaki
        return headers
206 f3787696 Sofia Papagiannaki
207 f3787696 Sofia Papagiannaki
    def get_account_groups(self, until=None):
208 f3787696 Sofia Papagiannaki
        r = self.get_account_info(until=until)
209 f3787696 Sofia Papagiannaki
        headers = dict(r._headers.values())
210 f3787696 Sofia Papagiannaki
        map(headers.pop,
211 f3787696 Sofia Papagiannaki
            [k for k in headers.keys()
212 f3787696 Sofia Papagiannaki
                if not k.startswith('X-Account-Group-')])
213 f3787696 Sofia Papagiannaki
        return headers
214 f3787696 Sofia Papagiannaki
215 f3787696 Sofia Papagiannaki
    def list_containers(self, format='json', headers={}, **params):
216 d6a92fa0 Sofia Papagiannaki
        _url = join_urls(self.pithos_path, self.user)
217 d6a92fa0 Sofia Papagiannaki
        parts = list(urlsplit(_url))
218 f3787696 Sofia Papagiannaki
        params['format'] = format
219 f3787696 Sofia Papagiannaki
        parts[3] = urlencode(params)
220 f3787696 Sofia Papagiannaki
        url = urlunsplit(parts)
221 f3787696 Sofia Papagiannaki
        _headers = dict(('HTTP_%s' % k.upper(), str(v))
222 f3787696 Sofia Papagiannaki
                        for k, v in headers.items())
223 f3787696 Sofia Papagiannaki
        r = self.get(url, **_headers)
224 f3787696 Sofia Papagiannaki
225 f3787696 Sofia Papagiannaki
        if format is None:
226 f3787696 Sofia Papagiannaki
            containers = r.content.split('\n')
227 f3787696 Sofia Papagiannaki
            if '' in containers:
228 f3787696 Sofia Papagiannaki
                containers.remove('')
229 f3787696 Sofia Papagiannaki
            return containers
230 f3787696 Sofia Papagiannaki
        elif format == 'json':
231 f3787696 Sofia Papagiannaki
            try:
232 f3787696 Sofia Papagiannaki
                containers = json.loads(r.content)
233 f3787696 Sofia Papagiannaki
            except:
234 f3787696 Sofia Papagiannaki
                self.fail('json format expected')
235 f3787696 Sofia Papagiannaki
            return containers
236 f3787696 Sofia Papagiannaki
        elif format == 'xml':
237 f3787696 Sofia Papagiannaki
            return minidom.parseString(r.content)
238 f3787696 Sofia Papagiannaki
239 f3787696 Sofia Papagiannaki
    def delete_container_content(self, cname):
240 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user, cname)
241 d6a92fa0 Sofia Papagiannaki
        r = self.delete('%s?delimiter=/' % url)
242 f3787696 Sofia Papagiannaki
        self.assertEqual(r.status_code, 204)
243 f3787696 Sofia Papagiannaki
        return r
244 f3787696 Sofia Papagiannaki
245 f3787696 Sofia Papagiannaki
    def delete_container(self, cname):
246 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user, cname)
247 d6a92fa0 Sofia Papagiannaki
        r = self.delete(url)
248 f3787696 Sofia Papagiannaki
        self.assertEqual(r.status_code, 204)
249 f3787696 Sofia Papagiannaki
        return r
250 f3787696 Sofia Papagiannaki
251 f3787696 Sofia Papagiannaki
    def create_container(self, cname):
252 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user, cname)
253 d6a92fa0 Sofia Papagiannaki
        r = self.put(url, data='')
254 f3787696 Sofia Papagiannaki
        self.assertTrue(r.status_code in (202, 201))
255 f3787696 Sofia Papagiannaki
        return r
256 f3787696 Sofia Papagiannaki
257 f3787696 Sofia Papagiannaki
    def upload_object(self, cname, oname=None, **meta):
258 f3787696 Sofia Papagiannaki
        oname = oname or get_random_word(8)
259 f3787696 Sofia Papagiannaki
        data = get_random_word(length=random.randint(1, 1024))
260 f3787696 Sofia Papagiannaki
        headers = dict(('HTTP_X_OBJECT_META_%s' % k.upper(), v)
261 f3787696 Sofia Papagiannaki
                       for k, v in meta.iteritems())
262 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user, cname, oname)
263 d6a92fa0 Sofia Papagiannaki
        r = self.put(url, data=data, **headers)
264 f3787696 Sofia Papagiannaki
        self.assertEqual(r.status_code, 201)
265 f3787696 Sofia Papagiannaki
        return oname, data, r
266 f3787696 Sofia Papagiannaki
267 f3787696 Sofia Papagiannaki
    def create_folder(self, cname, oname=get_random_word(8), **headers):
268 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user, cname, oname)
269 d6a92fa0 Sofia Papagiannaki
        r = self.put(url, data='', content_type='application/directory',
270 d6a92fa0 Sofia Papagiannaki
                     **headers)
271 f3787696 Sofia Papagiannaki
        self.assertEqual(r.status_code, 201)
272 f3787696 Sofia Papagiannaki
        return oname, r
273 f3787696 Sofia Papagiannaki
274 f3787696 Sofia Papagiannaki
    def list_objects(self, cname):
275 d6a92fa0 Sofia Papagiannaki
        url = join_urls(self.pithos_path, self.user, cname)
276 d6a92fa0 Sofia Papagiannaki
        r = self.get('%s?format=json' % url)
277 f3787696 Sofia Papagiannaki
        self.assertTrue(r.status_code in (200, 204))
278 f3787696 Sofia Papagiannaki
        try:
279 f3787696 Sofia Papagiannaki
            objects = json.loads(r.content)
280 f3787696 Sofia Papagiannaki
        except:
281 f3787696 Sofia Papagiannaki
            self.fail('json format expected')
282 f3787696 Sofia Papagiannaki
        return objects
283 f3787696 Sofia Papagiannaki
284 f3787696 Sofia Papagiannaki
    def assert_status(self, status, codes):
285 f3787696 Sofia Papagiannaki
        l = [elem for elem in return_codes]
286 f3787696 Sofia Papagiannaki
        if isinstance(codes, list):
287 f3787696 Sofia Papagiannaki
            l.extend(codes)
288 f3787696 Sofia Papagiannaki
        else:
289 f3787696 Sofia Papagiannaki
            l.append(codes)
290 f3787696 Sofia Papagiannaki
        self.assertTrue(status in l)
291 f3787696 Sofia Papagiannaki
292 f3787696 Sofia Papagiannaki
    def assert_extended(self, data, format, type, size=10000):
293 f3787696 Sofia Papagiannaki
        if format == 'xml':
294 f3787696 Sofia Papagiannaki
            self._assert_xml(data, type, size)
295 f3787696 Sofia Papagiannaki
        elif format == 'json':
296 f3787696 Sofia Papagiannaki
            self._assert_json(data, type, size)
297 f3787696 Sofia Papagiannaki
298 f3787696 Sofia Papagiannaki
    def _assert_json(self, data, type, size):
299 f3787696 Sofia Papagiannaki
        convert = lambda s: s.lower()
300 f3787696 Sofia Papagiannaki
        info = [convert(elem) for elem in details[type]]
301 f3787696 Sofia Papagiannaki
        self.assertTrue(len(data) <= size)
302 f3787696 Sofia Papagiannaki
        for item in info:
303 f3787696 Sofia Papagiannaki
            for i in data:
304 f3787696 Sofia Papagiannaki
                if 'subdir' in i.keys():
305 f3787696 Sofia Papagiannaki
                    continue
306 f3787696 Sofia Papagiannaki
                self.assertTrue(item in i.keys())
307 f3787696 Sofia Papagiannaki
308 f3787696 Sofia Papagiannaki
    def _assert_xml(self, data, type, size):
309 f3787696 Sofia Papagiannaki
        convert = lambda s: s.lower()
310 f3787696 Sofia Papagiannaki
        info = [convert(elem) for elem in details[type]]
311 f3787696 Sofia Papagiannaki
        try:
312 f3787696 Sofia Papagiannaki
            info.remove('content_encoding')
313 f3787696 Sofia Papagiannaki
        except ValueError:
314 f3787696 Sofia Papagiannaki
            pass
315 f3787696 Sofia Papagiannaki
        xml = data
316 f3787696 Sofia Papagiannaki
        entities = xml.getElementsByTagName(type)
317 f3787696 Sofia Papagiannaki
        self.assertTrue(len(entities) <= size)
318 f3787696 Sofia Papagiannaki
        for e in entities:
319 f3787696 Sofia Papagiannaki
            for item in info:
320 f3787696 Sofia Papagiannaki
                self.assertTrue(e.getElementsByTagName(item))
321 f3787696 Sofia Papagiannaki
322 f3787696 Sofia Papagiannaki
323 f3787696 Sofia Papagiannaki
class AssertMappingInvariant(object):
324 f3787696 Sofia Papagiannaki
    def __init__(self, callable, *args, **kwargs):
325 f3787696 Sofia Papagiannaki
        self.callable = callable
326 f3787696 Sofia Papagiannaki
        self.args = args
327 f3787696 Sofia Papagiannaki
        self.kwargs = kwargs
328 f3787696 Sofia Papagiannaki
329 f3787696 Sofia Papagiannaki
    def __enter__(self):
330 f3787696 Sofia Papagiannaki
        self.map = self.callable(*self.args, **self.kwargs)
331 f3787696 Sofia Papagiannaki
        return self.map
332 f3787696 Sofia Papagiannaki
333 f3787696 Sofia Papagiannaki
    def __exit__(self, type, value, tb):
334 f3787696 Sofia Papagiannaki
        map = self.callable(*self.args, **self.kwargs)
335 f3787696 Sofia Papagiannaki
        for k, v in self.map.items():
336 f3787696 Sofia Papagiannaki
            if is_date(v):
337 f3787696 Sofia Papagiannaki
                continue
338 f3787696 Sofia Papagiannaki
339 f3787696 Sofia Papagiannaki
            assert(k in map), '%s not in map' % k
340 f3787696 Sofia Papagiannaki
            assert v == map[k]
341 f3787696 Sofia Papagiannaki
342 f3787696 Sofia Papagiannaki
django_sqlalchemy_engines = {
343 f3787696 Sofia Papagiannaki
    'django.db.backends.postgresql_psycopg2': 'postgresql+psycopg2',
344 f3787696 Sofia Papagiannaki
    'django.db.backends.postgresql': 'postgresql',
345 f3787696 Sofia Papagiannaki
    'django.db.backends.mysql': '',
346 f3787696 Sofia Papagiannaki
    'django.db.backends.sqlite3': 'mssql',
347 f3787696 Sofia Papagiannaki
    'django.db.backends.oracle': 'oracle'}
348 f3787696 Sofia Papagiannaki
349 f3787696 Sofia Papagiannaki
350 d6a92fa0 Sofia Papagiannaki
def django_to_sqlalchemy():
351 d6a92fa0 Sofia Papagiannaki
    """Convert the django default database to sqlalchemy connection string"""
352 d6a92fa0 Sofia Papagiannaki
    # TODO support for more complex configuration
353 f3787696 Sofia Papagiannaki
    db = settings.DATABASES['default']
354 d6a92fa0 Sofia Papagiannaki
    name = db.get('TEST_NAME', 'test_%s' % db['NAME'])
355 f3787696 Sofia Papagiannaki
    if db['ENGINE'] == 'django.db.backends.sqlite3':
356 d6a92fa0 Sofia Papagiannaki
        db.get('TEST_NAME', db['NAME'])
357 d6a92fa0 Sofia Papagiannaki
        return 'sqlite:///%s' % name
358 f3787696 Sofia Papagiannaki
    else:
359 f3787696 Sofia Papagiannaki
        d = dict(scheme=django_sqlalchemy_engines.get(db['ENGINE']),
360 f3787696 Sofia Papagiannaki
                 user=db['USER'],
361 f3787696 Sofia Papagiannaki
                 pwd=db['PASSWORD'],
362 f3787696 Sofia Papagiannaki
                 host=db['HOST'].lower(),
363 f3787696 Sofia Papagiannaki
                 port=int(db['PORT']) if db['PORT'] != '' else '',
364 d6a92fa0 Sofia Papagiannaki
                 name=name)
365 f3787696 Sofia Papagiannaki
        return '%(scheme)s://%(user)s:%(pwd)s@%(host)s:%(port)s/%(name)s' % d
366 f3787696 Sofia Papagiannaki
367 f3787696 Sofia Papagiannaki
368 f3787696 Sofia Papagiannaki
def is_date(date):
369 f3787696 Sofia Papagiannaki
    __D = r'(?P<day>\d{2})'
370 f3787696 Sofia Papagiannaki
    __D2 = r'(?P<day>[ \d]\d)'
371 f3787696 Sofia Papagiannaki
    __M = r'(?P<mon>\w{3})'
372 f3787696 Sofia Papagiannaki
    __Y = r'(?P<year>\d{4})'
373 f3787696 Sofia Papagiannaki
    __Y2 = r'(?P<year>\d{2})'
374 f3787696 Sofia Papagiannaki
    __T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
375 f3787696 Sofia Papagiannaki
    RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (
376 f3787696 Sofia Papagiannaki
        __D, __M, __Y, __T))
377 f3787696 Sofia Papagiannaki
    RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (
378 f3787696 Sofia Papagiannaki
        __D, __M, __Y2, __T))
379 f3787696 Sofia Papagiannaki
    ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (
380 f3787696 Sofia Papagiannaki
        __M, __D2, __T, __Y))
381 f3787696 Sofia Papagiannaki
    for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
382 f3787696 Sofia Papagiannaki
        m = regex.match(date)
383 f3787696 Sofia Papagiannaki
        if m is not None:
384 f3787696 Sofia Papagiannaki
            return True
385 f3787696 Sofia Papagiannaki
    return False
386 f3787696 Sofia Papagiannaki
387 f3787696 Sofia Papagiannaki
388 f3787696 Sofia Papagiannaki
def strnextling(prefix):
389 f3787696 Sofia Papagiannaki
    """Return the first unicode string
390 f3787696 Sofia Papagiannaki
       greater than but not starting with given prefix.
391 f3787696 Sofia Papagiannaki
       strnextling('hello') -> 'hellp'
392 f3787696 Sofia Papagiannaki
    """
393 f3787696 Sofia Papagiannaki
    if not prefix:
394 f3787696 Sofia Papagiannaki
        ## all strings start with the null string,
395 f3787696 Sofia Papagiannaki
        ## therefore we have to approximate strnextling('')
396 f3787696 Sofia Papagiannaki
        ## with the last unicode character supported by python
397 f3787696 Sofia Papagiannaki
        ## 0x10ffff for wide (32-bit unicode) python builds
398 f3787696 Sofia Papagiannaki
        ## 0x00ffff for narrow (16-bit unicode) python builds
399 f3787696 Sofia Papagiannaki
        ## We will not autodetect. 0xffff is safe enough.
400 f3787696 Sofia Papagiannaki
        return unichr(0xffff)
401 f3787696 Sofia Papagiannaki
    s = prefix[:-1]
402 f3787696 Sofia Papagiannaki
    c = ord(prefix[-1])
403 f3787696 Sofia Papagiannaki
    if c >= 0xffff:
404 f3787696 Sofia Papagiannaki
        raise RuntimeError
405 f3787696 Sofia Papagiannaki
    s += unichr(c + 1)
406 f3787696 Sofia Papagiannaki
    return s
407 f3787696 Sofia Papagiannaki
408 f3787696 Sofia Papagiannaki
409 f3787696 Sofia Papagiannaki
def test_concurrently(times=2):
410 f3787696 Sofia Papagiannaki
    """
411 f3787696 Sofia Papagiannaki
    Add this decorator to small pieces of code that you want to test
412 f3787696 Sofia Papagiannaki
    concurrently to make sure they don't raise exceptions when run at the
413 f3787696 Sofia Papagiannaki
    same time.  E.g., some Django views that do a SELECT and then a subsequent
414 f3787696 Sofia Papagiannaki
    INSERT might fail when the INSERT assumes that the data has not changed
415 f3787696 Sofia Papagiannaki
    since the SELECT.
416 f3787696 Sofia Papagiannaki
    """
417 f3787696 Sofia Papagiannaki
    def test_concurrently_decorator(test_func):
418 f3787696 Sofia Papagiannaki
        def wrapper(*args, **kwargs):
419 f3787696 Sofia Papagiannaki
            exceptions = []
420 f3787696 Sofia Papagiannaki
421 f3787696 Sofia Papagiannaki
            def call_test_func():
422 f3787696 Sofia Papagiannaki
                try:
423 f3787696 Sofia Papagiannaki
                    test_func(*args, **kwargs)
424 f3787696 Sofia Papagiannaki
                except Exception, e:
425 f3787696 Sofia Papagiannaki
                    exceptions.append(e)
426 f3787696 Sofia Papagiannaki
                    raise
427 f3787696 Sofia Papagiannaki
428 f3787696 Sofia Papagiannaki
            threads = []
429 f3787696 Sofia Papagiannaki
            for i in range(times):
430 f3787696 Sofia Papagiannaki
                threads.append(threading.Thread())
431 f3787696 Sofia Papagiannaki
            for t in threads:
432 f3787696 Sofia Papagiannaki
                t.start()
433 f3787696 Sofia Papagiannaki
            for t in threads:
434 f3787696 Sofia Papagiannaki
                t.join()
435 f3787696 Sofia Papagiannaki
            if exceptions:
436 f3787696 Sofia Papagiannaki
                raise Exception(
437 f3787696 Sofia Papagiannaki
                    ('test_concurrently intercepted %s',
438 f3787696 Sofia Papagiannaki
                     'exceptions: %s') % (len(exceptions), exceptions))
439 f3787696 Sofia Papagiannaki
        return wrapper
440 f3787696 Sofia Papagiannaki
    return test_concurrently_decorator