From 4dc349755c8463c8a197433126c78988c74a1b43 Mon Sep 17 00:00:00 2001 From: Aleksey Lim Date: Mon, 24 Feb 2014 17:10:36 +0000 Subject: No need in extra HTTP headers after moving context resolves to node side --- 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 . +# 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 '' % (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 '' % 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 '' % 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() -- cgit v0.9.1