Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2014-02-24 17:10:36 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2014-02-24 17:10:36 (GMT)
commit4dc349755c8463c8a197433126c78988c74a1b43 (patch)
treebd8cd62a3c66dc8ca8dd0383676dbddae0039afc
parentd48da5dbad4f47d2aa6403ba13a8ca72fce5297f (diff)
No need in extra HTTP headers after moving context resolves to node side
-rwxr-xr-xmisc/aslo-sync4
-rwxr-xr-xsugar-network1
-rwxr-xr-xsugar-network-client3
-rw-r--r--sugar_network/client/cache.py4
-rw-r--r--sugar_network/db/metadata.py48
-rw-r--r--sugar_network/db/routes.py32
-rw-r--r--sugar_network/model/__init__.py52
-rw-r--r--sugar_network/model/routes.py4
-rw-r--r--sugar_network/node/routes.py19
-rw-r--r--sugar_network/toolkit/__init__.py42
-rw-r--r--sugar_network/toolkit/http.py10
-rw-r--r--sugar_network/toolkit/router.py107
-rw-r--r--tests/__init__.py25
-rwxr-xr-xtests/units/db/routes.py258
-rwxr-xr-xtests/units/model/context.py16
-rwxr-xr-xtests/units/model/model.py47
-rwxr-xr-xtests/units/node/node.py6
-rwxr-xr-xtests/units/toolkit/http.py83
-rwxr-xr-xtests/units/toolkit/router.py41
-rwxr-xr-xtests/units/toolkit/toolkit.py11
20 files changed, 290 insertions, 523 deletions
diff --git a/misc/aslo-sync b/misc/aslo-sync
index 581581a..147ac04 100755
--- a/misc/aslo-sync
+++ b/misc/aslo-sync
@@ -30,7 +30,7 @@ from sugar_network import db, client, model, toolkit
from sugar_network.node import data_root
from sugar_network.node.slave import SlaveRoutes
from sugar_network.node.routes import load_bundle
-from sugar_network.toolkit import util, licenses, application, Option
+from sugar_network.toolkit import spec, licenses, application, Option
DOWNLOAD_URL = 'http://download.sugarlabs.org/activities'
@@ -466,7 +466,7 @@ class Application(application.Application):
continue
try:
- util.parse_version(version)
+ spec.parse_version(version)
except Exception, error:
print '-- Cannot parse %r version for %r[%s]: %s' % \
(version, filename, version_id, error)
diff --git a/sugar-network b/sugar-network
index 818721e..63e1078 100755
--- a/sugar-network
+++ b/sugar-network
@@ -183,7 +183,6 @@ class Application(application.Application):
self._request('HEAD', False, response)
result = {}
result.update(response)
- result.update(response.meta)
self._dump(result)
def _request(self, method, post, response):
diff --git a/sugar-network-client b/sugar-network-client
index 6e0d772..87bf65e 100755
--- a/sugar-network-client
+++ b/sugar-network-client
@@ -28,7 +28,7 @@ from gevent import monkey
import sugar_network_webui as webui
from sugar_network import db, toolkit, client, node
from sugar_network.client.routes import CachedClientRoutes
-from sugar_network.node import stats_node, stats_user
+from sugar_network.node import stats_user
from sugar_network.model import RESOURCES
from sugar_network.toolkit.router import Router, Request, Response
from sugar_network.toolkit import mountpoints, printf, application
@@ -204,7 +204,6 @@ Option.seek('webui', webui)
Option.seek('client', client)
Option.seek('db', db)
Option.seek('node', [node.port, node.find_limit, node.sync_layers])
-Option.seek('node-stats', stats_node)
Option.seek('user-stats', stats_user)
app = Application(
diff --git a/sugar_network/client/cache.py b/sugar_network/client/cache.py
index df76a29..8bee316 100644
--- a/sugar_network/client/cache.py
+++ b/sugar_network/client/cache.py
@@ -13,6 +13,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# sugar-lint: disable
+
import os
import sys
import time
@@ -20,7 +22,7 @@ import logging
from os.path import exists
from sugar_network import client
-from sugar_network.db import files
+from sugar_network.db import blobs
from sugar_network.toolkit import pylru, enforce
diff --git a/sugar_network/db/metadata.py b/sugar_network/db/metadata.py
index 5282fd1..88d644b 100644
--- a/sugar_network/db/metadata.py
+++ b/sugar_network/db/metadata.py
@@ -16,8 +16,8 @@
import xapian
from sugar_network import toolkit
-from sugar_network.db import files
-from sugar_network.toolkit.router import ACL
+from sugar_network.db import blobs
+from sugar_network.toolkit.router import ACL, File
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import i18n, http, enforce
@@ -33,6 +33,7 @@ def stored_property(klass=None, *args, **kwargs):
return func(self, value)
def decorate_setter(func, attr):
+ # pylint: disable-msg=W0212
attr.prop.setter = lambda self, value: \
self._set(attr.name, func(self, value))
attr.prop.on_set = func
@@ -297,12 +298,12 @@ class Blob(Property):
self.mime_type = mime_type
def typecast(self, value):
- if isinstance(value, toolkit.File):
+ if isinstance(value, File):
return value.digest
- if isinstance(value, files.Digest):
+ if isinstance(value, File.Digest):
return value
- enforce(value is None or isinstance(value, basestring) or \
+ enforce(value is None or isinstance(value, basestring) or
isinstance(value, dict) and value or hasattr(value, 'read'),
'Inappropriate blob value')
@@ -310,45 +311,38 @@ class Blob(Property):
return ''
if not isinstance(value, dict):
- return files.post(value, {
- 'mime_type': this.request.content_type or self.mime_type,
- }).digest
+ mime_type = this.request.content_type or self.mime_type
+ return blobs.post(value, mime_type).digest
digest = this.resource[self.name] if self.name else None
if digest:
- meta = files.get(digest)
+ orig = blobs.get(digest)
enforce('digest' not in value or value.pop('digest') == digest,
"Inappropriate 'digest' value")
- enforce(meta.path or 'url' in meta or 'url' in value,
+ enforce(orig.path or 'location' in orig or 'location' in value,
'Blob points to nothing')
- if 'url' in value and meta.path:
- files.delete(digest)
- meta.update(value)
- value = meta
+ if 'location' in value and orig.path:
+ blobs.delete(digest)
+ orig.update(value)
+ value = orig
else:
- enforce('url' in value, 'Blob points to nothing')
+ enforce('location' in value, 'Blob points to nothing')
enforce('digest' in value, "Missed 'digest' value")
- if 'mime_type' not in value:
- value['mime_type'] = self.mime_type
+ if 'content-type' not in value:
+ value['content-type'] = self.mime_type
digest = value.pop('digest')
- files.update(digest, value)
+ blobs.update(digest, value)
return digest
def reprcast(self, value):
if not value:
- return toolkit.File.AWAY
- meta = files.get(value)
- if 'url' not in meta:
- meta['url'] = '%s/blobs/%s' % (this.request.static_prefix, value)
- meta['size'] = meta.size
- meta['mtime'] = meta.mtime
- meta['digest'] = value
- return meta
+ return File.AWAY
+ return blobs.get(value)
def teardown(self, value):
if value:
- files.delete(value)
+ blobs.delete(value)
def assert_access(self, mode, value=None):
if mode == ACL.WRITE and not value:
diff --git a/sugar_network/db/routes.py b/sugar_network/db/routes.py
index 2f8fc69..d8d2fb4 100644
--- a/sugar_network/db/routes.py
+++ b/sugar_network/db/routes.py
@@ -15,14 +15,14 @@
import re
import time
-import json
import logging
from contextlib import contextmanager
from sugar_network import toolkit
-from sugar_network.db import files
+from sugar_network.db import blobs
from sugar_network.db.metadata import Aggregated
-from sugar_network.toolkit.router import ACL, route, preroute, fallbackroute
+from sugar_network.toolkit.router import ACL, File
+from sugar_network.toolkit.router import route, preroute, fallbackroute
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import http, enforce
@@ -137,25 +137,20 @@ class Routes(object):
prop = directory.metadata[request.prop]
prop.assert_access(ACL.READ)
- meta = doc.meta(prop.name) or {}
- if 'value' in meta:
- value = _get_prop(doc, prop, meta.pop('value'))
- enforce(value is not toolkit.File.AWAY, http.NotFound, 'No blob')
+ meta = doc.meta(prop.name)
+ if meta:
+ value = meta['value']
+ response.last_modified = meta['mtime']
else:
value = prop.default
-
- response.meta = meta
- response.last_modified = meta.get('mtime')
- if isinstance(value, toolkit.File):
- response.content_length = value.get('size') or 0
- else:
- response.content_length = len(json.dumps(value))
+ value = _get_prop(doc, prop, value)
+ enforce(value is not File.AWAY, http.NotFound, 'No blob')
return value
@route('HEAD', [None, None, None])
def get_prop_meta(self, request, response):
- self.get_prop(request, response)
+ return self.get_prop(request, response)
@route('POST', [None, None, None],
acl=ACL.AUTH, mime_type='application/json')
@@ -193,7 +188,7 @@ class Routes(object):
@fallbackroute('GET', ['blobs'])
def blobs(self, request):
- return files.get(request.guid)
+ return blobs.get(request.guid)
def on_create(self, request, props):
ts = int(time.time())
@@ -280,7 +275,10 @@ class Routes(object):
result = {}
for name in props:
prop = doc.metadata[name]
- result[name] = _get_prop(doc, prop, doc.get(name))
+ value = _get_prop(doc, prop, doc.get(name))
+ if isinstance(value, File):
+ value = value.url
+ result[name] = value
return result
def _useradd(self, authors, user, role):
diff --git a/sugar_network/model/__init__.py b/sugar_network/model/__init__.py
index 6858957..f7be261 100644
--- a/sugar_network/model/__init__.py
+++ b/sugar_network/model/__init__.py
@@ -16,19 +16,20 @@
import os
import gettext
import logging
+import mimetypes
from os.path import join
import xapian
from sugar_network import toolkit, db
-from sugar_network.db import files
+from sugar_network.db import blobs
from sugar_network.model.routes import FrontRoutes
from sugar_network.toolkit.spec import parse_version, parse_requires
from sugar_network.toolkit.spec import EMPTY_LICENSE
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit.bundle import Bundle
from sugar_network.toolkit.router import ACL
-from sugar_network.toolkit import i18n, http, exception, enforce
+from sugar_network.toolkit import i18n, http, svg_to_png, exception, enforce
CONTEXT_TYPES = [
@@ -73,22 +74,24 @@ class Rating(db.List):
class Release(object):
- def typecast(self, rel):
+ def typecast(self, release):
if this.resource.exists and \
'activity' not in this.resource['type'] and \
'book' not in this.resource['type']:
- return rel
- if not isinstance(rel, dict):
- __, rel = load_bundle(files.post(rel), context=this.request.guid)
- return rel['spec']['*-*']['bundle'], rel
-
- def teardown(self, rel):
+ return release
+ if not isinstance(release, dict):
+ __, release = load_bundle(
+ blobs.post(release, this.request.content_type),
+ context=this.request.guid)
+ return release['spec']['*-*']['bundle'], release
+
+ def teardown(self, release):
if this.resource.exists and \
'activity' not in this.resource['type'] and \
'book' not in this.resource['type']:
return
- for spec in rel['spec'].values():
- files.delete(spec['bundle'])
+ for spec in release['spec'].values():
+ blobs.delete(spec['bundle'])
def encode(self, value):
return []
@@ -120,18 +123,9 @@ def populate_context_images(props, svg):
if 'guid' in props:
from sugar_network.toolkit.sugar import color_svg
svg = color_svg(svg, props['guid'])
- props['artifact_icon'] = files.post(
- svg,
- {'mime_type': 'image/svg+xml'},
- ).digest
- props['icon'] = files.post(
- toolkit.svg_to_png(svg, 55, 55),
- {'mime_type': 'image/png'},
- ).digest
- props['logo'] = files.post(
- toolkit.svg_to_png(svg, 140, 140),
- {'mime_type': 'image/png'},
- ).digest
+ props['artifact_icon'] = blobs.post(svg, 'image/svg+xml').digest
+ props['icon'] = blobs.post(svg_to_png(svg, 55, 55), 'image/png').digest
+ props['logo'] = blobs.post(svg_to_png(svg, 140, 140), 'image/png').digest
def load_bundle(blob, context=None, initial=False, extra_deps=None):
@@ -140,7 +134,6 @@ def load_bundle(blob, context=None, initial=False, extra_deps=None):
context_meta = None
release_notes = None
release = {}
- blob_meta = {}
version = None
try:
@@ -157,7 +150,6 @@ def load_bundle(blob, context=None, initial=False, extra_deps=None):
release['spec'] = {'*-*': {
'bundle': blob.digest,
}}
- blob_meta['mime_type'] = this.request.content_type
else:
context_type = 'activity'
unpack_size = 0
@@ -191,7 +183,7 @@ def load_bundle(blob, context=None, initial=False, extra_deps=None):
'bundle': blob.digest,
}}
release['unpack_size'] = unpack_size
- blob_meta['mime_type'] = 'application/vnd.olpc-sugar'
+ blob['content-type'] = 'application/vnd.olpc-sugar'
enforce(context, http.BadRequest, 'Context is not specified')
enforce(version, http.BadRequest, 'Version is not specified')
@@ -237,9 +229,11 @@ def load_bundle(blob, context=None, initial=False, extra_deps=None):
},
content_type='application/json')
- filename = ''.join(i18n.decode(context_doc['title']).split())
- blob_meta['name'] = '%s-%s' % (filename, version)
- files.update(blob.digest, blob_meta)
+ blob['content-disposition'] = 'attachment; filename="%s-%s%s"' % (
+ ''.join(i18n.decode(context_doc['title']).split()),
+ version, mimetypes.guess_extension(blob.get('content-type')) or '',
+ )
+ blobs.update(blob.digest, blob)
return context, release
diff --git a/sugar_network/model/routes.py b/sugar_network/model/routes.py
index ff0377f..35c56a9 100644
--- a/sugar_network/model/routes.py
+++ b/sugar_network/model/routes.py
@@ -15,7 +15,7 @@
import logging
-from sugar_network.db import files
+from sugar_network.db import blobs
from sugar_network.toolkit.router import route
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import coroutine
@@ -61,7 +61,7 @@ class FrontRoutes(object):
@route('GET', ['favicon.ico'])
def favicon(self, request, response):
- return files.get('favicon.ico')
+ return blobs.get('favicon.ico')
def _broadcast(self, event):
_logger.debug('Broadcast event: %r', event)
diff --git a/sugar_network/node/routes.py b/sugar_network/node/routes.py
index da6c675..66b7823 100644
--- a/sugar_network/node/routes.py
+++ b/sugar_network/node/routes.py
@@ -21,7 +21,7 @@ from ConfigParser import ConfigParser
from os.path import join, isdir, exists
from sugar_network import db, node, toolkit
-from sugar_network.db import files
+from sugar_network.db import blobs
from sugar_network.model import FrontRoutes, load_bundle
from sugar_network.node import stats_user, model
# pylint: disable-msg=W0611
@@ -119,11 +119,11 @@ class NodeRoutes(db.Routes, FrontRoutes):
arguments={'initial': False},
mime_type='application/json', acl=ACL.AUTH)
def submit_release(self, request, initial):
- blob = files.post(request.content_stream)
+ blob = blobs.post(request.content_stream, request.content_type)
try:
context, release = load_bundle(blob, initial=initial)
except Exception:
- files.delete(blob.digest)
+ blobs.delete(blob.digest)
raise
this.call(method='POST', path=['context', context, 'releases'],
content_type='application/json', content=release)
@@ -156,13 +156,8 @@ class NodeRoutes(db.Routes, FrontRoutes):
@route('GET', ['context', None], cmd='clone',
arguments={'requires': list})
def get_clone(self, request, response):
- response.meta = self.solve(request)
- return files.get(response.meta['files'][request.guid])
-
- @route('HEAD', ['context', None], cmd='clone',
- arguments={'requires': list})
- def head_clone(self, request, response):
- response.meta = self.solve(request)
+ solution = self.solve(request)
+ return blobs.get(solution['files'][request.guid])
@route('GET', ['user', None], cmd='stats-info',
mime_type='application/json', acl=ACL.AUTH)
@@ -210,7 +205,7 @@ class NodeRoutes(db.Routes, FrontRoutes):
def on_create(self, request, props):
if request.resource == 'user':
- with file(files.get(props['pubkey']).path) as f:
+ with file(blobs.get(props['pubkey']).path) as f:
props['guid'] = str(hashlib.sha1(f.read()).hexdigest())
db.Routes.on_create(self, request, props)
@@ -229,7 +224,7 @@ class NodeRoutes(db.Routes, FrontRoutes):
from M2Crypto import RSA
pubkey = self.volume['user'][auth.login]['pubkey']
- key = RSA.load_pub_key(files.get(pubkey).path)
+ key = RSA.load_pub_key(blobs.get(pubkey).path)
data = hashlib.sha1('%s:%s' % (auth.login, auth.nonce)).digest()
enforce(key.verify(data, auth.signature.decode('hex')),
http.Forbidden, 'Bad credentials')
diff --git a/sugar_network/toolkit/__init__.py b/sugar_network/toolkit/__init__.py
index 4088e07..073ec4d 100644
--- a/sugar_network/toolkit/__init__.py
+++ b/sugar_network/toolkit/__init__.py
@@ -450,45 +450,6 @@ def svg_to_png(data, w, h):
return result
-class File(dict):
-
- AWAY = None
-
- def __init__(self, path=None, meta=None, digest=None):
- self.path = path
- self.digest = digest
- dict.__init__(self, meta or {})
- self._stat = None
- self._name = self.get('filename')
-
- @property
- def size(self):
- if self._stat is None:
- self._stat = os.stat(self.path)
- return self._stat.st_size
-
- @property
- def mtime(self):
- if self._stat is None:
- self._stat = os.stat(self.path)
- return int(self._stat.st_mtime)
-
- @property
- def name(self):
- if self._name is None:
- self._name = self.get('name') or self.digest or 'blob'
- mime_type = self.get('mime_type')
- if mime_type:
- import mimetypes
- if not mimetypes.inited:
- mimetypes.init()
- self._name += mimetypes.guess_extension(mime_type) or ''
- return self._name
-
- def __repr__(self):
- return '<File path=%r digest=%r>' % (self.path, self.digest)
-
-
def TemporaryFile(*args, **kwargs):
if 'dir' not in kwargs:
kwargs['dir'] = cachedir.value
@@ -843,6 +804,3 @@ def _nb_read(stream):
return ''
finally:
fcntl.fcntl(fd, fcntl.F_SETFL, orig_flags)
-
-
-File.AWAY = File()
diff --git a/sugar_network/toolkit/http.py b/sugar_network/toolkit/http.py
index 8d913ae..47f13bc 100644
--- a/sugar_network/toolkit/http.py
+++ b/sugar_network/toolkit/http.py
@@ -142,7 +142,7 @@ class Connection(object):
request = Request(method='HEAD', path=path_, **kwargs)
response = Response()
self.call(request, response)
- return response.meta
+ return response
def get(self, path_=None, query_=None, **kwargs):
reply = self.request('GET', path_, params=query_ or kwargs)
@@ -274,13 +274,11 @@ class Connection(object):
if 'transfer-encoding' in reply.headers:
# `requests` library handles encoding on its own
del reply.headers['transfer-encoding']
- for key, value in reply.headers.items():
- if key.startswith('x-sn-'):
- response.meta[key[5:]] = json.loads(value)
- elif not resend:
- response[key] = value
if resend:
response.relocations += 1
+ else:
+ for key, value in reply.headers.items():
+ response[key] = value
if not resend:
break
path = reply.headers['location']
diff --git a/sugar_network/toolkit/router.py b/sugar_network/toolkit/router.py
index b37eee4..00e5d8a 100644
--- a/sugar_network/toolkit/router.py
+++ b/sugar_network/toolkit/router.py
@@ -346,15 +346,35 @@ class Request(dict):
(self.method, self.path, self.cmd, dict(self))
-class Response(dict):
+class CaseInsensitiveDict(dict):
+
+ def __contains__(self, key):
+ return dict.__contains__(self, key.lower())
+
+ def __getitem__(self, key):
+ return self.get(key.lower())
+
+ def __setitem__(self, key, value):
+ return self.set(key.lower(), value)
+
+ def __delitem__(self, key, value):
+ self.remove(key.lower())
+
+ def get(self, key):
+ return dict.get(self, key)
+
+ def set(self, key, value):
+ dict.__setitem__(self, key, value)
+
+ def remove(self, key):
+ dict.__delitem__(self, key)
+
+
+class Response(CaseInsensitiveDict):
status = '200 OK'
relocations = 0
- def __init__(self, **kwargs):
- dict.__init__(self, kwargs)
- self.meta = {}
-
@property
def content_length(self):
return int(self.get('content-length') or '0')
@@ -394,26 +414,47 @@ class Response(dict):
return result
def __repr__(self):
- items = ['%s=%r' % i for i in self.items() + self.meta.items()]
+ items = ['%s=%r' % i for i in self.items()]
return '<Response %r>' % items
- def __contains__(self, key):
- dict.__contains__(self, key.lower())
- def __getitem__(self, key):
- return self.get(key.lower())
+class File(CaseInsensitiveDict):
- def __setitem__(self, key, value):
- return self.set(key.lower(), value)
+ AWAY = None
- def __delitem__(self, key, value):
- self.remove(key.lower())
+ class Digest(str):
+ pass
- def set(self, key, value):
- dict.__setitem__(self, key, value)
+ def __init__(self, path, digest=None, meta=None):
+ CaseInsensitiveDict.__init__(self)
+ self.path = path
+ self.digest = File.Digest(digest) if digest else None
+ if meta is not None:
+ for key, value in meta:
+ self[key] = value
+ self._stat = None
- def remove(self, key):
- dict.__delitem__(self, key)
+ @property
+ def size(self):
+ if self._stat is None:
+ self._stat = os.stat(self.path)
+ return self._stat.st_size
+
+ @property
+ def mtime(self):
+ if self._stat is None:
+ self._stat = os.stat(self.path)
+ return int(self._stat.st_mtime)
+
+ @property
+ def url(self):
+ if self is File.AWAY:
+ return ''
+ return self.get('location') or \
+ '%s/blobs/%s' % (this.request.static_prefix, self.digest)
+
+ def __repr__(self):
+ return '<File %r>' % self.url
class Router(object):
@@ -530,11 +571,8 @@ class Router(object):
except Exception, exception:
raise
else:
- if not response.content_type:
- if isinstance(result, toolkit.File):
- response.content_type = result.get('mime_type')
- if not response.content_type:
- response.content_type = route_.mime_type
+ if route_.mime_type and 'content-type' not in response:
+ response.set('content-type', route_.mime_type)
finally:
for i in self._postroutes:
i(request, response, result, exception)
@@ -563,18 +601,14 @@ class Router(object):
result = self.call(request, response)
- if isinstance(result, toolkit.File):
- if 'url' in result:
- raise http.Redirect(result['url'])
+ if isinstance(result, File):
+ response.update(result)
+ if 'location' in result:
+ raise http.Redirect(result['location'])
enforce(isfile(result.path), 'No such file')
- if request.if_modified_since and result.mtime and \
+ if request.if_modified_since and \
result.mtime <= request.if_modified_since:
raise http.NotModified()
- response.last_modified = result.mtime
- response.content_type = result.get('mime_type') or \
- 'application/octet-stream'
- response['Content-Disposition'] = \
- 'attachment; filename="%s"' % result.name
result = file(result.path, 'rb')
if not hasattr(result, 'read'):
@@ -592,7 +626,6 @@ class Router(object):
response.status = error.status
if error.headers:
response.update(error.headers)
- response.content_type = None
except Exception, error:
toolkit.exception('Error while processing %r request', request.url)
if isinstance(error, http.Status):
@@ -601,7 +634,7 @@ class Router(object):
else:
response.status = '500 Internal Server Error'
if request.method == 'HEAD':
- response.meta['error'] = str(error)
+ response.status = response.status[:4] + str(error)
else:
content = {'error': str(error), 'request': request.url}
response.content_type = 'application/json'
@@ -623,9 +656,6 @@ class Router(object):
if 'content-length' not in response:
response.content_length = len(content) if content else 0
- for key, value in response.meta.items():
- response.set('X-SN-%s' % toolkit.ascii(key), json.dumps(value))
-
if request.method == 'HEAD' and content is not None:
_logger.warning('Content from HEAD response is ignored')
content = None
@@ -859,3 +889,6 @@ class _Authorization(str):
password = None
signature = None
nonce = None
+
+
+File.AWAY = File(None)
diff --git a/tests/__init__.py b/tests/__init__.py
index dea79f6..6a997e7 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -18,9 +18,9 @@ from M2Crypto import DSA
from gevent import monkey
from sugar_network.toolkit import coroutine, http, mountpoints, Option, gbus, i18n, languages
-from sugar_network.toolkit.router import Router
+from sugar_network.toolkit.router import Router, File
from sugar_network.toolkit.coroutine import this
-from sugar_network.db import files
+from sugar_network.db import blobs
from sugar_network.client import IPCConnection, journal, routes as client_routes
from sugar_network.client.routes import ClientRoutes, _Auth
from sugar_network import db, client, node, toolkit, model
@@ -158,17 +158,17 @@ class Test(unittest.TestCase):
os.makedirs('blobs')
self.blobs = {}
- def files_post(content, meta=None, digest_to_assert=None):
+ def files_post(content, mime_type=None, digest_to_assert=None):
if hasattr(content, 'read'):
content = content.read()
- digest = files.Digest(hash(content))
+ digest = File.Digest(hash(content))
if digest_to_assert:
assert digest == digest_to_assert
path = join('blobs', digest)
with file(path, 'w') as f:
f.write(content)
- self.blobs[digest] = meta or {}
- return toolkit.File(path, meta=meta, digest=digest)
+ self.blobs[digest] = {'content-type': mime_type or 'application/octet-stream'}
+ return File(path, digest, self.blobs[digest].items())
def files_update(digest, meta):
self.blobs.setdefault(digest, {}).update(meta)
@@ -176,11 +176,8 @@ class Test(unittest.TestCase):
def files_get(digest):
if digest not in self.blobs:
return None
- meta = toolkit.File(meta=self.blobs[digest])
path = join('blobs', digest)
- if exists(path):
- meta.path = path
- return meta
+ return File(path, digest, self.blobs[digest].items())
def files_delete(digest):
path = join('blobs', digest)
@@ -189,10 +186,10 @@ class Test(unittest.TestCase):
if digest in self.blobs:
del self.blobs[digest]
- self.override(files, 'post', files_post)
- self.override(files, 'update', files_update)
- self.override(files, 'get', files_get)
- self.override(files, 'delete', files_delete)
+ self.override(blobs, 'post', files_post)
+ self.override(blobs, 'update', files_update)
+ self.override(blobs, 'get', files_get)
+ self.override(blobs, 'delete', files_delete)
def stop_nodes(self):
if self.client is not None:
diff --git a/tests/units/db/routes.py b/tests/units/db/routes.py
index 8824ca8..7da2f75 100755
--- a/tests/units/db/routes.py
+++ b/tests/units/db/routes.py
@@ -16,7 +16,7 @@ src_root = abspath(dirname(__file__))
from __init__ import tests
from sugar_network import db, toolkit
-from sugar_network.db import files
+from sugar_network.db import blobs
from sugar_network.model.user import User
from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, ACL
from sugar_network.toolkit.coroutine import this
@@ -195,17 +195,28 @@ class RoutesTest(tests.Test):
self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob'])
self.assertRaises(http.BadRequest, this.call, method='PUT', path=['testdocument', guid, 'blob'],
- content={'url': 'foo'}, content_type='application/json')
+ content={'location': 'foo'}, content_type='application/json')
self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob'])
this.call(method='PUT', path=['testdocument', guid, 'blob'],
- content={'url': 'url', 'digest': 'digest', 'foo': 'bar'}, content_type='application/json')
- self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'url': 'url',
- 'foo': 'bar',
- },
- this.call(method='GET', path=['testdocument', guid, 'blob']))
+ content={'location': 'url', 'digest': 'digest', 'foo': 'bar', 'content-type': 'foo/bar'}, content_type='application/json')
+ self.assertEqual(
+ {'blob': 'url'},
+ this.call(method='GET', path=['testdocument', guid], reply='blob'))
+ response = []
+ [i for i in router({
+ 'REQUEST_METHOD': 'HEAD',
+ 'PATH_INFO': '/testdocument/%s/blob' % guid,
+ }, lambda status, headers: response.extend([status, headers]))]
+ self.assertEqual('303 See Other', response[0])
+ self.assertEqual(
+ sorted([
+ ('last-modified', formatdate(os.stat('testdocument/%s/%s/mtime' % (guid[:2], guid)).st_mtime, localtime=False, usegmt=True)),
+ ('location', 'url'),
+ ('content-type', 'foo/bar'),
+ ('foo', 'bar'),
+ ]),
+ sorted(response[1]))
def test_UpdateUrlBLOBsWithMeta(self):
@@ -218,26 +229,26 @@ class RoutesTest(tests.Test):
volume = db.Volume(tests.tmpdir, [TestDocument])
router = Router(db.Routes(volume))
- guid = this.call(method='POST', path=['testdocument'], content={'blob': {'digest': 'digest', 'url': 'url'}})
+ guid = this.call(method='POST', path=['testdocument'], content={'blob': {'digest': 'digest', 'location': 'url'}})
self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'url': 'url',
+ 'content-type': 'application/octet-stream',
+ 'location': 'url',
},
this.call(method='GET', path=['testdocument', guid, 'blob']))
self.assertRaises(http.BadRequest, this.call, method='PUT', path=['testdocument', guid, 'blob'],
content={'digest': 'fake'}, content_type='application/json')
self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'url': 'url',
+ 'content-type': 'application/octet-stream',
+ 'location': 'url',
},
this.call(method='GET', path=['testdocument', guid, 'blob']))
this.call(method='PUT', path=['testdocument', guid, 'blob'],
content={'foo': 'bar'}, content_type='application/json')
self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'url': 'url',
+ 'content-type': 'application/octet-stream',
+ 'location': 'url',
'foo': 'bar',
},
this.call(method='GET', path=['testdocument', guid, 'blob']))
@@ -256,11 +267,7 @@ class RoutesTest(tests.Test):
guid = this.call(method='POST', path=['testdocument'], content={'blob': 'blob'})
blob = this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'})
self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'size': os.stat(blob.path).st_size,
- 'mtime': int(os.stat(blob.path).st_mtime),
- 'url': 'http://localhost/blobs/%s' % hash('blob'),
- 'digest': str(hash('blob')),
+ 'content-type': 'application/octet-stream',
},
blob)
self.assertEqual('blob', file(blob.path).read())
@@ -269,11 +276,7 @@ class RoutesTest(tests.Test):
content={'digest': 'fake'}, content_type='application/json')
blob = this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'})
self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'size': os.stat(blob.path).st_size,
- 'mtime': int(os.stat(blob.path).st_mtime),
- 'digest': str(hash('blob')),
- 'url': 'http://localhost/blobs/%s' % hash('blob'),
+ 'content-type': 'application/octet-stream',
},
blob)
self.assertEqual('blob', file(blob.path).read())
@@ -282,11 +285,7 @@ class RoutesTest(tests.Test):
content={'foo': 'bar'}, content_type='application/json')
blob = this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'})
self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'size': os.stat(blob.path).st_size,
- 'mtime': int(os.stat(blob.path).st_mtime),
- 'digest': str(hash('blob')),
- 'url': 'http://localhost/blobs/%s' % hash('blob'),
+ 'content-type': 'application/octet-stream',
'foo': 'bar',
},
blob)
@@ -302,41 +301,35 @@ class RoutesTest(tests.Test):
volume = db.Volume(tests.tmpdir, [TestDocument])
router = Router(db.Routes(volume))
-
guid = this.call(method='POST', path=['testdocument'], content={'blob': 'blob'})
- this.call(method='PUT', path=['testdocument', guid, 'blob'],
- content={'foo': 'bar'}, content_type='application/json')
- file_blob = this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'})
- self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'size': os.stat(file_blob.path).st_size,
- 'mtime': int(os.stat(file_blob.path).st_mtime),
- 'digest': str(hash('blob')),
- 'url': 'http://localhost/blobs/%s' % hash('blob'),
- 'foo': 'bar',
- }, file_blob)
- self.assertEqual('blob', file(file_blob.path).read())
+ self.assertEqual(
+ {'blob': 'http://localhost/blobs/%s' % hash('blob')},
+ this.call(method='GET', path=['testdocument', guid], reply='blob', environ={'HTTP_HOST': 'localhost'}))
+ self.assertEqual(
+ ['blob'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'GET',
+ 'PATH_INFO': '/testdocument/%s/blob' % guid,
+ }, lambda *args: None)])
+ assert exists(this.call(method='GET', path=['testdocument', guid, 'blob']).path)
this.call(method='PUT', path=['testdocument', guid, 'blob'],
- content={'url': 'url'}, content_type='application/json')
- self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'url': 'url',
- 'foo': 'bar',
- }, this.call(method='GET', path=['testdocument', guid, 'blob']))
- assert not exists(file_blob.path)
+ content={'location': 'url'}, content_type='application/json')
+ self.assertEqual(
+ {'blob': 'url'},
+ this.call(method='GET', path=['testdocument', guid], reply='blob', environ={'HTTP_HOST': 'localhost'}))
+ assert not exists(this.call(method='GET', path=['testdocument', guid, 'blob']).path)
this.call(method='PUT', path=['testdocument', guid, 'blob'],
- content='blob', content_type='application/octet-stream', environ={'HTTP_HOST': 'localhost'})
- self.assertEqual({
- 'mime_type': 'application/octet-stream',
- 'size': os.stat(file_blob.path).st_size,
- 'mtime': int(os.stat(file_blob.path).st_mtime),
- 'digest': str(hash('blob')),
- 'url': 'http://localhost/blobs/%s' % hash('blob'),
- }, this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'}))
- self.assertEqual('blob', file(file_blob.path).read())
+ content='new_blob', content_type='application/octet-stream', environ={'HTTP_HOST': 'localhost'})
+ self.assertEqual(
+ ['new_blob'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'GET',
+ 'PATH_INFO': '/testdocument/%s/blob' % guid,
+ }, lambda *args: None)])
+ assert exists(this.call(method='GET', path=['testdocument', guid, 'blob']).path)
def test_RemoveBLOBs(self):
@@ -412,21 +405,23 @@ class RoutesTest(tests.Test):
router = Router(db.Routes(volume))
guid = this.call(method='POST', path=['testdocument'], content={})
- response = Response()
- this.call(response=response,
- method='PUT', path=['testdocument', guid, 'blob'], content='blob1')
- response = Response()
- self.assertEqual('default', this.call(response=response,
- method='GET', path=['testdocument', guid, 'blob'])['mime_type'])
- self.assertEqual('default', response.content_type)
-
- response = Response()
- this.call(response=response,
- method='PUT', path=['testdocument', guid, 'blob'], content='blob1', content_type='foo')
- response = Response()
- self.assertEqual('foo', this.call(response=response,
- method='GET', path=['testdocument', guid, 'blob'])['mime_type'])
- self.assertEqual('foo', response.content_type)
+ this.call(method='PUT', path=['testdocument', guid, 'blob'], content='blob1')
+ response = []
+ [i for i in router({
+ 'REQUEST_METHOD': 'GET',
+ 'PATH_INFO': '/testdocument/%s/blob' % guid,
+ }, lambda status, headers: response.extend([status, headers]))]
+ self.assertEqual('200 OK', response[0])
+ self.assertEqual('default', dict(response[1]).get('content-type'))
+
+ this.call(method='PUT', path=['testdocument', guid, 'blob'], content='blob1', content_type='foo')
+ response = []
+ [i for i in router({
+ 'REQUEST_METHOD': 'GET',
+ 'PATH_INFO': '/testdocument/%s/blob' % guid,
+ }, lambda status, headers: response.extend([status, headers]))]
+ self.assertEqual('200 OK', response[0])
+ self.assertEqual('foo', dict(response[1]).get('content-type'))
def test_GetBLOBs(self):
@@ -448,24 +443,12 @@ class RoutesTest(tests.Test):
self.assertEqual('blob', file(this.call(method='GET', path=['testdocument', guid, 'blob']).path).read())
self.assertEqual({
- 'blob': {
- 'mime_type': u'application/octet-stream',
- 'url': 'http://localhost/blobs/%s' % digest,
- 'size': len(blob),
- 'digest': digest,
- 'mtime': int(os.stat(blob_path).st_mtime),
- },
+ 'blob': 'http://localhost/blobs/%s' % digest,
},
this.call(method='GET', path=['testdocument', guid], reply=['blob'], environ={'HTTP_HOST': 'localhost'}))
self.assertEqual([{
- 'blob': {
- 'mime_type': u'application/octet-stream',
- 'url': 'http://localhost/blobs/%s' % digest,
- 'size': len(blob),
- 'digest': digest,
- 'mtime': int(os.stat(blob_path).st_mtime),
- },
+ 'blob': 'http://localhost/blobs/%s' % digest,
}],
this.call(method='GET', path=['testdocument'], reply=['blob'], environ={'HTTP_HOST': 'localhost'})['result'])
@@ -483,30 +466,30 @@ class RoutesTest(tests.Test):
self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid1, 'blob'])
self.assertEqual(
- {'blob': {}},
+ {'blob': ''},
this.call(method='GET', path=['testdocument', guid1], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'}))
blob = 'file'
guid2 = this.call(method='POST', path=['testdocument'], content={'blob': blob})
self.assertEqual(
'http://127.0.0.1/blobs/%s' % hash(blob),
- this.call(method='GET', path=['testdocument', guid2], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'})['blob']['url'])
+ this.call(method='GET', path=['testdocument', guid2], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'})['blob'])
- guid3 = this.call(method='POST', path=['testdocument'], content={'blob': {'url': 'http://foo', 'digest': 'digest'}}, content_type='application/json')
+ guid3 = this.call(method='POST', path=['testdocument'], content={'blob': {'location': 'http://foo', 'digest': 'digest'}}, content_type='application/json')
self.assertEqual(
'http://foo',
- this.call(method='GET', path=['testdocument', guid3, 'blob'])['url'])
+ this.call(method='GET', path=['testdocument', guid3, 'blob'])['location'])
self.assertEqual(
'http://foo',
- this.call(method='GET', path=['testdocument', guid3], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'})['blob']['url'])
+ this.call(method='GET', path=['testdocument', guid3], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'})['blob'])
self.assertEqual(
sorted([
- None,
+ '',
'http://127.0.0.1/blobs/%s' % hash(blob),
'http://foo',
]),
- sorted([i['blob'].get('url') for i in this.call(method='GET', path=['testdocument'], reply=['blob'],
+ sorted([i['blob'] for i in this.call(method='GET', path=['testdocument'], reply=['blob'],
environ={'HTTP_HOST': '127.0.0.1'})['result']]))
def test_CommandsGetAbsentBlobs(self):
@@ -523,7 +506,7 @@ class RoutesTest(tests.Test):
guid = this.call(method='POST', path=['testdocument'], content={})
self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob'])
self.assertEqual(
- {'blob': {}},
+ {'blob': ''},
this.call(method='GET', path=['testdocument', guid], reply=['blob'], environ={'HTTP_HOST': 'localhost'}))
def test_Command_ReplyForGET(self):
@@ -740,11 +723,11 @@ class RoutesTest(tests.Test):
guid = this.call(method='POST', path=['testdocument'], content={})
this.call(method='PUT', path=['testdocument', guid, 'blob'], content={
'digest': 'digest',
- 'url': 'http://sugarlabs.org',
+ 'location': 'http://sugarlabs.org',
}, content_type='application/json')
self.assertEqual(
'http://sugarlabs.org',
- this.call(method='GET', path=['testdocument', guid, 'blob'])['url'])
+ this.call(method='GET', path=['testdocument', guid, 'blob'])['location'])
def test_on_create(self):
@@ -1231,65 +1214,6 @@ class RoutesTest(tests.Test):
'default',
this.call(method='GET', path=['testdocument', guid, 'prop']))
- def test_prop_meta(self):
- files.update('url', {'url': 'http://new', 'foo': 'bar', 'size': 100})
-
- class TestDocument(db.Resource):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.stored_property(db.Blob)
- def blob1(self, value):
- return value
-
- @db.stored_property(db.Blob)
- def blob2(self, value):
- return value
-
- @blob2.setter
- def blob2(self, value):
- return 'url'
-
- volume = db.Volume(tests.tmpdir, [TestDocument])
- router = Router(db.Routes(volume))
- guid = this.call(method='POST', path=['testdocument'], content = {'prop': 'prop', 'blob1': 'blob', 'blob2': ''})
-
- response = Response()
- assert this.call(response=response,
- method='HEAD', path=['testdocument', guid, 'prop']) is None
- meta = volume['testdocument'].get(guid).meta('prop')
- meta.pop('value')
- self.assertEqual(meta, response.meta)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified)
-
- response = Response()
- assert this.call(response=response,
- method='HEAD', path=['testdocument', guid, 'blob1'], environ={'HTTP_HOST': 'localhost'}) is None
- meta = volume['testdocument'].get(guid).meta('blob1')
- meta.pop('value')
- self.assertEqual(meta, response.meta)
- self.assertEqual(len('blob'), response.content_length)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified)
-
- response = Response()
- assert this.call(response=response,
- method='HEAD', path=['testdocument', guid, 'blob2']) is None
- meta = volume['testdocument'].get(guid).meta('blob2')
- meta.pop('value')
- self.assertEqual(meta, response.meta)
- self.assertEqual(100, response.content_length)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified)
-
- response = Response()
- assert this.call(response=response,
- method='GET', path=['testdocument', guid, 'blob2']) is not None
- meta = volume['testdocument'].get(guid).meta('blob2')
- meta.pop('value')
- self.assertEqual(meta, response.meta)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified)
-
def test_DefaultAuthor(self):
class User(db.Resource):
@@ -1888,7 +1812,7 @@ class RoutesTest(tests.Test):
agg1: {'seqno': 2, 'value': str(hash('blob1'))},
},
volume['document'].get(guid)['blobs'])
- assert files.get(str(hash('blob1')))
+ assert blobs.get(str(hash('blob1')))
agg2 = this.call(method='POST', path=['document', guid, 'blobs'], content='blob2')
self.assertEqual({
@@ -1896,7 +1820,7 @@ class RoutesTest(tests.Test):
agg2: {'seqno': 3, 'value': str(hash('blob2'))},
},
volume['document'].get(guid)['blobs'])
- assert files.get(str(hash('blob2')))
+ assert blobs.get(str(hash('blob2')))
this.call(method='DELETE', path=['document', guid, 'blobs', agg1])
self.assertEqual({
@@ -1904,8 +1828,8 @@ class RoutesTest(tests.Test):
agg2: {'seqno': 3, 'value': str(hash('blob2'))},
},
volume['document'].get(guid)['blobs'])
- assert files.get(str(hash('blob1'))) is None
- assert files.get(str(hash('blob2')))
+ assert blobs.get(str(hash('blob1'))) is None
+ assert blobs.get(str(hash('blob2')))
this.call(method='DELETE', path=['document', guid, 'blobs', agg2])
self.assertEqual({
@@ -1913,8 +1837,8 @@ class RoutesTest(tests.Test):
agg2: {'seqno': 5},
},
volume['document'].get(guid)['blobs'])
- assert files.get(str(hash('blob1'))) is None
- assert files.get(str(hash('blob2'))) is None
+ assert blobs.get(str(hash('blob1'))) is None
+ assert blobs.get(str(hash('blob2'))) is None
agg3 = this.call(method='POST', path=['document', guid, 'blobs'], content='blob3')
self.assertEqual({
@@ -1923,9 +1847,9 @@ class RoutesTest(tests.Test):
agg3: {'seqno': 6, 'value': str(hash('blob3'))},
},
volume['document'].get(guid)['blobs'])
- assert files.get(str(hash('blob1'))) is None
- assert files.get(str(hash('blob2'))) is None
- assert files.get(str(hash('blob3')))
+ assert blobs.get(str(hash('blob1'))) is None
+ assert blobs.get(str(hash('blob2'))) is None
+ assert blobs.get(str(hash('blob3')))
def test_AggregatedSearch(self):
diff --git a/tests/units/model/context.py b/tests/units/model/context.py
index ef505cc..8fd5b56 100755
--- a/tests/units/model/context.py
+++ b/tests/units/model/context.py
@@ -7,7 +7,7 @@ from os.path import exists
from __init__ import tests
from sugar_network import db
-from sugar_network.db import files
+from sugar_network.db import blobs
from sugar_network.client import IPCConnection, Connection, keyfile
from sugar_network.model.context import Context
from sugar_network.toolkit.coroutine import this
@@ -86,7 +86,7 @@ class ContextTest(tests.Test):
},
},
}, conn.get(['context', context, 'releases']))
- assert files.get(str(hash(bundle1)))
+ assert blobs.get(str(hash(bundle1)))
activity_info2 = '\n'.join([
'[Activity]',
@@ -130,8 +130,8 @@ class ContextTest(tests.Test):
},
},
}, conn.get(['context', context, 'releases']))
- assert files.get(str(hash(bundle1)))
- assert files.get(str(hash(bundle2)))
+ assert blobs.get(str(hash(bundle1)))
+ assert blobs.get(str(hash(bundle2)))
conn.delete(['context', context, 'releases', release1])
self.assertEqual({
@@ -154,8 +154,8 @@ class ContextTest(tests.Test):
},
},
}, conn.get(['context', context, 'releases']))
- assert files.get(str(hash(bundle1))) is None
- assert files.get(str(hash(bundle2)))
+ assert blobs.get(str(hash(bundle1))) is None
+ assert blobs.get(str(hash(bundle2)))
conn.delete(['context', context, 'releases', release2])
self.assertEqual({
@@ -168,8 +168,8 @@ class ContextTest(tests.Test):
'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
},
}, conn.get(['context', context, 'releases']))
- assert files.get(str(hash(bundle1))) is None
- assert files.get(str(hash(bundle2))) is None
+ assert blobs.get(str(hash(bundle1))) is None
+ assert blobs.get(str(hash(bundle2))) is None
def test_IncrementReleasesSeqnoOnNewReleases(self):
events = []
diff --git a/tests/units/model/model.py b/tests/units/model/model.py
index f3e4442..28d8244 100755
--- a/tests/units/model/model.py
+++ b/tests/units/model/model.py
@@ -3,11 +3,12 @@
# sugar-lint: disable
import base64
+import mimetypes
from __init__ import tests
from sugar_network import db
-from sugar_network.db import files
+from sugar_network.db import blobs
from sugar_network.model import load_bundle
from sugar_network.model.post import Post
from sugar_network.client import IPCConnection, Connection, keyfile
@@ -64,15 +65,15 @@ class ModelTest(tests.Test):
('topdir/activity/activity.info', activity_info),
('topdir/CHANGELOG', changelog),
)
- blob = files.post(bundle)
+ blob = blobs.post(bundle)
this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID)
context, release = load_bundle(blob, 'bundle_id')
self.assertEqual({
- 'mime_type': 'application/vnd.olpc-sugar',
- 'name': 'Activity-1',
- }, files.get(blob.digest))
+ 'content-type': 'application/vnd.olpc-sugar',
+ 'content-disposition': 'attachment; filename="Activity-1%s"' % (mimetypes.guess_extension('application/vnd.olpc-sugar') or ''),
+ }, blobs.get(blob.digest))
self.assertEqual('bundle_id', context)
self.assertEqual([[1], 0], release['version'])
self.assertEqual('developer', release['stability'])
@@ -113,16 +114,16 @@ class ModelTest(tests.Test):
'description': 'description',
})
bundle = 'non-activity'
- blob = files.post(bundle)
+ blob = blobs.post(bundle)
+ blob['content-type'] = 'application/pdf'
- this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID,
- content_type = 'content/type', version='2', license='GPL')
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID, version='2', license='GPL')
context, release = load_bundle(blob, 'bundle_id')
self.assertEqual({
- 'mime_type': 'content/type',
- 'name': 'NonActivity-2',
- }, files.get(blob.digest))
+ 'content-type': 'application/pdf',
+ 'content-disposition': 'attachment; filename="NonActivity-2.pdf"',
+ }, blobs.get(blob.digest))
self.assertEqual('bundle_id', context)
self.assertEqual([[2], 0], release['version'])
self.assertEqual(['GPL'], release['license'])
@@ -160,7 +161,7 @@ class ModelTest(tests.Test):
'activity_version = 1',
])
bundle = self.zips(('topdir/activity/activity.info', activity_info_wo_license))
- blob_wo_license = files.post(bundle)
+ blob_wo_license = blobs.post(bundle)
self.assertRaises(http.BadRequest, load_bundle, blob_wo_license, 'bundle_id')
volume['context'].update('bundle_id', {'releases': {
@@ -199,7 +200,7 @@ class ModelTest(tests.Test):
'description': 'description',
})
- blob = files.post('non-activity')
+ blob = blobs.post('non-activity')
this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID, version='1')
self.assertRaises(http.BadRequest, load_bundle, blob, 'bundle_id')
@@ -239,7 +240,7 @@ class ModelTest(tests.Test):
'description': 'description',
})
- blob = files.post('non-activity')
+ blob = blobs.post('non-activity')
this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID, version='2', license='GPL')
self.assertRaises(http.BadRequest, load_bundle, blob, 'bundle_id')
@@ -259,7 +260,7 @@ class ModelTest(tests.Test):
('topdir/activity/activity.info', activity_info),
('topdir/CHANGELOG', changelog),
)
- blob = files.post(bundle)
+ blob = blobs.post(bundle)
self.assertRaises(http.BadRequest, load_bundle, blob, 'bundle_id')
def test_load_bundle_MissedContext(self):
@@ -278,7 +279,7 @@ class ModelTest(tests.Test):
'stability = developer',
'requires = sugar>=0.88; dep'
])))
- blob = files.post(bundle)
+ blob = blobs.post(bundle)
this.request = Request(principal=tests.UID)
self.assertRaises(http.NotFound, load_bundle, blob, initial=False)
@@ -304,7 +305,7 @@ class ModelTest(tests.Test):
])),
('ImageViewer.activity/activity/activity-imageviewer.svg', ''),
)
- blob = files.post(bundle)
+ blob = blobs.post(bundle)
this.request = Request(principal=tests.UID)
context, release = load_bundle(blob, initial=True)
@@ -377,7 +378,7 @@ class ModelTest(tests.Test):
('ImageViewer.activity/activity/activity-imageviewer.svg', svg),
)
- blob = files.post(bundle)
+ blob = blobs.post(bundle)
this.request = Request(method='POST', path=['context', 'org.laptop.ImageViewerActivity'], principal=tests.UID)
context, release = load_bundle(blob, initial=True)
@@ -395,7 +396,7 @@ class ModelTest(tests.Test):
'en': 'It has features one would expect of a standard image viewer, like zoom, rotate, etc.',
},
context['description'])
- self.assertEqual(svg, file(files.get(context['artifact_icon']).path).read())
+ self.assertEqual(svg, file(blobs.get(context['artifact_icon']).path).read())
assert context['icon'] != 'missing.png'
assert context['logo'] != 'missing-logo.png'
self.assertEqual('http://wiki.sugarlabs.org/go/Activities/Image_Viewer', context['homepage'])
@@ -425,7 +426,7 @@ class ModelTest(tests.Test):
'license = Public Domain',
'stability = developer',
])))
- blob = files.post(bundle)
+ blob = blobs.post(bundle)
this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID2)
context, release = load_bundle(blob, 'bundle_id')
@@ -443,8 +444,8 @@ class ModelTest(tests.Test):
'fr': 'Activity 1 third-party release',
}, post['title'])
- files.delete(blob.digest)
- blob = files.post(bundle)
+ blobs.delete(blob.digest)
+ blob = blobs.post(bundle)
this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID)
context, release = load_bundle(blob, 'bundle_id')
@@ -486,7 +487,7 @@ class ModelTest(tests.Test):
])),
('ImageViewer.activity/activity/activity-imageviewer.svg', ''),
)
- blob = files.post(bundle)
+ blob = blobs.post(bundle)
this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID)
context, release = load_bundle(blob, 'bundle_id')
diff --git a/tests/units/node/node.py b/tests/units/node/node.py
index 9b1f702..025a0c0 100755
--- a/tests/units/node/node.py
+++ b/tests/units/node/node.py
@@ -722,12 +722,6 @@ class NodeTest(tests.Test):
response = Response()
reply = conn.call(Request(method='GET', path=['context', 'activity'], cmd='clone'), response)
assert activity_blob == reply.read()
- self.assertEqual({
- 'commands': {'activity': {'exec': 'true'}},
- 'files': {'activity': activity_file, 'dep': dep_file},
- 'packages': {'package': ['package.bin']},
- },
- response.meta)
def test_AggpropInsertAccess(self):
diff --git a/tests/units/toolkit/http.py b/tests/units/toolkit/http.py
index d21af37..2ac3cab 100755
--- a/tests/units/toolkit/http.py
+++ b/tests/units/toolkit/http.py
@@ -107,89 +107,6 @@ class HTTPTest(tests.Test):
})
self.assertEqual('result', json.load(client.call(request)))
- def test_call_ReturnMeta(self):
-
- class Commands(object):
-
- @route('HEAD')
- def f1(self, response):
- response.meta['str'] = 'str'
- response.meta['bool'] = True
- response.meta['int'] = -1
-
- @route('POST')
- def f2(self):
- response.meta['str'] = 'STR'
- response.meta['bool'] = False
- response.meta['int'] = 1
-
- @route('GET')
- def f3(self):
- response.meta['str'] = 'FOO'
- response.meta['bool'] = True
- response.meta['int'] = 10
-
- server = coroutine.WSGIServer(('127.0.0.1', local.ipc_port.value), Router(Commands()))
- coroutine.spawn(server.serve_forever)
- coroutine.dispatch()
- conn = http.Connection('http://127.0.0.1:%s' % local.ipc_port.value)
-
- request = Request({
- 'REQUEST_METHOD': 'HEAD',
- 'PATH_INFO': '/',
- })
- response = Response()
- conn.call(request, response)
- self.assertEqual({
- 'int': -1,
- 'bool': True,
- 'str': 'str',
- }, response.meta)
-
- response = Response()
- conn.call(Request(method='POST'), response)
- self.assertEqual({
- 'int': 1,
- 'bool': False,
- 'str': 'STR',
- }, response.meta)
-
- response = Response()
- conn.call(Request(method='GET'), response)
- self.assertEqual({
- 'int': 10,
- 'bool': True,
- 'str': 'FOO',
- }, response.meta)
-
- def test_call_ReturnMetaOnRedirects(self):
-
- class Front(object):
-
- @route('GET')
- def get(self, response):
- response.meta['front'] = 'value1'
- raise http.Redirect('http://127.0.0.1:%s' % (local.ipc_port.value + 1))
-
- server = coroutine.WSGIServer(('127.0.0.1', local.ipc_port.value), Router(Front()))
- coroutine.spawn(server.serve_forever)
-
- class Back(object):
-
- @route('GET')
- def get(self, response):
- response.meta['back'] = 'value2'
-
- server = coroutine.WSGIServer(('127.0.0.1', local.ipc_port.value + 1), Router(Back()))
- coroutine.spawn(server.serve_forever)
-
- conn = http.Connection('http://127.0.0.1:%s' % local.ipc_port.value)
- coroutine.dispatch()
-
- response = Response()
- stream = conn.call(Request(method='GET'), response)
- self.assertEqual({'front': 'value1', 'back': 'value2'}, response.meta)
-
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/toolkit/router.py b/tests/units/toolkit/router.py
index 3dd1306..7d8af39 100755
--- a/tests/units/toolkit/router.py
+++ b/tests/units/toolkit/router.py
@@ -10,7 +10,7 @@ from cStringIO import StringIO
from __init__ import tests, src_root
from sugar_network import db, client, toolkit
-from sugar_network.toolkit.router import Router, Request, _parse_accept_language, route, fallbackroute, preroute, postroute
+from sugar_network.toolkit.router import Router, Request, _parse_accept_language, route, fallbackroute, preroute, postroute, File
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import http, coroutine
@@ -984,8 +984,8 @@ class RouterTest(tests.Test):
lambda status, headers: response.extend([status, dict(headers)]))
self.assertEqual('', ''.join([i for i in reply]))
self.assertEqual([
- '001 Status',
- {'X-SN-error': '"Status-Error"'},
+ '001 Status-Error',
+ {},
],
response)
@@ -1025,7 +1025,7 @@ class RouterTest(tests.Test):
@route('GET')
def get(self, response):
- return toolkit.File(meta={'url': URL})
+ return File(None, meta=[('location', URL)])
router = Router(CommandsProcessor())
@@ -1226,13 +1226,9 @@ class RouterTest(tests.Test):
class CommandsProcessor(object):
- @route('GET', [], '1')
- def cmd1(self, request):
- return toolkit.File('blob.data', {'name': 'foo', 'mime_type': 'application/octet-stream'})
-
- @route('GET', [], cmd='2')
- def cmd2(self, request):
- return toolkit.File('blob.data', {'filename': 'foo.bar'})
+ @route('GET', [])
+ def probe(self, request):
+ return File('blob.data', meta=[('content-disposition', 'attachment; filename="foo.bar"')])
router = Router(CommandsProcessor())
@@ -1240,27 +1236,6 @@ class RouterTest(tests.Test):
reply = router({
'PATH_INFO': '/',
'REQUEST_METHOD': 'GET',
- 'QUERY_STRING': 'cmd=1',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = 'value'
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '200 OK',
- {
- 'last-modified': formatdate(os.stat('blob.data').st_mtime, localtime=False, usegmt=True),
- 'content-length': str(len(result)),
- 'content-type': 'application/octet-stream',
- 'content-disposition': 'attachment; filename="foo.obj"',
- }
- ],
- response)
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'QUERY_STRING': 'cmd=2',
},
lambda status, headers: response.extend([status, dict(headers)]))
result = 'value'
@@ -1268,9 +1243,7 @@ class RouterTest(tests.Test):
self.assertEqual([
'200 OK',
{
- 'last-modified': formatdate(os.stat('blob.data').st_mtime, localtime=False, usegmt=True),
'content-length': str(len(result)),
- 'content-type': 'application/octet-stream',
'content-disposition': 'attachment; filename="foo.bar"',
}
],
diff --git a/tests/units/toolkit/toolkit.py b/tests/units/toolkit/toolkit.py
index 07ed9c6..87f0c2f 100755
--- a/tests/units/toolkit/toolkit.py
+++ b/tests/units/toolkit/toolkit.py
@@ -8,7 +8,7 @@ from cStringIO import StringIO
from __init__ import tests
from sugar_network import toolkit
-from sugar_network.toolkit import Seqno, Sequence, File
+from sugar_network.toolkit import Seqno, Sequence
class UtilTest(tests.Test):
@@ -421,15 +421,6 @@ class UtilTest(tests.Test):
['d', 'a', 'b', 'c'],
[i for i in stack])
- def test_FileName(self):
- self.assertEqual('blob', File().name)
- self.assertEqual('blob', File('foo/bar').name)
- self.assertEqual('digest', File(digest='digest').name)
- self.assertEqual('foo', File(meta={'filename': 'foo'}).name)
- self.assertEqual('foo', File(meta={'name': 'foo'}).name)
- self.assertEqual('foo', File(meta={'filename': 'foo', 'mime_type': 'image/png'}).name)
- self.assertEqual('digest.png', File(digest='digest', meta={'mime_type': 'image/png'}).name)
-
if __name__ == '__main__':
tests.main()