Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2014-02-04 12:19:15 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2014-02-18 21:20:34 (GMT)
commit6447b7951a66021f288f5b2b0c8cc301257d36ee (patch)
tree2c7d269a0dba29a6466996889a1c9980971a0e06 /tests
parentb68085299cee6e5488e8301042cde13d040494ca (diff)
Polish design
The major points: * minimize number of resource types * use aggregated properties instead of resources * separate blob storage from resources db
Diffstat (limited to 'tests')
-rw-r--r--tests/__init__.py88
-rw-r--r--tests/data/locale/en/LC_MESSAGES/sugar-network.mobin0 -> 407 bytes
-rw-r--r--tests/data/locale/es/LC_MESSAGES/sugar-network.mobin0 -> 2248 bytes
-rw-r--r--tests/data/locale/fr/LC_MESSAGES/sugar-network.mobin0 -> 2211 bytes
-rwxr-xr-xtests/units/client/cache.py26
-rwxr-xr-xtests/units/client/routes.py10
-rw-r--r--tests/units/db/__main__.py7
-rwxr-xr-xtests/units/db/files.py320
-rwxr-xr-xtests/units/db/index.py157
-rwxr-xr-xtests/units/db/metadata.py71
-rwxr-xr-xtests/units/db/resource.py312
-rwxr-xr-xtests/units/db/routes.py1628
-rwxr-xr-xtests/units/db/storage.py19
-rw-r--r--tests/units/model/__main__.py2
-rwxr-xr-xtests/units/model/context.py327
-rwxr-xr-xtests/units/model/model.py519
-rwxr-xr-xtests/units/model/post.py176
-rwxr-xr-xtests/units/model/release.py124
-rwxr-xr-xtests/units/model/routes.py86
-rw-r--r--tests/units/node/__main__.py4
-rwxr-xr-xtests/units/node/master.py214
-rwxr-xr-xtests/units/node/model.py660
-rwxr-xr-xtests/units/node/node.py1058
-rwxr-xr-xtests/units/node/obs.py22
-rwxr-xr-xtests/units/node/stats_node.py338
-rwxr-xr-xtests/units/node/sync_online.py22
-rwxr-xr-xtests/units/node/volume.py826
-rw-r--r--tests/units/toolkit/__main__.py2
-rwxr-xr-xtests/units/toolkit/coroutine.py31
-rwxr-xr-xtests/units/toolkit/i18n.py68
-rwxr-xr-xtests/units/toolkit/router.py126
-rwxr-xr-xtests/units/toolkit/toolkit.py37
32 files changed, 3557 insertions, 3723 deletions
diff --git a/tests/__init__.py b/tests/__init__.py
index 2e058f5..b93e388 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -8,6 +8,7 @@ import shutil
import hashlib
import logging
import zipfile
+import gettext
import unittest
import tempfile
import subprocess
@@ -16,17 +17,19 @@ from os.path import dirname, join, exists, abspath, isfile
from M2Crypto import DSA
from gevent import monkey
-from sugar_network.toolkit import coroutine, http, mountpoints, Option, gbus
+from sugar_network.toolkit import coroutine, http, mountpoints, Option, gbus, i18n, languages
from sugar_network.toolkit.router import Router
+from sugar_network.toolkit.coroutine import this
+from sugar_network.db import files
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
from sugar_network.client import solver
from sugar_network.model.user import User
from sugar_network.model.context import Context
-from sugar_network.model.release import Release
+from sugar_network.model.post import Post
from sugar_network.node.master import MasterRoutes
-from sugar_network.node import stats_user, stats_node, obs, slave, downloads
+from sugar_network.node import stats_user, obs, slave, downloads
from requests import adapters
@@ -41,6 +44,9 @@ monkey.patch_select()
monkey.patch_ssl()
monkey.patch_time()
+gettext._default_localedir = join(root, 'data', 'locale')
+languages.LANGUAGES = ['en', 'es', 'fr']
+
def main():
shutil.rmtree(tmproot, ignore_errors=True)
@@ -57,7 +63,7 @@ class Test(unittest.TestCase):
os.environ['LANG'] = 'en_US'
os.environ['LANGUAGE'] = 'en_US'
- toolkit._default_langs = None
+ i18n._default_langs = None
global tmpdir
tmpdir = join(tmp_root or tmproot, '.'.join(self.id().split('.')[1:]))
@@ -102,13 +108,10 @@ class Test(unittest.TestCase):
mountpoints._connects.clear()
mountpoints._found.clear()
mountpoints._COMPLETE_MOUNT_TIMEOUT = .1
- stats_node.stats_node.value = False
- stats_node.stats_node_step.value = 1
- stats_node.stats_node_rras.value = ['RRA:AVERAGE:0.5:1:60']
stats_user.stats_user.value = False
stats_user.stats_user_step.value = 1
stats_user._user_cache.clear()
- obs._client = None
+ obs._conn = None
obs._repos = {'base': [], 'presolve': []}
http._RECONNECTION_NUMBER = 0
toolkit.cachedir.value = tmpdir + '/tmp'
@@ -122,8 +125,7 @@ class Test(unittest.TestCase):
db.Volume.model = [
'sugar_network.model.user',
'sugar_network.model.context',
- 'sugar_network.model.artifact',
- 'sugar_network.model.release',
+ 'sugar_network.model.post',
'sugar_network.model.report',
]
@@ -137,10 +139,16 @@ class Test(unittest.TestCase):
self.node = None
self.client = None
-
self.forks = []
self.fork_num = fork_num
+ this.request = None
+ this.volume = None
+ this.call = None
+ this.broadcast = lambda x: x
+
+ self.override_files()
+
def tearDown(self):
self.stop_nodes()
while db.Volume._flush_pool:
@@ -150,6 +158,46 @@ class Test(unittest.TestCase):
setattr(mod, name, old_handler)
sys.stdout.flush()
+ def override_files(self):
+ os.makedirs('blobs')
+ self.blobs = {}
+
+ def files_post(content, meta=None, digest_to_assert=None):
+ if hasattr(content, 'read'):
+ content = content.read()
+ digest = files.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)
+
+ def files_update(digest, meta):
+ self.blobs.setdefault(digest, {}).update(meta)
+
+ 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
+
+ def files_delete(digest):
+ path = join('blobs', digest)
+ if exists(path):
+ os.unlink(path)
+ 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)
+
def stop_nodes(self):
if self.client is not None:
self.client.close()
@@ -267,17 +315,20 @@ class Test(unittest.TestCase):
def start_master(self, classes=None, routes=MasterRoutes):
if classes is None:
- classes = [User, Context, Release]
+ classes = [User, Context, Post]
self.node_volume = db.Volume('master', classes)
self.node_routes = routes('guid', self.node_volume)
- self.node = coroutine.WSGIServer(('127.0.0.1', 8888), Router(self.node_routes))
+ self.node_router = Router(self.node_routes)
+ self.node = coroutine.WSGIServer(('127.0.0.1', 8888), self.node_router)
coroutine.spawn(self.node.serve_forever)
coroutine.dispatch(.1)
+ this.volume = self.node_volume
+ this.call = self.node_router.call
return self.node_volume
def fork_master(self, classes=None, routes=MasterRoutes):
if classes is None:
- classes = [User, Context, Release]
+ classes = [User, Context]
def node():
volume = db.Volume('master', classes)
@@ -291,18 +342,19 @@ class Test(unittest.TestCase):
def start_client(self, classes=None, routes=ClientRoutes):
if classes is None:
- classes = [User, Context, Release]
+ classes = [User, Context]
volume = db.Volume('client', classes)
self.client_routes = routes(volume, client.api_url.value)
self.client = coroutine.WSGIServer(
('127.0.0.1', client.ipc_port.value), Router(self.client_routes))
coroutine.spawn(self.client.serve_forever)
coroutine.dispatch()
+ this.volume = volume
return volume
def start_online_client(self, classes=None):
if classes is None:
- classes = [User, Context, Release]
+ classes = [User, Context]
self.start_master(classes)
volume = db.Volume('client', classes)
self.client_routes = ClientRoutes(volume, client.api_url.value)
@@ -311,6 +363,7 @@ class Test(unittest.TestCase):
('127.0.0.1', client.ipc_port.value), Router(self.client_routes))
coroutine.spawn(self.client.serve_forever)
coroutine.dispatch()
+ this.volume = volume
return volume
def start_offline_client(self, resources=None):
@@ -319,6 +372,7 @@ class Test(unittest.TestCase):
server = coroutine.WSGIServer(('127.0.0.1', client.ipc_port.value), Router(self.client_routes))
coroutine.spawn(server.serve_forever)
coroutine.dispatch()
+ this.volume = self.home_volume
return IPCConnection()
def restful_server(self, classes=None):
@@ -337,7 +391,7 @@ class Test(unittest.TestCase):
node.find_limit.value = 1024
db.index_write_queue.value = 10
- volume = db.Volume('remote', classes or [User, Context, Release])
+ volume = db.Volume('remote', classes or [User, Context])
self.node_routes = MasterRoutes('guid', volume)
httpd = coroutine.WSGIServer(('127.0.0.1', 8888), Router(self.node_routes))
try:
diff --git a/tests/data/locale/en/LC_MESSAGES/sugar-network.mo b/tests/data/locale/en/LC_MESSAGES/sugar-network.mo
new file mode 100644
index 0000000..c601536
--- /dev/null
+++ b/tests/data/locale/en/LC_MESSAGES/sugar-network.mo
Binary files differ
diff --git a/tests/data/locale/es/LC_MESSAGES/sugar-network.mo b/tests/data/locale/es/LC_MESSAGES/sugar-network.mo
new file mode 100644
index 0000000..d39d878
--- /dev/null
+++ b/tests/data/locale/es/LC_MESSAGES/sugar-network.mo
Binary files differ
diff --git a/tests/data/locale/fr/LC_MESSAGES/sugar-network.mo b/tests/data/locale/fr/LC_MESSAGES/sugar-network.mo
new file mode 100644
index 0000000..dc4a83e
--- /dev/null
+++ b/tests/data/locale/fr/LC_MESSAGES/sugar-network.mo
Binary files differ
diff --git a/tests/units/client/cache.py b/tests/units/client/cache.py
index e980549..51245ee 100755
--- a/tests/units/client/cache.py
+++ b/tests/units/client/cache.py
@@ -12,7 +12,6 @@ from __init__ import tests
from sugar_network import db
from sugar_network.model.context import Context
-from sugar_network.model.release import Release
from sugar_network.client import cache_limit, cache_limit_percent, cache_lifetime, IPCConnection
from sugar_network.client.cache import Cache
from sugar_network.toolkit import http
@@ -32,7 +31,7 @@ class CacheTest(tests.Test):
self.override(os, 'statvfs', lambda *args: statvfs())
def test_open(self):
- volume = db.Volume('db', [Context, Release])
+ volume = db.Volume('db', [Context])
volume['release'].create({
'guid': '1',
@@ -83,7 +82,7 @@ class CacheTest(tests.Test):
self.assertEqual(['5', '4', '1'], [i for i in cache])
def test_open_IgnoreClones(self):
- volume = db.Volume('db', [Context, Release])
+ volume = db.Volume('db', [Context])
volume['context'].create({
'guid': 'context',
@@ -109,7 +108,7 @@ class CacheTest(tests.Test):
self.assertEqual([], [i for i in cache])
def test_ensure_AfterOpen(self):
- volume = db.Volume('db', [Context, Release])
+ volume = db.Volume('db', [Context])
volume['release'].create({'data': {'blob_size': 1}, 'guid': '1', 'context': 'context', 'version': '1', 'license': ['GPL'], 'stability': 'stable'})
os.utime('db/release/1/1', (1, 1))
@@ -143,7 +142,7 @@ class CacheTest(tests.Test):
self.assertRaises(RuntimeError, cache.ensure, 2, 0)
def test_ensure_Live(self):
- volume = db.Volume('db', [Context, Release])
+ volume = db.Volume('db', [Context])
cache = Cache(volume)
# To initiate the cache
@@ -159,7 +158,7 @@ class CacheTest(tests.Test):
self.assertRaises(RuntimeError, cache.ensure, 1, 0)
def test_ensure_ConsiderTmpSize(self):
- volume = db.Volume('db', [Context, Release])
+ volume = db.Volume('db', [Context])
volume['release'].create({'data': {'blob_size': 1}, 'guid': '1', 'context': 'context', 'version': '1', 'license': ['GPL'], 'stability': 'stable'})
cache = Cache(volume)
@@ -175,7 +174,7 @@ class CacheTest(tests.Test):
def test_recycle(self):
ts = time.time()
- volume = db.Volume('db', [Context, Release])
+ volume = db.Volume('db', [Context])
volume['release'].create({'data': {'blob_size': 1}, 'guid': '1', 'context': 'context', 'version': '1', 'license': ['GPL'], 'stability': 'stable'})
os.utime('db/release/1/1', (ts - 1.5 * 86400, ts - 1.5 * 86400))
volume['release'].create({'data': {'blob_size': 1}, 'guid': '2', 'context': 'context', 'version': '1', 'license': ['GPL'], 'stability': 'stable'})
@@ -205,7 +204,7 @@ class CacheTest(tests.Test):
cache.recycle()
def test_checkin(self):
- volume = db.Volume('db', [Context, Release])
+ volume = db.Volume('db', [Context])
cache = Cache(volume)
volume['release'].create({'guid': '1', 'context': 'context', 'version': '1', 'license': ['GPL'], 'stability': 'stable'})
@@ -229,7 +228,7 @@ class CacheTest(tests.Test):
conn = IPCConnection()
self.statvfs.f_blocks = 0
- impl1 = conn.upload(['release'], StringIO(self.zips(['TestActivity/activity/activity.info', [
+ bundle = self.zips(['TestActivity/activity/activity.info', [
'[Activity]',
'name = TestActivity',
'bundle_id = context',
@@ -238,9 +237,12 @@ class CacheTest(tests.Test):
'activity_version = 1',
'license = Public Domain',
'stability = stable',
- ]])), cmd='submit', initial=True)
-
+ ]])
+ impl1 = conn.upload(['release'], StringIO(bundle), cmd='submit', initial=True)
+ print self.blobs[str(hash(bundle))]
conn.put(['context', 'context'], True, cmd='clone')
+ print self.blobs[str(hash(bundle))]
+ return
self.assertEqual([], [i for i in self.client_routes._cache])
assert local_volume['release'].exists(impl1)
@@ -271,7 +273,7 @@ class CacheTest(tests.Test):
assert local_volume['release'].exists(impl2)
def test_Acquiring(self):
- volume = db.Volume('db', [Context, Release])
+ volume = db.Volume('db', [Context])
cache = Cache(volume)
volume['release'].create({'guid': '1', 'context': 'context', 'version': '1', 'license': ['GPL'], 'stability': 'stable'})
diff --git a/tests/units/client/routes.py b/tests/units/client/routes.py
index 0b757f5..9fad249 100755
--- a/tests/units/client/routes.py
+++ b/tests/units/client/routes.py
@@ -16,7 +16,7 @@ from sugar_network.client.routes import ClientRoutes, CachedClientRoutes
from sugar_network.model.user import User
from sugar_network.model.report import Report
from sugar_network.toolkit.router import Router, Request, Response
-from sugar_network.toolkit import coroutine
+from sugar_network.toolkit import coroutine, i18n
import requests
@@ -420,28 +420,28 @@ class RoutesTest(tests.Test):
'description': '',
})
- toolkit._default_langs = None
+ i18n._default_langs = None
os.environ['LANGUAGE'] = 'es:ru:en'
ipc = IPCConnection()
self.assertEqual('3', ipc.get(['context', guid1, 'title']))
self.assertEqual('2', ipc.get(['context', guid2, 'title']))
self.assertEqual('1', ipc.get(['context', guid3, 'title']))
- toolkit._default_langs = None
+ i18n._default_langs = None
os.environ['LANGUAGE'] = 'ru:en'
ipc = IPCConnection()
self.assertEqual('2', ipc.get(['context', guid1, 'title']))
self.assertEqual('2', ipc.get(['context', guid2, 'title']))
self.assertEqual('1', ipc.get(['context', guid3, 'title']))
- toolkit._default_langs = None
+ i18n._default_langs = None
os.environ['LANGUAGE'] = 'en'
ipc = IPCConnection()
self.assertEqual('1', ipc.get(['context', guid1, 'title']))
self.assertEqual('1', ipc.get(['context', guid2, 'title']))
self.assertEqual('1', ipc.get(['context', guid3, 'title']))
- toolkit._default_langs = None
+ i18n._default_langs = None
os.environ['LANGUAGE'] = 'foo'
ipc = IPCConnection()
self.assertEqual('1', ipc.get(['context', guid1, 'title']))
diff --git a/tests/units/db/__main__.py b/tests/units/db/__main__.py
index fc91d7c..3b1b9ec 100644
--- a/tests/units/db/__main__.py
+++ b/tests/units/db/__main__.py
@@ -2,11 +2,12 @@
from __init__ import tests
-from resource import *
-from index import *
-#from migrate import *
+from metadata import *
from storage import *
+from index import *
+from resource import *
from routes import *
+#from migrate import *
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/db/files.py b/tests/units/db/files.py
new file mode 100755
index 0000000..0d806df
--- /dev/null
+++ b/tests/units/db/files.py
@@ -0,0 +1,320 @@
+
+ def test_diff_WithBlobsSetByUrl(self):
+ URL = 'http://src.sugarlabs.org/robots.txt'
+ URL_content = urllib2.urlopen(URL).read()
+
+ class Document(db.Resource):
+
+ @db.blob_property()
+ def blob(self, value):
+ return value
+
+ directory = Directory(tests.tmpdir, Document, IndexWriter)
+
+ directory.create({'guid': '1', 'ctime': 1, 'mtime': 1})
+ directory.update('1', {'blob': {'url': URL}})
+ self.utime('1/1', 1)
+
+ out_seq = Sequence()
+ self.assertEqual([
+ {'guid': '1', 'diff': {
+ 'guid': {'value': '1', 'mtime': 1},
+ 'ctime': {'value': 1, 'mtime': 1},
+ 'mtime': {'value': 1, 'mtime': 1},
+ 'blob': {
+ 'url': URL,
+ 'mtime': 1,
+ },
+ }},
+ ],
+ [i for i in diff(directory, [[0, None]], out_seq)])
+ self.assertEqual([[1, 2]], out_seq)
+
+ def test_merge_AvoidCalculatedBlobs(self):
+
+ class Document(db.Resource):
+
+ @db.blob_property()
+ def blob(self, value):
+ return {'url': 'http://foo/bar', 'mime_type': 'image/png'}
+
+ directory1 = Directory('document1', Document, IndexWriter)
+ directory1.create({'guid': 'guid', 'ctime': 1, 'mtime': 1})
+ for i in os.listdir('document1/gu/guid'):
+ os.utime('document1/gu/guid/%s' % i, (1, 1))
+
+ directory2 = Directory('document2', Document, IndexWriter)
+ for patch in diff(directory1, [[0, None]], Sequence()):
+ directory2.merge(**patch)
+
+ doc = directory2.get('guid')
+ self.assertEqual(1, doc.get('seqno'))
+ self.assertEqual(1, doc.meta('guid')['mtime'])
+ assert not exists('document2/gu/guid/blob')
+
+ def test_merge_Blobs(self):
+
+ class Document(db.Resource):
+
+ @db.blob_property()
+ def blob(self, value):
+ return value
+
+ directory = Directory('document', Document, IndexWriter)
+ self.touch(('blob', 'blob-1'))
+ directory.merge('1', {
+ 'guid': {'mtime': 1, 'value': '1'},
+ 'ctime': {'mtime': 2, 'value': 2},
+ 'mtime': {'mtime': 3, 'value': 3},
+ 'blob': {'mtime': 4, 'blob': 'blob'},
+ })
+
+ self.assertEqual(
+ [(2, 3, '1')],
+ [(i['ctime'], i['mtime'], i['guid']) for i in directory.find()[0]])
+
+ doc = directory.get('1')
+ self.assertEqual(1, doc.get('seqno'))
+ self.assertEqual(1, doc.meta('guid')['mtime'])
+ self.assertEqual(2, doc.meta('ctime')['mtime'])
+ self.assertEqual(3, doc.meta('mtime')['mtime'])
+ self.assertEqual(4, doc.meta('blob')['mtime'])
+ self.assertEqual('blob-1', file('document/1/1/blob.blob').read())
+
+ self.touch(('blob', 'blob-2'))
+ directory.merge('1', {
+ 'blob': {'mtime': 5, 'blob': 'blob'},
+ })
+
+ self.assertEqual(5, doc.meta('blob')['mtime'])
+ self.assertEqual('blob-2', file('document/1/1/blob.blob').read())
+
+
+ def test_DeleteOldBlobOnUpdate(self):
+
+ class Document(db.Resource):
+
+ @db.blob_property()
+ def blob(self, value):
+ return value
+
+ directory = Directory(tests.tmpdir, Document, IndexWriter)
+
+ directory.create({'guid': 'guid', 'blob': 'foo'})
+ assert exists('gu/guid/blob.blob')
+ directory.update('guid', {'blob': {'url': 'foo'}})
+ assert not exists('gu/guid/blob.blob')
+
+ directory.update('guid', {'blob': 'foo'})
+ assert exists('gu/guid/blob.blob')
+ directory.update('guid', {'blob': {}})
+ assert not exists('gu/guid/blob.blob')
+
+ def test_diff_Blobs(self):
+
+ class Document(db.Resource):
+
+ @db.blob_property()
+ def prop(self, value):
+ return value
+
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
+
+ guid = call(cp, method='POST', document='document', content={})
+ call(cp, method='PUT', document='document', guid=guid, content={'prop': 'payload'})
+ self.utime('db', 0)
+
+ patch = diff(volume, toolkit.Sequence([[1, None]]))
+ self.assertEqual(
+ {'resource': 'document'},
+ next(patch))
+ record = next(patch)
+ self.assertEqual('payload', ''.join([i for i in record.pop('blob')]))
+ self.assertEqual(
+ {'guid': guid, 'blob_size': len('payload'), 'diff': {
+ 'prop': {
+ 'digest': hashlib.sha1('payload').hexdigest(),
+ 'blob_size': len('payload'),
+ 'mime_type': 'application/octet-stream',
+ 'mtime': 0,
+ },
+ }},
+ record)
+ self.assertEqual(
+ {'guid': guid, 'diff': {
+ 'guid': {'value': guid, 'mtime': 0},
+ 'author': {'mtime': 0, 'value': {}},
+ 'layer': {'mtime': 0, 'value': []},
+ 'tags': {'mtime': 0, 'value': []},
+ 'mtime': {'value': 0, 'mtime': 0},
+ 'ctime': {'value': 0, 'mtime': 0},
+ }},
+ next(patch))
+ self.assertEqual(
+ {'commit': [[1, 2]]},
+ next(patch))
+ self.assertRaises(StopIteration, next, patch)
+
+ def test_diff_BlobUrls(self):
+ url = 'http://src.sugarlabs.org/robots.txt'
+ blob = urllib2.urlopen(url).read()
+
+ class Document(db.Resource):
+
+ @db.blob_property()
+ def prop(self, value):
+ return value
+
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
+
+ guid = call(cp, method='POST', document='document', content={})
+ call(cp, method='PUT', document='document', guid=guid, content={'prop': {'url': url}})
+ self.utime('db', 1)
+
+ self.assertEqual([
+ {'resource': 'document'},
+ {'guid': guid,
+ 'diff': {
+ 'guid': {'value': guid, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
+ 'layer': {'mtime': 1, 'value': []},
+ 'tags': {'mtime': 1, 'value': []},
+ 'mtime': {'value': 0, 'mtime': 1},
+ 'ctime': {'value': 0, 'mtime': 1},
+ 'prop': {'url': url, 'mtime': 1},
+ },
+ },
+ {'commit': [[1, 2]]},
+ ],
+ [i for i in diff(volume, toolkit.Sequence([[1, None]]))])
+
+ patch = diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=True)
+ self.assertEqual(
+ {'resource': 'document'},
+ next(patch))
+ record = next(patch)
+ self.assertEqual(blob, ''.join([i for i in record.pop('blob')]))
+ self.assertEqual(
+ {'guid': guid, 'blob_size': len(blob), 'diff': {'prop': {'mtime': 1}}},
+ record)
+ self.assertEqual(
+ {'guid': guid, 'diff': {
+ 'guid': {'value': guid, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
+ 'layer': {'mtime': 1, 'value': []},
+ 'tags': {'mtime': 1, 'value': []},
+ 'mtime': {'value': 0, 'mtime': 1},
+ 'ctime': {'value': 0, 'mtime': 1},
+ }},
+ next(patch))
+ self.assertEqual(
+ {'commit': [[1, 2]]},
+ next(patch))
+ self.assertRaises(StopIteration, next, patch)
+
+ def test_diff_SkipBrokenBlobUrls(self):
+
+ class Document(db.Resource):
+
+ @db.blob_property()
+ def prop(self, value):
+ return value
+
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
+
+ guid1 = call(cp, method='POST', document='document', content={})
+ call(cp, method='PUT', document='document', guid=guid1, content={'prop': {'url': 'http://foo/bar'}})
+ guid2 = call(cp, method='POST', document='document', content={})
+ self.utime('db', 1)
+
+ self.assertEqual([
+ {'resource': 'document'},
+ {'guid': guid1,
+ 'diff': {
+ 'guid': {'value': guid1, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
+ 'layer': {'mtime': 1, 'value': []},
+ 'tags': {'mtime': 1, 'value': []},
+ 'mtime': {'value': 0, 'mtime': 1},
+ 'ctime': {'value': 0, 'mtime': 1},
+ 'prop': {'url': 'http://foo/bar', 'mtime': 1},
+ },
+ },
+ {'guid': guid2,
+ 'diff': {
+ 'guid': {'value': guid2, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
+ 'layer': {'mtime': 1, 'value': []},
+ 'tags': {'mtime': 1, 'value': []},
+ 'mtime': {'value': 0, 'mtime': 1},
+ 'ctime': {'value': 0, 'mtime': 1},
+ },
+ },
+ {'commit': [[1, 3]]},
+ ],
+ [i for i in diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=False)])
+
+ self.assertEqual([
+ {'resource': 'document'},
+ {'guid': guid1,
+ 'diff': {
+ 'guid': {'value': guid1, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
+ 'layer': {'mtime': 1, 'value': []},
+ 'tags': {'mtime': 1, 'value': []},
+ 'mtime': {'value': 0, 'mtime': 1},
+ 'ctime': {'value': 0, 'mtime': 1},
+ },
+ },
+ {'guid': guid2,
+ 'diff': {
+ 'guid': {'value': guid2, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
+ 'layer': {'mtime': 1, 'value': []},
+ 'tags': {'mtime': 1, 'value': []},
+ 'mtime': {'value': 0, 'mtime': 1},
+ 'ctime': {'value': 0, 'mtime': 1},
+ },
+ },
+ {'commit': [[1, 3]]},
+ ],
+ [i for i in diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=True)])
+
+ def test_merge_Blobs(self):
+
+ class Document(db.Resource):
+
+ @db.blob_property()
+ def prop(self, value):
+ return value
+
+ volume = db.Volume('db', [Document])
+
+ merge(volume, [
+ {'resource': 'document'},
+ {'guid': '1', 'diff': {
+ 'guid': {'value': '1', 'mtime': 1.0},
+ 'ctime': {'value': 2, 'mtime': 2.0},
+ 'mtime': {'value': 3, 'mtime': 3.0},
+ 'prop': {
+ 'blob': StringIO('payload'),
+ 'blob_size': len('payload'),
+ 'digest': hashlib.sha1('payload').hexdigest(),
+ 'mime_type': 'foo/bar',
+ 'mtime': 1,
+ },
+ }},
+ {'commit': [[1, 1]]},
+ ])
+
+ assert volume['document'].exists('1')
+ blob = volume['document'].get('1')['prop']
+ self.assertEqual(1, blob['mtime'])
+ self.assertEqual('foo/bar', blob['mime_type'])
+ self.assertEqual(hashlib.sha1('payload').hexdigest(), blob['digest'])
+ self.assertEqual(tests.tmpdir + '/db/document/1/1/prop.blob', blob['blob'])
+ self.assertEqual('payload', file(blob['blob']).read())
+
diff --git a/tests/units/db/index.py b/tests/units/db/index.py
index 9d996b0..cb144c6 100755
--- a/tests/units/db/index.py
+++ b/tests/units/db/index.py
@@ -12,23 +12,22 @@ from __init__ import tests
from sugar_network import toolkit
from sugar_network.db import index
-from sugar_network.db.index import _fmt_prop_value
-from sugar_network.db.metadata import Metadata, IndexedProperty, GUID_PREFIX, Property
+from sugar_network.db.metadata import Metadata, Property, GUID_PREFIX, Boolean, Enum, List, Localized, Numeric
from sugar_network.toolkit.router import ACL
-from sugar_network.toolkit import coroutine
+from sugar_network.toolkit import coroutine, i18n
class IndexTest(tests.Test):
def test_Term_AvoidCollisionsWithGuid(self):
- self.assertRaises(RuntimeError, IndexedProperty, 'key', 0, 'I')
- self.assertRaises(RuntimeError, IndexedProperty, 'key', 0, 'K')
- self.assertRaises(RuntimeError, IndexedProperty, 'key', 1, 'I')
- IndexedProperty('key', 1, 'K')
- IndexedProperty('guid', 0, 'I')
+ self.assertRaises(RuntimeError, Property, 'key', 0, 'I')
+ self.assertRaises(RuntimeError, Property, 'key', 0, 'K')
+ self.assertRaises(RuntimeError, Property, 'key', 1, 'I')
+ Property('key', 1, 'K')
+ Property('guid', 0, 'I')
def test_Create(self):
- db = Index({'key': IndexedProperty('key', 1, 'K')})
+ db = Index({'key': Property('key', 1, 'K')})
self.assertEqual(
([], 0),
@@ -47,8 +46,8 @@ class IndexTest(tests.Test):
def test_update(self):
db = Index({
- 'var_1': IndexedProperty('var_1', 1, 'A'),
- 'var_2': IndexedProperty('var_2', 2, 'B'),
+ 'var_1': Property('var_1', 1, 'A'),
+ 'var_2': Property('var_2', 2, 'B'),
})
db.store('1', {'var_1': 'value_1', 'var_2': 'value_2'})
@@ -62,7 +61,7 @@ class IndexTest(tests.Test):
db._find(reply=['var_1', 'var_2']))
def test_delete(self):
- db = Index({'key': IndexedProperty('key', 1, 'K')})
+ db = Index({'key': Property('key', 1, 'K')})
db.store('1', {'key': 'value'})
self.assertEqual(
@@ -74,8 +73,17 @@ class IndexTest(tests.Test):
([], 0),
db._find(reply=['key']))
- def test_IndexByFmt(self):
- db = Index({'key': IndexedProperty('key', 1, 'K', fmt=lambda x: "foo" + x)})
+ def test_IndexCalculatedValue(self):
+
+ class Property2(Property):
+
+ def encode(self, value):
+ yield "foo" + value
+
+ def decode(self, value):
+ return "foo" + value
+
+ db = Index({'key': Property2('key', 1, 'K')})
db.store('1', {'key': 'bar'})
@@ -92,15 +100,17 @@ class IndexTest(tests.Test):
[],
db._find(key='fake', reply=['key'])[0])
- def test_IndexByFmtGenerator(self):
+ def test_IndexCalculatedValues(self):
- def iterate(value):
- if value != 'fake':
- yield 'foo'
- yield 'bar'
- yield value
+ class Property2(Property):
- db = Index({'key': IndexedProperty('key', 1, 'K', fmt=iterate)})
+ def encode(self, value):
+ if value != 'fake':
+ yield 'foo'
+ yield 'bar'
+ yield value
+
+ db = Index({'key': Property2('key', 1, 'K')})
db.store('1', {'key': 'value'})
self.assertEqual(
@@ -118,9 +128,9 @@ class IndexTest(tests.Test):
def test_find(self):
db = Index({
- 'var_1': IndexedProperty('var_1', 1, 'A', full_text=True),
- 'var_2': IndexedProperty('var_2', 2, 'B', full_text=True),
- 'var_3': IndexedProperty('var_3', 3, 'C', full_text=True),
+ 'var_1': Property('var_1', 1, 'A', full_text=True),
+ 'var_2': Property('var_2', 2, 'B', full_text=True),
+ 'var_3': Property('var_3', 3, 'C', full_text=True),
})
db.store('1', {'var_1': '1', 'var_2': 'у', 'var_3': 'г'})
@@ -149,7 +159,7 @@ class IndexTest(tests.Test):
def test_find_NoneFilters(self):
db = Index({
- 'prop': IndexedProperty('prop', 1, 'P', full_text=True),
+ 'prop': Property('prop', 1, 'P', full_text=True),
})
db.store('guid', {'prop': 'value'})
@@ -164,9 +174,9 @@ class IndexTest(tests.Test):
[{'guid': 'guid', 'prop': 'value'}],
db._find(guid=None, reply=['prop'])[0])
- def test_find_WithTypeCast(self):
+ def test_find_DecodeArgs(self):
db = Index({
- 'var_1': IndexedProperty('var_1', 1, 'A', typecast=bool),
+ 'var_1': Boolean('var_1', 1, 'A'),
})
db.store('1', {'var_1': True})
@@ -181,9 +191,9 @@ class IndexTest(tests.Test):
def test_find_WithProps(self):
db = Index({
- 'var_1': IndexedProperty('var_1', 1, 'A', full_text=True),
- 'var_2': IndexedProperty('var_2', 2, 'B', full_text=True),
- 'var_3': IndexedProperty('var_3', 3, 'C', full_text=True),
+ 'var_1': Property('var_1', 1, 'A', full_text=True),
+ 'var_2': Property('var_2', 2, 'B', full_text=True),
+ 'var_3': Property('var_3', 3, 'C', full_text=True),
})
db.store('1', {'var_1': '1', 'var_2': 'у', 'var_3': 'г'})
@@ -209,9 +219,9 @@ class IndexTest(tests.Test):
def test_find_WithAllBooleanProps(self):
db = Index({
- 'var_1': IndexedProperty('var_1', 1, 'A', boolean=True, full_text=True),
- 'var_2': IndexedProperty('var_2', 2, 'B', boolean=True, full_text=True),
- 'var_3': IndexedProperty('var_3', 3, 'C', boolean=True, full_text=True),
+ 'var_1': Property('var_1', 1, 'A', boolean=True, full_text=True),
+ 'var_2': Property('var_2', 2, 'B', boolean=True, full_text=True),
+ 'var_3': Property('var_3', 3, 'C', boolean=True, full_text=True),
})
db.store('1', {'var_1': '1', 'var_2': 'у', 'var_3': 'г'})
@@ -232,9 +242,9 @@ class IndexTest(tests.Test):
def test_find_WithBooleanProps(self):
db = Index({
- 'var_1': IndexedProperty('var_1', 1, 'A', boolean=True, full_text=True),
- 'var_2': IndexedProperty('var_2', 2, 'B', boolean=False, full_text=True),
- 'var_3': IndexedProperty('var_3', 3, 'C', boolean=True, full_text=True),
+ 'var_1': Property('var_1', 1, 'A', boolean=True, full_text=True),
+ 'var_2': Property('var_2', 2, 'B', boolean=False, full_text=True),
+ 'var_3': Property('var_3', 3, 'C', boolean=True, full_text=True),
})
db.store('1', {'var_1': '1', 'var_2': 'у', 'var_3': 'г'})
@@ -254,7 +264,7 @@ class IndexTest(tests.Test):
db._find(query='б', var_1='1', var_2='у', var_3='г', reply=['var_1']))
def test_find_ExactQuery(self):
- db = Index({'key': IndexedProperty('key', 1, 'K', full_text=True)})
+ db = Index({'key': Property('key', 1, 'K', full_text=True)})
db.store('1', {'key': 'фу'})
db.store('2', {'key': 'фу бар'})
@@ -280,7 +290,7 @@ class IndexTest(tests.Test):
def test_find_ExactQueryTerms(self):
term = 'azAZ09_'
- db = Index({term: IndexedProperty(term, 1, 'T', full_text=True)})
+ db = Index({term: Property(term, 1, 'T', full_text=True)})
db.store('1', {term: 'test'})
db.store('2', {term: 'test fail'})
@@ -290,7 +300,7 @@ class IndexTest(tests.Test):
db._find(query='%s:=test' % term, reply=['guid']))
def test_find_ReturnPortions(self):
- db = Index({'key': IndexedProperty('key', 1, 'K')})
+ db = Index({'key': Property('key', 1, 'K')})
db.store('1', {'key': '1'})
db.store('2', {'key': '2'})
@@ -311,8 +321,8 @@ class IndexTest(tests.Test):
def test_find_OrderBy(self):
db = Index({
- 'var_1': IndexedProperty('var_1', 1, 'A'),
- 'var_2': IndexedProperty('var_2', 2, 'B'),
+ 'var_1': Property('var_1', 1, 'A'),
+ 'var_2': Property('var_2', 2, 'B'),
})
db.store('1', {'var_1': '1', 'var_2': '3'})
@@ -341,15 +351,15 @@ class IndexTest(tests.Test):
def test_find_GroupBy(self):
db = Index({
- 'var_1': IndexedProperty('var_1', 1, 'A'),
- 'var_2': IndexedProperty('var_2', 2, 'B'),
- 'var_3': IndexedProperty('var_3', 3, 'C'),
- 'var_4': IndexedProperty('var_4', 4, 'D'),
+ 'var_1': Property('var_1', 1, 'A'),
+ 'var_2': Property('var_2', 2, 'B'),
+ 'var_3': Property('var_3', 3, 'C'),
+ 'var_4': Property('var_4', 4, 'D'),
})
- db.store('1', {'var_1': '1', 'var_2': '1', 'var_3': '3', 'var_4': 0})
- db.store('2', {'var_1': '2', 'var_2': '1', 'var_3': '4', 'var_4': 0})
- db.store('3', {'var_1': '3', 'var_2': '2', 'var_3': '4', 'var_4': 0})
+ db.store('1', {'var_1': '1', 'var_2': '1', 'var_3': '3', 'var_4': '0'})
+ db.store('2', {'var_1': '2', 'var_2': '1', 'var_3': '4', 'var_4': '0'})
+ db.store('3', {'var_1': '3', 'var_2': '2', 'var_3': '4', 'var_4': '0'})
self.assertEqual(
[{'guid': '1', 'var_1': '1'}, {'guid': '3', 'var_1': '3'}],
@@ -366,7 +376,7 @@ class IndexTest(tests.Test):
def test_MultipleValues(self):
db = Index({
- 'prop': IndexedProperty('prop', prefix='B', typecast=[1, 2], full_text=True),
+ 'prop': List(name='prop', prefix='B', subtype=Enum([1, 2, 3]), full_text=True),
})
db.store('1', {'prop': [1, 2]})
db.store('2', {'prop': [2, 3]})
@@ -385,7 +395,7 @@ class IndexTest(tests.Test):
db.close()
db = Index({
- 'prop': IndexedProperty('prop', prefix='B', typecast=[], full_text=True),
+ 'prop': List(name='prop', prefix='B', full_text=True),
})
db.store('1', {'prop': ['a', 'b']})
db.store('2', {'prop': ['b', 'c']})
@@ -448,7 +458,7 @@ class IndexTest(tests.Test):
db.close()
def test_find_OrderByGUIDAllTime(self):
- db = Index({'prop': IndexedProperty('prop', 1, 'P')})
+ db = Index({'prop': Property('prop', 1, 'P')})
db.store('3', {'prop': '1'})
db.store('2', {'prop': '1'})
@@ -469,7 +479,7 @@ class IndexTest(tests.Test):
def test_find_Region(self):
term = 'azAZ09_'
- db = Index({term: IndexedProperty(term, 1, 'T', full_text=True)})
+ db = Index({term: Property(term, 1, 'T', full_text=True)})
db.store('1', {term: 'test'})
db.store('2', {term: 'test fail'})
@@ -479,7 +489,7 @@ class IndexTest(tests.Test):
db._find(query='%s:=test' % term, reply=['guid']))
def test_find_WithListProps(self):
- db = Index({'prop': IndexedProperty('prop', None, 'A', full_text=True, typecast=[])})
+ db = Index({'prop': List(name='prop', prefix='A', full_text=True)})
db.store('1', {'prop': ('a', )})
db.store('2', {'prop': ('a', 'aa')})
@@ -571,10 +581,10 @@ class IndexTest(tests.Test):
self.assertEqual(1, len(commits))
def test_SortLocalizedProps(self):
- toolkit._default_langs = ['default_lang']
+ i18n._default_langs = ['default_lang']
current_lang = locale.getdefaultlocale()[0].replace('_', '-')
- db = Index({'prop': IndexedProperty('prop', 1, 'A', localized=True)})
+ db = Index({'prop': Localized(name='prop', slot=1, prefix='A')})
db.store('0', {'prop': {'foo': '5'}})
db.store('1', {'prop': {current_lang: '4', 'default_lang': '1', 'foo': '3'}})
@@ -598,7 +608,7 @@ class IndexTest(tests.Test):
db._find(order_by='-prop')[0])
def test_SearchByLocalizedProps(self):
- db = Index({'prop': IndexedProperty('prop', 1, 'A', localized=True, full_text=True)})
+ db = Index({'prop': Localized(name='prop', slot=1, prefix='A', full_text=True)})
db.store('1', {'prop': {'a': 'ё'}})
db.store('2', {'prop': {'a': 'ё', 'b': 'ю'}})
@@ -635,7 +645,7 @@ class IndexTest(tests.Test):
sorted(db._find(query='prop:я')[0]))
def test_find_MultipleFilter(self):
- db = Index({'prop': IndexedProperty('prop', 1, 'A')})
+ db = Index({'prop': Property('prop', 1, 'A')})
db.store('1', {'prop': 'a'})
db.store('2', {'prop': 'b'})
@@ -677,7 +687,7 @@ class IndexTest(tests.Test):
db._find(prop=['b', 'foo', 'bar'], reply=['guid'])[0])
def test_find_AndNotFilter(self):
- db = Index({'prop': IndexedProperty('prop', 1, 'A')})
+ db = Index({'prop': Property('prop', 1, 'A')})
db.store('1', {'prop': 'a'})
db.store('2', {'prop': 'b'})
@@ -721,24 +731,21 @@ class IndexTest(tests.Test):
]),
sorted(db._find(prop=['a', 'c'], reply=['guid'], **{'!prop': 'b'})[0]))
- def test_fmt_prop_value(self):
- prop = Property('prop')
- self.assertEqual(['0'], [i for i in _fmt_prop_value(prop, 0)])
- self.assertEqual(['1'], [i for i in _fmt_prop_value(prop, 1)])
- self.assertEqual(['0'], [i for i in _fmt_prop_value(prop, 0)])
- self.assertEqual(['1.1'], [i for i in _fmt_prop_value(prop, 1.1)])
- self.assertEqual(['0', '1'], [i for i in _fmt_prop_value(prop, [0, 1])])
- self.assertEqual(['2', '1'], [i for i in _fmt_prop_value(prop, [2, 1])])
- self.assertEqual(['probe', 'True', '0'], [i for i in _fmt_prop_value(prop, ['probe', True, 0])])
- self.assertEqual(['True'], [i for i in _fmt_prop_value(prop, True)])
- self.assertEqual(['False'], [i for i in _fmt_prop_value(prop, False)])
+ def test_find_CustomEncode(self):
+ db = Index({'trait': Numeric('trait', 1, 'A')})
+
+ db.store('1', {'trait': 1})
+ db.store('2', {'trait': 2})
+ db.store('11', {'trait': 11})
+
+ self.assertEqual([{'guid': '1'}], db._find(trait='1')[0])
+ self.assertEqual([{'guid': '1'}], db._find(trait=1)[0])
- prop = Property('prop', typecast=bool)
- self.assertEqual(['1'], [i for i in _fmt_prop_value(prop, True)])
- self.assertEqual(['0'], [i for i in _fmt_prop_value(prop, False)])
+ self.assertEqual([{'guid': '2'}], db._find(trait='2')[0])
+ self.assertEqual([{'guid': '2'}], db._find(trait=2)[0])
- prop = Property('prop', fmt=lambda x: x.keys())
- self.assertEqual(['a', '2'], [i for i in _fmt_prop_value(prop, {'a': 1, 2: 'b'})])
+ self.assertEqual([{'guid': '11'}], db._find(trait='11')[0])
+ self.assertEqual([{'guid': '11'}], db._find(trait=11)[0])
class Index(index.IndexWriter):
@@ -750,7 +757,7 @@ class Index(index.IndexWriter):
metadata = Metadata(Index)
metadata.update(props)
- metadata['guid'] = IndexedProperty('guid',
+ metadata['guid'] = Property('guid',
acl=ACL.CREATE | ACL.READ, slot=0,
prefix=GUID_PREFIX)
diff --git a/tests/units/db/metadata.py b/tests/units/db/metadata.py
new file mode 100755
index 0000000..a0ba512
--- /dev/null
+++ b/tests/units/db/metadata.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# sugar-lint: disable
+
+from __init__ import tests
+
+from sugar_network import db
+
+
+class MetadataTest(tests.Test):
+
+ def test_Typecast(self):
+ prop = db.Numeric()
+ self.assertEqual(1, prop.typecast(1))
+ self.assertEqual(1, prop.typecast(1.1))
+ self.assertEqual(1, prop.typecast('1'))
+ self.assertRaises(ValueError, prop.typecast, '1.0')
+ self.assertRaises(ValueError, prop.typecast, '')
+ self.assertRaises(TypeError, prop.typecast, None)
+
+ prop = db.Boolean()
+ self.assertEqual(False, prop.typecast(0))
+ self.assertEqual(True, prop.typecast(1))
+ self.assertEqual(True, prop.typecast(1.1))
+ self.assertEqual(True, prop.typecast('1'))
+ self.assertEqual(False, prop.typecast('false'))
+ self.assertEqual(True, prop.typecast(True))
+ self.assertEqual(False, prop.typecast(False))
+ self.assertEqual(False, prop.typecast('False'))
+ self.assertEqual(False, prop.typecast('0'))
+ self.assertEqual(False, prop.typecast(''))
+ self.assertEqual(False, prop.typecast(None))
+
+ prop = db.List(subtype=db.Numeric())
+ self.assertEqual([1], prop.typecast(1))
+ self.assertEqual([], prop.typecast(None))
+ self.assertRaises(ValueError, prop.typecast, '')
+ self.assertEqual([], prop.typecast([]))
+ self.assertEqual([123], prop.typecast('123'))
+ self.assertRaises(ValueError, prop.typecast, 'a')
+ self.assertEqual([123, 4, 5], prop.typecast(['123', 4, 5.6]))
+
+ prop = db.Enum(items=[1, 2])
+ self.assertRaises(ValueError, prop.typecast, 0)
+ self.assertRaises(TypeError, prop.typecast, None)
+ self.assertRaises(ValueError, prop.typecast, '')
+ self.assertRaises(ValueError, prop.typecast, 'A')
+ self.assertRaises(ValueError, prop.typecast, '3')
+ self.assertEqual(1, prop.typecast(1))
+ self.assertEqual(2, prop.typecast(2))
+ self.assertEqual(1, prop.typecast('1'))
+
+ prop = db.List()
+ self.assertEqual([], prop.typecast(None))
+ self.assertEqual([''], prop.typecast(''))
+ self.assertEqual([''], prop.typecast(['']))
+ self.assertEqual([], prop.typecast([]))
+ self.assertEqual([0], prop.typecast(0))
+ self.assertEqual([''], prop.typecast(''))
+ self.assertEqual(['foo'], prop.typecast('foo'))
+
+ prop = db.List(subtype=db.Enum(['A', 'B', 'C']))
+ self.assertRaises(ValueError, prop.typecast, '')
+ self.assertRaises(ValueError, prop.typecast, [''])
+ self.assertEqual([], prop.typecast([]))
+ self.assertEqual(['A', 'B', 'C'], prop.typecast(['A', 'B', 'C']))
+ self.assertRaises(ValueError, prop.typecast, ['a'])
+ self.assertRaises(ValueError, prop.typecast, ['A', 'x'])
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/db/resource.py b/tests/units/db/resource.py
index d09010e..ef305ec 100755
--- a/tests/units/db/resource.py
+++ b/tests/units/db/resource.py
@@ -23,11 +23,16 @@ from sugar_network.db import directory as directory_
from sugar_network.db.directory import Directory
from sugar_network.db.index import IndexWriter
from sugar_network.toolkit.router import ACL
+from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import http, Sequence
class ResourceTest(tests.Test):
+ def setUp(self, fork_num=0):
+ tests.Test.setUp(self, fork_num)
+ this.broadcast = lambda x: x
+
def test_ActiveProperty_Slotted(self):
class Document(db.Resource):
@@ -345,31 +350,31 @@ class ResourceTest(tests.Test):
return value
directory = Directory(tests.tmpdir, Document, IndexWriter)
+ guid = directory.create({'guid': '1', 'prop1': '1', 'prop2': '2'})
+ doc = directory.get(guid)
- self.assertRaises(http.NotFound, directory.patch, 'absent', {})
-
- directory.create({'guid': '1', 'prop1': '1', 'prop2': '2'})
- self.assertEqual({}, directory.patch('1', {}))
- self.assertEqual({}, directory.patch('1', {'prop1': '1', 'prop2': '2'}))
- self.assertEqual({'prop1': '1_'}, directory.patch('1', {'prop1': '1_', 'prop2': '2'}))
- self.assertEqual({'prop1': '1_', 'prop2': '2_'}, directory.patch('1', {'prop1': '1_', 'prop2': '2_'}))
+ self.assertEqual({}, doc.patch({}))
+ self.assertEqual({}, doc.patch({'prop1': '1', 'prop2': '2'}))
+ self.assertEqual({'prop1': '1_'}, doc.patch({'prop1': '1_', 'prop2': '2'}))
+ self.assertEqual({'prop1': '1_', 'prop2': '2_'}, doc.patch({'prop1': '1_', 'prop2': '2_'}))
def test_patch_LocalizedProps(self):
class Document(db.Resource):
- @db.indexed_property(slot=1, localized=True)
+ @db.indexed_property(db.Localized, slot=1)
def prop(self, value):
return value
directory = Directory(tests.tmpdir, Document, IndexWriter)
+ guid = directory.create({'guid': '1', 'prop': {'ru': 'ru'}})
+ doc = directory.get(guid)
- directory.create({'guid': '1', 'prop': {'ru': 'ru'}})
- self.assertEqual({}, directory.patch('1', {'prop': 'ru'}))
- self.assertEqual({'prop': {'ru': 'ru_'}}, directory.patch('1', {'prop': {'ru': 'ru_'}}))
- self.assertEqual({'prop': {'en': 'en'}}, directory.patch('1', {'prop': {'en': 'en'}}))
- self.assertEqual({'prop': {'ru': 'ru', 'en': 'en'}}, directory.patch('1', {'prop': {'ru': 'ru', 'en': 'en'}}))
- self.assertEqual({'prop': {'ru': 'ru_', 'en': 'en'}}, directory.patch('1', {'prop': {'ru': 'ru_', 'en': 'en'}}))
+ self.assertEqual({}, doc.patch({'prop': {'ru': 'ru'}}))
+ self.assertEqual({'prop': {'ru': 'ru_'}}, doc.patch({'prop': {'ru': 'ru_'}}))
+ self.assertEqual({'prop': {'en': 'en'}}, doc.patch({'prop': {'en': 'en'}}))
+ self.assertEqual({'prop': {'ru': 'ru', 'en': 'en'}}, doc.patch({'prop': {'ru': 'ru', 'en': 'en'}}))
+ self.assertEqual({'prop': {'ru': 'ru_', 'en': 'en'}}, doc.patch({'prop': {'ru': 'ru_', 'en': 'en'}}))
def test_diff(self):
@@ -379,21 +384,13 @@ class ResourceTest(tests.Test):
def prop(self, value):
return value
- @db.blob_property()
- def blob(self, value):
- return value
-
directory = Directory(tests.tmpdir, Document, IndexWriter)
- self.touch(('blob', '1'))
directory.create({'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1})
- directory.update('1', {'blob': {'blob': 'blob'}})
for i in os.listdir('1/1'):
os.utime('1/1/%s' % i, (1, 1))
- self.touch(('blob', '2'))
directory.create({'guid': '2', 'prop': '2', 'ctime': 2, 'mtime': 2})
- directory.update('2', {'blob': {'blob': 'blob'}})
for i in os.listdir('2/2'):
os.utime('2/2/%s' % i, (2, 2))
@@ -408,22 +405,12 @@ class ResourceTest(tests.Test):
'ctime': {'value': 1, 'mtime': 1},
'prop': {'value': '1', 'mtime': 1},
'mtime': {'value': 1, 'mtime': 1},
- 'blob': {
- 'mtime': 1,
- 'blob': tests.tmpdir + '/1/1/blob.blob',
- 'blob_size': 1,
- },
}},
{'guid': '2', 'diff': {
'guid': {'value': '2', 'mtime': 2},
'ctime': {'value': 2, 'mtime': 2},
'prop': {'value': '2', 'mtime': 2},
'mtime': {'value': 2, 'mtime': 2},
- 'blob': {
- 'mtime': 2,
- 'blob': tests.tmpdir + '/2/2/blob.blob',
- 'blob_size': 1,
- },
}},
{'guid': '3', 'diff': {
'guid': {'value': '3', 'mtime': 3},
@@ -433,7 +420,7 @@ class ResourceTest(tests.Test):
}},
],
[i for i in diff(directory, [[0, None]], out_seq)])
- self.assertEqual([[1, 5]], out_seq)
+ self.assertEqual([[1, 3]], out_seq)
out_seq = Sequence()
self.assertEqual([
@@ -442,26 +429,15 @@ class ResourceTest(tests.Test):
'ctime': {'value': 2, 'mtime': 2},
'prop': {'value': '2', 'mtime': 2},
'mtime': {'value': 2, 'mtime': 2},
- 'blob': {
- 'mtime': 2,
- 'blob': tests.tmpdir + '/2/2/blob.blob',
- 'blob_size': 1,
- },
}},
],
- [i for i in diff(directory, [[3, 4]], out_seq)])
- self.assertEqual([[3, 4]], out_seq)
-
- out_seq = Sequence()
- self.assertEqual([
- ],
- [i for i in diff(directory, [[3, 3]], out_seq)])
- self.assertEqual([], out_seq)
+ [i for i in diff(directory, [[2, 2]], out_seq)])
+ self.assertEqual([[2, 2]], out_seq)
out_seq = Sequence()
self.assertEqual([
],
- [i for i in diff(directory, [[6, 100]], out_seq)])
+ [i for i in diff(directory, [[4, 100]], out_seq)])
self.assertEqual([], out_seq)
directory.update('2', {'prop': '22'})
self.assertEqual([
@@ -469,8 +445,8 @@ class ResourceTest(tests.Test):
'prop': {'value': '22', 'mtime': int(os.stat('2/2/prop').st_mtime)},
}},
],
- [i for i in diff(directory, [[6, 100]], out_seq)])
- self.assertEqual([[6, 6]], out_seq)
+ [i for i in diff(directory, [[4, 100]], out_seq)])
+ self.assertEqual([[4, 4]], out_seq)
def test_diff_IgnoreCalcProps(self):
@@ -535,37 +511,6 @@ class ResourceTest(tests.Test):
self.assertEqual([[1, 1], [4, 4]], out_seq)
- def test_diff_WithBlobsSetByUrl(self):
- URL = 'http://src.sugarlabs.org/robots.txt'
- URL_content = urllib2.urlopen(URL).read()
-
- class Document(db.Resource):
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- directory = Directory(tests.tmpdir, Document, IndexWriter)
-
- directory.create({'guid': '1', 'ctime': 1, 'mtime': 1})
- directory.update('1', {'blob': {'url': URL}})
- self.utime('1/1', 1)
-
- out_seq = Sequence()
- self.assertEqual([
- {'guid': '1', 'diff': {
- 'guid': {'value': '1', 'mtime': 1},
- 'ctime': {'value': 1, 'mtime': 1},
- 'mtime': {'value': 1, 'mtime': 1},
- 'blob': {
- 'url': URL,
- 'mtime': 1,
- },
- }},
- ],
- [i for i in diff(directory, [[0, None]], out_seq)])
- self.assertEqual([[1, 2]], out_seq)
-
def test_diff_Filter(self):
class Document(db.Resource):
@@ -626,7 +571,7 @@ class ResourceTest(tests.Test):
class Document(db.Resource):
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType())
+ @db.stored_property(db.Aggregated)
def prop(self, value):
return value
@@ -768,21 +713,13 @@ class ResourceTest(tests.Test):
def prop(self, value):
return value
- @db.blob_property()
- def blob(self, value):
- return value
-
directory1 = Directory('document1', Document, IndexWriter)
directory1.create({'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1})
- self.touch(('blob', '1'))
- directory1.update('1', {'blob': {'blob': 'blob'}})
for i in os.listdir('document1/1/1'):
os.utime('document1/1/1/%s' % i, (1, 1))
directory1.create({'guid': '2', 'prop': '2', 'ctime': 2, 'mtime': 2})
- self.touch(('blob', '2'))
- directory1.update('2', {'blob': {'blob': 'blob'}})
for i in os.listdir('document1/2/2'):
os.utime('document1/2/2/%s' % i, (2, 2))
@@ -808,7 +745,6 @@ class ResourceTest(tests.Test):
self.assertEqual(1, doc.meta('ctime')['mtime'])
self.assertEqual(1, doc.meta('prop')['mtime'])
self.assertEqual(1, doc.meta('mtime')['mtime'])
- self.assertEqual(1, doc.meta('blob')['mtime'])
doc = directory2.get('2')
self.assertEqual(2, doc.get('seqno'))
@@ -816,7 +752,6 @@ class ResourceTest(tests.Test):
self.assertEqual(2, doc.meta('ctime')['mtime'])
self.assertEqual(2, doc.meta('prop')['mtime'])
self.assertEqual(2, doc.meta('mtime')['mtime'])
- self.assertEqual(2, doc.meta('blob')['mtime'])
doc = directory2.get('3')
self.assertEqual(3, doc.get('seqno'))
@@ -824,28 +759,25 @@ class ResourceTest(tests.Test):
self.assertEqual(3, doc.meta('ctime')['mtime'])
self.assertEqual(3, doc.meta('prop')['mtime'])
self.assertEqual(3, doc.meta('mtime')['mtime'])
- self.assertEqual(None, doc.meta('blob'))
def test_merge_Update(self):
class Document(db.Resource):
- @db.blob_property()
- def blob(self, value):
+ @db.stored_property(default='')
+ def prop(self, value):
return value
directory1 = Directory('document1', Document, IndexWriter)
directory2 = Directory('document2', Document, IndexWriter)
directory1.create({'guid': 'guid', 'ctime': 1, 'mtime': 1})
- self.touch(('blob', '1'))
- directory1.update('guid', {'blob': {'blob': 'blob'}})
+ directory1.update('guid', {'prop': '1'})
for i in os.listdir('document1/gu/guid'):
os.utime('document1/gu/guid/%s' % i, (1, 1))
directory2.create({'guid': 'guid', 'ctime': 2, 'mtime': 2})
- self.touch(('blob', '2'))
- directory2.update('guid', {'blob': {'blob': 'blob'}})
+ directory2.update('guid', {'prop': '2'})
for i in os.listdir('document2/gu/guid'):
os.utime('document2/gu/guid/%s' % i, (2, 2))
@@ -858,8 +790,8 @@ class ResourceTest(tests.Test):
self.assertEqual(2, doc.meta('guid')['mtime'])
self.assertEqual(2, doc.meta('ctime')['mtime'])
self.assertEqual(2, doc.meta('mtime')['mtime'])
- self.assertEqual(2, doc.meta('blob')['mtime'])
- self.assertEqual('2', file('document2/gu/guid/blob.blob').read())
+ self.assertEqual(2, doc.meta('prop')['mtime'])
+ self.assertEqual('2', doc.meta('prop')['value'])
for patch in diff(directory1, [[0, None]], Sequence()):
directory2.merge(**patch)
@@ -872,8 +804,8 @@ class ResourceTest(tests.Test):
self.assertEqual(2, doc.meta('guid')['mtime'])
self.assertEqual(2, doc.meta('ctime')['mtime'])
self.assertEqual(2, doc.meta('mtime')['mtime'])
- self.assertEqual(2, doc.meta('blob')['mtime'])
- self.assertEqual('2', file('document2/gu/guid/blob.blob').read())
+ self.assertEqual(2, doc.meta('prop')['mtime'])
+ self.assertEqual('2', doc.meta('prop')['value'])
os.utime('document1/gu/guid/mtime', (3, 3))
for patch in diff(directory1, [[0, None]], Sequence()):
@@ -887,10 +819,10 @@ class ResourceTest(tests.Test):
self.assertEqual(2, doc.meta('guid')['mtime'])
self.assertEqual(2, doc.meta('ctime')['mtime'])
self.assertEqual(3, doc.meta('mtime')['mtime'])
- self.assertEqual(2, doc.meta('blob')['mtime'])
- self.assertEqual('2', file('document2/gu/guid/blob.blob').read())
+ self.assertEqual(2, doc.meta('prop')['mtime'])
+ self.assertEqual('2', doc.meta('prop')['value'])
- os.utime('document1/gu/guid/blob', (4, 4))
+ os.utime('document1/gu/guid/prop', (4, 4))
for patch in diff(directory1, [[0, None]], Sequence()):
directory2.merge(**patch)
@@ -902,132 +834,14 @@ class ResourceTest(tests.Test):
self.assertEqual(2, doc.meta('guid')['mtime'])
self.assertEqual(2, doc.meta('ctime')['mtime'])
self.assertEqual(3, doc.meta('mtime')['mtime'])
- self.assertEqual(4, doc.meta('blob')['mtime'])
- self.assertEqual('1', file('document2/gu/guid/blob.blob').read())
-
- def test_merge_SeqnoLessMode(self):
-
- class Document(db.Resource):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- directory1 = Directory('document1', Document, IndexWriter)
- directory1.create({'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1})
-
- directory2 = Directory('document2', Document, IndexWriter)
- for patch in diff(directory1, [[0, None]], Sequence()):
- directory2.merge(shift_seqno=False, **patch)
- self.assertEqual(
- [(1, 1, '1', '1')],
- [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory2.find()[0]])
- doc = directory2.get('1')
- self.assertEqual(0, doc.get('seqno'))
- self.assertEqual(0, doc.meta('guid')['seqno'])
- self.assertEqual(0, doc.meta('prop')['seqno'])
-
- directory3 = Directory('document3', Document, IndexWriter)
- for patch in diff(directory1, [[0, None]], Sequence()):
- directory3.merge(**patch)
- self.assertEqual(
- [(1, 1, '1', '1')],
- [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory3.find()[0]])
- doc = directory3.get('1')
- self.assertEqual(1, doc.get('seqno'))
- self.assertEqual(1, doc.meta('guid')['seqno'])
- self.assertEqual(1, doc.meta('prop')['seqno'])
-
- time.sleep(1)
- directory1.update('1', {'prop': '2', 'ctime': 2, 'mtime': 2})
-
- for patch in diff(directory1, [[0, None]], Sequence()):
- directory3.merge(shift_seqno=False, **patch)
- self.assertEqual(
- [(2, 2, '1', '2')],
- [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory3.find()[0]])
- doc = directory3.get('1')
- self.assertEqual(1, doc.get('seqno'))
- self.assertEqual(1, doc.meta('guid')['seqno'])
- self.assertEqual(1, doc.meta('prop')['seqno'])
-
- time.sleep(1)
- directory1.update('1', {'prop': '3', 'ctime': 3, 'mtime': 3})
-
- for patch in diff(directory1, [[0, None]], Sequence()):
- directory3.merge(**patch)
- self.assertEqual(
- [(3, 3, '1', '3')],
- [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory3.find()[0]])
- doc = directory3.get('1')
- self.assertEqual(2, doc.get('seqno'))
- self.assertEqual(1, doc.meta('guid')['seqno'])
- self.assertEqual(2, doc.meta('prop')['seqno'])
-
- def test_merge_AvoidCalculatedBlobs(self):
-
- class Document(db.Resource):
-
- @db.blob_property()
- def blob(self, value):
- return {'url': 'http://foo/bar', 'mime_type': 'image/png'}
-
- directory1 = Directory('document1', Document, IndexWriter)
- directory1.create({'guid': 'guid', 'ctime': 1, 'mtime': 1})
- for i in os.listdir('document1/gu/guid'):
- os.utime('document1/gu/guid/%s' % i, (1, 1))
-
- directory2 = Directory('document2', Document, IndexWriter)
- for patch in diff(directory1, [[0, None]], Sequence()):
- directory2.merge(**patch)
-
- doc = directory2.get('guid')
- self.assertEqual(1, doc.get('seqno'))
- self.assertEqual(1, doc.meta('guid')['mtime'])
- assert not exists('document2/gu/guid/blob')
-
- def test_merge_Blobs(self):
-
- class Document(db.Resource):
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- directory = Directory('document', Document, IndexWriter)
- self.touch(('blob', 'blob-1'))
- directory.merge('1', {
- 'guid': {'mtime': 1, 'value': '1'},
- 'ctime': {'mtime': 2, 'value': 2},
- 'mtime': {'mtime': 3, 'value': 3},
- 'blob': {'mtime': 4, 'blob': 'blob'},
- })
-
- self.assertEqual(
- [(2, 3, '1')],
- [(i['ctime'], i['mtime'], i['guid']) for i in directory.find()[0]])
-
- doc = directory.get('1')
- self.assertEqual(1, doc.get('seqno'))
- self.assertEqual(1, doc.meta('guid')['mtime'])
- self.assertEqual(2, doc.meta('ctime')['mtime'])
- self.assertEqual(3, doc.meta('mtime')['mtime'])
- self.assertEqual(4, doc.meta('blob')['mtime'])
- self.assertEqual('blob-1', file('document/1/1/blob.blob').read())
-
- self.touch(('blob', 'blob-2'))
- directory.merge('1', {
- 'blob': {'mtime': 5, 'blob': 'blob'},
- })
-
- self.assertEqual(5, doc.meta('blob')['mtime'])
- self.assertEqual('blob-2', file('document/1/1/blob.blob').read())
+ self.assertEqual(4, doc.meta('prop')['mtime'])
+ self.assertEqual('1', doc.meta('prop')['value'])
def test_merge_Aggprops(self):
class Document(db.Resource):
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType())
+ @db.stored_property(db.Aggregated)
def prop(self, value):
return value
@@ -1079,6 +893,28 @@ class ResourceTest(tests.Test):
},
directory.get('1')['prop'])
+ def test_merge_CallSetters(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(db.Numeric)
+ def prop(self, value):
+ return value
+
+ @prop.setter
+ def prop(self, value):
+ return value + 1
+
+ directory = Directory('document', Document, IndexWriter)
+
+ directory.merge('1', {
+ 'guid': {'mtime': 1, 'value': '1'},
+ 'ctime': {'mtime': 1, 'value': 1},
+ 'mtime': {'mtime': 1, 'value': 1},
+ 'prop': {'mtime': 1, 'value': 1},
+ })
+ self.assertEqual(2, directory.get('1')['prop'])
+
def test_wipe(self):
class Document(db.Resource):
@@ -1088,31 +924,11 @@ class ResourceTest(tests.Test):
guid = directory.create({'prop': '1'})
self.assertEqual([guid], [i.guid for i in directory.find()[0]])
directory.commit()
- assert directory.mtime != 0
+ assert exists('index/mtime')
directory.wipe()
self.assertEqual([], [i.guid for i in directory.find()[0]])
- assert directory.mtime == 0
-
- def test_DeleteOldBlobOnUpdate(self):
-
- class Document(db.Resource):
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- directory = Directory(tests.tmpdir, Document, IndexWriter)
-
- directory.create({'guid': 'guid', 'blob': 'foo'})
- assert exists('gu/guid/blob.blob')
- directory.update('guid', {'blob': {'url': 'foo'}})
- assert not exists('gu/guid/blob.blob')
-
- directory.update('guid', {'blob': 'foo'})
- assert exists('gu/guid/blob.blob')
- directory.update('guid', {'blob': {}})
- assert not exists('gu/guid/blob.blob')
+ assert not exists('index/mtime')
def diff(directory, in_seq, out_seq, exclude_seq=None, **kwargs):
diff --git a/tests/units/db/routes.py b/tests/units/db/routes.py
index 5908d0f..8824ca8 100755
--- a/tests/units/db/routes.py
+++ b/tests/units/db/routes.py
@@ -16,10 +16,11 @@ src_root = abspath(dirname(__file__))
from __init__ import tests
from sugar_network import db, toolkit
-from sugar_network.db.routes import _typecast_prop_value
-from sugar_network.db.metadata import Property
-from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, Blob, ACL
-from sugar_network.toolkit import coroutine, http
+from sugar_network.db import files
+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
+from sugar_network.toolkit import coroutine, http, i18n
class RoutesTest(tests.Test):
@@ -36,18 +37,19 @@ class RoutesTest(tests.Test):
def wo_default(self, value):
return value
- @db.indexed_property(slot=1, default='not_stored_default')
+ @db.stored_property(default='not_stored_default')
def not_stored_default(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [Document], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
- self.assertRaises(RuntimeError, self.call, 'POST', ['document'], content={})
+ self.assertRaises(RuntimeError, this.call, method='POST', path=['document'], content={})
- guid = self.call('POST', ['document'], content={'wo_default': 'wo_default'})
- self.assertEqual('default', self.call('GET', ['document', guid, 'w_default']))
- self.assertEqual('wo_default', self.call('GET', ['document', guid, 'wo_default']))
- self.assertEqual('not_stored_default', self.call('GET', ['document', guid, 'not_stored_default']))
+ guid = this.call(method='POST', path=['document'], content={'wo_default': 'wo_default'})
+ self.assertEqual('default', this.call(method='GET', path=['document', guid, 'w_default']))
+ self.assertEqual('wo_default', this.call(method='GET', path=['document', guid, 'wo_default']))
+ self.assertEqual('not_stored_default', this.call(method='GET', path=['document', guid, 'not_stored_default']))
def test_Populate(self):
self.touch(
@@ -65,10 +67,10 @@ class RoutesTest(tests.Test):
class Document(db.Resource):
pass
- with db.Volume(tests.tmpdir, [Document], lambda event: None) as volume:
- for cls in volume.values():
- for __ in cls.populate():
- pass
+ with db.Volume(tests.tmpdir, [Document]) as volume:
+ router = Router(db.Routes(volume))
+ for __ in volume['document'].populate():
+ pass
self.assertEqual(
sorted(['1', '2']),
sorted([i.guid for i in volume['document'].find()[0]]))
@@ -78,10 +80,10 @@ class RoutesTest(tests.Test):
class Document(db.Resource):
pass
- with db.Volume(tests.tmpdir, [Document], lambda event: None) as volume:
- for cls in volume.values():
- for __ in cls.populate():
- pass
+ with db.Volume(tests.tmpdir, [Document]) as volume:
+ router = Router(db.Routes(volume))
+ for __ in volume['document'].populate():
+ pass
self.assertEqual(
sorted(['1', '2']),
sorted([i.guid for i in volume['document'].find()[0]]))
@@ -94,12 +96,14 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- self.volume['testdocument'].create({'guid': 'guid'})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+
+ volume['testdocument'].create({'guid': 'guid'})
self.assertEqual({
'total': 1,
@@ -107,11 +111,11 @@ class RoutesTest(tests.Test):
{'guid': 'guid', 'prop': ''},
],
},
- self.call('GET', path=['testdocument'], reply=['guid', 'prop']))
+ this.call(method='GET', path=['testdocument'], reply=['guid', 'prop']))
- guid_1 = self.call('POST', path=['testdocument'], content={'prop': 'value_1'})
+ guid_1 = this.call(method='POST', path=['testdocument'], content={'prop': 'value_1'})
assert guid_1
- guid_2 = self.call('POST', path=['testdocument'], content={'prop': 'value_2'})
+ guid_2 = this.call(method='POST', path=['testdocument'], content={'prop': 'value_2'})
assert guid_2
self.assertEqual(
@@ -120,9 +124,9 @@ class RoutesTest(tests.Test):
{'guid': guid_1, 'prop': 'value_1'},
{'guid': guid_2, 'prop': 'value_2'},
]),
- sorted(self.call('GET', path=['testdocument'], reply=['guid', 'prop'])['result']))
+ sorted(this.call(method='GET', path=['testdocument'], reply=['guid', 'prop'])['result']))
- self.call('PUT', path=['testdocument', guid_1], content={'prop': 'value_3'})
+ this.call(method='PUT', path=['testdocument', guid_1], content={'prop': 'value_3'})
self.assertEqual(
sorted([
@@ -130,240 +134,397 @@ class RoutesTest(tests.Test):
{'guid': guid_1, 'prop': 'value_3'},
{'guid': guid_2, 'prop': 'value_2'},
]),
- sorted(self.call('GET', path=['testdocument'], reply=['guid', 'prop'])['result']))
+ sorted(this.call(method='GET', path=['testdocument'], reply=['guid', 'prop'])['result']))
- self.call('DELETE', path=['testdocument', guid_2])
+ this.call(method='DELETE', path=['testdocument', guid_2])
self.assertEqual(
sorted([
{'guid': 'guid', 'prop': ''},
{'guid': guid_1, 'prop': 'value_3'},
]),
- sorted(self.call('GET', path=['testdocument'], reply=['guid', 'prop'])['result']))
+ sorted(this.call(method='GET', path=['testdocument'], reply=['guid', 'prop'])['result']))
- self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid_2])
+ self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid_2])
self.assertEqual(
{'guid': guid_1, 'prop': 'value_3'},
- self.call('GET', path=['testdocument', guid_1], reply=['guid', 'prop']))
+ this.call(method='GET', path=['testdocument', guid_1], reply=['guid', 'prop']))
self.assertEqual(
'value_3',
- self.call('GET', path=['testdocument', guid_1, 'prop']))
+ this.call(method='GET', path=['testdocument', guid_1, 'prop']))
def test_SetBLOBs(self):
class TestDocument(db.Resource):
- @db.blob_property()
+ @db.stored_property(db.Blob)
def blob(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- self.call('PUT', path=['testdocument', guid, 'blob'], content='blob1')
- self.assertEqual('blob1', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+ guid = this.call(method='POST', path=['testdocument'], content={})
+ self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob'])
- self.call('PUT', path=['testdocument', guid, 'blob'], content_stream=StringIO('blob2'))
- self.assertEqual('blob2', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+ this.call(method='PUT', path=['testdocument', guid, 'blob'], content='blob1')
+ self.assertEqual('blob1', file(this.call(method='GET', path=['testdocument', guid, 'blob']).path).read())
- self.call('PUT', path=['testdocument', guid, 'blob'], content=None)
- self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob'])
+ this.call(method='PUT', path=['testdocument', guid, 'blob'], content_stream=StringIO('blob2'))
+ self.assertEqual('blob2', file(this.call(method='GET', path=['testdocument', guid, 'blob']).path).read())
- def test_SetBLOBsByMeta(self):
+ this.call(method='PUT', path=['testdocument', guid, 'blob'], content=None)
+ self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob'])
+
+ def test_CreateBLOBsWithMeta(self):
class TestDocument(db.Resource):
- @db.blob_property(mime_type='default')
+ @db.stored_property(db.Blob)
def blob(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content={})
- self.assertRaises(RuntimeError, self.call, 'PUT', path=['testdocument', guid, 'blob'],
+ self.assertRaises(http.BadRequest, this.call, method='PUT', path=['testdocument', guid, 'blob'],
content={}, content_type='application/json')
- self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob'])
+ 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')
+ 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']))
+
+ def test_UpdateUrlBLOBsWithMeta(self):
+
+ class TestDocument(db.Resource):
+
+ @db.stored_property(db.Blob)
+ def blob(self, value):
+ return value
+
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+
+ guid = this.call(method='POST', path=['testdocument'], content={'blob': {'digest': 'digest', 'url': 'url'}})
+ self.assertEqual({
+ 'mime_type': 'application/octet-stream',
+ 'url': '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',
+ },
+ 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',
+ 'foo': 'bar',
+ },
+ this.call(method='GET', path=['testdocument', guid, 'blob']))
+
+ def test_UpdateFileBLOBsWithMeta(self):
+
+ class TestDocument(db.Resource):
+
+ @db.stored_property(db.Blob)
+ def blob(self, value):
+ return value
+
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+
+ 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')),
+ },
+ blob)
+ self.assertEqual('blob', file(blob.path).read())
+
+ self.assertRaises(http.BadRequest, this.call, method='PUT', path=['testdocument', guid, 'blob'],
+ 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'),
+ },
+ blob)
+ self.assertEqual('blob', file(blob.path).read())
+
+ this.call(method='PUT', path=['testdocument', guid, 'blob'],
+ 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'),
+ 'foo': 'bar',
+ },
+ blob)
+ self.assertEqual('blob', file(blob.path).read())
+
+ def test_SwitchBLOBsType(self):
+
+ class TestDocument(db.Resource):
+
+ @db.stored_property(db.Blob)
+ def blob(self, value):
+ return value
+
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- self.call('PUT', path=['testdocument', guid, 'blob'],
- content={'url': 'foo', 'bar': 'probe'}, content_type='application/json')
- blob = self.call('GET', path=['testdocument', guid, 'blob'])
- self.assertEqual('foo', blob['url'])
+ 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())
+
+ 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)
+
+ 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())
def test_RemoveBLOBs(self):
class TestDocument(db.Resource):
- @db.blob_property(mime_type='default')
+ @db.stored_property(db.Blob)
def blob(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={'blob': 'blob'})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content={'blob': 'blob'})
- self.assertEqual('blob', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+ self.assertEqual('blob', file(this.call(method='GET', path=['testdocument', guid, 'blob']).path).read())
- self.call('PUT', path=['testdocument', guid, 'blob'])
- self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob'])
+ this.call(method='PUT', path=['testdocument', guid, 'blob'])
+ self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob'])
- def test_RemoveTempBLOBFilesOnFails(self):
+ def test_ReuploadBLOBs(self):
class TestDocument(db.Resource):
- @db.blob_property(mime_type='default')
+ @db.stored_property(db.Blob)
+ def blob(self, value):
+ return value
+
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content={'blob': 'blob1'})
+
+ blob1 = this.call(method='GET', path=['testdocument', guid, 'blob'])
+ self.assertEqual('blob1', file(blob1.path).read())
+
+ this.call(method='PUT', path=['testdocument', guid, 'blob'], content='blob2')
+ blob2 = this.call(method='GET', path=['testdocument', guid, 'blob'])
+ self.assertEqual('blob2', file(blob2.path).read())
+ assert blob1.path != blob2.path
+ assert not exists(blob1.path)
+
+ def test_RemoveBLOBsOnFailedSetter(self):
+
+ class TestDocument(db.Resource):
+
+ @db.stored_property(db.Blob)
def blob(self, value):
return value
@blob.setter
def blob(self, value):
- raise RuntimeError()
+ if value:
+ raise RuntimeError()
+ return value
+
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
+ guid = this.call(method='POST', path=['testdocument'], content={})
+ self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob'])
- self.assertRaises(RuntimeError, self.call, 'PUT', path=['testdocument', guid, 'blob'], content='probe')
- self.assertEqual(0, len(os.listdir('tmp')))
+ self.assertRaises(RuntimeError, this.call, method='PUT', path=['testdocument', guid, 'blob'], content='probe')
+ self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob'])
+ assert not exists('blobs/%s' % hash('probe'))
def test_SetBLOBsWithMimeType(self):
class TestDocument(db.Resource):
- @db.blob_property(mime_type='default')
+ @db.stored_property(db.Blob, mime_type='default')
def blob(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content={})
- self.call('PUT', path=['testdocument', guid, 'blob'], content='blob1')
- self.assertEqual('default', self.call('GET', path=['testdocument', guid, 'blob'])['mime_type'])
- self.assertEqual('default', self.response.content_type)
+ 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)
- self.call('PUT', path=['testdocument', guid, 'blob'], content='blob1', content_type='foo')
- self.assertEqual('foo', self.call('GET', path=['testdocument', guid, 'blob'])['mime_type'])
- self.assertEqual('foo', self.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)
def test_GetBLOBs(self):
class TestDocument(db.Resource):
- @db.blob_property()
+ @db.stored_property(db.Blob)
def blob(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+
+ guid = this.call(method='POST', path=['testdocument'], content={})
blob = 'blob'
- self.call('PUT', path=['testdocument', guid, 'blob'], content=blob)
-
- blob_path = tests.tmpdir + '/testdocument/%s/%s/blob' % (guid[:2], guid)
- blob_meta = {
- 'seqno': 2,
- 'blob': blob_path + '.blob',
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'application/octet-stream',
- 'mtime': int(os.stat(blob_path).st_mtime),
- }
+ this.call(method='PUT', path=['testdocument', guid, 'blob'], content=blob)
+ digest = str(hash(blob))
+ blob_path = 'blobs/%s' % digest
- self.assertEqual('blob', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+ self.assertEqual('blob', file(this.call(method='GET', path=['testdocument', guid, 'blob']).path).read())
self.assertEqual({
'blob': {
- 'url': 'http://localhost/testdocument/%s/blob' % guid,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
'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),
},
},
- self.call('GET', path=['testdocument', guid], reply=['blob'], host='localhost'))
+ this.call(method='GET', path=['testdocument', guid], reply=['blob'], environ={'HTTP_HOST': 'localhost'}))
self.assertEqual([{
'blob': {
- 'url': 'http://localhost/testdocument/%s/blob' % guid,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
'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),
},
}],
- self.call('GET', path=['testdocument'], reply=['blob'], host='localhost')['result'])
+ this.call(method='GET', path=['testdocument'], reply=['blob'], environ={'HTTP_HOST': 'localhost'})['result'])
def test_GetBLOBsByUrls(self):
class TestDocument(db.Resource):
- @db.blob_property()
+ @db.stored_property(db.Blob)
def blob(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid1 = self.call('POST', path=['testdocument'], content={})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid1 = this.call(method='POST', path=['testdocument'], content={})
- self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid1, 'blob'])
+ self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid1, 'blob'])
self.assertEqual(
- {'blob': {'url': 'http://127.0.0.1/testdocument/%s/blob' % guid1}},
- self.call('GET', path=['testdocument', guid1], reply=['blob'], host='127.0.0.1'))
+ {'blob': {}},
+ this.call(method='GET', path=['testdocument', guid1], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'}))
blob = 'file'
- guid2 = self.call('POST', path=['testdocument'], content={'blob': blob})
- self.assertEqual('file', file(self.call('GET', path=['testdocument', guid2, 'blob'])['blob']).read())
- self.assertEqual({
- 'blob': {
- 'url': 'http://127.0.0.1/testdocument/%s/blob' % guid2,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': u'application/octet-stream',
- },
- },
- self.call('GET', path=['testdocument', guid2], reply=['blob'], host='127.0.0.1'))
+ 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'])
- guid3 = self.call('POST', path=['testdocument'], content={'blob': {'url': 'http://foo'}}, content_type='application/json')
- self.assertEqual('http://foo', self.call('GET', path=['testdocument', guid3, 'blob'])['url'])
- self.assertEqual({
- 'blob': {
- 'url': 'http://foo',
- },
- },
- self.call('GET', path=['testdocument', guid3], reply=['blob'], host='127.0.0.1'))
+ guid3 = this.call(method='POST', path=['testdocument'], content={'blob': {'url': 'http://foo', 'digest': 'digest'}}, content_type='application/json')
+ self.assertEqual(
+ 'http://foo',
+ this.call(method='GET', path=['testdocument', guid3, 'blob'])['url'])
+ self.assertEqual(
+ 'http://foo',
+ this.call(method='GET', path=['testdocument', guid3], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'})['blob']['url'])
self.assertEqual(
sorted([
- {'blob': {
- 'url': 'http://127.0.0.1/testdocument/%s/blob' % guid1,
- }},
- { 'blob': {
- 'url': 'http://127.0.0.1/testdocument/%s/blob' % guid2,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': u'application/octet-stream',
- }},
- { 'blob': {
- 'url': 'http://foo',
- }},
+ None,
+ 'http://127.0.0.1/blobs/%s' % hash(blob),
+ 'http://foo',
]),
- sorted(self.call('GET', path=['testdocument'], reply=['blob'], host='127.0.0.1')['result']))
+ sorted([i['blob'].get('url') for i in this.call(method='GET', path=['testdocument'], reply=['blob'],
+ environ={'HTTP_HOST': '127.0.0.1'})['result']]))
def test_CommandsGetAbsentBlobs(self):
class TestDocument(db.Resource):
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.blob_property()
+ @db.stored_property(db.Blob)
def blob(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- guid = self.call('POST', path=['testdocument'], content={'prop': 'value'})
- self.assertEqual('value', self.call('GET', path=['testdocument', guid, 'prop']))
- self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob'])
+ guid = this.call(method='POST', path=['testdocument'], content={})
+ self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob'])
self.assertEqual(
- {'blob': {'url': 'http://localhost/testdocument/%s/blob' % guid}},
- self.call('GET', path=['testdocument', guid], reply=['blob'], host='localhost'))
+ {'blob': {}},
+ this.call(method='GET', path=['testdocument', guid], reply=['blob'], environ={'HTTP_HOST': 'localhost'}))
def test_Command_ReplyForGET(self):
@@ -373,44 +534,46 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={'prop': 'value'})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content={'prop': 'value'})
self.assertEqual(
['guid', 'prop'],
- self.call('GET', path=['testdocument', guid], reply=['guid', 'prop']).keys())
+ this.call(method='GET', path=['testdocument', guid], reply=['guid', 'prop']).keys())
self.assertEqual(
['guid'],
- self.call('GET', path=['testdocument'])['result'][0].keys())
+ this.call(method='GET', path=['testdocument'])['result'][0].keys())
self.assertEqual(
sorted(['guid', 'prop']),
- sorted(self.call('GET', path=['testdocument'], reply=['prop', 'guid'])['result'][0].keys()))
+ sorted(this.call(method='GET', path=['testdocument'], reply=['prop', 'guid'])['result'][0].keys()))
self.assertEqual(
sorted(['prop']),
- sorted(self.call('GET', path=['testdocument'], reply=['prop'])['result'][0].keys()))
+ sorted(this.call(method='GET', path=['testdocument'], reply=['prop'])['result'][0].keys()))
def test_DecodeBeforeSetting(self):
class TestDocument(db.Resource):
- @db.indexed_property(slot=1, typecast=int)
+ @db.indexed_property(db.Numeric, slot=1)
def prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- guid = self.call('POST', path=['testdocument'], content={'prop': '-1'})
- self.assertEqual(-1, self.call('GET', path=['testdocument', guid, 'prop']))
+ guid = this.call(method='POST', path=['testdocument'], content={'prop': '-1'})
+ self.assertEqual(-1, this.call(method='GET', path=['testdocument', guid, 'prop']))
def test_LocalizedSet(self):
- toolkit._default_langs = ['en']
+ i18n._default_langs = ['en']
class TestDocument(db.Resource):
@@ -418,32 +581,23 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- directory = self.volume['testdocument']
-
- guid = directory.create({'localized_prop': 'value_raw'})
- self.assertEqual({'en': 'value_raw'}, directory.get(guid)['localized_prop'])
- self.assertEqual(
- [guid],
- [i.guid for i in directory.find(localized_prop='value_raw')[0]])
-
- directory.update(guid, {'localized_prop': 'value_raw2'})
- self.assertEqual({'en': 'value_raw2'}, directory.get(guid)['localized_prop'])
- self.assertEqual(
- [guid],
- [i.guid for i in directory.find(localized_prop='value_raw2')[0]])
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ directory = volume['testdocument']
+ guid = this.call(method='POST', path=['testdocument'], content={'localized_prop': 'value_ru'},
+ environ={'HTTP_ACCEPT_LANGUAGE': 'ru'})
- guid = self.call('POST', path=['testdocument'], accept_language=['ru'], content={'localized_prop': 'value_ru'})
self.assertEqual({'ru': 'value_ru'}, directory.get(guid)['localized_prop'])
self.assertEqual(
[guid],
[i.guid for i in directory.find(localized_prop='value_ru')[0]])
- self.call('PUT', path=['testdocument', guid], accept_language=['en'], content={'localized_prop': 'value_en'})
+ this.call(method='PUT', path=['testdocument', guid], content={'localized_prop': 'value_en'},
+ environ={'HTTP_ACCEPT_LANGUAGE': 'en'})
self.assertEqual({'ru': 'value_ru', 'en': 'value_en'}, directory.get(guid)['localized_prop'])
self.assertEqual(
[guid],
@@ -460,14 +614,15 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- directory = self.volume['testdocument']
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ directory = volume['testdocument']
- guid = self.call('POST', path=['testdocument'], content={
+ guid = this.call(method='POST', path=['testdocument'], content={
'localized_prop': {
'ru': 'value_ru',
'es': 'value_es',
@@ -475,63 +630,78 @@ class RoutesTest(tests.Test):
},
})
- toolkit._default_langs = ['en']
+ i18n._default_langs = ['en']
self.assertEqual(
{'localized_prop': 'value_en'},
- self.call('GET', path=['testdocument', guid], reply=['localized_prop']))
+ this.call(method='GET', path=['testdocument', guid], reply=['localized_prop']))
self.assertEqual(
{'localized_prop': 'value_ru'},
- self.call('GET', path=['testdocument', guid], accept_language=['ru'], reply=['localized_prop']))
+ this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'ru'}))
self.assertEqual(
'value_ru',
- self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['ru', 'es']))
+ this.call(method='GET', path=['testdocument', guid, 'localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'ru,es'}))
self.assertEqual(
[{'localized_prop': 'value_ru'}],
- self.call('GET', path=['testdocument'], accept_language=['foo', 'ru', 'es'], reply=['localized_prop'])['result'])
+ this.call(method='GET', path=['testdocument'], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'foo,ru,es'})['result'])
self.assertEqual(
{'localized_prop': 'value_ru'},
- self.call('GET', path=['testdocument', guid], accept_language=['ru-RU'], reply=['localized_prop']))
+ this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'ru-RU'}))
self.assertEqual(
'value_ru',
- self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['ru-RU', 'es']))
+ this.call(method='GET', path=['testdocument', guid, 'localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'ru-RU,es'}))
self.assertEqual(
[{'localized_prop': 'value_ru'}],
- self.call('GET', path=['testdocument'], accept_language=['foo', 'ru-RU', 'es'], reply=['localized_prop'])['result'])
+ this.call(method='GET', path=['testdocument'], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'ru-RU,es'})['result'])
self.assertEqual(
{'localized_prop': 'value_es'},
- self.call('GET', path=['testdocument', guid], accept_language=['es'], reply=['localized_prop']))
+ this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'es'}))
self.assertEqual(
'value_es',
- self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['es', 'ru']))
+ this.call(method='GET', path=['testdocument', guid, 'localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'es,ru'}))
self.assertEqual(
[{'localized_prop': 'value_es'}],
- self.call('GET', path=['testdocument'], accept_language=['foo', 'es', 'ru'], reply=['localized_prop'])['result'])
+ this.call(method='GET', path=['testdocument'], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'foo,es,ru'})['result'])
self.assertEqual(
{'localized_prop': 'value_en'},
- self.call('GET', path=['testdocument', guid], accept_language=['fr'], reply=['localized_prop']))
+ this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'fr'}))
self.assertEqual(
'value_en',
- self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['fr', 'za']))
+ this.call(method='GET', path=['testdocument', guid, 'localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'fr,za'}))
self.assertEqual(
[{'localized_prop': 'value_en'}],
- self.call('GET', path=['testdocument'], accept_language=['foo', 'fr', 'za'], reply=['localized_prop'])['result'])
+ this.call(method='GET', path=['testdocument'], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'foo,fr,za'})['result'])
- toolkit._default_langs = ['foo']
+ i18n._default_langs = ['foo']
fallback_lang = sorted(['ru', 'es', 'en'])[0]
self.assertEqual(
{'localized_prop': 'value_%s' % fallback_lang},
- self.call('GET', path=['testdocument', guid], accept_language=['fr'], reply=['localized_prop']))
+ this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'fr'}))
self.assertEqual(
'value_%s' % fallback_lang,
- self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['fr', 'za']))
+ this.call(method='GET', path=['testdocument', guid, 'localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'fr,za'}))
self.assertEqual(
[{'localized_prop': 'value_%s' % fallback_lang}],
- self.call('GET', path=['testdocument'], accept_language=['foo', 'fr', 'za'], reply=['localized_prop'])['result'])
+ this.call(method='GET', path=['testdocument'], reply=['localized_prop'],
+ environ={'HTTP_ACCEPT_LANGUAGE': 'foo,fr,za'})['result'])
def test_OpenByModuleName(self):
self.touch(
@@ -543,9 +713,9 @@ class RoutesTest(tests.Test):
)
sys.path.insert(0, '.')
- volume = db.Volume('.', ['foo.bar'], lambda event: None)
- assert exists('bar/index')
+ volume = db.Volume('.', ['foo.bar'])
volume['bar'].find()
+ assert exists('bar/index')
volume.close()
def test_Command_GetBlobSetByUrl(self):
@@ -556,21 +726,25 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.blob_property()
+ @db.stored_property(db.Blob)
def blob(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
- self.call('PUT', path=['testdocument', guid, 'blob'], url='http://sugarlabs.org')
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content={})
+ this.call(method='PUT', path=['testdocument', guid, 'blob'], content={
+ 'digest': 'digest',
+ 'url': 'http://sugarlabs.org',
+ }, content_type='application/json')
self.assertEqual(
'http://sugarlabs.org',
- self.call('GET', path=['testdocument', guid, 'blob'])['url'])
+ this.call(method='GET', path=['testdocument', guid, 'blob'])['url'])
def test_on_create(self):
@@ -580,24 +754,25 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
ts = int(time.time())
- guid = self.call('POST', path=['testdocument'], content={})
- assert self.volume['testdocument'].get(guid)['ctime'] in range(ts - 1, ts + 1)
- assert self.volume['testdocument'].get(guid)['mtime'] in range(ts - 1, ts + 1)
+ guid = this.call(method='POST', path=['testdocument'], content={})
+ assert volume['testdocument'].get(guid)['ctime'] in range(ts - 1, ts + 1)
+ assert volume['testdocument'].get(guid)['mtime'] in range(ts - 1, ts + 1)
def test_on_create_Override(self):
class Routes(db.Routes):
- def on_create(self, request, props, event):
+ def on_create(self, request, props):
props['prop'] = 'overriden'
- db.Routes.on_create(self, request, props, event)
+ db.Routes.on_create(self, request, props)
class TestDocument(db.Resource):
@@ -605,17 +780,18 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(Routes(volume))
- guid = self.call('POST', ['testdocument'], content={'prop': 'foo'}, routes=Routes)
- self.assertEqual('overriden', self.volume['testdocument'].get(guid)['prop'])
+ guid = this.call(method='POST', path=['testdocument'], content={'prop': 'foo'}, routes=Routes)
+ self.assertEqual('overriden', volume['testdocument'].get(guid)['prop'])
- self.call('PUT', ['testdocument', guid], content={'prop': 'bar'}, routes=Routes)
- self.assertEqual('bar', self.volume['testdocument'].get(guid)['prop'])
+ this.call(method='PUT', path=['testdocument', guid], content={'prop': 'bar'}, routes=Routes)
+ self.assertEqual('bar', volume['testdocument'].get(guid)['prop'])
def test_on_update(self):
@@ -625,26 +801,28 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
- prev_mtime = self.volume['testdocument'].get(guid)['mtime']
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+
+ guid = this.call(method='POST', path=['testdocument'], content={})
+ prev_mtime = volume['testdocument'].get(guid)['mtime']
time.sleep(1)
- self.call('PUT', path=['testdocument', guid], content={'prop': 'probe'})
- assert self.volume['testdocument'].get(guid)['mtime'] - prev_mtime >= 1
+ this.call(method='PUT', path=['testdocument', guid], content={'prop': 'probe'})
+ assert volume['testdocument'].get(guid)['mtime'] - prev_mtime >= 1
def test_on_update_Override(self):
class Routes(db.Routes):
- def on_update(self, request, props, event):
+ def on_update(self, request, props):
props['prop'] = 'overriden'
- db.Routes.on_update(self, request, props, event)
+ db.Routes.on_update(self, request, props)
class TestDocument(db.Resource):
@@ -652,17 +830,18 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(Routes(volume))
- guid = self.call('POST', ['testdocument'], content={'prop': 'foo'}, routes=Routes)
- self.assertEqual('foo', self.volume['testdocument'].get(guid)['prop'])
+ guid = this.call(method='POST', path=['testdocument'], content={'prop': 'foo'}, routes=Routes)
+ self.assertEqual('foo', volume['testdocument'].get(guid)['prop'])
- self.call('PUT', ['testdocument', guid], content={'prop': 'bar'}, routes=Routes)
- self.assertEqual('overriden', self.volume['testdocument'].get(guid)['prop'])
+ this.call(method='PUT', path=['testdocument', guid], content={'prop': 'bar'}, routes=Routes)
+ self.assertEqual('overriden', volume['testdocument'].get(guid)['prop'])
def __test_DoNotPassGuidsForCreate(self):
@@ -672,13 +851,15 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.indexed_property(prefix='L', localized=True, default='')
+ @db.indexed_property(db.Localized, prefix='L', default={})
def localized_prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- self.assertRaises(http.Forbidden, self.call, 'POST', path=['testdocument'], content={'guid': 'foo'})
- guid = self.call('POST', path=['testdocument'], content={})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+
+ self.assertRaises(http.Forbidden, this.call, method='POST', path=['testdocument'], content={'guid': 'foo'})
+ guid = this.call(method='POST', path=['testdocument'], content={})
assert guid
def test_seqno(self):
@@ -689,7 +870,8 @@ class RoutesTest(tests.Test):
class Document2(db.Resource):
pass
- volume = db.Volume(tests.tmpdir, [Document1, Document2], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [Document1, Document2])
+ router = Router(db.Routes(volume))
assert not exists('seqno')
self.assertEqual(0, volume.seqno.value)
@@ -706,8 +888,8 @@ class RoutesTest(tests.Test):
self.assertEqual(4, volume.seqno.value)
assert not exists('seqno')
volume.seqno.commit()
- assert exists('seqno')
- volume = db.Volume(tests.tmpdir, [Document1, Document2], lambda event: None)
+ assert exists('db.seqno')
+ volume = db.Volume(tests.tmpdir, [Document1, Document2])
self.assertEqual(4, volume.seqno.value)
def test_Events(self):
@@ -726,7 +908,7 @@ class RoutesTest(tests.Test):
def prop(self, value):
pass
- @db.blob_property()
+ @db.stored_property(db.Blob)
def blob(self, value):
return value
@@ -739,13 +921,15 @@ class RoutesTest(tests.Test):
)
events = []
- volume = db.Volume(tests.tmpdir, [Document1, Document2], lambda event: events.append(event))
+ this.broadcast = lambda x: events.append(x)
+ volume = db.Volume(tests.tmpdir, [Document1, Document2])
+ volume['document1']
+ volume['document2']
coroutine.sleep(.1)
mtime = int(os.stat('document1/index/mtime').st_mtime)
self.assertEqual([
{'event': 'commit', 'resource': 'document1', 'mtime': mtime},
- {'event': 'populate', 'resource': 'document1', 'mtime': mtime},
],
events)
del events[:]
@@ -794,43 +978,45 @@ class RoutesTest(tests.Test):
def prop(self, value):
pass
- @db.blob_property(acl=ACL.READ)
+ @db.stored_property(db.Blob, acl=ACL.READ)
def blob(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content={})
- self.assertRaises(http.Forbidden, self.call, 'POST', path=['testdocument'], content={'prop': 'value'})
- self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid], content={'prop': 'value'})
- self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid], content={'blob': 'value'})
- self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid, 'prop'], content='value')
- self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid, 'blob'], content='value')
+ self.assertRaises(http.Forbidden, this.call, method='POST', path=['testdocument'], content={'prop': 'value'})
+ self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid], content={'prop': 'value'})
+ self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid], content={'blob': 'value'})
+ self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid, 'prop'], content='value')
+ self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid, 'blob'], content='value')
def test_BlobsWritePermissions(self):
class TestDocument(db.Resource):
- @db.blob_property(acl=ACL.CREATE | ACL.WRITE)
+ @db.stored_property(db.Blob, acl=ACL.CREATE | ACL.WRITE)
def blob1(self, value):
return value
- @db.blob_property(acl=ACL.CREATE)
+ @db.stored_property(db.Blob, acl=ACL.CREATE)
def blob2(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- guid = self.call('POST', path=['testdocument'], content={})
- self.call('PUT', path=['testdocument', guid], content={'blob1': 'value1', 'blob2': 'value2'})
- self.call('PUT', path=['testdocument', guid], content={'blob1': 'value1'})
- self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid], content={'blob2': 'value2_'})
+ guid = this.call(method='POST', path=['testdocument'], content={})
+ this.call(method='PUT', path=['testdocument', guid], content={'blob1': 'value1', 'blob2': 'value2'})
+ this.call(method='PUT', path=['testdocument', guid], content={'blob1': 'value1'})
+ self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid], content={'blob2': 'value2_'})
- guid = self.call('POST', path=['testdocument'], content={})
- self.call('PUT', path=['testdocument', guid, 'blob1'], content='value1')
- self.call('PUT', path=['testdocument', guid, 'blob2'], content='value2')
- self.call('PUT', path=['testdocument', guid, 'blob1'], content='value1_')
- self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid, 'blob2'], content='value2_')
+ guid = this.call(method='POST', path=['testdocument'], content={})
+ this.call(method='PUT', path=['testdocument', guid, 'blob1'], content='value1')
+ this.call(method='PUT', path=['testdocument', guid, 'blob2'], content='value2')
+ this.call(method='PUT', path=['testdocument', guid, 'blob1'], content='value1_')
+ self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid, 'blob2'], content='value2_')
def test_properties_OverrideGet(self):
@@ -844,30 +1030,32 @@ class RoutesTest(tests.Test):
def prop2(self, value):
return -1
- @db.blob_property()
+ @db.stored_property(db.Blob)
def blob(self, meta):
meta['blob'] = 'new-blob'
return meta
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+
+ guid = this.call(method='POST', path=['testdocument'], content={})
self.touch(('new-blob', 'new-blob'))
- self.call('PUT', path=['testdocument', guid, 'blob'], content='old-blob')
+ this.call(method='PUT', path=['testdocument', guid, 'blob'], content='old-blob')
self.assertEqual(
'new-blob',
- self.call('GET', path=['testdocument', guid, 'blob'])['blob'])
+ this.call(method='GET', path=['testdocument', guid, 'blob'])['blob'])
self.assertEqual(
'1',
- self.call('GET', path=['testdocument', guid, 'prop1']))
+ this.call(method='GET', path=['testdocument', guid, 'prop1']))
self.assertEqual(
-1,
- self.call('GET', path=['testdocument', guid, 'prop2']))
+ this.call(method='GET', path=['testdocument', guid, 'prop2']))
self.assertEqual(
{'prop1': '1', 'prop2': -1},
- self.call('GET', path=['testdocument', guid], reply=['prop1', 'prop2']))
+ this.call(method='GET', path=['testdocument', guid], reply=['prop1', 'prop2']))
- def test_properties_OverrideSet(self):
+ def test_properties_OverrideSetter(self):
class TestDocument(db.Resource):
@@ -879,53 +1067,47 @@ class RoutesTest(tests.Test):
def prop(self, value):
return '_%s' % value
- @db.blob_property()
- def blob1(self, meta):
- return meta
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content={})
- @blob1.setter
- def blob1(self, value):
- return Blob({'url': file(value['blob']).read()})
+ self.assertEqual('_1', this.call(method='GET', path=['testdocument', guid, 'prop']))
- @db.blob_property()
- def blob2(self, meta):
- return meta
+ this.call(method='PUT', path=['testdocument', guid, 'prop'], content='2')
+ self.assertEqual('_2', this.call(method='GET', path=['testdocument', guid, 'prop']))
- @blob2.setter
- def blob2(self, value):
- with toolkit.NamedTemporaryFile(delete=False) as f:
- f.write(' %s ' % file(value['blob']).read())
- value['blob'] = f.name
- return value
+ this.call(method='PUT', path=['testdocument', guid], content={'prop': 3})
+ self.assertEqual('_3', this.call(method='GET', path=['testdocument', guid, 'prop']))
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={})
+ def test_properties_AccessToOldValuesInSetters(self):
+
+ class TestDocument(db.Resource):
- self.assertEqual('_1', self.call('GET', path=['testdocument', guid, 'prop']))
- self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob1'])
+ @db.stored_property(db.Numeric)
+ def prop(self, value):
+ return value
- self.call('PUT', path=['testdocument', guid, 'prop'], content='2')
- self.assertEqual('_2', self.call('GET', path=['testdocument', guid, 'prop']))
- self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob1'])
+ @prop.setter
+ def prop(self, value):
+ return value + (self['prop'] or 0)
- self.call('PUT', path=['testdocument', guid], content={'prop': 3})
- self.assertEqual('_3', self.call('GET', path=['testdocument', guid, 'prop']))
- self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob1'])
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- self.call('PUT', path=['testdocument', guid, 'blob1'], content='blob_url')
- self.assertEqual('blob_url', self.call('GET', path=['testdocument', guid, 'blob1'])['url'])
+ guid = this.call(method='POST', path=['testdocument'], content={'prop': 1})
+ self.assertEqual(1, this.call(method='GET', path=['testdocument', guid, 'prop']))
- guid = self.call('POST', path=['testdocument'], content={'blob2': 'foo'})
- self.assertEqual(' foo ', file(self.call('GET', path=['testdocument', guid, 'blob2'])['blob']).read())
+ this.call(method='PUT', path=['testdocument', guid, 'prop'], content='2')
+ self.assertEqual(3, this.call(method='GET', path=['testdocument', guid, 'prop']))
- self.call('PUT', path=['testdocument', guid, 'blob2'], content='bar')
- self.assertEqual(' bar ', file(self.call('GET', path=['testdocument', guid, 'blob2'])['blob']).read())
+ this.call(method='PUT', path=['testdocument', guid], content={'prop': 3})
+ self.assertEqual(6, this.call(method='GET', path=['testdocument', guid, 'prop']))
def test_properties_CallSettersAtTheEnd(self):
class TestDocument(db.Resource):
- @db.indexed_property(slot=1, typecast=int)
+ @db.indexed_property(db.Numeric, slot=1)
def prop1(self, value):
return value
@@ -933,7 +1115,7 @@ class RoutesTest(tests.Test):
def prop1(self, value):
return self['prop3'] + value
- @db.indexed_property(slot=2, typecast=int)
+ @db.indexed_property(db.Numeric, slot=2)
def prop2(self, value):
return value
@@ -941,107 +1123,40 @@ class RoutesTest(tests.Test):
def prop2(self, value):
return self['prop3'] - value
- @db.indexed_property(slot=3, typecast=int)
+ @db.indexed_property(db.Numeric, slot=3)
def prop3(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={'prop1': 1, 'prop2': 2, 'prop3': 3})
- self.assertEqual(4, self.call('GET', path=['testdocument', guid, 'prop1']))
- self.assertEqual(1, self.call('GET', path=['testdocument', guid, 'prop2']))
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+
+ guid = this.call(method='POST', path=['testdocument'], content={'prop1': 1, 'prop2': 2, 'prop3': 3})
+ self.assertEqual(4, this.call(method='GET', path=['testdocument', guid, 'prop1']))
+ self.assertEqual(1, this.call(method='GET', path=['testdocument', guid, 'prop2']))
def test_properties_PopulateRequiredPropsInSetters(self):
class TestDocument(db.Resource):
- @db.indexed_property(slot=1, typecast=int)
+ @db.indexed_property(db.Numeric, slot=1)
def prop1(self, value):
return value
@prop1.setter
def prop1(self, value):
- self['prop2'] = value + 1
+ self.post('prop2', value + 1)
return value
- @db.indexed_property(slot=2, typecast=int)
+ @db.indexed_property(db.Numeric, slot=2)
def prop2(self, value):
return value
- @db.blob_property()
- def prop3(self, value):
- return value
-
- @prop3.setter
- def prop3(self, value):
- self['prop1'] = -1
- self['prop2'] = -2
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={'prop1': 1})
- self.assertEqual(1, self.call('GET', path=['testdocument', guid, 'prop1']))
- self.assertEqual(2, self.call('GET', path=['testdocument', guid, 'prop2']))
-
- def test_properties_PopulateRequiredPropsInBlobSetter(self):
-
- class TestDocument(db.Resource):
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- @blob.setter
- def blob(self, value):
- self['prop1'] = 1
- self['prop2'] = 2
- return value
-
- @db.indexed_property(slot=1, typecast=int)
- def prop1(self, value):
- return value
-
- @db.indexed_property(slot=2, typecast=int)
- def prop2(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={'blob': ''})
- self.assertEqual(1, self.call('GET', path=['testdocument', guid, 'prop1']))
- self.assertEqual(2, self.call('GET', path=['testdocument', guid, 'prop2']))
-
- def __test_SubCall(self):
-
- class TestDocument(db.Resource):
-
- @db.blob_property(mime_type='application/json')
- def blob(self, value):
- return value
-
- @blob.setter
- def blob(self, value):
- blob = file(value['blob']).read()
- if '!' not in blob:
- meta = self.meta('blob')
- if meta:
- blob = file(meta['blob']).read() + blob
- with toolkit.NamedTemporaryFile(delete=False) as f:
- f.write(blob)
- value['blob'] = f.name
- coroutine.spawn(self.post, blob)
- return value
-
- def post(self, value):
- self.request.call('PUT', path=['testdocument', self.guid, 'blob'], content=value + '!')
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
-
- guid = self.call('POST', path=['testdocument'], content={'blob': '0'})
- coroutine.dispatch()
- self.assertEqual('0!', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
-
- self.call('PUT', path=['testdocument', guid, 'blob'], content='1')
- coroutine.dispatch()
- self.assertEqual('0!1!', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+ guid = this.call(method='POST', path=['testdocument'], content={'prop1': 1})
+ self.assertEqual(1, this.call(method='GET', path=['testdocument', guid, 'prop1']))
+ self.assertEqual(2, this.call(method='GET', path=['testdocument', guid, 'prop2']))
def test_Group(self):
@@ -1051,15 +1166,16 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- self.call('POST', path=['testdocument'], content={'prop': 1})
- self.call('POST', path=['testdocument'], content={'prop': 2})
- self.call('POST', path=['testdocument'], content={'prop': 1})
+ this.call(method='POST', path=['testdocument'], content={'prop': 1})
+ this.call(method='POST', path=['testdocument'], content={'prop': 2})
+ this.call(method='POST', path=['testdocument'], content={'prop': 1})
self.assertEqual(
sorted([{'prop': 1}, {'prop': 2}]),
- sorted(self.call('GET', path=['testdocument'], reply='prop', group_by='prop')['result']))
+ sorted(this.call(method='GET', path=['testdocument'], reply='prop', group_by='prop')['result']))
def test_CallSetterEvenIfThereIsNoCreatePermissions(self):
@@ -1073,12 +1189,13 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value + 1
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
- self.assertRaises(http.Forbidden, self.call, 'POST', path=['testdocument'], content={'prop': 1})
+ self.assertRaises(http.Forbidden, this.call, method='POST', path=['testdocument'], content={'prop': 1})
- guid = self.call('POST', path=['testdocument'], content={})
- self.assertEqual(1, self.call('GET', path=['testdocument', guid, 'prop']))
+ guid = this.call(method='POST', path=['testdocument'], content={})
+ self.assertEqual(1, this.call(method='GET', path=['testdocument', guid, 'prop']))
def test_ReturnDefualtsForMissedProps(self):
@@ -1088,57 +1205,34 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', path=['testdocument'], content={'prop': 'set'})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content={'prop': 'set'})
self.assertEqual(
[{'prop': 'set'}],
- self.call('GET', path=['testdocument'], reply='prop')['result'])
+ this.call(method='GET', path=['testdocument'], reply='prop')['result'])
self.assertEqual(
{'prop': 'set'},
- self.call('GET', path=['testdocument', guid], reply='prop'))
+ this.call(method='GET', path=['testdocument', guid], reply='prop'))
self.assertEqual(
'set',
- self.call('GET', path=['testdocument', guid, 'prop']))
+ this.call(method='GET', path=['testdocument', guid, 'prop']))
os.unlink('testdocument/%s/%s/prop' % (guid[:2], guid))
self.assertEqual(
[{'prop': 'default'}],
- self.call('GET', path=['testdocument'], reply='prop')['result'])
+ this.call(method='GET', path=['testdocument'], reply='prop')['result'])
self.assertEqual(
{'prop': 'default'},
- self.call('GET', path=['testdocument', guid], reply='prop'))
+ this.call(method='GET', path=['testdocument', guid], reply='prop'))
self.assertEqual(
'default',
- self.call('GET', path=['testdocument', guid, 'prop']))
-
- def test_PopulateNonDefualtPropsInSetters(self):
-
- class TestDocument(db.Resource):
-
- @db.indexed_property(slot=1)
- def prop1(self, value):
- return value
-
- @db.indexed_property(slot=2, default='default')
- def prop2(self, value):
- return all
-
- @prop2.setter
- def prop2(self, value):
- if value != 'default':
- self['prop1'] = value
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
-
- self.assertRaises(RuntimeError, self.call, 'POST', path=['testdocument'], content={})
-
- guid = self.call('POST', path=['testdocument'], content={'prop2': 'value2'})
- self.assertEqual('value2', self.call('GET', path=['testdocument', guid, 'prop1']))
+ 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):
@@ -1146,44 +1240,55 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- @db.blob_property()
+ @db.stored_property(db.Blob)
def blob1(self, value):
return value
- @db.blob_property()
+ @db.stored_property(db.Blob)
def blob2(self, value):
return value
@blob2.setter
def blob2(self, value):
- return {'url': 'http://new', 'foo': 'bar', 'blob_size': 100}
+ return 'url'
- self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
- guid = self.call('POST', ['testdocument'], content = {'prop': 'prop', 'blob1': 'blob', 'blob2': ''})
+ volume = db.Volume(tests.tmpdir, [TestDocument])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['testdocument'], content = {'prop': 'prop', 'blob1': 'blob', 'blob2': ''})
- assert self.call('HEAD', ['testdocument', guid, 'prop']) is None
- meta = self.volume['testdocument'].get(guid).meta('prop')
+ 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, self.response.meta)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), self.response.last_modified)
-
- assert self.call('HEAD', ['testdocument', guid, 'blob1'], host='localhost') is None
- meta = self.volume['testdocument'].get(guid).meta('blob1')
- meta.pop('blob')
- self.assertEqual(meta, self.response.meta)
- self.assertEqual(len('blob'), self.response.content_length)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), self.response.last_modified)
-
- assert self.call('HEAD', ['testdocument', guid, 'blob2']) is None
- meta = self.volume['testdocument'].get(guid).meta('blob2')
- self.assertEqual(meta, self.response.meta)
- self.assertEqual(100, self.response.content_length)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), self.response.last_modified)
-
- assert self.call('GET', ['testdocument', guid, 'blob2']) is not None
- meta = self.volume['testdocument'].get(guid).meta('blob2')
- self.assertEqual(meta, self.response.meta)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), self.response.last_modified)
+ 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):
@@ -1196,25 +1301,26 @@ class RoutesTest(tests.Test):
class Document(db.Resource):
pass
- self.volume = db.Volume('db', [User, Document])
+ volume = db.Volume(tests.tmpdir, [User, Document])
+ router = Router(db.Routes(volume))
- guid = self.call('POST', ['document'], content={}, principal='user')
+ guid = this.call(method='POST', path=['document'], content={}, principal='user')
self.assertEqual(
[{'name': 'user', 'role': 2}],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual(
{'user': {'role': 2, 'order': 0}},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.volume['user'].create({'guid': 'user', 'pubkey': '', 'name': 'User'})
+ volume['user'].create({'guid': 'user', 'pubkey': '', 'name': 'User'})
- guid = self.call('POST', ['document'], content={}, principal='user')
+ guid = this.call(method='POST', path=['document'], content={}, principal='user')
self.assertEqual(
[{'guid': 'user', 'name': 'User', 'role': 3}],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual(
{'user': {'name': 'User', 'role': 3, 'order': 0}},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
def test_FindByAuthor(self):
@@ -1227,36 +1333,37 @@ class RoutesTest(tests.Test):
class Document(db.Resource):
pass
- self.volume = db.Volume('db', [User, Document])
+ volume = db.Volume(tests.tmpdir, [User, Document])
+ router = Router(db.Routes(volume))
- self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'UserName1'})
- self.volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User Name2'})
- self.volume['user'].create({'guid': 'user3', 'pubkey': '', 'name': 'User Name 3'})
+ volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'UserName1'})
+ volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User Name2'})
+ volume['user'].create({'guid': 'user3', 'pubkey': '', 'name': 'User Name 3'})
- guid1 = self.call('POST', ['document'], content={}, principal='user1')
- guid2 = self.call('POST', ['document'], content={}, principal='user2')
- guid3 = self.call('POST', ['document'], content={}, principal='user3')
+ guid1 = this.call(method='POST', path=['document'], content={}, principal='user1')
+ guid2 = this.call(method='POST', path=['document'], content={}, principal='user2')
+ guid3 = this.call(method='POST', path=['document'], content={}, principal='user3')
self.assertEqual(sorted([
{'guid': guid1},
]),
- self.call('GET', ['document'], author='UserName1')['result'])
+ this.call(method='GET', path=['document'], author='UserName1')['result'])
self.assertEqual(sorted([
{'guid': guid1},
]),
- sorted(self.call('GET', ['document'], query='author:UserName')['result']))
+ sorted(this.call(method='GET', path=['document'], query='author:UserName')['result']))
self.assertEqual(sorted([
{'guid': guid1},
{'guid': guid2},
{'guid': guid3},
]),
- sorted(self.call('GET', ['document'], query='author:User')['result']))
+ sorted(this.call(method='GET', path=['document'], query='author:User')['result']))
self.assertEqual(sorted([
{'guid': guid2},
{'guid': guid3},
]),
- sorted(self.call('GET', ['document'], query='author:Name')['result']))
+ sorted(this.call(method='GET', path=['document'], query='author:Name')['result']))
def test_PreserveAuthorsOrder(self):
@@ -1269,99 +1376,77 @@ class RoutesTest(tests.Test):
class Document(db.Resource):
pass
- self.volume = db.Volume('db', [User, Document])
+ volume = db.Volume(tests.tmpdir, [User, Document])
+ router = Router(db.Routes(volume))
- self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'})
- self.volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'})
- self.volume['user'].create({'guid': 'user3', 'pubkey': '', 'name': 'User3'})
+ volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'})
+ volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'})
+ volume['user'].create({'guid': 'user3', 'pubkey': '', 'name': 'User3'})
- guid = self.call('POST', ['document'], content={}, principal='user1')
- self.call('PUT', ['document', guid], cmd='useradd', user='user2', role=0)
- self.call('PUT', ['document', guid], cmd='useradd', user='user3', role=0)
+ guid = this.call(method='POST', path=['document'], content={}, principal='user1')
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2', role=0)
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='user3', role=0)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
{'guid': 'user2', 'name': 'User2', 'role': 1},
{'guid': 'user3', 'name': 'User3', 'role': 1},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
'user2': {'name': 'User2', 'role': 1, 'order': 1},
'user3': {'name': 'User3', 'role': 1, 'order': 2},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.call('PUT', ['document', guid], cmd='userdel', user='user2', principal='user1')
- self.call('PUT', ['document', guid], cmd='useradd', user='user2', role=0)
+ this.call(method='PUT', path=['document', guid], cmd='userdel', user='user2', principal='user1')
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2', role=0)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
{'guid': 'user3', 'name': 'User3', 'role': 1},
{'guid': 'user2', 'name': 'User2', 'role': 1},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
'user3': {'name': 'User3', 'role': 1, 'order': 2},
'user2': {'name': 'User2', 'role': 1, 'order': 3},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.call('PUT', ['document', guid], cmd='userdel', user='user2', principal='user1')
- self.call('PUT', ['document', guid], cmd='useradd', user='user2', role=0)
+ this.call(method='PUT', path=['document', guid], cmd='userdel', user='user2', principal='user1')
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2', role=0)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
{'guid': 'user3', 'name': 'User3', 'role': 1},
{'guid': 'user2', 'name': 'User2', 'role': 1},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
'user3': {'name': 'User3', 'role': 1, 'order': 2},
'user2': {'name': 'User2', 'role': 1, 'order': 3},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.call('PUT', ['document', guid], cmd='userdel', user='user3', principal='user1')
- self.call('PUT', ['document', guid], cmd='useradd', user='user3', role=0)
+ this.call(method='PUT', path=['document', guid], cmd='userdel', user='user3', principal='user1')
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='user3', role=0)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
{'guid': 'user2', 'name': 'User2', 'role': 1},
{'guid': 'user3', 'name': 'User3', 'role': 1},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
'user2': {'name': 'User2', 'role': 1, 'order': 3},
'user3': {'name': 'User3', 'role': 1, 'order': 4},
},
- self.volume['document'].get(guid)['author'])
-
- def test_CopyAthors(self):
-
- class User(db.Resource):
-
- @db.indexed_property(slot=1)
- def name(self, value):
- return value
-
- class Document(db.Resource):
- pass
-
- self.volume = db.Volume('db', [User, Document])
- self.volume['user'].create({'guid': 'user', 'pubkey': '', 'name': 'User'})
-
- guid1 = self.call('POST', ['document'], content={}, principal='user')
- self.assertEqual({'user': {'name': 'User', 'role': 3, 'order': 0}}, self.volume['document'].get(guid1)['author'])
- author = self.call('GET', ['document', guid1, 'author'])
- self.assertEqual([{'guid': 'user', 'role': 3, 'name': 'User'}], author)
-
- guid2 = self.volume['document'].create({'author': author}, setters=True)
- author = self.call('GET', ['document', guid1, 'author'])
- self.assertEqual({'user': {'name': 'User', 'role': 3, 'order': 0}}, self.volume['document'].get(guid2)['author'])
+ volume['document'].get(guid)['author'])
def test_AddUser(self):
@@ -1374,62 +1459,63 @@ class RoutesTest(tests.Test):
class Document(db.Resource):
pass
- self.volume = db.Volume('db', [User, Document])
+ volume = db.Volume(tests.tmpdir, [User, Document])
+ router = Router(db.Routes(volume))
- self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'})
- self.volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'})
+ volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'})
+ volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'})
- guid = self.call('POST', ['document'], content={}, principal='user1')
+ guid = this.call(method='POST', path=['document'], content={}, principal='user1')
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.call('PUT', ['document', guid], cmd='useradd', user='user2', role=2)
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2', role=2)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
{'guid': 'user2', 'name': 'User2', 'role': 3},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
'user2': {'name': 'User2', 'role': 3, 'order': 1},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.call('PUT', ['document', guid], cmd='useradd', user='User3', role=3)
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='User3', role=3)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
{'guid': 'user2', 'name': 'User2', 'role': 3},
{'name': 'User3', 'role': 2},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
'user2': {'name': 'User2', 'role': 3, 'order': 1},
'User3': {'role': 2, 'order': 2},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.call('PUT', ['document', guid], cmd='useradd', user='User4', role=4)
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='User4', role=4)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
{'guid': 'user2', 'name': 'User2', 'role': 3},
{'name': 'User3', 'role': 2},
{'name': 'User4', 'role': 0},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
'user2': {'name': 'User2', 'role': 3, 'order': 1},
'User3': {'role': 2, 'order': 2},
'User4': {'role': 0, 'order': 3},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
def test_UpdateAuthor(self):
@@ -1442,46 +1528,47 @@ class RoutesTest(tests.Test):
class Document(db.Resource):
pass
- self.volume = db.Volume('db', [User, Document])
+ volume = db.Volume(tests.tmpdir, [User, Document])
+ router = Router(db.Routes(volume))
- self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'})
- guid = self.call('POST', ['document'], content={}, principal='user1')
+ volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'})
+ guid = this.call(method='POST', path=['document'], content={}, principal='user1')
- self.call('PUT', ['document', guid], cmd='useradd', user='User2', role=0)
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='User2', role=0)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
{'name': 'User2', 'role': 0},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
'User2': {'role': 0, 'order': 1},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.call('PUT', ['document', guid], cmd='useradd', user='user1', role=0)
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='user1', role=0)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 1},
{'name': 'User2', 'role': 0},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 1, 'order': 0},
'User2': {'role': 0, 'order': 1},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.call('PUT', ['document', guid], cmd='useradd', user='User2', role=2)
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='User2', role=2)
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 1},
{'name': 'User2', 'role': 2},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 1, 'order': 0},
'User2': {'role': 2, 'order': 1},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
def test_DelUser(self):
@@ -1494,150 +1581,73 @@ class RoutesTest(tests.Test):
class Document(db.Resource):
pass
- self.volume = db.Volume('db', [User, Document])
+ volume = db.Volume(tests.tmpdir, [User, Document])
+ router = Router(db.Routes(volume))
- self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'})
- self.volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'})
- guid = self.call('POST', ['document'], content={}, principal='user1')
- self.call('PUT', ['document', guid], cmd='useradd', user='user2')
- self.call('PUT', ['document', guid], cmd='useradd', user='User3')
+ volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'})
+ volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'})
+ guid = this.call(method='POST', path=['document'], content={}, principal='user1')
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2')
+ this.call(method='PUT', path=['document', guid], cmd='useradd', user='User3')
self.assertEqual([
{'guid': 'user1', 'name': 'User1', 'role': 3},
{'guid': 'user2', 'name': 'User2', 'role': 1},
{'name': 'User3', 'role': 0},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user1': {'name': 'User1', 'role': 3, 'order': 0},
'user2': {'name': 'User2', 'role': 1, 'order': 1},
'User3': {'role': 0, 'order': 2},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
# Do not remove yourself
- self.assertRaises(RuntimeError, self.call, 'PUT', ['document', guid], cmd='userdel', user='user1', principal='user1')
- self.assertRaises(RuntimeError, self.call, 'PUT', ['document', guid], cmd='userdel', user='user2', principal='user2')
+ self.assertRaises(RuntimeError, this.call, method='PUT', path=['document', guid], cmd='userdel', user='user1', principal='user1')
+ self.assertRaises(RuntimeError, this.call, method='PUT', path=['document', guid], cmd='userdel', user='user2', principal='user2')
- self.call('PUT', ['document', guid], cmd='userdel', user='user1', principal='user2')
+ this.call(method='PUT', path=['document', guid], cmd='userdel', user='user1', principal='user2')
self.assertEqual([
{'guid': 'user2', 'name': 'User2', 'role': 1},
{'name': 'User3', 'role': 0},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user2': {'name': 'User2', 'role': 1, 'order': 1},
'User3': {'role': 0, 'order': 2},
},
- self.volume['document'].get(guid)['author'])
+ volume['document'].get(guid)['author'])
- self.call('PUT', ['document', guid], cmd='userdel', user='User3', principal='user2')
+ this.call(method='PUT', path=['document', guid], cmd='userdel', user='User3', principal='user2')
self.assertEqual([
{'guid': 'user2', 'name': 'User2', 'role': 1},
],
- self.call('GET', ['document', guid, 'author']))
+ this.call(method='GET', path=['document', guid, 'author']))
self.assertEqual({
'user2': {'name': 'User2', 'role': 1, 'order': 1},
},
- self.volume['document'].get(guid)['author'])
-
- def test_typecast_prop_value(self):
- prop = Property('prop', typecast=int)
- self.assertEqual(1, _typecast_prop_value(prop.typecast, 1))
- self.assertEqual(1, _typecast_prop_value(prop.typecast, 1.1))
- self.assertEqual(1, _typecast_prop_value(prop.typecast, '1'))
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '1.0')
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '')
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None)
-
- prop = Property('prop', typecast=float)
- self.assertEqual(1.0, _typecast_prop_value(prop.typecast, 1))
- self.assertEqual(1.1, _typecast_prop_value(prop.typecast, 1.1))
- self.assertEqual(1.0, _typecast_prop_value(prop.typecast, '1'))
- self.assertEqual(1.1, _typecast_prop_value(prop.typecast, '1.1'))
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '')
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None)
-
- prop = Property('prop', typecast=bool)
- self.assertEqual(False, _typecast_prop_value(prop.typecast, 0))
- self.assertEqual(True, _typecast_prop_value(prop.typecast, 1))
- self.assertEqual(True, _typecast_prop_value(prop.typecast, 1.1))
- self.assertEqual(True, _typecast_prop_value(prop.typecast, '1'))
- self.assertEqual(True, _typecast_prop_value(prop.typecast, 'false'))
- self.assertEqual(False, _typecast_prop_value(prop.typecast, ''))
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None)
-
- prop = Property('prop', typecast=[int])
- self.assertEqual((1,), _typecast_prop_value(prop.typecast, 1))
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None)
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '')
- self.assertEqual((), _typecast_prop_value(prop.typecast, []))
- self.assertEqual((123,), _typecast_prop_value(prop.typecast, '123'))
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, 'a')
- self.assertEqual((123, 4, 5), _typecast_prop_value(prop.typecast, ['123', 4, 5.6]))
-
- prop = Property('prop', typecast=[1, 2])
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, 0)
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None)
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '')
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, 'A')
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '3')
- self.assertEqual(1, _typecast_prop_value(prop.typecast, 1))
- self.assertEqual(2, _typecast_prop_value(prop.typecast, 2))
- self.assertEqual(1, _typecast_prop_value(prop.typecast, '1'))
-
- prop = Property('prop', typecast=[str])
- self.assertEqual(('',), _typecast_prop_value(prop.typecast, ''))
- self.assertEqual(('',), _typecast_prop_value(prop.typecast, ['']))
- self.assertEqual((), _typecast_prop_value(prop.typecast, []))
-
- prop = Property('prop', typecast=[])
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None)
- self.assertEqual(('',), _typecast_prop_value(prop.typecast, ''))
- self.assertEqual(('',), _typecast_prop_value(prop.typecast, ['']))
- self.assertEqual((), _typecast_prop_value(prop.typecast, []))
- self.assertEqual(('0',), _typecast_prop_value(prop.typecast, 0))
- self.assertEqual(('',), _typecast_prop_value(prop.typecast, ''))
- self.assertEqual(('foo',), _typecast_prop_value(prop.typecast, 'foo'))
-
- prop = Property('prop', typecast=[['A', 'B', 'C']])
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '')
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, [''])
- self.assertEqual((), _typecast_prop_value(prop.typecast, []))
- self.assertEqual(('A', 'B', 'C'), _typecast_prop_value(prop.typecast, ['A', 'B', 'C']))
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, ['a'])
- self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, ['A', 'x'])
-
- prop = Property('prop', typecast=bool)
- self.assertEqual(True, _typecast_prop_value(prop.typecast, True))
- self.assertEqual(False, _typecast_prop_value(prop.typecast, False))
- self.assertEqual(True, _typecast_prop_value(prop.typecast, 'False'))
- self.assertEqual(True, _typecast_prop_value(prop.typecast, '0'))
-
- prop = Property('prop', typecast=[['A', 'B', 'C']])
- self.assertEqual(('A', 'B', 'C'), _typecast_prop_value(prop.typecast, ['A', 'B', 'C']))
-
- prop = Property('prop', typecast=lambda x: x + 1)
- self.assertEqual(1, _typecast_prop_value(prop.typecast, 0))
+ volume['document'].get(guid)['author'])
def test_DefaultOrder(self):
class Document(db.Resource):
pass
- self.volume = db.Volume('db', [Document])
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
- self.volume['document'].create({'guid': '3', 'ctime': 3})
- self.volume['document'].create({'guid': '2', 'ctime': 2})
- self.volume['document'].create({'guid': '1', 'ctime': 1})
+ volume['document'].create({'guid': '3', 'ctime': 3})
+ volume['document'].create({'guid': '2', 'ctime': 2})
+ volume['document'].create({'guid': '1', 'ctime': 1})
self.assertEqual([
{'guid': '1'},
{'guid': '2'},
{'guid': '3'},
],
- self.call('GET', ['document'])['result'])
+ this.call(method='GET', path=['document'])['result'])
- def test_SetDefaultPropsOnNoneValues(self):
+ def test_DefaultsOnNonePostValues(self):
class Document(db.Resource):
@@ -1645,10 +1655,11 @@ class RoutesTest(tests.Test):
def prop(self, value):
return value
- self.volume = db.Volume('db', [Document])
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
- guid = self.call('POST', ['document'], content={'prop': None})
- self.assertEqual('default', self.volume['document'].get(guid).meta('prop')['value'])
+ guid = this.call(method='POST', path=['document'], content={'prop': None})
+ self.assertEqual('default', this.call(method='GET', path=['document', guid, 'prop']))
def test_InsertAggprops(self):
@@ -1658,117 +1669,316 @@ class RoutesTest(tests.Test):
def prop1(self, value):
return value
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.WRITE)
- def prop2(self, value):
- return value
-
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.INSERT)
+ @db.stored_property(db.Aggregated, acl=ACL.INSERT)
def prop3(self, value):
return value
events = []
- self.volume = db.Volume('db', [Document], lambda event: events.append(event))
- guid = self.call('POST', ['document'], content={})
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
+ this.broadcast = lambda x: events.append(x)
+ guid = this.call(method='POST', path=['document'], content={})
- self.assertRaises(http.NotFound, self.call, 'POST', ['document', 'foo', 'bar'], content={})
- self.assertRaises(http.NotFound, self.call, 'POST', ['document', guid, 'bar'], content={})
- self.assertRaises(http.BadRequest, self.call, 'POST', ['document', guid, 'prop1'], content={})
- self.assertRaises(http.Forbidden, self.call, 'POST', ['document', guid, 'prop2'], content={})
+ self.assertRaises(http.NotFound, this.call, method='POST', path=['document', 'foo', 'bar'], content={})
+ self.assertRaises(http.NotFound, this.call, method='POST', path=['document', guid, 'bar'], content={})
+ self.assertRaises(http.BadRequest, this.call, method='POST', path=['document', guid, 'prop1'], content={})
del events[:]
self.override(time, 'time', lambda: 0)
self.override(toolkit, 'uuid', lambda: '0')
- self.assertEqual('0', self.call('POST', ['document', guid, 'prop3'], content={}))
+ self.assertEqual('0', this.call(method='POST', path=['document', guid, 'prop3'], content=0))
self.assertEqual({
- '0': {'seqno': 2},
+ '0': {'seqno': 2, 'value': 0},
},
- self.volume['document'].get(guid)['prop3'])
+ volume['document'].get(guid)['prop3'])
self.assertEqual([
{'event': 'update', 'resource': 'document', 'guid': guid},
],
events)
self.override(time, 'time', lambda: 1)
- self.assertEqual('1', self.call('POST', ['document', guid, 'prop3'], content={'guid': '1', 'foo': 'bar'}))
+ self.override(toolkit, 'uuid', lambda: '1')
+ self.assertEqual('1', this.call(method='POST', path=['document', guid, 'prop3'], content={'foo': 'bar'}))
self.assertEqual({
- '0': {'seqno': 2},
- '1': {'seqno': 3, 'foo': 'bar'},
+ '0': {'seqno': 2, 'value': 0},
+ '1': {'seqno': 3, 'value': {'foo': 'bar'}},
},
- self.volume['document'].get(guid)['prop3'])
+ volume['document'].get(guid)['prop3'])
self.override(time, 'time', lambda: 2)
self.override(toolkit, 'uuid', lambda: '2')
- self.assertEqual('2', self.call('POST', ['document', guid, 'prop3'], content={'prop': 'more'}))
+ self.assertEqual('2', this.call(method='POST', path=['document', guid, 'prop3'], content=None))
self.assertEqual({
- '0': {'seqno': 2},
- '1': {'seqno': 3, 'foo': 'bar'},
- '2': {'seqno': 4, 'prop': 'more'},
+ '0': {'seqno': 2, 'value': 0},
+ '1': {'seqno': 3, 'value': {'foo': 'bar'}},
+ '2': {'seqno': 4, 'value': None},
},
- self.volume['document'].get(guid)['prop3'])
+ volume['document'].get(guid)['prop3'])
def test_RemoveAggprops(self):
class Document(db.Resource):
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.INSERT)
+ @db.stored_property(db.Aggregated, acl=ACL.INSERT)
def prop1(self, value):
return value
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.INSERT | ACL.REMOVE)
+ @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE)
def prop2(self, value):
return value
events = []
- self.volume = db.Volume('db', [Document], lambda event: events.append(event))
- guid = self.call('POST', ['document'], content={})
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
+ this.broadcast = lambda x: events.append(x)
+ guid = this.call(method='POST', path=['document'], content={})
- agg_guid = self.call('POST', ['document', guid, 'prop1'], content={'probe': 'value'})
+ agg_guid = this.call(method='POST', path=['document', guid, 'prop1'], content=2)
del events[:]
self.assertEqual(
- {agg_guid: {'seqno': 2, 'probe': 'value'}},
- self.volume['document'].get(guid)['prop1'])
- self.assertRaises(http.Forbidden, self.call, 'DELETE', ['document', guid, 'prop1', agg_guid])
+ {agg_guid: {'seqno': 2, 'value': 2}},
+ volume['document'].get(guid)['prop1'])
+ self.assertRaises(http.Forbidden, this.call, method='DELETE', path=['document', guid, 'prop1', agg_guid])
self.assertEqual(
- {agg_guid: {'seqno': 2, 'probe': 'value'}},
- self.volume['document'].get(guid)['prop1'])
+ {agg_guid: {'seqno': 2, 'value': 2}},
+ volume['document'].get(guid)['prop1'])
self.assertEqual([], events)
- agg_guid = self.call('POST', ['document', guid, 'prop2'], content={'probe': 'value'})
+ agg_guid = this.call(method='POST', path=['document', guid, 'prop2'], content=3)
del events[:]
self.assertEqual(
- {agg_guid: {'seqno': 3, 'probe': 'value'}},
- self.volume['document'].get(guid)['prop2'])
- self.call('DELETE', ['document', guid, 'prop2', agg_guid])
+ {agg_guid: {'seqno': 3, 'value': 3}},
+ volume['document'].get(guid)['prop2'])
+ this.call(method='DELETE', path=['document', guid, 'prop2', agg_guid])
self.assertEqual(
{agg_guid: {'seqno': 4}},
- self.volume['document'].get(guid)['prop2'])
+ volume['document'].get(guid)['prop2'])
+ self.assertEqual([
+ {'event': 'update', 'resource': 'document', 'guid': guid},
+ ],
+ events)
+
+ def test_FailOnAbsentAggprops(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE | ACL.REPLACE)
+ def prop(self, value):
+ return value
+
+ events = []
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
+ this.broadcast = lambda x: events.append(x)
+ guid = this.call(method='POST', path=['document'], content={})
+ del events[:]
+
+ self.assertRaises(http.NotFound, this.call, method='DELETE', path=['document', guid, 'prop', 'absent'])
+ self.assertEqual([], events)
+
+ def test_UpdateAggprops(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(db.Aggregated)
+ def prop1(self, value):
+ return value
+
+ @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE | ACL.REPLACE)
+ def prop2(self, value):
+ return value
+
+ events = []
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
+ this.broadcast = lambda x: events.append(x)
+ guid = this.call(method='POST', path=['document'], content={})
+
+ agg_guid = this.call(method='POST', path=['document', guid, 'prop1'], content=1)
+ del events[:]
+ self.assertEqual(
+ {agg_guid: {'seqno': 2, 'value': 1}},
+ volume['document'].get(guid)['prop1'])
+ self.assertRaises(http.Forbidden, this.call, method='PUT', path=['document', guid, 'prop1', agg_guid], content=2)
+ self.assertEqual(
+ {agg_guid: {'seqno': 2, 'value': 1}},
+ volume['document'].get(guid)['prop1'])
+ self.assertEqual([], events)
+
+ agg_guid = this.call(method='POST', path=['document', guid, 'prop2'], content=2)
+ del events[:]
+ self.assertEqual(
+ {agg_guid: {'seqno': 3, 'value': 2}},
+ volume['document'].get(guid)['prop2'])
+ this.call(method='PUT', path=['document', guid, 'prop2', agg_guid], content=3)
+ self.assertEqual(
+ {agg_guid: {'seqno': 4, 'value': 3}},
+ volume['document'].get(guid)['prop2'])
+ self.assertEqual([
+ {'event': 'update', 'resource': 'document', 'guid': guid},
+ ],
+ events)
+
+ def test_PostAbsentAggpropsOnUpdate(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE | ACL.REPLACE)
+ def prop(self, value):
+ return value
+
+ events = []
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
+ this.broadcast = lambda x: events.append(x)
+ guid = this.call(method='POST', path=['document'], content={})
+ del events[:]
+
+ this.call(method='PUT', path=['document', guid, 'prop', 'absent'], content='probe')
+ self.assertEqual(
+ {'absent': {'seqno': 2, 'value': 'probe'}},
+ volume['document'].get(guid)['prop'])
self.assertEqual([
{'event': 'update', 'resource': 'document', 'guid': guid},
],
events)
- def call(self, method=None, path=None,
- accept_language=None, content=None, content_stream=None, cmd=None,
- content_type=None, host=None, request=None, routes=db.Routes, principal=None,
- **kwargs):
- if request is None:
- environ = {
- 'REQUEST_METHOD': method,
- 'PATH_INFO': '/'.join([''] + path),
- 'HTTP_ACCEPT_LANGUAGE': ','.join(accept_language or []),
- 'HTTP_HOST': host,
- 'wsgi.input': content_stream,
- }
- if content_type:
- environ['CONTENT_TYPE'] = content_type
- if content_stream is not None:
- environ['CONTENT_LENGTH'] = str(len(content_stream.getvalue()))
- request = Request(environ, cmd=cmd, content=content)
- request.update(kwargs)
- request.principal = principal
- router = Router(routes(self.volume))
- self.response = Response()
- return router._call_route(request, self.response)
+ def test_OriginalAggprops(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE)
+ def prop(self, value):
+ return value
+
+ volume = db.Volume(tests.tmpdir, [User, Document])
+ router = Router(db.Routes(volume))
+ volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'})
+ volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'})
+
+ guid = this.call(method='POST', path=['document'], content={}, principal=tests.UID)
+ assert ACL.ORIGINAL & volume['document'][guid]['author'][tests.UID]['role']
+
+ agg_guid1 = this.call(method='POST', path=['document', guid, 'prop'], content=1, principal=tests.UID)
+ assert tests.UID2 not in volume['document'][guid]['prop'][agg_guid1]['author']
+ assert ACL.ORIGINAL & volume['document'][guid]['prop'][agg_guid1]['author'][tests.UID]['role']
+
+ agg_guid2 = this.call(method='POST', path=['document', guid, 'prop'], content=1, principal=tests.UID2)
+ assert tests.UID not in volume['document'][guid]['prop'][agg_guid2]['author']
+ assert not (ACL.ORIGINAL & volume['document'][guid]['prop'][agg_guid2]['author'][tests.UID2]['role'])
+
+ this.call(method='DELETE', path=['document', guid, 'prop', agg_guid2], principal=tests.UID2)
+ assert tests.UID not in volume['document'][guid]['prop'][agg_guid2]['author']
+ assert not (ACL.ORIGINAL & volume['document'][guid]['prop'][agg_guid2]['author'][tests.UID2]['role'])
+
+ def test_AggregatedBlobs(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(db.Aggregated, subtype=db.Blob())
+ def blobs(self, value):
+ return value
+
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
+ guid = this.call(method='POST', path=['document'], content={})
+
+ agg1 = this.call(method='POST', path=['document', guid, 'blobs'], content='blob1')
+ self.assertEqual({
+ agg1: {'seqno': 2, 'value': str(hash('blob1'))},
+ },
+ volume['document'].get(guid)['blobs'])
+ assert files.get(str(hash('blob1')))
+
+ agg2 = this.call(method='POST', path=['document', guid, 'blobs'], content='blob2')
+ self.assertEqual({
+ agg1: {'seqno': 2, 'value': str(hash('blob1'))},
+ agg2: {'seqno': 3, 'value': str(hash('blob2'))},
+ },
+ volume['document'].get(guid)['blobs'])
+ assert files.get(str(hash('blob2')))
+
+ this.call(method='DELETE', path=['document', guid, 'blobs', agg1])
+ self.assertEqual({
+ agg1: {'seqno': 4},
+ 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')))
+
+ this.call(method='DELETE', path=['document', guid, 'blobs', agg2])
+ self.assertEqual({
+ agg1: {'seqno': 4},
+ agg2: {'seqno': 5},
+ },
+ volume['document'].get(guid)['blobs'])
+ assert files.get(str(hash('blob1'))) is None
+ assert files.get(str(hash('blob2'))) is None
+
+ agg3 = this.call(method='POST', path=['document', guid, 'blobs'], content='blob3')
+ self.assertEqual({
+ agg1: {'seqno': 4},
+ agg2: {'seqno': 5},
+ 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')))
+
+ def test_AggregatedSearch(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(db.Aggregated, prefix='A', full_text=True)
+ def comments(self, value):
+ return value
+
+ @db.stored_property(prefix='B', full_text=False, default='')
+ def prop(self, value):
+ return value
+
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
+
+ guid1 = this.call(method='POST', path=['document'], content={})
+ this.call(method='POST', path=['document', guid1, 'comments'], content='a')
+ this.call(method='POST', path=['document', guid1, 'comments'], content='b')
+ this.call(method='PUT', path=['document', guid1, 'prop'], content='c')
+
+ guid2 = this.call(method='POST', path=['document'], content={})
+ this.call(method='POST', path=['document', guid2, 'comments'], content='c')
+ this.call(method='POST', path=['document', guid2, 'comments'], content='a')
+ this.call(method='PUT', path=['document', guid2, 'prop'], content='b')
+
+ guid3 = this.call(method='POST', path=['document'], content={})
+ this.call(method='POST', path=['document', guid3, 'comments'], content='a c')
+ this.call(method='POST', path=['document', guid3, 'comments'], content='b d')
+ this.call(method='PUT', path=['document', guid3, 'prop'], content='e')
+
+ self.assertEqual(
+ sorted([guid1, guid2, guid3]),
+ sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='a')['result']]))
+ self.assertEqual(
+ sorted([guid1, guid3]),
+ sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='b')['result']]))
+ self.assertEqual(
+ sorted([guid2, guid3]),
+ sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='c')['result']]))
+ self.assertEqual(
+ sorted([]),
+ sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='absent')['result']]))
+
+ self.assertEqual(
+ sorted([guid1, guid2, guid3]),
+ sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='comments:a')['result']]))
+ self.assertEqual(
+ sorted([guid1, guid3]),
+ sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='comments:b')['result']]))
+ self.assertEqual(
+ sorted([guid2, guid3]),
+ sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='comments:c')['result']]))
if __name__ == '__main__':
diff --git a/tests/units/db/storage.py b/tests/units/db/storage.py
index 6eb62e5..bb61f8a 100755
--- a/tests/units/db/storage.py
+++ b/tests/units/db/storage.py
@@ -11,8 +11,7 @@ from os.path import exists
from __init__ import tests
-from sugar_network.db.metadata import Metadata, StoredProperty
-from sugar_network.db.metadata import BlobProperty
+from sugar_network.db.metadata import Metadata, Property
from sugar_network.db.storage import Storage
from sugar_network.toolkit import BUFFER_SIZE
@@ -30,7 +29,7 @@ class StorageTest(tests.Test):
return Storage(tests.tmpdir, metadata)
def test_Record_get(self):
- storage = self.storage([StoredProperty('prop')])
+ storage = self.storage([Property('prop')])
self.assertEqual(None, storage.get('guid').get('prop'))
self.touch(('gu/guid/prop', json.dumps({
@@ -45,7 +44,7 @@ class StorageTest(tests.Test):
storage.get('guid').get('prop'))
def test_Record_set(self):
- storage = self.storage([StoredProperty('prop')])
+ storage = self.storage([Property('prop')])
storage.get('guid').set('prop', value='value', foo='bar')
self.assertEqual({
@@ -56,7 +55,7 @@ class StorageTest(tests.Test):
storage.get('guid').get('prop'))
def test_delete(self):
- storage = self.storage([StoredProperty('prop')])
+ storage = self.storage([Property('prop')])
assert not exists('ab/absent')
storage.delete('absent')
@@ -69,8 +68,8 @@ class StorageTest(tests.Test):
def test_Record_consistent(self):
storage = self.storage([
- StoredProperty('guid'),
- StoredProperty('prop'),
+ Property('guid'),
+ Property('prop'),
])
record = storage.get('guid')
@@ -83,7 +82,7 @@ class StorageTest(tests.Test):
self.assertEqual(True, record.consistent)
def test_walk(self):
- storage = self.storage([StoredProperty('guid')])
+ storage = self.storage([Property('guid')])
storage.get('guid1').set('guid', value=1, mtime=1)
storage.get('guid2').set('guid', value=2, mtime=2)
@@ -107,8 +106,8 @@ class StorageTest(tests.Test):
def test_walk_SkipGuidLess(self):
storage = self.storage([
- StoredProperty('guid'),
- StoredProperty('prop'),
+ Property('guid'),
+ Property('prop'),
])
record = storage.get('guid1')
diff --git a/tests/units/model/__main__.py b/tests/units/model/__main__.py
index 2766988..3814380 100644
--- a/tests/units/model/__main__.py
+++ b/tests/units/model/__main__.py
@@ -2,9 +2,9 @@
from __init__ import tests
+from model import *
from post import *
from context import *
-from release import *
from routes import *
if __name__ == '__main__':
diff --git a/tests/units/model/context.py b/tests/units/model/context.py
index 3389f41..71357f2 100755
--- a/tests/units/model/context.py
+++ b/tests/units/model/context.py
@@ -1,82 +1,331 @@
#!/usr/bin/env python
# sugar-lint: disable
+from cStringIO import StringIO
from os.path import exists
from __init__ import tests
from sugar_network import db
-from sugar_network.node import obs
+from sugar_network.db import files
+from sugar_network.client import IPCConnection, Connection, keyfile
from sugar_network.model.context import Context
-from sugar_network.client import IPCConnection
-from sugar_network.toolkit import coroutine, enforce
+from sugar_network.toolkit.coroutine import this
+from sugar_network.toolkit.router import Request
+from sugar_network.toolkit import i18n, http, coroutine, enforce
class ContextTest(tests.Test):
def test_SetCommonLayerForPackages(self):
- self.start_online_client()
- ipc = IPCConnection()
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
- guid = ipc.post(['context'], {
+ guid = conn.post(['context'], {
'type': 'package',
'title': 'title',
'summary': 'summary',
'description': 'description',
})
- self.assertEqual(['common'], ipc.get(['context', guid, 'layer']))
+ self.assertEqual(['common'], conn.get(['context', guid, 'layer']))
- guid = ipc.post(['context'], {
+ guid = conn.post(['context'], {
'type': 'package',
'title': 'title',
'summary': 'summary',
'description': 'description',
'layer': 'foo',
})
- self.assertEqual(['foo', 'common'], ipc.get(['context', guid, 'layer']))
+ self.assertEqual(['foo', 'common'], conn.get(['context', guid, 'layer']))
- guid = ipc.post(['context'], {
+ guid = conn.post(['context'], {
'type': 'package',
'title': 'title',
'summary': 'summary',
'description': 'description',
'layer': ['common', 'bar'],
})
- self.assertEqual(['common', 'bar'], ipc.get(['context', guid, 'layer']))
+ self.assertEqual(['common', 'bar'], conn.get(['context', guid, 'layer']))
- def test_DefaultImages(self):
- self.start_online_client()
- ipc = IPCConnection()
+ def test_Releases(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
- guid = ipc.post(['context'], {
- 'guid': 'guid',
+ context = conn.post(['context'], {
'type': 'activity',
- 'title': 'title',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ activity_info1 = '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ ])
+ bundle1 = self.zips(('topdir/activity/activity.info', activity_info1))
+ release1 = conn.upload(['context', context, 'releases'], StringIO(bundle1))
+ assert release1 == str(hash(bundle1))
+ self.assertEqual({
+ release1: {
+ 'seqno': 5,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {
+ 'license': ['Public Domain'],
+ 'announce': next(volume['post'].find(query='title:1')[0]).guid,
+ 'release': [[1], 0],
+ 'requires': [],
+ 'spec': {'*-*': {'bundle': str(hash(bundle1)), 'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
+ 'stability': 'stable',
+ 'unpack_size': len(activity_info1),
+ 'version': '1',
+ },
+ },
+ }, conn.get(['context', context, 'releases']))
+ assert files.get(str(hash(bundle1)))
+
+ activity_info2 = '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 2',
+ 'license = Public Domain',
+ ])
+ bundle2 = self.zips(('topdir/activity/activity.info', activity_info2))
+ release2 = conn.upload(['context', context, 'releases'], StringIO(bundle2))
+ assert release2 == str(hash(bundle2))
+ self.assertEqual({
+ release1: {
+ 'seqno': 5,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {
+ 'license': ['Public Domain'],
+ 'announce': next(volume['post'].find(query='title:1')[0]).guid,
+ 'release': [[1], 0],
+ 'requires': [],
+ 'spec': {'*-*': {'bundle': str(hash(bundle1)), 'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
+ 'stability': 'stable',
+ 'unpack_size': len(activity_info1),
+ 'version': '1',
+ },
+ },
+ release2: {
+ 'seqno': 7,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {
+ 'license': ['Public Domain'],
+ 'announce': next(volume['post'].find(query='title:2')[0]).guid,
+ 'release': [[2], 0],
+ 'requires': [],
+ 'spec': {'*-*': {'bundle': str(hash(bundle2)), 'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
+ 'stability': 'stable',
+ 'unpack_size': len(activity_info2),
+ 'version': '2',
+ },
+ },
+ }, conn.get(['context', context, 'releases']))
+ assert files.get(str(hash(bundle1)))
+ assert files.get(str(hash(bundle2)))
+
+ conn.delete(['context', context, 'releases', release1])
+ self.assertEqual({
+ release1: {
+ 'seqno': 8,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ },
+ release2: {
+ 'seqno': 7,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {
+ 'license': ['Public Domain'],
+ 'announce': next(volume['post'].find(query='title:2')[0]).guid,
+ 'release': [[2], 0],
+ 'requires': [],
+ 'spec': {'*-*': {'bundle': str(hash(bundle2)), 'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
+ 'stability': 'stable',
+ 'unpack_size': len(activity_info2),
+ 'version': '2',
+ },
+ },
+ }, conn.get(['context', context, 'releases']))
+ assert files.get(str(hash(bundle1))) is None
+ assert files.get(str(hash(bundle2)))
+
+ conn.delete(['context', context, 'releases', release2])
+ self.assertEqual({
+ release1: {
+ 'seqno': 8,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ },
+ release2: {
+ 'seqno': 9,
+ '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
+
+ def test_IncrementReleasesSeqnoOnNewReleases(self):
+ events = []
+ volume = self.start_master()
+ this.broadcast = lambda x: events.append(x)
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ context = conn.post(['context'], {
+ 'type': 'activity',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ self.assertEqual([
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(0, volume.releases_seqno.value)
+
+ conn.put(['context', context], {
+ 'summary': 'summary2',
+ })
+ self.assertEqual([
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(0, volume.releases_seqno.value)
+
+ bundle = self.zips(('topdir/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ ])))
+ release = conn.upload(['context', context, 'releases'], StringIO(bundle))
+ self.assertEqual([
+ {'event': 'release', 'seqno': 1},
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(1, volume.releases_seqno.value)
+
+ bundle = self.zips(('topdir/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 2',
+ 'license = Public Domain',
+ ])))
+ release = conn.upload(['context', context, 'releases'], StringIO(bundle))
+ self.assertEqual([
+ {'event': 'release', 'seqno': 1},
+ {'event': 'release', 'seqno': 2},
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(2, volume.releases_seqno.value)
+
+ bundle = self.zips(('topdir/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 2',
+ 'license = Public Domain',
+ ])))
+ release = conn.upload(['context', context, 'releases'], StringIO(bundle))
+ self.assertEqual([
+ {'event': 'release', 'seqno': 1},
+ {'event': 'release', 'seqno': 2},
+ {'event': 'release', 'seqno': 3},
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(3, volume.releases_seqno.value)
+
+ conn.delete(['context', context, 'releases', release])
+ self.assertEqual([
+ {'event': 'release', 'seqno': 1},
+ {'event': 'release', 'seqno': 2},
+ {'event': 'release', 'seqno': 3},
+ {'event': 'release', 'seqno': 4},
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(4, volume.releases_seqno.value)
+
+ def test_IncrementReleasesSeqnoOnDependenciesChange(self):
+ events = []
+ volume = self.start_master()
+ this.broadcast = lambda x: events.append(x)
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ context = conn.post(['context'], {
+ 'type': 'activity',
+ 'title': 'Activity',
'summary': 'summary',
'description': 'description',
})
- assert exists('master/context/gu/guid/artifact_icon.blob')
- assert exists('master/context/gu/guid/icon.blob')
- assert exists('master/context/gu/guid/logo.blob')
-
- def test_RatingSort(self):
- directory = db.Volume('db', [Context])['context']
-
- directory.create({'guid': '1', 'type': 'activity', 'title': '', 'summary': '', 'description': '', 'rating': [0, 0]})
- directory.create({'guid': '2', 'type': 'activity', 'title': '', 'summary': '', 'description': '', 'rating': [1, 2]})
- directory.create({'guid': '3', 'type': 'activity', 'title': '', 'summary': '', 'description': '', 'rating': [1, 4]})
- directory.create({'guid': '4', 'type': 'activity', 'title': '', 'summary': '', 'description': '', 'rating': [10, 10]})
- directory.create({'guid': '5', 'type': 'activity', 'title': '', 'summary': '', 'description': '', 'rating': [30, 90]})
-
- self.assertEqual(
- ['1', '2', '3', '4', '5'],
- [i.guid for i in directory.find()[0]])
- self.assertEqual(
- ['1', '4', '2', '5', '3'],
- [i.guid for i in directory.find(order_by='rating')[0]])
- self.assertEqual(
- ['3', '5', '2', '4', '1'],
- [i.guid for i in directory.find(order_by='-rating')[0]])
+ self.assertEqual([
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(0, volume.releases_seqno.value)
+
+ conn.put(['context', context], {
+ 'dependencies': 'dep',
+ })
+ self.assertEqual([
+ {'event': 'release', 'seqno': 1},
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(1, volume.releases_seqno.value)
+
+ def test_IncrementReleasesSeqnoOnDeletes(self):
+ events = []
+ volume = self.start_master()
+ this.broadcast = lambda x: events.append(x)
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ context = conn.post(['context'], {
+ 'type': 'activity',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ self.assertEqual([
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(0, volume.releases_seqno.value)
+
+ conn.put(['context', context], {
+ 'layer': ['deleted'],
+ })
+ self.assertEqual([
+ {'event': 'release', 'seqno': 1},
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(1, volume.releases_seqno.value)
+
+ conn.put(['context', context], {
+ 'layer': [],
+ })
+ self.assertEqual([
+ {'event': 'release', 'seqno': 1},
+ {'event': 'release', 'seqno': 2},
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(2, volume.releases_seqno.value)
+
+ def test_RestoreReleasesSeqno(self):
+ events = []
+ volume = self.start_master()
+ this.broadcast = lambda x: events.append(x)
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ context = conn.post(['context'], {
+ 'type': 'activity',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ 'dependencies': 'dep',
+ })
+ self.assertEqual(1, volume.releases_seqno.value)
+
+ volume.close()
+ volume = db.Volume('master', [])
+ self.assertEqual(1, volume.releases_seqno.value)
if __name__ == '__main__':
diff --git a/tests/units/model/model.py b/tests/units/model/model.py
new file mode 100755
index 0000000..f8b3866
--- /dev/null
+++ b/tests/units/model/model.py
@@ -0,0 +1,519 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# sugar-lint: disable
+
+import base64
+
+from __init__ import tests
+
+from sugar_network import db
+from sugar_network.db import files
+from sugar_network.model import load_bundle
+from sugar_network.model.post import Post
+from sugar_network.client import IPCConnection, Connection, keyfile
+from sugar_network.toolkit.router import Request
+from sugar_network.toolkit.coroutine import this
+from sugar_network.toolkit import i18n, http, coroutine, enforce
+
+
+class ModelTest(tests.Test):
+
+ def test_RatingSort(self):
+ directory = db.Volume('db', [Post])['post']
+
+ directory.create({'guid': '1', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'rating': [0, 0]})
+ directory.create({'guid': '2', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'rating': [1, 2]})
+ directory.create({'guid': '3', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'rating': [1, 4]})
+ directory.create({'guid': '4', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'rating': [10, 10]})
+ directory.create({'guid': '5', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'rating': [30, 90]})
+
+ self.assertEqual(
+ ['1', '2', '3', '4', '5'],
+ [i.guid for i in directory.find()[0]])
+ self.assertEqual(
+ ['1', '4', '2', '5', '3'],
+ [i.guid for i in directory.find(order_by='rating')[0]])
+ self.assertEqual(
+ ['3', '5', '2', '4', '1'],
+ [i.guid for i in directory.find(order_by='-rating')[0]])
+
+ def test_load_bundle_Activity(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ conn.post(['context'], {
+ 'guid': 'bundle_id',
+ 'type': 'activity',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ activity_info = '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = bundle_id',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ 'stability = developer',
+ 'requires = sugar>=0.88; dep'
+ ])
+ changelog = "LOG"
+ bundle = self.zips(
+ ('topdir/activity/activity.info', activity_info),
+ ('topdir/CHANGELOG', changelog),
+ )
+ blob = files.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))
+ self.assertEqual('bundle_id', context)
+ self.assertEqual('1', release['version'])
+ self.assertEqual('developer', release['stability'])
+ self.assertEqual(['Public Domain'], release['license'])
+ self.assertEqual('developer', release['stability'])
+ self.assertEqual(sorted(['dep', 'sugar-0.88']), sorted(release['requires']))
+ self.assertEqual({
+ '*-*': {
+ 'bundle': blob.digest,
+ 'commands': {'activity': {'exec': 'true'}},
+ 'requires': {'dep': {}, 'sugar': {'restrictions': [('0.88', None)]}},
+ },
+ },
+ release['spec'])
+ self.assertEqual(len(activity_info) + len(changelog), release['unpack_size'])
+
+ post = volume['post'][release['announce']]
+ assert tests.UID in post['author']
+ self.assertEqual('notification', post['type'])
+ self.assertEqual({
+ 'en': 'Activity 1 release',
+ 'es': 'Activity 1 release',
+ 'fr': 'Activity 1 release',
+ }, post['title'])
+ self.assertEqual({
+ 'en-us': 'LOG',
+ }, post['message'])
+
+ def test_load_bundle_NonActivity(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ conn.post(['context'], {
+ 'guid': 'bundle_id',
+ 'type': 'book',
+ 'title': 'NonActivity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ bundle = 'non-activity'
+ blob = files.post(bundle)
+
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID,
+ content_type = 'content/type', version='2', license='GPL')
+ context, release = load_bundle(blob, 'bundle_id')
+
+ self.assertEqual({
+ 'mime_type': 'content/type',
+ 'name': 'NonActivity-2',
+ }, files.get(blob.digest))
+ self.assertEqual('bundle_id', context)
+ self.assertEqual('2', release['version'])
+ self.assertEqual(['GPL'], release['license'])
+
+ post = volume['post'][release['announce']]
+ assert tests.UID in post['author']
+ self.assertEqual('notification', post['type'])
+ self.assertEqual({
+ 'en': 'NonActivity 2 release',
+ 'es': 'NonActivity 2 release',
+ 'fr': 'NonActivity 2 release',
+ }, post['title'])
+ self.assertEqual({
+ 'en-us': '',
+ }, post['message'])
+
+ def test_load_bundle_ReuseActivityLicense(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ conn.post(['context'], {
+ 'guid': 'bundle_id',
+ 'type': 'activity',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ activity_info_wo_license = '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = bundle_id',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ ])
+ bundle = self.zips(('topdir/activity/activity.info', activity_info_wo_license))
+ blob_wo_license = files.post(bundle)
+ self.assertRaises(http.BadRequest, load_bundle, blob_wo_license, 'bundle_id')
+
+ volume['context'].update('bundle_id', {'releases': {
+ 'new': {'release': 2, 'license': ['New']},
+ }})
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID)
+ context, release = load_bundle(blob_wo_license, 'bundle_id')
+ self.assertEqual(['New'], release['license'])
+
+ volume['context'].update('bundle_id', {'releases': {
+ 'new': {'release': 2, 'license': ['New']},
+ 'old': {'release': 1, 'license': ['Old']},
+ }})
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID)
+ context, release = load_bundle(blob_wo_license, 'bundle_id')
+ self.assertEqual(['New'], release['license'])
+
+ volume['context'].update('bundle_id', {'releases': {
+ 'new': {'release': 2, 'license': ['New']},
+ 'old': {'release': 1, 'license': ['Old']},
+ 'newest': {'release': 3, 'license': ['Newest']},
+ }})
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID)
+ context, release = load_bundle(blob_wo_license, 'bundle_id')
+ self.assertEqual(['Newest'], release['license'])
+
+ def test_load_bundle_ReuseNonActivityLicense(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ conn.post(['context'], {
+ 'guid': 'bundle_id',
+ 'type': 'book',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ blob = files.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')
+
+ volume['context'].update('bundle_id', {'releases': {
+ 'new': {'release': 2, 'license': ['New']},
+ }})
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID, version='1')
+ context, release = load_bundle(blob, 'bundle_id')
+ self.assertEqual(['New'], release['license'])
+
+ volume['context'].update('bundle_id', {'releases': {
+ 'new': {'release': 2, 'license': ['New']},
+ 'old': {'release': 1, 'license': ['Old']},
+ }})
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID, version='1')
+ context, release = load_bundle(blob, 'bundle_id')
+ self.assertEqual(['New'], release['license'])
+
+ volume['context'].update('bundle_id', {'releases': {
+ 'new': {'release': 2, 'license': ['New']},
+ 'old': {'release': 1, 'license': ['Old']},
+ 'newest': {'release': 3, 'license': ['Newest']},
+ }})
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID, version='1')
+ context, release = load_bundle(blob, 'bundle_id')
+ self.assertEqual(['Newest'], release['license'])
+
+ def test_load_bundle_WrontContextType(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ conn.post(['context'], {
+ 'guid': 'bundle_id',
+ 'type': 'group',
+ 'title': 'NonActivity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ blob = files.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')
+
+ activity_info = '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = bundle_id',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ 'stability = developer',
+ 'requires = sugar>=0.88; dep'
+ ])
+ changelog = "LOG"
+ bundle = self.zips(
+ ('topdir/activity/activity.info', activity_info),
+ ('topdir/CHANGELOG', changelog),
+ )
+ blob = files.post(bundle)
+ self.assertRaises(http.BadRequest, load_bundle, blob, 'bundle_id')
+
+ def test_load_bundle_MissedContext(self):
+ volume = self.start_master()
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ bundle = self.zips(('topdir/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = bundle_id',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ 'stability = developer',
+ 'requires = sugar>=0.88; dep'
+ ])))
+ blob = files.post(bundle)
+
+ this.request = Request(principal=tests.UID)
+ self.assertRaises(http.NotFound, load_bundle, blob, initial=False)
+
+ def test_load_bundle_CreateContext(self):
+ volume = self.start_master()
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ bundle = self.zips(
+ ('ImageViewer.activity/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'bundle_id = org.laptop.ImageViewerActivity',
+ 'name = Image Viewer',
+ 'summary = The Image Viewer activity is a simple and fast image viewer tool',
+ 'description = It has features one would expect of a standard image viewer, like zoom, rotate, etc.',
+ 'homepage = http://wiki.sugarlabs.org/go/Activities/Image_Viewer',
+ 'activity_version = 1',
+ 'license = GPLv2+',
+ 'icon = activity-imageviewer',
+ 'exec = true',
+ 'mime_types = image/bmp;image/gif',
+ ])),
+ ('ImageViewer.activity/activity/activity-imageviewer.svg', ''),
+ )
+ blob = files.post(bundle)
+
+ this.request = Request(principal=tests.UID)
+ context, release = load_bundle(blob, initial=True)
+ self.assertEqual('org.laptop.ImageViewerActivity', context)
+
+ context = volume['context'].get('org.laptop.ImageViewerActivity')
+ self.assertEqual({'en': 'Image Viewer'}, context['title'])
+ self.assertEqual({'en': 'The Image Viewer activity is a simple and fast image viewer tool'}, context['summary'])
+ self.assertEqual({'en': 'It has features one would expect of a standard image viewer, like zoom, rotate, etc.'}, context['description'])
+ self.assertEqual('http://wiki.sugarlabs.org/go/Activities/Image_Viewer', context['homepage'])
+ self.assertEqual(['image/bmp', 'image/gif'], context['mime_types'])
+ assert context['ctime'] > 0
+ assert context['mtime'] > 0
+ self.assertEqual({tests.UID: {'role': 3, 'name': 'user', 'order': 0}}, context['author'])
+
+ post = volume['post'][release['announce']]
+ assert tests.UID in post['author']
+ self.assertEqual('notification', post['type'])
+ self.assertEqual({
+ 'en': 'Image Viewer 1 release',
+ 'es': 'Image Viewer 1 release',
+ 'fr': 'Image Viewer 1 release',
+ }, post['title'])
+
+ def test_load_bundle_UpdateContext(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ conn.post(['context'], {
+ 'guid': 'org.laptop.ImageViewerActivity',
+ 'type': 'activity',
+ 'title': {'en': ''},
+ 'summary': {'en': ''},
+ 'description': {'en': ''},
+ })
+ svg = '\n'.join([
+ '<?xml version="1.0" encoding="UTF-8"?>',
+ '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [',
+ ' <!ENTITY fill_color "#123456">',
+ ' <!ENTITY stroke_color "#123456">',
+ ']>',
+ '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">',
+ ' <rect x="3" y="7" width="44" height="36" style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:3"/>',
+ ' <polyline points="15,7 25,1 35,7" style="fill:none;;stroke:&stroke_color;;stroke-width:1.25"/>',
+ ' <circle cx="14" cy="19" r="4.5" style="fill:&stroke_color;;stroke:&stroke_color;;stroke-width:1.5"/>',
+ ' <polyline points="3,36 16,32 26,35" style="fill:none;;stroke:&stroke_color;;stroke-width:2.5"/>',
+ ' <polyline points="15,43 37,28 47,34 47,43" style="fill:&stroke_color;;stroke:&stroke_color;;stroke-width:3"/>',
+ ' <polyline points="22,41.5 35,30 27,41.5" style="fill:&fill_color;;stroke:none;;stroke-width:0"/>',
+ ' <polyline points="26,23 28,25 30,23" style="fill:none;;stroke:&stroke_color;;stroke-width:.9"/>',
+ ' <polyline points="31.2,20 33.5,17.7 35.8,20" style="fill:none;;stroke:&stroke_color;;stroke-width:1"/>',
+ ' <polyline points="36,13 38.5,15.5 41,13" style="fill:none;;stroke:&stroke_color;;stroke-width:1"/>',
+ '</svg>',
+ ])
+ bundle = self.zips(
+ ('ImageViewer.activity/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'bundle_id = org.laptop.ImageViewerActivity',
+ 'name = Image Viewer',
+ 'summary = The Image Viewer activity is a simple and fast image viewer tool',
+ 'description = It has features one would expect of a standard image viewer, like zoom, rotate, etc.',
+ 'homepage = http://wiki.sugarlabs.org/go/Activities/Image_Viewer',
+ 'activity_version = 22',
+ 'license = GPLv2+',
+ 'icon = activity-imageviewer',
+ 'exec = true',
+ 'mime_types = image/bmp;image/gif',
+ ])),
+ ('ImageViewer.activity/locale/ru/LC_MESSAGES/org.laptop.ImageViewerActivity.mo',
+ base64.b64decode('3hIElQAAAAAMAAAAHAAAAHwAAAARAAAA3AAAAAAAAAAgAQAADwAAACEBAAAOAAAAMQEAAA0AAABAAQAACgAAAE4BAAAMAAAAWQEAAA0AAABmAQAAJwAAAHQBAAAUAAAAnAEAABAAAACxAQAABwAAAMIBAAAIAAAAygEAANEBAADTAQAAIQAAAKUDAAATAAAAxwMAABwAAADbAwAAFwAAAPgDAAAhAAAAEAQAAB0AAAAyBAAAQAAAAFAEAAA9AAAAkQQAADUAAADPBAAAFAAAAAUFAAAQAAAAGgUAAAEAAAACAAAABwAAAAAAAAADAAAAAAAAAAwAAAAJAAAAAAAAAAoAAAAEAAAAAAAAAAAAAAALAAAABgAAAAgAAAAFAAAAAENob29zZSBkb2N1bWVudABEb3dubG9hZGluZy4uLgBGaXQgdG8gd2luZG93AEZ1bGxzY3JlZW4ASW1hZ2UgVmlld2VyAE9yaWdpbmFsIHNpemUAUmV0cmlldmluZyBzaGFyZWQgaW1hZ2UsIHBsZWFzZSB3YWl0Li4uAFJvdGF0ZSBhbnRpY2xvY2t3aXNlAFJvdGF0ZSBjbG9ja3dpc2UAWm9vbSBpbgBab29tIG91dABQcm9qZWN0LUlkLVZlcnNpb246IFBBQ0tBR0UgVkVSU0lPTgpSZXBvcnQtTXNnaWQtQnVncy1UbzogClBPVC1DcmVhdGlvbi1EYXRlOiAyMDEyLTA5LTI3IDE0OjU3LTA0MDAKUE8tUmV2aXNpb24tRGF0ZTogMjAxMC0wOS0yMiAxMzo1MCswMjAwCkxhc3QtVHJhbnNsYXRvcjoga3JvbTlyYSA8a3JvbTlyYUBnbWFpbC5jb20+Ckxhbmd1YWdlLVRlYW06IExBTkdVQUdFIDxMTEBsaS5vcmc+Ckxhbmd1YWdlOiAKTUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PVVURi04CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IDhiaXQKUGx1cmFsLUZvcm1zOiBucGx1cmFscz0zOyBwbHVyYWw9KG4lMTA9PTEgJiYgbiUxMDAhPTExID8gMCA6IG4lMTA+PTIgJiYgbiUxMDw9NCAmJiAobiUxMDA8MTAgfHwgbiUxMDA+PTIwKSA/IDEgOiAyKTsKWC1HZW5lcmF0b3I6IFBvb3RsZSAyLjAuMwoA0JLRi9Cx0LXRgNC40YLQtSDQtNC+0LrRg9C80LXQvdGCANCX0LDQs9GA0YPQt9C60LAuLi4A0KPQvNC10YHRgtC40YLRjCDQsiDQvtC60L3QtQDQn9C+0LvQvdGL0Lkg0Y3QutGA0LDQvQDQn9GA0L7RgdC80L7RgtGAINC60LDRgNGC0LjQvdC+0LoA0JjRgdGC0LjQvdC90YvQuSDRgNCw0LfQvNC10YAA0J/QvtC70YPRh9C10L3QuNC1INC40LfQvtCx0YDQsNC20LXQvdC40LksINC/0L7QtNC+0LbQtNC40YLQtS4uLgDQn9C+0LLQtdGA0L3Rg9GC0Ywg0L/RgNC+0YLQuNCyINGH0LDRgdC+0LLQvtC5INGB0YLRgNC10LvQutC4ANCf0L7QstC10YDQvdGD0YLRjCDQv9C+INGH0LDRgdC+0LLQvtC5INGB0YLRgNC10LvQutC1ANCf0YDQuNCx0LvQuNC30LjRgtGMANCe0YLQtNCw0LvQuNGC0YwA')),
+ ('ImageViewer.activity/activity/activity-imageviewer.svg', svg),
+ )
+
+ blob = files.post(bundle)
+ this.request = Request(method='POST', path=['context', 'org.laptop.ImageViewerActivity'], principal=tests.UID)
+ context, release = load_bundle(blob, initial=True)
+
+ context = volume['context'].get('org.laptop.ImageViewerActivity')
+ self.assertEqual({
+ 'en': 'Image Viewer',
+ 'ru': u'Просмотр картинок',
+ },
+ context['title'])
+ self.assertEqual({
+ 'en': 'The Image Viewer activity is a simple and fast image viewer tool',
+ },
+ context['summary'])
+ self.assertEqual({
+ '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())
+ assert context['icon'] != 'missing.png'
+ assert context['logo'] != 'missing-logo.png'
+ self.assertEqual('http://wiki.sugarlabs.org/go/Activities/Image_Viewer', context['homepage'])
+ self.assertEqual(['image/bmp', 'image/gif'], context['mime_types'])
+
+ def test_load_bundle_3rdPartyRelease(self):
+ i18n._default_langs = ['en']
+ volume = self.start_master()
+ volume['user'].create({'guid': tests.UID2, 'name': 'user2', 'pubkey': tests.PUBKEY2})
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ conn.post(['context'], {
+ 'guid': 'bundle_id',
+ 'type': 'activity',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ bundle = self.zips(('topdir/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'name = Activity2',
+ 'bundle_id = bundle_id',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ 'stability = developer',
+ ])))
+ blob = files.post(bundle)
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID2)
+ context, release = load_bundle(blob, 'bundle_id')
+
+ assert tests.UID in volume['context']['bundle_id']['author']
+ assert tests.UID2 not in volume['context']['bundle_id']['author']
+ self.assertEqual({'en': 'Activity'}, volume['context']['bundle_id']['title'])
+
+ post = volume['post'][release['announce']]
+ assert tests.UID not in post['author']
+ assert tests.UID2 in post['author']
+ self.assertEqual('notification', post['type'])
+ self.assertEqual({
+ 'en': 'Activity 1 third-party release',
+ 'es': 'Activity 1 third-party release',
+ 'fr': 'Activity 1 third-party release',
+ }, post['title'])
+
+ files.delete(blob.digest)
+ blob = files.post(bundle)
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID)
+ context, release = load_bundle(blob, 'bundle_id')
+
+ assert tests.UID in volume['context']['bundle_id']['author']
+ assert tests.UID2 not in volume['context']['bundle_id']['author']
+ self.assertEqual({'en': 'Activity2'}, volume['context']['bundle_id']['title'])
+
+ post = volume['post'][release['announce']]
+ assert tests.UID in post['author']
+ assert tests.UID2 not in post['author']
+ self.assertEqual('notification', post['type'])
+ self.assertEqual({
+ 'en': 'Activity2 1 release',
+ 'es': 'Activity2 1 release',
+ 'fr': 'Activity2 1 release',
+ }, post['title'])
+
+ def test_load_bundle_PopulateRequires(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ conn.post(['context'], {
+ 'guid': 'bundle_id',
+ 'type': 'activity',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ bundle = self.zips(
+ ('ImageViewer.activity/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'bundle_id = bundle_id',
+ 'name = Image Viewer',
+ 'activity_version = 22',
+ 'license = GPLv2+',
+ 'icon = activity-imageviewer',
+ 'exec = true',
+ 'requires = dep1, dep2<10, dep3<=20, dep4>30, dep5>=40, dep6>5<7, dep7>=1<=3',
+ ])),
+ ('ImageViewer.activity/activity/activity-imageviewer.svg', ''),
+ )
+ blob = files.post(bundle)
+ this.request = Request(method='POST', path=['context', 'bundle_id'], principal=tests.UID)
+ context, release = load_bundle(blob, 'bundle_id')
+
+ self.assertEqual(
+ sorted([
+ 'dep1', 'dep2', 'dep3', 'dep4-31', 'dep5-40',
+ 'dep6-6',
+ 'dep7-1', 'dep7-2', 'dep7-3',
+ ]),
+ sorted(release['requires']))
+
+ def test_load_bundle_IgnoreNotSupportedContextTypes(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ context = conn.post(['context'], {
+ 'type': 'package',
+ 'title': '',
+ 'summary': '',
+ 'description': '',
+ })
+ this.request = Request(method='POST', path=['context', context])
+ aggid = conn.post(['context', context, 'releases'], -1)
+ self.assertEqual({
+ aggid: {'seqno': 3, 'value': -1, 'author': {tests.UID: {'role': 3, 'name': tests.UID, 'order': 0}}},
+ }, volume['context'][context]['releases'])
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/model/post.py b/tests/units/model/post.py
index dc6f6f4..45b85e1 100755
--- a/tests/units/model/post.py
+++ b/tests/units/model/post.py
@@ -8,74 +8,27 @@ from sugar_network.client import Connection, keyfile
from sugar_network.model.user import User
from sugar_network.model.context import Context
from sugar_network.model.post import Post
-from sugar_network.model.release import Release
+from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import http
class PostTest(tests.Test):
- def test_SetContext(self):
- volume = self.start_master([User, Context, Release, Post])
- client = Connection(auth=http.SugarAuth(keyfile.value))
-
- self.assertRaises(http.NotFound, client.post, ['post'], {'type': 'comment', 'title': '', 'message': '', 'topic': 'absent'})
-
- context = client.post(['context'], {
- 'type': 'package',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- topic = client.post(['post'], {
- 'context': context,
- 'title': 'title',
- 'message': 'message',
- 'type': 'update',
- })
- comment = client.post(['post'], {
- 'topic': topic,
- 'title': 'title',
- 'message': 'message',
- 'type': 'comment',
- })
- self.assertEqual(
- context,
- client.get(['post', comment, 'context']))
-
- def test_RatingSort(self):
- directory = db.Volume('db', [Post])['post']
-
- directory.create({'guid': '1', 'context': '', 'type': 'comment', 'title': '', 'message': '', 'rating': [0, 0]})
- directory.create({'guid': '2', 'context': '', 'type': 'comment', 'title': '', 'message': '', 'rating': [1, 2]})
- directory.create({'guid': '3', 'context': '', 'type': 'comment', 'title': '', 'message': '', 'rating': [1, 4]})
- directory.create({'guid': '4', 'context': '', 'type': 'comment', 'title': '', 'message': '', 'rating': [10, 10]})
- directory.create({'guid': '5', 'context': '', 'type': 'comment', 'title': '', 'message': '', 'rating': [30, 90]})
-
- self.assertEqual(
- ['1', '2', '3', '4', '5'],
- [i.guid for i in directory.find()[0]])
- self.assertEqual(
- ['1', '4', '2', '5', '3'],
- [i.guid for i in directory.find(order_by='rating')[0]])
- self.assertEqual(
- ['3', '5', '2', '4', '1'],
- [i.guid for i in directory.find(order_by='-rating')[0]])
-
def test_FindComments(self):
directory = db.Volume('db', [Post])['post']
- directory.create({'guid': '1', 'context': '', 'type': 'comment', 'title': '', 'message': '', 'comments': {
- '1': {'message': 'foo'},
+ directory.create({'guid': '1', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'comments': {
+ '1': {'value': {'en': 'foo'}},
}})
- directory.create({'guid': '2', 'context': '', 'type': 'comment', 'title': '', 'message': '', 'comments': {
- '1': {'message': 'bar'},
+ directory.create({'guid': '2', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'comments': {
+ '1': {'value': {'en': 'bar'}},
}})
- directory.create({'guid': '3', 'context': '', 'type': 'comment', 'title': '', 'message': '', 'comments': {
- '1': {'message': 'bar'},
- '2': {'message': 'foo'},
+ directory.create({'guid': '3', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'comments': {
+ '1': {'value': {'en': 'bar'}},
+ '2': {'value': {'en': 'foo'}},
}})
- directory.create({'guid': '4', 'context': '', 'type': 'comment', 'title': '', 'message': '', 'comments': {
- '1': {'message': 'foo bar'},
+ directory.create({'guid': '4', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'comments': {
+ '1': {'value': {'en': 'foo bar'}},
}})
self.assertEqual(
@@ -92,6 +45,115 @@ class PostTest(tests.Test):
['1', '3', '4'],
[i.guid for i in directory.find(query='comments:foo')[0]])
+ def test_ShiftContextRating(self):
+ volume = db.Volume('db', [Context, Post])
+ this.volume = volume
+
+ context = volume['context'].create({
+ 'type': 'activity',
+ 'title': {},
+ 'summary': {},
+ 'description': {},
+ })
+ self.assertEqual([0, 0], volume['context'][context]['rating'])
+
+ volume['post'].create({
+ 'context': context,
+ 'type': 'post',
+ 'title': {},
+ 'message': {},
+ })
+ self.assertEqual([0, 0], volume['context'][context]['rating'])
+
+ volume['post'].create({
+ 'context': context,
+ 'type': 'post',
+ 'title': {},
+ 'message': {},
+ 'vote': 0,
+ })
+ self.assertEqual([0, 0], volume['context'][context]['rating'])
+
+ volume['post'].create({
+ 'context': context,
+ 'type': 'post',
+ 'title': {},
+ 'message': {},
+ 'vote': 1,
+ })
+ self.assertEqual([1, 1], volume['context'][context]['rating'])
+
+ volume['post'].create({
+ 'context': context,
+ 'type': 'post',
+ 'title': {},
+ 'message': {},
+ 'vote': 2,
+ })
+ self.assertEqual([2, 3], volume['context'][context]['rating'])
+
+ def test_ShiftTopicRating(self):
+ volume = db.Volume('db2', [Context, Post])
+ this.volume = volume
+
+ context = volume['context'].create({
+ 'type': 'activity',
+ 'title': {},
+ 'summary': {},
+ 'description': {},
+ })
+ topic = volume['post'].create({
+ 'context': context,
+ 'type': 'post',
+ 'title': {},
+ 'message': {},
+ })
+ self.assertEqual([0, 0], volume['context'][context]['rating'])
+ self.assertEqual([0, 0], volume['post'][topic]['rating'])
+
+ volume['post'].create({
+ 'context': context,
+ 'topic': topic,
+ 'type': 'post',
+ 'title': {},
+ 'message': {},
+ })
+ self.assertEqual([0, 0], volume['context'][context]['rating'])
+ self.assertEqual([0, 0], volume['post'][topic]['rating'])
+
+ volume['post'].create({
+ 'context': context,
+ 'topic': topic,
+ 'type': 'post',
+ 'title': {},
+ 'message': {},
+ 'vote': 0,
+ })
+ self.assertEqual([0, 0], volume['context'][context]['rating'])
+ self.assertEqual([0, 0], volume['post'][topic]['rating'])
+
+ volume['post'].create({
+ 'context': context,
+ 'topic': topic,
+ 'type': 'post',
+ 'title': {},
+ 'message': {},
+ 'vote': 1,
+ })
+ self.assertEqual([0, 0], volume['context'][context]['rating'])
+ self.assertEqual([1, 1], volume['post'][topic]['rating'])
+
+ volume['post'].create({
+ 'context': context,
+ 'topic': topic,
+ 'type': 'post',
+ 'title': {},
+ 'message': {},
+ 'vote': 2,
+ })
+ self.assertEqual([0, 0], volume['context'][context]['rating'])
+ self.assertEqual([2, 3], volume['post'][topic]['rating'])
+
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/model/release.py b/tests/units/model/release.py
deleted file mode 100755
index 2f4bfb1..0000000
--- a/tests/units/model/release.py
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import os
-
-import xapian
-
-from __init__ import tests
-
-from sugar_network import db
-from sugar_network.model import release
-from sugar_network.model.release import _fmt_version, Release
-from sugar_network.client import IPCConnection
-from sugar_network.toolkit import http, coroutine
-
-
-class ReleaseTest(tests.Test):
-
- def test_fmt_version(self):
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''5''000')),
- _fmt_version('1'))
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0002''0000''5''000')),
- _fmt_version('1.2'))
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0020''0300''5''000')),
- _fmt_version('1.20.300'))
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0020''0300''5''000')),
- _fmt_version('1.20.300.4444'))
-
- self.assertEqual(
- xapian.sortable_serialise(eval('1''9999''0000''5''000')),
- _fmt_version('10001.99999.10000'))
-
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''3''000')),
- _fmt_version('1-pre'))
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''4''000')),
- _fmt_version('1-rc'))
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''5''000')),
- _fmt_version('1-'))
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''6''000')),
- _fmt_version('1-r'))
-
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''3''001')),
- _fmt_version('1-pre1'))
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''4''002')),
- _fmt_version('1-rc2'))
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''6''003')),
- _fmt_version('1-r3'))
-
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''6''000')),
- _fmt_version('1-r-2-3'))
- self.assertEqual(
- xapian.sortable_serialise(eval('1''0000''0000''6''001')),
- _fmt_version('1-r1.2-3'))
-
- def test_OriginalAuthor(self):
- self.start_online_client()
- client = IPCConnection()
-
- self.node_volume['context'].create({
- 'guid': 'context',
- 'type': 'book',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- 'author': {'fake': None},
- })
-
- guid = client.post(['release'], {
- 'context': 'context',
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- self.assertEqual([], self.node_volume['release'].get(guid)['layer'])
-
- guid = client.post(['release'], {
- 'context': 'context',
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- 'layer': ['foo'],
- })
- self.assertEqual(['foo'], self.node_volume['release'].get(guid)['layer'])
-
- self.node_volume['context'].update('context', {'author': {tests.UID: None}})
-
- guid = client.post(['release'], {
- 'context': 'context',
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- self.assertEqual(['origin'], self.node_volume['release'].get(guid)['layer'])
-
- guid = client.post(['release'], {
- 'context': 'context',
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- 'layer': ['foo'],
- })
- self.assertEqual(
- sorted(['foo', 'origin']),
- sorted(self.node_volume['release'].get(guid)['layer']))
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/model/routes.py b/tests/units/model/routes.py
index 989dfc1..3c21483 100755
--- a/tests/units/model/routes.py
+++ b/tests/units/model/routes.py
@@ -10,36 +10,15 @@ from os.path import exists
from __init__ import tests, src_root
from sugar_network import db, model
+from sugar_network.db import files
from sugar_network.model.user import User
from sugar_network.toolkit.router import Router, Request
+from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import coroutine
class RoutesTest(tests.Test):
- def test_StaticFiles(self):
- router = Router(model.FrontRoutes())
- local_path = src_root + '/sugar_network/static/httpdocs/images/missing.png'
-
- response = []
- reply = router({
- 'PATH_INFO': '/static/images/missing.png',
- 'REQUEST_METHOD': 'GET',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = file(local_path).read()
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '200 OK',
- {
- 'last-modified': formatdate(os.stat(local_path).st_mtime, localtime=False, usegmt=True),
- 'content-length': str(len(result)),
- 'content-type': 'image/png',
- 'content-disposition': 'attachment; filename="missing.png"',
- }
- ],
- response)
-
def test_Subscribe(self):
class Document(db.Resource):
@@ -49,7 +28,7 @@ class RoutesTest(tests.Test):
return value
routes = model.FrontRoutes()
- volume = db.Volume('db', [Document], routes.broadcast)
+ volume = db.Volume('db', [Document])
events = []
def read_events():
@@ -69,6 +48,7 @@ class RoutesTest(tests.Test):
job.kill()
self.assertEqual([
+ {'event': 'pong'},
{'guid': 'guid', 'resource': 'document', 'event': 'create'},
{'guid': 'guid', 'resource': 'document', 'event': 'update'},
{'guid': 'guid', 'event': 'delete', 'resource': u'document'},
@@ -77,66 +57,10 @@ class RoutesTest(tests.Test):
def test_SubscribeWithPong(self):
routes = model.FrontRoutes()
- for event in routes.subscribe(ping=True):
+ for event in routes.subscribe():
break
self.assertEqual({'event': 'pong'}, event)
- def test_feed(self):
- volume = db.Volume('db', model.RESOURCES)
- routes = model.VolumeRoutes(volume)
-
- volume['context'].create({
- 'guid': 'context',
- 'type': 'activity',
- 'title': '',
- 'summary': '',
- 'description': '',
- 'dependencies': ['foo', 'bar'],
- })
- volume['release'].create({
- 'guid': 'release',
- 'context': 'context',
- 'license': 'GPLv3',
- 'version': '1',
- 'date': 0,
- 'stability': 'stable',
- 'notes': '',
- 'data': {
- 'spec': {
- '*-*': {
- 'commands': {'activity': {'exec': 'true'}},
- 'requires': {'dep': {}, 'sugar': {'restrictions': [['0.88', None]]}},
- },
- },
- },
- })
-
- self.assertEqual({
- 'releases': [
- {
- 'guid': 'release',
- 'author': {},
- 'ctime': 0,
- 'data': {
- 'spec': {
- '*-*': {
- 'commands': {'activity': {'exec': 'true'}},
- 'requires': {'dep': {}, 'sugar': {'restrictions': [['0.88', None]]}},
- },
- },
- },
- 'layer': [],
- 'license': 'GPLv3',
- 'notes': {'en-us': ''},
- 'stability': 'stable',
- 'tags': [],
- 'version': '1',
- 'requires': {'bar': {}, 'foo': {}},
- },
- ],
- },
- routes.feed(Request(method='GET', path=['context', 'context']), 'foo'))
-
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/node/__main__.py b/tests/units/node/__main__.py
index ac37315..dfadaf3 100644
--- a/tests/units/node/__main__.py
+++ b/tests/units/node/__main__.py
@@ -4,16 +4,14 @@ from __init__ import tests
from downloads import *
from files import *
-from master import *
from node import *
from obs import *
-from stats_node import *
from stats_user import *
from sync import *
from sync_master import *
from sync_offline import *
from sync_online import *
-from volume import *
+from model import *
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/node/master.py b/tests/units/node/master.py
deleted file mode 100755
index b3eaa75..0000000
--- a/tests/units/node/master.py
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import os
-
-from __init__ import tests
-
-from sugar_network.node import obs
-from sugar_network.client import IPCConnection
-from sugar_network.toolkit import coroutine, enforce
-
-
-class MasterTest(tests.Test):
-
- def test_Aliases(self):
- self.override(obs, 'get_repos', lambda: [
- {'distributor_id': 'Gentoo', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']},
- {'distributor_id': 'Debian', 'name': 'Debian-6.0', 'arches': ['x86']},
- {'distributor_id': 'Debian', 'name': 'Debian-7.0', 'arches': ['x86_64']},
- ])
- self.override(obs, 'resolve', lambda repo, arch, names: ['fake'])
-
- self.start_online_client()
- ipc = IPCConnection()
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
-
- ipc.put(['context', guid, 'aliases'], {
- 'Gentoo': {
- 'binary': [['pkg1.bin', 'pkg2.bin']],
- 'devel': [['pkg3.devel']],
- },
- 'Debian': {
- 'binary': [['pkg4.bin']],
- 'devel': [['pkg5.devel', 'pkg6.devel']],
- },
- })
- coroutine.dispatch()
- self.assertEqual({
- 'Gentoo-2.1': {'status': 'success', 'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']},
- 'Debian-6.0': {'status': 'success', 'binary': ['pkg4.bin'], 'devel': ['pkg5.devel', 'pkg6.devel']},
- 'Debian-7.0': {'status': 'success', 'binary': ['pkg4.bin'], 'devel': ['pkg5.devel', 'pkg6.devel']},
- },
- ipc.get(['context', guid, 'packages']))
-
- def test_WrongAliases(self):
- self.override(obs, 'get_repos', lambda: [
- {'distributor_id': 'Gentoo', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']},
- {'distributor_id': 'Debian', 'name': 'Debian-6.0', 'arches': ['x86']},
- {'distributor_id': 'Debian', 'name': 'Debian-7.0', 'arches': ['x86_64']},
- ])
- self.override(obs, 'resolve', lambda repo, arch, names: enforce(False, 'resolve failed'))
-
- self.start_online_client()
- ipc = IPCConnection()
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
-
- ipc.put(['context', guid, 'aliases'], {
- 'Gentoo': {
- 'binary': [['pkg1.bin', 'pkg2.bin']],
- 'devel': [['pkg3.devel']],
- },
- 'Debian': {
- 'binary': [['pkg4.bin']],
- 'devel': [['pkg5.devel', 'pkg6.devel']],
- },
- })
- coroutine.dispatch()
- self.assertEqual({
- 'Gentoo-2.1': {'status': 'resolve failed'},
- 'Debian-6.0': {'status': 'resolve failed'},
- 'Debian-7.0': {'status': 'resolve failed'},
- },
- ipc.get(['context', guid, 'packages']))
-
- def test_MultipleAliases(self):
-
- def resolve(repo, arch, names):
- enforce(not [i for i in names if 'fake' in i], 'resolve failed')
- return ['fake']
-
- self.override(obs, 'get_repos', lambda: [
- {'distributor_id': 'Gentoo', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']},
- ])
- self.override(obs, 'resolve', resolve)
-
- self.start_online_client()
- ipc = IPCConnection()
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
-
- ipc.put(['context', guid, 'aliases'], {
- 'Gentoo': {
- 'binary': [['fake.bin'], ['proper.bin'], ['not-reach.bin']],
- 'devel': [['fake.devel'], ['proper.devel'], ['not-reach.devel']],
- },
- })
- coroutine.dispatch()
- self.assertEqual({
- 'Gentoo-2.1': {'status': 'success', 'binary': ['proper.bin'], 'devel': ['proper.devel']},
- },
- ipc.get(['context', guid, 'packages']))
-
- ipc.put(['context', guid, 'aliases'], {
- 'Gentoo': {
- 'binary': [['proper.bin']],
- 'devel': [['fake.devel']],
- },
- })
- coroutine.dispatch()
- self.assertEqual({
- 'Gentoo-2.1': {'status': 'resolve failed', 'binary': ['proper.bin']},
- },
- ipc.get(['context', guid, 'packages']))
-
- ipc.put(['context', guid, 'aliases'], {
- 'Gentoo': {
- 'binary': [['fake.bin']],
- 'devel': [['proper.devel']],
- },
- })
- coroutine.dispatch()
- self.assertEqual({
- 'Gentoo-2.1': {'status': 'resolve failed'},
- },
- ipc.get(['context', guid, 'packages']))
-
- def test_InvalidateSolutions(self):
- self.override(obs, 'get_repos', lambda: [
- {'distributor_id': 'Gentoo', 'name': 'Gentoo-2.1', 'arches': ['x86_64']},
- ])
- self.override(obs, 'resolve', lambda repo, arch, names: ['fake'])
-
- self.start_online_client()
- ipc = IPCConnection()
-
- events = []
- def read_events():
- for event in ipc.subscribe():
- if event.get('resource') == 'release':
- events.append(event)
- job = coroutine.spawn(read_events)
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- coroutine.sleep(.5)
- self.assertEqual([], events)
-
- ipc.put(['context', guid, 'aliases'], {
- 'Gentoo': {
- 'binary': [['bin']],
- 'devel': [['devel']],
- },
- })
- coroutine.sleep(.5)
- self.assertEqual([
- {'event': 'populate', 'resource': 'release', 'mtime': int(os.stat('master/release/index/mtime').st_mtime)},
- ],
- events)
- self.assertEqual({
- 'Gentoo-2.1': {'status': 'success', 'binary': ['bin'], 'devel': ['devel']},
- },
- ipc.get(['context', guid, 'packages']))
-
- def test_InvalidateSolutionsOnDependenciesChanges(self):
- self.start_online_client()
- ipc = IPCConnection()
-
- events = []
- def read_events():
- for event in ipc.subscribe():
- if event.get('resource') == 'release':
- events.append(event)
- job = coroutine.spawn(read_events)
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- 'dependencies': [],
- })
- self.assertEqual(0, len(events))
-
- ipc.put(['context', guid, 'dependencies'], ['foo'])
- coroutine.sleep(.1)
- self.assertEqual([
- {'event': 'populate', 'resource': 'release', 'mtime': int(os.stat('master/release/index/mtime').st_mtime)},
- ],
- events)
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/node/model.py b/tests/units/node/model.py
new file mode 100755
index 0000000..68215c1
--- /dev/null
+++ b/tests/units/node/model.py
@@ -0,0 +1,660 @@
+#!/usr/bin/env python
+# sugar-lint: disable
+
+import os
+import time
+
+from __init__ import tests
+
+from sugar_network import db, toolkit
+from sugar_network.db import files
+from sugar_network.client import Connection, keyfile, api_url
+from sugar_network.model.user import User
+from sugar_network.model.post import Post
+from sugar_network.node import model, obs
+from sugar_network.node.routes import NodeRoutes
+from sugar_network.toolkit.coroutine import this
+from sugar_network.toolkit.router import Request, Router
+from sugar_network.toolkit import i18n, http, coroutine, enforce
+
+
+class ModelTest(tests.Test):
+
+ def test_IncrementReleasesSeqno(self):
+ events = []
+ volume = self.start_master([User, model.Context, Post])
+ this.broadcast = lambda x: events.append(x)
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ context = conn.post(['context'], {
+ 'type': 'group',
+ 'title': 'Activity',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ self.assertEqual([
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(0, volume.releases_seqno.value)
+
+ aggid = conn.post(['context', context, 'releases'], -1)
+ self.assertEqual([
+ {'event': 'release', 'seqno': 1},
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(1, volume.releases_seqno.value)
+
+ def test_diff(self):
+ self.override(time, 'time', lambda: 0)
+ self.override(NodeRoutes, 'authorize', lambda self, user, role: True)
+
+ class Document(db.Resource):
+
+ @db.indexed_property(slot=1)
+ def prop(self, value):
+ return value
+
+ volume = self.start_master([User, Document])
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ guid1 = conn.post(['document'], {'prop': 'a'})
+ self.utime('master/document/%s/%s' % (guid1[:2], guid1), 1)
+ guid2 = conn.post(['document'], {'prop': 'b'})
+ self.utime('master/document/%s/%s' % (guid2[:2], guid2), 2)
+
+ in_seq = toolkit.Sequence([[1, None]])
+ self.assertEqual([
+ {'resource': 'document'},
+ {'guid': guid1,
+ 'diff': {
+ 'guid': {'value': guid1, 'mtime': 1},
+ 'mtime': {'value': 0, 'mtime': 1},
+ 'ctime': {'value': 0, 'mtime': 1},
+ 'prop': {'value': 'a', 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
+ 'layer': {'mtime': 1, 'value': []},
+ 'tags': {'mtime': 1, 'value': []},
+ },
+ },
+ {'guid': guid2,
+ 'diff': {
+ 'guid': {'value': guid2, 'mtime': 2},
+ 'mtime': {'value': 0, 'mtime': 2},
+ 'ctime': {'value': 0, 'mtime': 2},
+ 'prop': {'value': 'b', 'mtime': 2},
+ 'author': {'mtime': 2, 'value': {}},
+ 'layer': {'mtime': 2, 'value': []},
+ 'tags': {'mtime': 2, 'value': []},
+ },
+ },
+ {'commit': [[1, 2]]},
+ ],
+ [i for i in model.diff(volume, in_seq)])
+ self.assertEqual([[1, None]], in_seq)
+
+ def test_diff_Partial(self):
+ self.override(time, 'time', lambda: 0)
+ self.override(NodeRoutes, 'authorize', lambda self, user, role: True)
+
+ class Document(db.Resource):
+
+ @db.indexed_property(slot=1)
+ def prop(self, value):
+ return value
+
+ volume = self.start_master([User, Document])
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ guid1 = conn.post(['document'], {'prop': 'a'})
+ self.utime('master/document/%s/%s' % (guid1[:2], guid1), 1)
+ guid2 = conn.post(['document'], {'prop': 'b'})
+ self.utime('master/document/%s/%s' % (guid2[:2], guid2), 2)
+
+ in_seq = toolkit.Sequence([[1, None]])
+ patch = model.diff(volume, in_seq)
+ self.assertEqual({'resource': 'document'}, next(patch))
+ self.assertEqual(guid1, next(patch)['guid'])
+ self.assertEqual({'commit': []}, patch.throw(StopIteration()))
+ try:
+ next(patch)
+ assert False
+ except StopIteration:
+ pass
+
+ patch = model.diff(volume, in_seq)
+ self.assertEqual({'resource': 'document'}, next(patch))
+ self.assertEqual(guid1, next(patch)['guid'])
+ self.assertEqual(guid2, next(patch)['guid'])
+ self.assertEqual({'commit': [[1, 1]]}, patch.throw(StopIteration()))
+ try:
+ next(patch)
+ assert False
+ except StopIteration:
+ pass
+
+ def test_diff_Stretch(self):
+ self.override(time, 'time', lambda: 0)
+ self.override(NodeRoutes, 'authorize', lambda self, user, role: True)
+
+ class Document(db.Resource):
+
+ @db.indexed_property(slot=1)
+ def prop(self, value):
+ return value
+
+ volume = self.start_master([User, Document])
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ guid1 = conn.post(['document'], {'prop': 'a'})
+ self.utime('master/document/%s/%s' % (guid1[:2], guid1), 1)
+ guid2 = conn.post(['document'], {'prop': 'b'})
+ volume['document'].delete(guid2)
+ guid3 = conn.post(['document'], {'prop': 'c'})
+ self.utime('master/document/%s/%s' % (guid3[:2], guid3), 2)
+ guid4 = conn.post(['document'], {'prop': 'd'})
+ volume['document'].delete(guid4)
+ guid5 = conn.post(['document'], {'prop': 'f'})
+ self.utime('master/document/%s/%s' % (guid5[:2], guid5), 2)
+
+ in_seq = toolkit.Sequence([[1, None]])
+ patch = model.diff(volume, in_seq)
+ self.assertEqual({'resource': 'document'}, patch.send(None))
+ self.assertEqual(guid1, patch.send(None)['guid'])
+ self.assertEqual(guid3, patch.send(None)['guid'])
+ self.assertEqual(guid5, patch.send(None)['guid'])
+ self.assertEqual({'commit': [[1, 1], [3, 3]]}, patch.throw(StopIteration()))
+ try:
+ patch.send(None)
+ assert False
+ except StopIteration:
+ pass
+
+ patch = model.diff(volume, in_seq)
+ self.assertEqual({'resource': 'document'}, patch.send(None))
+ self.assertEqual(guid1, patch.send(None)['guid'])
+ self.assertEqual(guid3, patch.send(None)['guid'])
+ self.assertEqual(guid5, patch.send(None)['guid'])
+ self.assertEqual({'commit': [[1, 5]]}, patch.send(None))
+ try:
+ patch.send(None)
+ assert False
+ except StopIteration:
+ pass
+
+ def test_diff_DoNotStretchContinuesPacket(self):
+ self.override(time, 'time', lambda: 0)
+ self.override(NodeRoutes, 'authorize', lambda self, user, role: True)
+
+ class Document(db.Resource):
+
+ @db.indexed_property(slot=1)
+ def prop(self, value):
+ return value
+
+ volume = self.start_master([User, Document])
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ guid1 = conn.post(['document'], {'prop': 'a'})
+ volume['document'].delete(guid1)
+ guid2 = conn.post(['document'], {'prop': 'b'})
+ volume['document'].delete(guid2)
+ guid3 = conn.post(['document'], {'prop': 'c'})
+ self.utime('master/document/%s/%s' % (guid3[:2], guid3), 2)
+ guid4 = conn.post(['document'], {'prop': 'd'})
+ volume['document'].delete(guid4)
+ guid5 = conn.post(['document'], {'prop': 'f'})
+ self.utime('master/document/%s/%s' % (guid5[:2], guid5), 2)
+
+ in_seq = toolkit.Sequence([[1, None]])
+ patch = model.diff(volume, in_seq, toolkit.Sequence([[1, 1]]))
+ self.assertEqual({'resource': 'document'}, patch.send(None))
+ self.assertEqual(guid3, patch.send(None)['guid'])
+ self.assertEqual(guid5, patch.send(None)['guid'])
+ self.assertEqual({'commit': [[1, 1], [3, 3], [5, 5]]}, patch.send(None))
+ try:
+ patch.send(None)
+ assert False
+ except StopIteration:
+ pass
+
+ def test_diff_TheSameInSeqForAllDocuments(self):
+ self.override(time, 'time', lambda: 0)
+ self.override(NodeRoutes, 'authorize', lambda self, user, role: True)
+
+ class Document1(db.Resource):
+ pass
+
+ class Document2(db.Resource):
+ pass
+
+ class Document3(db.Resource):
+ pass
+
+ volume = self.start_master([User, Document1, Document2, Document3])
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ guid3 = conn.post(['document1'], {})
+ self.utime('master/document/%s/%s' % (guid3[:2], guid3), 3)
+ guid2 = conn.post(['document2'], {})
+ self.utime('master/document/%s/%s' % (guid2[:2], guid2), 2)
+ guid1 = conn.post(['document3'], {})
+ self.utime('master/document/%s/%s' % (guid1[:2], guid1), 1)
+
+ in_seq = toolkit.Sequence([[1, None]])
+ patch = model.diff(volume, in_seq)
+ self.assertEqual({'resource': 'document1'}, patch.send(None))
+ self.assertEqual(guid3, patch.send(None)['guid'])
+ self.assertEqual({'resource': 'document2'}, patch.send(None))
+ self.assertEqual(guid2, patch.send(None)['guid'])
+ self.assertEqual({'resource': 'document3'}, patch.send(None))
+ self.assertEqual(guid1, patch.send(None)['guid'])
+ self.assertEqual({'commit': [[1, 3]]}, patch.send(None))
+ try:
+ patch.send(None)
+ assert False
+ except StopIteration:
+ pass
+
+ def test_merge_Create(self):
+ self.override(time, 'time', lambda: 0)
+ self.override(NodeRoutes, 'authorize', lambda self, user, role: True)
+
+ class Document1(db.Resource):
+
+ @db.indexed_property(slot=1)
+ def prop(self, value):
+ return value
+
+ class Document2(db.Resource):
+ pass
+
+ self.touch(('master/db.seqno', '100'))
+ volume = self.start_master([Document1, Document2])
+
+ records = [
+ {'resource': 'document1'},
+ {'guid': '1', 'diff': {
+ 'guid': {'value': '1', 'mtime': 1.0},
+ 'ctime': {'value': 2, 'mtime': 2.0},
+ 'mtime': {'value': 3, 'mtime': 3.0},
+ 'prop': {'value': '4', 'mtime': 4.0},
+ }},
+ {'resource': 'document2'},
+ {'guid': '5', 'diff': {
+ 'guid': {'value': '5', 'mtime': 5.0},
+ 'ctime': {'value': 6, 'mtime': 6.0},
+ 'mtime': {'value': 7, 'mtime': 7.0},
+ }},
+ {'commit': [[1, 2]]},
+ ]
+ self.assertEqual(([[1, 2]], [[101, 102]]), model.merge(volume, records))
+
+ self.assertEqual(
+ {'guid': '1', 'prop': '4', 'ctime': 2, 'mtime': 3},
+ volume['document1'].get('1').properties(['guid', 'ctime', 'mtime', 'prop']))
+ self.assertEqual(1, os.stat('master/document1/1/1/guid').st_mtime)
+ self.assertEqual(2, os.stat('master/document1/1/1/ctime').st_mtime)
+ self.assertEqual(3, os.stat('master/document1/1/1/mtime').st_mtime)
+ self.assertEqual(4, os.stat('master/document1/1/1/prop').st_mtime)
+
+ self.assertEqual(
+ {'guid': '5', 'ctime': 6, 'mtime': 7},
+ volume['document2'].get('5').properties(['guid', 'ctime', 'mtime']))
+ self.assertEqual(5, os.stat('master/document2/5/5/guid').st_mtime)
+ self.assertEqual(6, os.stat('master/document2/5/5/ctime').st_mtime)
+ self.assertEqual(7, os.stat('master/document2/5/5/mtime').st_mtime)
+
+ def test_merge_Update(self):
+ self.override(time, 'time', lambda: 0)
+ self.override(NodeRoutes, 'authorize', lambda self, user, role: True)
+
+ class Document(db.Resource):
+
+ @db.indexed_property(slot=1)
+ def prop(self, value):
+ return value
+
+ self.touch(('master/db.seqno', '100'))
+ volume = db.Volume('master', [Document])
+ volume['document'].create({'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1})
+ for i in os.listdir('master/document/1/1'):
+ os.utime('master/document/1/1/%s' % i, (2, 2))
+
+ records = [
+ {'resource': 'document'},
+ {'guid': '1', 'diff': {'prop': {'value': '2', 'mtime': 1.0}}},
+ {'commit': [[1, 1]]},
+ ]
+ self.assertEqual(([[1, 1]], []), model.merge(volume, records))
+ self.assertEqual(
+ {'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1},
+ volume['document'].get('1').properties(['guid', 'ctime', 'mtime', 'prop']))
+ self.assertEqual(2, os.stat('master/document/1/1/prop').st_mtime)
+
+ records = [
+ {'resource': 'document'},
+ {'guid': '1', 'diff': {'prop': {'value': '3', 'mtime': 2.0}}},
+ {'commit': [[2, 2]]},
+ ]
+ self.assertEqual(([[2, 2]], []), model.merge(volume, records))
+ self.assertEqual(
+ {'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1},
+ volume['document'].get('1').properties(['guid', 'ctime', 'mtime', 'prop']))
+ self.assertEqual(2, os.stat('master/document/1/1/prop').st_mtime)
+
+ records = [
+ {'resource': 'document'},
+ {'guid': '1', 'diff': {'prop': {'value': '4', 'mtime': 3.0}}},
+ {'commit': [[3, 3]]},
+ ]
+ self.assertEqual(([[3, 3]], [[102, 102]]), model.merge(volume, records))
+ self.assertEqual(
+ {'guid': '1', 'prop': '4', 'ctime': 1, 'mtime': 1},
+ volume['document'].get('1').properties(['guid', 'ctime', 'mtime', 'prop']))
+ self.assertEqual(3, os.stat('master/document/1/1/prop').st_mtime)
+
+ def test_merge_MultipleCommits(self):
+ self.override(time, 'time', lambda: 0)
+
+ class Document(db.Resource):
+
+ @db.stored_property()
+ def prop(self, value):
+ return value
+
+ self.touch(('master/db.seqno', '100'))
+ volume = db.Volume('master', [Document])
+
+ def generator():
+ for i in [
+ {'resource': 'document'},
+ {'commit': [[1, 1]]},
+ {'guid': '1', 'diff': {
+ 'guid': {'value': '1', 'mtime': 1.0},
+ 'ctime': {'value': 2, 'mtime': 2.0},
+ 'mtime': {'value': 3, 'mtime': 3.0},
+ 'prop': {'value': '4', 'mtime': 4.0},
+ }},
+ {'commit': [[2, 3]]},
+ ]:
+ yield i
+
+ records = generator()
+ self.assertEqual(([[1, 3]], [[101, 101]]), model.merge(volume, records))
+ assert volume['document'].exists('1')
+
+ def test_diff_ByLayers(self):
+ self.override(time, 'time', lambda: 0)
+ self.override(NodeRoutes, 'authorize', lambda self, user, role: True)
+
+ class Context(db.Resource):
+ pass
+
+ class Post(db.Resource):
+ pass
+
+ this.request = Request()
+ volume = db.Volume('db', [Context, Post])
+ volume['context'].create({'guid': '0', 'ctime': 1, 'mtime': 1, 'layer': ['layer0', 'common']})
+ volume['context'].create({'guid': '1', 'ctime': 1, 'mtime': 1, 'layer': ['layer1']})
+ volume['post'].create({'guid': '3', 'ctime': 3, 'mtime': 3, 'layer': 'layer3'})
+
+ volume['context'].update('0', {'tags': '0'})
+ volume['context'].update('1', {'tags': '1'})
+ volume['post'].update('3', {'tags': '3'})
+ self.utime('db', 0)
+
+ self.assertEqual(sorted([
+ {'resource': 'context'},
+ {'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
+ {'guid': '1', 'diff': {'tags': {'value': '1', 'mtime': 0}}},
+ {'resource': 'post'},
+ {'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
+ {'commit': [[4, 6]]},
+ ]),
+ sorted([i for i in model.diff(volume, toolkit.Sequence([[4, None]]))]))
+
+ self.assertEqual(sorted([
+ {'resource': 'context'},
+ {'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
+ {'guid': '1', 'diff': {'tags': {'value': '1', 'mtime': 0}}},
+ {'resource': 'post'},
+ {'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
+ {'commit': [[4, 6]]},
+ ]),
+ sorted([i for i in model.diff(volume, toolkit.Sequence([[4, None]]), layer='layer1')]))
+
+ self.assertEqual(sorted([
+ {'resource': 'context'},
+ {'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
+ {'resource': 'post'},
+ {'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
+ {'commit': [[4, 6]]},
+ ]),
+ sorted([i for i in model.diff(volume, toolkit.Sequence([[4, None]]), layer='layer2')]))
+
+ self.assertEqual(sorted([
+ {'resource': 'context'},
+ {'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
+ {'resource': 'post'},
+ {'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
+ {'commit': [[4, 6]]},
+ ]),
+ sorted([i for i in model.diff(volume, toolkit.Sequence([[4, None]]), layer='foo')]))
+
+ def test_Packages(self):
+ self.override(obs, 'get_repos', lambda: [
+ {'lsb_id': 'Gentoo', 'lsb_release': '2.1', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']},
+ {'lsb_id': 'Debian', 'lsb_release': '6.0', 'name': 'Debian-6.0', 'arches': ['x86']},
+ {'lsb_id': 'Debian', 'lsb_release': '7.0', 'name': 'Debian-7.0', 'arches': ['x86_64']},
+ ])
+ self.override(obs, 'resolve', lambda repo, arch, names: ['fake'])
+
+ volume = self.start_master([User, model.Context])
+ conn = http.Connection(api_url.value, http.SugarAuth(keyfile.value))
+
+ guid = conn.post(['context'], {
+ 'type': 'package',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ conn.put(['context', guid, 'releases', '*'], {
+ 'binary': ['pkg1.bin', 'pkg2.bin'],
+ 'devel': 'pkg3.devel',
+ })
+ self.assertEqual({
+ '*': {
+ 'seqno': 3,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']},
+ },
+ 'status': {
+ 'Gentoo-2.1': 'success',
+ 'Debian-6.0': 'success',
+ 'Debian-7.0': 'success',
+ },
+ },
+ volume['context'][guid]['releases'])
+
+ guid = conn.post(['context'], {
+ 'type': 'package',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ conn.put(['context', guid, 'releases', 'Gentoo'], {
+ 'binary': ['pkg1.bin', 'pkg2.bin'],
+ 'devel': 'pkg3.devel',
+ })
+ self.assertEqual({
+ 'Gentoo': {
+ 'seqno': 5,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']},
+ },
+ 'status': {
+ 'Gentoo-2.1': 'success',
+ },
+ },
+ volume['context'][guid]['releases'])
+
+ guid = conn.post(['context'], {
+ 'type': 'package',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ conn.put(['context', guid, 'releases', 'Debian-6.0'], {
+ 'binary': ['pkg1.bin', 'pkg2.bin'],
+ 'devel': 'pkg3.devel',
+ })
+ self.assertEqual({
+ 'Debian-6.0': {
+ 'seqno': 7,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']},
+ },
+ 'status': {
+ 'Debian-6.0': 'success',
+ },
+ },
+ volume['context'][guid]['releases'])
+
+ def test_UnresolvedPackages(self):
+ self.override(obs, 'get_repos', lambda: [
+ {'lsb_id': 'Gentoo', 'lsb_release': '2.1', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']},
+ ])
+ self.override(obs, 'resolve', lambda repo, arch, names: enforce(False, 'resolve failed'))
+
+ volume = self.start_master([User, model.Context])
+ conn = http.Connection(api_url.value, http.SugarAuth(keyfile.value))
+
+ guid = conn.post(['context'], {
+ 'type': 'package',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ conn.put(['context', guid, 'releases', '*'], {
+ 'binary': ['pkg1.bin', 'pkg2.bin'],
+ 'devel': 'pkg3.devel',
+ })
+ self.assertEqual({
+ '*': {
+ 'seqno': 3,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']},
+ },
+ 'status': {
+ 'Gentoo-2.1': 'resolve failed',
+ },
+ },
+ volume['context'][guid]['releases'])
+
+ def test_PackageOverrides(self):
+ self.override(obs, 'get_repos', lambda: [
+ {'lsb_id': 'Gentoo', 'lsb_release': '2.1', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']},
+ {'lsb_id': 'Debian', 'lsb_release': '6.0', 'name': 'Debian-6.0', 'arches': ['x86']},
+ {'lsb_id': 'Debian', 'lsb_release': '7.0', 'name': 'Debian-7.0', 'arches': ['x86_64']},
+ ])
+
+ volume = self.start_master([User, model.Context])
+ conn = http.Connection(api_url.value, http.SugarAuth(keyfile.value))
+ guid = conn.post(['context'], {
+ 'type': 'package',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ self.override(obs, 'resolve', lambda repo, arch, names: enforce(False, '1'))
+ conn.put(['context', guid, 'releases', '*'], {'binary': '1'})
+ self.assertEqual({
+ '*': {
+ 'seqno': 3,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['1']},
+ },
+ 'status': {
+ 'Gentoo-2.1': '1',
+ 'Debian-6.0': '1',
+ 'Debian-7.0': '1',
+ },
+ },
+ volume['context'][guid]['releases'])
+
+ self.override(obs, 'resolve', lambda repo, arch, names: enforce(False, '2'))
+ conn.put(['context', guid, 'releases', 'Debian'], {'binary': '2'})
+ self.assertEqual({
+ '*': {
+ 'seqno': 3,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['1']},
+ },
+ 'Debian': {
+ 'seqno': 4,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['2']},
+ },
+ 'status': {
+ 'Gentoo-2.1': '1',
+ 'Debian-6.0': '2',
+ 'Debian-7.0': '2',
+ },
+ },
+ volume['context'][guid]['releases'])
+
+ self.override(obs, 'resolve', lambda repo, arch, names: enforce(False, '3'))
+ conn.put(['context', guid, 'releases', 'Debian-6.0'], {'binary': '3'})
+ self.assertEqual({
+ '*': {
+ 'seqno': 3,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['1']},
+ },
+ 'Debian': {
+ 'seqno': 4,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['2']},
+ },
+ 'Debian-6.0': {
+ 'seqno': 5,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['3']},
+ },
+ 'status': {
+ 'Gentoo-2.1': '1',
+ 'Debian-6.0': '3',
+ 'Debian-7.0': '2',
+ },
+ },
+ volume['context'][guid]['releases'])
+
+ self.override(obs, 'resolve', lambda repo, arch, names: enforce(False, '4'))
+ conn.put(['context', guid, 'releases', 'Debian'], {'binary': '4'})
+ self.assertEqual({
+ '*': {
+ 'seqno': 3,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['1']},
+ },
+ 'Debian': {
+ 'seqno': 6,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['4']},
+ },
+ 'Debian-6.0': {
+ 'seqno': 5,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {'binary': ['3']},
+ },
+ 'status': {
+ 'Gentoo-2.1': '1',
+ 'Debian-6.0': '3',
+ 'Debian-7.0': '4',
+ },
+ },
+ volume['context'][guid]['releases'])
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/node/node.py b/tests/units/node/node.py
index d8f00ec..0058918 100755
--- a/tests/units/node/node.py
+++ b/tests/units/node/node.py
@@ -16,17 +16,17 @@ from os.path import exists, join
from __init__ import tests
from sugar_network import db, node, model, client
-from sugar_network.client import Connection, keyfile
+from sugar_network.db import files
+from sugar_network.client import Connection, keyfile, api_url
from sugar_network.toolkit import http, coroutine
from sugar_network.toolkit.rrd import Rrd
-from sugar_network.node import stats_user, stats_node, obs
-from sugar_network.node.routes import NodeRoutes, generate_node_stats
+from sugar_network.node import stats_user
+from sugar_network.node.routes import NodeRoutes
from sugar_network.node.master import MasterRoutes
from sugar_network.model.user import User
from sugar_network.model.context import Context
-from sugar_network.model.release import Release
from sugar_network.model.user import User
-from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, Blob, ACL, route
+from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, ACL, route
from sugar_network.toolkit import http
@@ -40,7 +40,7 @@ class NodeTest(tests.Test):
def test_UserStats(self):
volume = db.Volume('db', model.RESOURCES)
- cp = NodeRoutes('guid', volume)
+ cp = NodeRoutes('guid', volume=volume)
call(cp, method='POST', document='user', principal=tests.UID, content={
'name': 'user',
@@ -100,69 +100,10 @@ class NodeTest(tests.Test):
},
call(cp, method='GET', cmd='stats-info', document='user', guid=tests.UID, principal=tests.UID))
- def test_NodeStats(self):
- stats_node.stats_node.value = True
- stats_node.stats_node_rras.value = ['RRA:AVERAGE:0.5:1:60', 'RRA:AVERAGE:0.5:3:60']
- rrd = Rrd('stats/node', stats_node.stats_node_step.value, stats_node.stats_node_rras.value)
-
- ts = int(time.time()) / 3 * 3
- for i in range(10):
- rrd['user'].put({'total': i}, ts + i)
-
- volume = db.Volume('db', model.RESOURCES)
- cp = NodeRoutes('guid', volume)
-
- self.assertEqual({
- 'user': [
- (ts + 0, {'total': 0.0}),
- (ts + 1, {'total': 1.0}),
- (ts + 2, {'total': 2.0}),
- (ts + 3, {'total': 3.0}),
- ],
- },
- call(cp, method='GET', cmd='stats', source='user.total', start=ts, end=ts + 3, records=4))
-
- self.assertEqual({
- 'user': [
- (ts + 0, {'total': 0.0}),
- (ts + 3, {'total': 2.0}),
- (ts + 6, {'total': 5.0}),
- (ts + 9, {'total': 8.0}),
- ],
- },
- call(cp, method='GET', cmd='stats', source='user.total', start=ts, end=ts + 9, records=3))
-
- def test_NodeStatsDefaults(self):
- stats_node.stats_node.value = True
- rrd = Rrd('stats/node', stats_node.stats_node_step.value, stats_node.stats_node_rras.value)
-
- ts = int(time.time())
- for i in range(10):
- rrd['user'].put({'total': i}, ts + i)
-
- volume = db.Volume('db', model.RESOURCES)
- cp = NodeRoutes('guid', volume)
-
- self.assertEqual({
- 'user': [
- (ts + 0, {'total': 0.0}),
- (ts + 1, {'total': 1.0}),
- (ts + 2, {'total': 2.0}),
- (ts + 3, {'total': 3.0}),
- (ts + 4, {'total': 4.0}),
- (ts + 5, {'total': 5.0}),
- (ts + 6, {'total': 6.0}),
- (ts + 7, {'total': 7.0}),
- (ts + 8, {'total': 8.0}),
- (ts + 9, {'total': 9.0}),
- ],
- },
- call(cp, method='GET', cmd='stats', source='user.total'))
-
def test_HandleDeletes(self):
volume = db.Volume('db', model.RESOURCES)
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- cp = NodeRoutes('guid', volume)
+ cp = NodeRoutes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
guid = call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
@@ -192,33 +133,41 @@ class NodeTest(tests.Test):
coroutine.dispatch()
self.assertRaises(http.NotFound, call, cp, method='GET', document='context', guid=guid, reply=['guid', 'title'])
self.assertEqual(['deleted'], volume['context'].get(guid)['layer'])
- self.assertEqual({'event': 'delete', 'resource': 'context', 'guid': guid}, events[0])
- def test_SimulateDeleteEvents(self):
- volume = db.Volume('db', model.RESOURCES)
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- cp = NodeRoutes('guid', volume)
+ def test_DeletedRestoredHandlers(self):
+ trigger = []
- guid = call(cp, method='POST', document='context', principal=tests.UID, content={
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
+ class TestDocument(db.Resource):
- def subscribe():
- for event in cp.subscribe():
- events.append(event)
- events = []
- coroutine.spawn(subscribe)
- coroutine.dispatch()
+ def deleted(self):
+ trigger.append(False)
- call(cp, method='PUT', document='context', guid=guid, principal=tests.UID, content={'layer': ['deleted']})
- coroutine.dispatch()
- self.assertEqual({'event': 'delete', 'resource': 'context', 'guid': guid}, events[0])
+ def restored(self):
+ trigger.append(True)
+
+ volume = self.start_master([TestDocument, User])
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
+
+ guid = conn.post(['testdocument'], {})
+ self.assertEqual([], trigger)
+
+ conn.put(['testdocument', guid, 'layer'], ['deleted'])
+ self.assertEqual([False], trigger)
+
+ conn.put(['testdocument', guid, 'layer'], [])
+ self.assertEqual([False, True], trigger)
+
+ conn.put(['testdocument', guid, 'layer'], ['bar'])
+ self.assertEqual([False, True], trigger)
+
+ conn.put(['testdocument', guid, 'layer'], ['deleted'])
+ self.assertEqual([False, True, False], trigger)
+
+ conn.put(['testdocument', guid, 'layer'], ['deleted', 'foo'])
+ self.assertEqual([False, True, False], trigger)
def test_RegisterUser(self):
- cp = NodeRoutes('guid', db.Volume('db', [User]))
+ cp = NodeRoutes('guid', volume=db.Volume('db', [User]))
guid = call(cp, method='POST', document='user', principal=tests.UID2, content={
'name': 'user',
@@ -229,7 +178,7 @@ class NodeTest(tests.Test):
def test_UnauthorizedCommands(self):
volume = db.Volume('db', model.RESOURCES)
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
class Routes(NodeRoutes):
@@ -244,7 +193,7 @@ class NodeTest(tests.Test):
class Document(db.Resource):
pass
- cp = Routes('guid', db.Volume('db', [User, Document]))
+ cp = Routes('guid', volume=db.Volume('db', [User, Document]))
guid = call(cp, method='POST', document='document', principal=tests.UID, content={})
self.assertRaises(http.Unauthorized, call, cp, method='GET', cmd='probe1', document='document', guid=guid)
@@ -267,8 +216,8 @@ class NodeTest(tests.Test):
pass
volume = db.Volume('db', [User, Document])
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- cp = Routes('guid', volume)
+ cp = Routes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
guid = call(cp, method='POST', document='document', principal=tests.UID, content={})
@@ -278,7 +227,7 @@ class NodeTest(tests.Test):
call(cp, method='GET', cmd='probe2', document='document', guid=guid)
def test_ForbiddenCommandsForUserResource(self):
- cp = NodeRoutes('guid', db.Volume('db', [User]))
+ cp = NodeRoutes('guid', volume=db.Volume('db', [User]))
call(cp, method='POST', document='user', principal=tests.UID2, content={
'name': 'user1',
@@ -304,9 +253,9 @@ class NodeTest(tests.Test):
return 'ok'
volume = db.Volume('db', [User])
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- volume['user'].create({'guid': tests.UID2, 'name': 'test', 'pubkey': {'blob': StringIO(tests.PUBKEY2)}})
- cp = Routes('guid', volume)
+ cp = Routes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
+ volume['user'].create({'guid': tests.UID2, 'name': 'test', 'pubkey': tests.PUBKEY2})
self.assertRaises(http.Forbidden, call, cp, method='PROBE')
self.assertRaises(http.Forbidden, call, cp, method='PROBE', principal=tests.UID2)
@@ -321,9 +270,9 @@ class NodeTest(tests.Test):
return value
volume = db.Volume('db', [User, Document])
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- volume['user'].create({'guid': tests.UID2, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY2)}})
- cp = NodeRoutes('guid', volume)
+ cp = NodeRoutes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
+ volume['user'].create({'guid': tests.UID2, 'name': 'user', 'pubkey': tests.PUBKEY2})
guid = call(cp, method='POST', document='document', principal=tests.UID, content={'prop': '1'})
self.assertRaises(http.Forbidden, call, cp, 'PUT', document='document', guid=guid, content={'prop': '2'}, principal=tests.UID2)
@@ -342,9 +291,9 @@ class NodeTest(tests.Test):
return value
volume = db.Volume('db', [User, Document])
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- volume['user'].create({'guid': tests.UID2, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY2)}})
- cp = NodeRoutes('guid', volume)
+ cp = NodeRoutes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
+ volume['user'].create({'guid': tests.UID2, 'name': 'user', 'pubkey': tests.PUBKEY2})
guid = call(cp, method='POST', document='document', principal=tests.UID, content={'prop': '1'})
@@ -363,8 +312,8 @@ class NodeTest(tests.Test):
pass
volume = db.Volume('db', [User])
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- cp = Routes('guid', volume)
+ cp = Routes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
self.assertRaises(http.Forbidden, call, cp, 'PROBE', principal=tests.UID)
self.touch(('authorization.conf', [
@@ -386,7 +335,7 @@ class NodeTest(tests.Test):
pass
volume = db.Volume('db', [User])
- cp = Routes('guid', volume)
+ cp = Routes('guid', volume=volume)
self.assertRaises(http.Unauthorized, call, cp, 'PROBE1')
self.assertRaises(http.Forbidden, call, cp, 'PROBE2')
@@ -401,8 +350,8 @@ class NodeTest(tests.Test):
def test_SetUser(self):
volume = db.Volume('db', model.RESOURCES)
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- cp = NodeRoutes('guid', volume)
+ cp = NodeRoutes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
guid = call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
@@ -416,8 +365,8 @@ class NodeTest(tests.Test):
def test_find_MaxLimit(self):
volume = db.Volume('db', model.RESOURCES)
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- cp = NodeRoutes('guid', volume)
+ cp = NodeRoutes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
@@ -438,23 +387,26 @@ class NodeTest(tests.Test):
'description': 'description',
})
- node.find_limit.value = 3
+ cp._find_limit = 3
self.assertEqual(3, len(call(cp, method='GET', document='context', limit=1024)['result']))
- node.find_limit.value = 2
+ cp._find_limit = 2
self.assertEqual(2, len(call(cp, method='GET', document='context', limit=1024)['result']))
- node.find_limit.value = 1
+ cp._find_limit = 1
self.assertEqual(1, len(call(cp, method='GET', document='context', limit=1024)['result']))
def test_DeletedDocuments(self):
volume = db.Volume('db', model.RESOURCES)
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- cp = NodeRoutes('guid', volume)
+ cp = NodeRoutes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
guid = call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
'title': 'title1',
'summary': 'summary',
'description': 'description',
+ 'artifact_icon': '',
+ 'icon': '',
+ 'logo': '',
})
call(cp, method='GET', document='context', guid=guid)
@@ -468,8 +420,8 @@ class NodeTest(tests.Test):
def test_CreateGUID(self):
# TODO Temporal security hole, see TODO
volume = db.Volume('db', model.RESOURCES)
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- cp = NodeRoutes('guid', volume)
+ cp = NodeRoutes('guid', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
call(cp, method='POST', document='context', principal=tests.UID, content={
'guid': 'foo',
'type': 'activity',
@@ -483,10 +435,10 @@ class NodeTest(tests.Test):
def test_CreateMalformedGUID(self):
volume = db.Volume('db', model.RESOURCES)
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
cp = MasterRoutes('guid', volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
- self.assertRaises(RuntimeError, call, cp, method='POST', document='context', principal=tests.UID, content={
+ self.assertRaises(http.BadRequest, call, cp, method='POST', document='context', principal=tests.UID, content={
'guid': '!?',
'type': 'activity',
'title': 'title',
@@ -496,8 +448,8 @@ class NodeTest(tests.Test):
def test_FailOnExistedGUID(self):
volume = db.Volume('db', model.RESOURCES)
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
cp = MasterRoutes('guid', volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
guid = call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
@@ -506,7 +458,7 @@ class NodeTest(tests.Test):
'description': 'description',
})
- self.assertRaises(RuntimeError, call, cp, method='POST', document='context', principal=tests.UID, content={
+ self.assertRaises(http.BadRequest, call, cp, method='POST', document='context', principal=tests.UID, content={
'guid': guid,
'type': 'activity',
'title': 'title',
@@ -566,139 +518,9 @@ class NodeTest(tests.Test):
def test_Clone(self):
volume = self.start_master()
- client = Connection(auth=http.SugarAuth(keyfile.value))
+ client = http.Connection(api_url.value, http.SugarAuth(keyfile.value))
- context = client.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl1 = client.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- blob1 = self.zips(('topdir/probe', 'probe1'))
- volume['release'].update(impl1, {'data': {
- 'blob': StringIO(blob1),
- 'spec': {
- '*-*': {
- 'requires': {
- 'dep1': {},
- },
- },
- },
- }})
- impl2 = client.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '2',
- 'stability': 'stable',
- 'notes': '',
- })
- blob2 = self.zips(('topdir/probe', 'probe2'))
- volume['release'].update(impl2, {'data': {
- 'blob': StringIO(blob2),
- 'spec': {
- '*-*': {
- 'requires': {
- 'dep2': {'restrictions': [[None, '2']]},
- 'dep3': {},
- },
- },
- },
- }})
- impl3 = client.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '3',
- 'stability': 'stable',
- 'notes': '',
- })
- blob3 = self.zips(('topdir/probe', 'probe3'))
- volume['release'].update(impl3, {'data': {
- 'blob': StringIO(blob3),
- 'spec': {
- '*-*': {
- 'requires': {
- 'dep2': {'restrictions': [['2', None]]},
- },
- },
- },
- }})
- impl4 = client.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '4',
- 'stability': 'developer',
- 'notes': '',
- })
- blob4 = self.zips(('topdir/probe', 'probe4'))
- volume['release'].update(impl4, {'data': {
- 'blob': StringIO(blob4),
- 'spec': {
- '*-*': {
- 'requires': {},
- },
- },
- }})
-
- self.assertEqual(blob3, client.get(['context', context], cmd='clone'))
- self.assertEqual(blob4, client.get(['context', context], cmd='clone', stability='developer'))
- self.assertEqual(blob1, client.get(['context', context], cmd='clone', version='1'))
-
- self.assertEqual(blob1, client.get(['context', context], cmd='clone', requires='dep1'))
- self.assertEqual(blob3, client.get(['context', context], cmd='clone', requires='dep2'))
- self.assertEqual(blob2, client.get(['context', context], cmd='clone', requires='dep2=1'))
- self.assertEqual(blob3, client.get(['context', context], cmd='clone', requires='dep2=2'))
- self.assertEqual(blob2, client.get(['context', context], cmd='clone', requires='dep3'))
-
- self.assertRaises(http.NotFound, client.get, ['context', context], cmd='clone', requires='dep4')
- self.assertRaises(http.NotFound, client.get, ['context', context], cmd='clone', stability='foo')
-
- response = Response()
- client.call(Request(method='GET', path=['context', context], cmd='clone'), response)
- self.assertEqual({
- 'context': context,
- 'stability': 'stable',
- 'guid': impl3,
- 'version': '3',
- 'license': ['GPLv3+'],
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl3).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'blob_size': len(blob3),
- 'spec': {
- '*-*': {
- 'requires': {
- 'dep2': {
- 'restrictions': [['2', None]],
- },
- },
- },
- },
- },
- },
- response.meta)
-
- def test_release(self):
- volume = self.start_master()
- conn = Connection(auth=http.SugarAuth(keyfile.value))
-
- conn.post(['context'], {
- 'guid': 'bundle_id',
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- activity_info = '\n'.join([
+ blob1 = self.zips(('topdir/activity/activity.info', '\n'.join([
'[Activity]',
'name = TestActivitry',
'bundle_id = bundle_id',
@@ -706,42 +528,12 @@ class NodeTest(tests.Test):
'icon = icon',
'activity_version = 1',
'license = Public Domain',
- 'stability = developer',
- 'requires = sugar>=0.88; dep'
- ])
- changelog = "LOG"
- bundle1 = self.zips(
- ('topdir/activity/activity.info', activity_info),
- ('topdir/CHANGELOG', changelog),
- )
- guid1 = json.load(conn.request('POST', ['release'], bundle1, params={'cmd': 'submit'}).raw)
-
- impl = volume['release'].get(guid1)
- self.assertEqual('bundle_id', impl['context'])
- self.assertEqual('1', impl['version'])
- self.assertEqual('developer', impl['stability'])
- self.assertEqual(['Public Domain'], impl['license'])
- self.assertEqual('developer', impl['stability'])
- self.assertEqual({'en-us': changelog}, impl['notes'])
- assert impl['ctime'] > 0
- assert impl['mtime'] > 0
- self.assertEqual({tests.UID: {'role': 3, 'name': 'f470db873b6a35903aca1f2492188e1c4b9ffc42', 'order': 0}}, impl['author'])
-
- data = impl.meta('data')
- self.assertEqual({
- '*-*': {
- 'commands': {'activity': {'exec': 'true'}},
- 'requires': {'dep': {}, 'sugar': {'restrictions': [['0.88', None]]}},
- },
- },
- data['spec'])
-
- self.assertEqual('application/vnd.olpc-sugar', data['mime_type'])
- self.assertEqual(len(bundle1), data['blob_size'])
- self.assertEqual(len(activity_info) + len(changelog), data.get('unpack_size'))
- self.assertEqual(bundle1, conn.get(['context', 'bundle_id'], cmd='clone', stability='developer'))
+ 'requires = dep1',
+ 'stability = stable',
+ ])))
+ release1 = json.load(client.request('POST', ['context'], blob1, params={'cmd': 'submit', 'initial': True}).raw)
- activity_info = '\n'.join([
+ blob2 = self.zips(('topdir/activity/activity.info', '\n'.join([
'[Activity]',
'name = TestActivitry',
'bundle_id = bundle_id',
@@ -749,606 +541,152 @@ class NodeTest(tests.Test):
'icon = icon',
'activity_version = 2',
'license = Public Domain',
+ 'requires = dep2 < 3; dep3',
'stability = stable',
- ])
- bundle2 = self.zips(('topdir/activity/activity.info', activity_info))
- guid2 = json.load(conn.request('POST', ['release'], bundle2, params={'cmd': 'submit'}).raw)
-
- self.assertEqual('1', volume['release'].get(guid1)['version'])
- self.assertEqual(['origin'], volume['release'].get(guid1)['layer'])
- self.assertEqual('2', volume['release'].get(guid2)['version'])
- self.assertEqual(['origin'], volume['release'].get(guid2)['layer'])
- self.assertEqual(bundle2, conn.get(['context', 'bundle_id'], cmd='clone'))
+ ])))
+ release2 = json.load(client.request('POST', ['context'], blob2, params={'cmd': 'submit'}).raw)
- activity_info = '\n'.join([
+ blob3 = self.zips(('topdir/activity/activity.info', '\n'.join([
'[Activity]',
'name = TestActivitry',
'bundle_id = bundle_id',
'exec = true',
'icon = icon',
- 'activity_version = 1',
+ 'activity_version = 3',
'license = Public Domain',
+ 'requires = dep2 >= 2',
'stability = stable',
- ])
- bundle3 = self.zips(('topdir/activity/activity.info', activity_info))
- guid3 = json.load(conn.request('POST', ['release'], bundle3, params={'cmd': 'submit'}).raw)
-
- self.assertEqual('1', volume['release'].get(guid1)['version'])
- self.assertEqual(sorted(['origin', 'deleted']), sorted(volume['release'].get(guid1)['layer']))
- self.assertEqual('2', volume['release'].get(guid2)['version'])
- self.assertEqual(['origin'], volume['release'].get(guid2)['layer'])
- self.assertEqual('1', volume['release'].get(guid3)['version'])
- self.assertEqual(['origin'], volume['release'].get(guid3)['layer'])
- self.assertEqual(bundle2, conn.get(['context', 'bundle_id'], cmd='clone'))
+ ])))
+ release3 = json.load(client.request('POST', ['context'], blob3, params={'cmd': 'submit'}).raw)
- activity_info = '\n'.join([
+ blob4 = self.zips(('topdir/activity/activity.info', '\n'.join([
'[Activity]',
'name = TestActivitry',
'bundle_id = bundle_id',
'exec = true',
'icon = icon',
- 'activity_version = 2',
+ 'activity_version = 4',
'license = Public Domain',
- 'stability = buggy',
- ])
- bundle4 = self.zips(('topdir/activity/activity.info', activity_info))
- guid4 = json.load(conn.request('POST', ['release'], bundle4, params={'cmd': 'submit'}).raw)
-
- self.assertEqual('1', volume['release'].get(guid1)['version'])
- self.assertEqual(sorted(['origin', 'deleted']), sorted(volume['release'].get(guid1)['layer']))
- self.assertEqual('2', volume['release'].get(guid2)['version'])
- self.assertEqual(sorted(['origin', 'deleted']), sorted(volume['release'].get(guid2)['layer']))
- self.assertEqual('1', volume['release'].get(guid3)['version'])
- self.assertEqual(['origin'], volume['release'].get(guid3)['layer'])
- self.assertEqual('2', volume['release'].get(guid4)['version'])
- self.assertEqual(['origin'], volume['release'].get(guid4)['layer'])
- self.assertEqual(bundle3, conn.get(['context', 'bundle_id'], cmd='clone'))
-
- def test_release_UpdateContext(self):
- volume = self.start_master()
- conn = Connection(auth=http.SugarAuth(keyfile.value))
+ 'stability = developer',
+ ])))
+ release4 = json.load(client.request('POST', ['context'], blob4, params={'cmd': 'submit'}).raw)
- conn.post(['context'], {
- 'guid': 'org.laptop.ImageViewerActivity',
- 'type': 'activity',
- 'title': {'en': ''},
- 'summary': {'en': ''},
- 'description': {'en': ''},
- })
- svg = '\n'.join([
- '<?xml version="1.0" encoding="UTF-8"?>',
- '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [',
- ' <!ENTITY fill_color "#123456">',
- ' <!ENTITY stroke_color "#123456">',
- ']>',
- '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">',
- ' <rect x="3" y="7" width="44" height="36" style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:3"/>',
- ' <polyline points="15,7 25,1 35,7" style="fill:none;;stroke:&stroke_color;;stroke-width:1.25"/>',
- ' <circle cx="14" cy="19" r="4.5" style="fill:&stroke_color;;stroke:&stroke_color;;stroke-width:1.5"/>',
- ' <polyline points="3,36 16,32 26,35" style="fill:none;;stroke:&stroke_color;;stroke-width:2.5"/>',
- ' <polyline points="15,43 37,28 47,34 47,43" style="fill:&stroke_color;;stroke:&stroke_color;;stroke-width:3"/>',
- ' <polyline points="22,41.5 35,30 27,41.5" style="fill:&fill_color;;stroke:none;;stroke-width:0"/>',
- ' <polyline points="26,23 28,25 30,23" style="fill:none;;stroke:&stroke_color;;stroke-width:.9"/>',
- ' <polyline points="31.2,20 33.5,17.7 35.8,20" style="fill:none;;stroke:&stroke_color;;stroke-width:1"/>',
- ' <polyline points="36,13 38.5,15.5 41,13" style="fill:none;;stroke:&stroke_color;;stroke-width:1"/>',
- '</svg>',
- ])
- bundle = self.zips(
- ('ImageViewer.activity/activity/activity.info', '\n'.join([
- '[Activity]',
- 'bundle_id = org.laptop.ImageViewerActivity',
- 'name = Image Viewer',
- 'summary = The Image Viewer activity is a simple and fast image viewer tool',
- 'description = It has features one would expect of a standard image viewer, like zoom, rotate, etc.',
- 'homepage = http://wiki.sugarlabs.org/go/Activities/Image_Viewer',
- 'activity_version = 22',
- 'license = GPLv2+',
- 'icon = activity-imageviewer',
- 'exec = true',
- 'mime_types = image/bmp;image/gif',
- ])),
- ('ImageViewer.activity/locale/ru/LC_MESSAGES/org.laptop.ImageViewerActivity.mo',
- base64.b64decode('3hIElQAAAAAMAAAAHAAAAHwAAAARAAAA3AAAAAAAAAAgAQAADwAAACEBAAAOAAAAMQEAAA0AAABAAQAACgAAAE4BAAAMAAAAWQEAAA0AAABmAQAAJwAAAHQBAAAUAAAAnAEAABAAAACxAQAABwAAAMIBAAAIAAAAygEAANEBAADTAQAAIQAAAKUDAAATAAAAxwMAABwAAADbAwAAFwAAAPgDAAAhAAAAEAQAAB0AAAAyBAAAQAAAAFAEAAA9AAAAkQQAADUAAADPBAAAFAAAAAUFAAAQAAAAGgUAAAEAAAACAAAABwAAAAAAAAADAAAAAAAAAAwAAAAJAAAAAAAAAAoAAAAEAAAAAAAAAAAAAAALAAAABgAAAAgAAAAFAAAAAENob29zZSBkb2N1bWVudABEb3dubG9hZGluZy4uLgBGaXQgdG8gd2luZG93AEZ1bGxzY3JlZW4ASW1hZ2UgVmlld2VyAE9yaWdpbmFsIHNpemUAUmV0cmlldmluZyBzaGFyZWQgaW1hZ2UsIHBsZWFzZSB3YWl0Li4uAFJvdGF0ZSBhbnRpY2xvY2t3aXNlAFJvdGF0ZSBjbG9ja3dpc2UAWm9vbSBpbgBab29tIG91dABQcm9qZWN0LUlkLVZlcnNpb246IFBBQ0tBR0UgVkVSU0lPTgpSZXBvcnQtTXNnaWQtQnVncy1UbzogClBPVC1DcmVhdGlvbi1EYXRlOiAyMDEyLTA5LTI3IDE0OjU3LTA0MDAKUE8tUmV2aXNpb24tRGF0ZTogMjAxMC0wOS0yMiAxMzo1MCswMjAwCkxhc3QtVHJhbnNsYXRvcjoga3JvbTlyYSA8a3JvbTlyYUBnbWFpbC5jb20+Ckxhbmd1YWdlLVRlYW06IExBTkdVQUdFIDxMTEBsaS5vcmc+Ckxhbmd1YWdlOiAKTUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PVVURi04CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IDhiaXQKUGx1cmFsLUZvcm1zOiBucGx1cmFscz0zOyBwbHVyYWw9KG4lMTA9PTEgJiYgbiUxMDAhPTExID8gMCA6IG4lMTA+PTIgJiYgbiUxMDw9NCAmJiAobiUxMDA8MTAgfHwgbiUxMDA+PTIwKSA/IDEgOiAyKTsKWC1HZW5lcmF0b3I6IFBvb3RsZSAyLjAuMwoA0JLRi9Cx0LXRgNC40YLQtSDQtNC+0LrRg9C80LXQvdGCANCX0LDQs9GA0YPQt9C60LAuLi4A0KPQvNC10YHRgtC40YLRjCDQsiDQvtC60L3QtQDQn9C+0LvQvdGL0Lkg0Y3QutGA0LDQvQDQn9GA0L7RgdC80L7RgtGAINC60LDRgNGC0LjQvdC+0LoA0JjRgdGC0LjQvdC90YvQuSDRgNCw0LfQvNC10YAA0J/QvtC70YPRh9C10L3QuNC1INC40LfQvtCx0YDQsNC20LXQvdC40LksINC/0L7QtNC+0LbQtNC40YLQtS4uLgDQn9C+0LLQtdGA0L3Rg9GC0Ywg0L/RgNC+0YLQuNCyINGH0LDRgdC+0LLQvtC5INGB0YLRgNC10LvQutC4ANCf0L7QstC10YDQvdGD0YLRjCDQv9C+INGH0LDRgdC+0LLQvtC5INGB0YLRgNC10LvQutC1ANCf0YDQuNCx0LvQuNC30LjRgtGMANCe0YLQtNCw0LvQuNGC0YwA')),
- ('ImageViewer.activity/activity/activity-imageviewer.svg', svg),
- )
- impl = json.load(conn.request('POST', ['release'], bundle, params={'cmd': 'submit'}).raw)
+ assert blob3 == client.get(['context', 'bundle_id'], cmd='clone')
+ assert blob4 == client.get(['context', 'bundle_id'], cmd='clone', stability='developer')
+ assert blob1 == client.get(['context', 'bundle_id'], cmd='clone', version='1')
- context = volume['context'].get('org.laptop.ImageViewerActivity')
- self.assertEqual({
- 'en': 'Image Viewer',
- 'ru': u'Просмотр картинок',
- },
- context['title'])
- self.assertEqual({
- 'en': 'The Image Viewer activity is a simple and fast image viewer tool',
- },
- context['summary'])
- self.assertEqual({
- 'en': 'It has features one would expect of a standard image viewer, like zoom, rotate, etc.',
- },
- context['description'])
- self.assertEqual(svg, file(context['artifact_icon']['blob']).read())
- assert 'blob' in context['icon']
- assert 'blob' in context['logo']
- self.assertEqual('http://wiki.sugarlabs.org/go/Activities/Image_Viewer', context['homepage'])
- self.assertEqual(['image/bmp', 'image/gif'], context['mime_types'])
-
- def test_release_CreateContext(self):
- volume = self.start_master()
- conn = Connection(auth=http.SugarAuth(keyfile.value))
-
- bundle = self.zips(
- ('ImageViewer.activity/activity/activity.info', '\n'.join([
- '[Activity]',
- 'bundle_id = org.laptop.ImageViewerActivity',
- 'name = Image Viewer',
- 'summary = The Image Viewer activity is a simple and fast image viewer tool',
- 'description = It has features one would expect of a standard image viewer, like zoom, rotate, etc.',
- 'homepage = http://wiki.sugarlabs.org/go/Activities/Image_Viewer',
- 'activity_version = 22',
- 'license = GPLv2+',
- 'icon = activity-imageviewer',
- 'exec = true',
- 'mime_types = image/bmp;image/gif',
- ])),
- ('ImageViewer.activity/activity/activity-imageviewer.svg', ''),
- )
- self.assertRaises(http.NotFound, conn.request, 'POST', ['release'], bundle, params={'cmd': 'submit'})
- impl = json.load(conn.request('POST', ['release'], bundle, params={'cmd': 'submit', 'initial': 1}).raw)
-
- context = volume['context'].get('org.laptop.ImageViewerActivity')
- self.assertEqual({'en': 'Image Viewer'}, context['title'])
- self.assertEqual({'en': 'The Image Viewer activity is a simple and fast image viewer tool'}, context['summary'])
- self.assertEqual({'en': 'It has features one would expect of a standard image viewer, like zoom, rotate, etc.'}, context['description'])
- self.assertEqual('http://wiki.sugarlabs.org/go/Activities/Image_Viewer', context['homepage'])
- self.assertEqual(['image/bmp', 'image/gif'], context['mime_types'])
- assert context['ctime'] > 0
- assert context['mtime'] > 0
- self.assertEqual({tests.UID: {'role': 3, 'name': 'f470db873b6a35903aca1f2492188e1c4b9ffc42', 'order': 0}}, context['author'])
-
- def test_release_ByNonAuthors(self):
- volume = self.start_master()
- bundle = self.zips(
- ('ImageViewer.activity/activity/activity.info', '\n'.join([
- '[Activity]',
- 'bundle_id = org.laptop.ImageViewerActivity',
- 'name = Image Viewer',
- 'activity_version = 1',
- 'license = GPLv2+',
- 'icon = activity-imageviewer',
- 'exec = true',
- ])),
- ('ImageViewer.activity/activity/activity-imageviewer.svg', ''),
- )
+ assert blob1 == client.get(['context', 'bundle_id'], cmd='clone', requires='dep1')
+ assert blob3 == client.get(['context', 'bundle_id'], cmd='clone', requires='dep2')
+ assert blob2 == client.get(['context', 'bundle_id'], cmd='clone', requires='dep2=1')
+ assert blob3 == client.get(['context', 'bundle_id'], cmd='clone', requires='dep2=2')
+ assert blob2 == client.get(['context', 'bundle_id'], cmd='clone', requires='dep3')
- conn = Connection(auth=http.SugarAuth(join(tests.root, 'data', tests.UID)))
- impl1 = json.load(conn.request('POST', ['release'], bundle, params={'cmd': 'submit', 'initial': 1}).raw)
- impl2 = json.load(conn.request('POST', ['release'], bundle, params={'cmd': 'submit'}).raw)
- self.assertEqual(sorted(['origin', 'deleted']), sorted(volume['release'].get(impl1)['layer']))
- self.assertEqual(['origin'], volume['release'].get(impl2)['layer'])
+ self.assertRaises(http.NotFound, client.get, ['context', 'bundle_id'], cmd='clone', requires='dep4')
+ self.assertRaises(http.NotFound, client.get, ['context', 'bundle_id'], cmd='clone', stability='foo')
- conn = Connection(auth=http.SugarAuth(join(tests.root, 'data', tests.UID2)))
- conn.get(cmd='whoami')
- impl3 = json.load(conn.request('POST', ['release'], bundle, params={'cmd': 'submit'}).raw)
- self.assertEqual(sorted(['origin', 'deleted']), sorted(volume['release'].get(impl1)['layer']))
- self.assertEqual(sorted(['origin', 'deleted']), sorted(volume['release'].get(impl2)['layer']))
- self.assertEqual([], volume['release'].get(impl3)['layer'])
+ response = Response()
+ client.call(Request(method='GET', path=['context', 'bundle_id'], cmd='clone'), response)
+ announce = next(volume['post'].find(query='3', limit=1)[0]).guid
+ self.assertEqual({
+ 'license': ['Public Domain'],
+ 'unpack_size': 162,
+ 'stability': 'stable',
+ 'version': '3',
+ 'release': [[3], 0],
+ 'announce': announce,
+ 'requires': ['dep2-2'],
+ 'spec': {
+ '*-*': {
+ 'commands': {'activity': {'exec': u'true'}},
+ 'requires': {'dep2': {'restrictions': [['2', None]]}},
+ 'bundle': str(hash(blob3)),
+ },
+ },
+ }, response.meta)
- def test_release_PopulateRequires(self):
+ def test_release(self):
volume = self.start_master()
conn = Connection(auth=http.SugarAuth(keyfile.value))
+ activity_info = '\n'.join([
+ '[Activity]',
+ 'name = TestActivitry',
+ 'bundle_id = bundle_id',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ 'stability = developer',
+ ])
+ changelog = "LOG"
bundle = self.zips(
- ('ImageViewer.activity/activity/activity.info', '\n'.join([
- '[Activity]',
- 'bundle_id = org.laptop.ImageViewerActivity',
- 'name = Image Viewer',
- 'activity_version = 22',
- 'license = GPLv2+',
- 'icon = activity-imageviewer',
- 'exec = true',
- 'requires = dep1, dep2<10, dep3<=20, dep4>30, dep5>=40, dep6>5<7, dep7>=1<=3',
- ])),
- ('ImageViewer.activity/activity/activity-imageviewer.svg', ''),
+ ('topdir/activity/activity.info', activity_info),
+ ('topdir/CHANGELOG', changelog),
)
- self.assertRaises(http.NotFound, conn.request, 'POST', ['release'], bundle, params={'cmd': 'submit'})
- impl = json.load(conn.request('POST', ['release'], bundle, params={'cmd': 'submit', 'initial': 1}).raw)
-
- self.assertEqual(
- sorted([
- 'dep1', 'dep2', 'dep3', 'dep4-31', 'dep5-40',
- 'dep6-6',
- 'dep7-1', 'dep7-2', 'dep7-3',
- ]),
- sorted(volume['release'].get(impl)['requires']))
-
- def test_generate_node_stats_Posts(self):
- node.stats_root.value = 'stats'
- stats_node.stats_node.value = True
- stats_node.stats_node_rras.value = ['RRA:AVERAGE:0.5:1:10', 'RRA:AVERAGE:0.5:10:10']
- volume = db.Volume('db', model.RESOURCES)
-
- ts = 1000000000
-
- volume['user'].create({
- 'guid': 'user_1',
- 'ctime': ts + 1,
- 'mtime': ts + 1,
- 'layer': [],
- 'name': '',
- })
- volume['context'].create({
- 'guid': 'context_1',
- 'ctime': ts + 1,
- 'mtime': ts + 1,
- 'layer': [],
- 'type': 'activity',
- 'title': '',
- 'summary': '',
- 'description': '',
- })
- volume['release'].create({
- 'guid': 'impl_1',
- 'ctime': ts + 2,
- 'mtime': ts + 2,
- 'layer': [],
- 'context': 'context_1',
- 'license': ['GPL-3'],
- 'version': '1',
- })
- volume['post'].create({
- 'guid': 'topic_1',
- 'ctime': ts + 3,
- 'mtime': ts + 3,
- 'layer': [],
- 'context': 'context_1',
- 'type': 'object',
- 'title': '',
- 'message': '',
- })
- volume['post'].create({
- 'guid': 'solution_1',
- 'ctime': ts + 5,
- 'mtime': ts + 5,
- 'layer': [],
- 'context': 'context_1',
- 'topic': 'topic_1',
- 'title': '',
- 'message': '',
- 'type': 'answer',
- })
- volume['post'].create({
- 'guid': 'review_1',
- 'ctime': ts + 6,
- 'mtime': ts + 6,
- 'layer': [],
- 'context': 'context_1',
- 'vote': 1,
- 'title': '',
- 'message': '',
- 'type': 'review',
- })
- volume['post'].create({
- 'guid': 'review_2',
- 'ctime': ts + 6,
- 'mtime': ts + 6,
- 'layer': [],
- 'context': 'context_1',
- 'topic': 'topic_1',
- 'vote': 2,
- 'title': '',
- 'message': '',
- 'type': 'feedback',
- })
- volume['report'].create({
- 'guid': 'report_1',
- 'ctime': ts + 8,
- 'mtime': ts + 8,
- 'layer': [],
- 'context': 'context_1',
- 'release': 'impl_1',
- 'error': '',
- })
- volume['user'].create({
- 'guid': 'user_2',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'name': '',
- })
- volume['context'].create({
- 'guid': 'context_2',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'type': 'activity',
- 'title': '',
- 'summary': '',
- 'description': '',
- })
- volume['release'].create({
- 'guid': 'impl_2',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'context': 'context_2',
- 'license': ['GPL-3'],
- 'version': '1',
- })
- volume['release'].create({
- 'guid': 'impl_3',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'context': 'context_2',
- 'license': ['GPL-3'],
- 'version': '1',
- })
- volume['post'].create({
- 'guid': 'review_3',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'context': 'context_2',
- 'vote': 3,
- 'title': '',
- 'message': '',
- 'type': 'review',
- })
- volume['post'].create({
- 'guid': 'review_4',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'context': 'context_2',
- 'vote': 4,
- 'title': '',
- 'message': '',
- 'type': 'review',
- })
- volume['report'].create({
- 'guid': 'report_2',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'context': 'context_2',
- 'release': 'impl_1',
- 'error': '',
- })
- volume['report'].create({
- 'guid': 'report_3',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'context': 'context_2',
- 'release': 'impl_1',
- 'error': '',
- })
- volume['post'].create({
- 'guid': 'topic_2',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'context': 'context_2',
- 'type': 'object',
- 'title': '',
- 'message': '',
- })
- volume['post'].create({
- 'guid': 'solution_2',
- 'ctime': ts + 4,
- 'mtime': ts + 4,
- 'layer': [],
- 'context': 'context_2',
- 'topic': 'topic_2',
- 'title': '',
- 'message': '',
- 'type': 'answer',
- })
-
- self.override(time, 'time', lambda: ts + 9)
- old_stats = stats_node.Sniffer(volume, 'stats/node')
- old_stats.log(Request(method='GET', path=['release', 'impl_1', 'data']))
- old_stats.log(Request(method='GET', path=['post', 'topic_1', 'data']))
- old_stats.commit(ts + 1)
- old_stats.commit_objects()
- old_stats.commit(ts + 2)
- old_stats.commit(ts + 3)
- old_stats.log(Request(method='GET', path=['release', 'impl_1', 'data']))
- old_stats.log(Request(method='GET', path=['release', 'impl_2', 'data']))
- old_stats.commit(ts + 4)
- old_stats.commit_objects()
- old_stats.commit(ts + 5)
- old_stats.commit(ts + 6)
- old_stats.log(Request(method='GET', path=['post', 'topic_1', 'data']))
- old_stats.log(Request(method='GET', path=['post', 'topic_2', 'data']))
- old_stats.commit(ts + 7)
- old_stats.commit_objects()
- old_stats.commit(ts + 8)
- old_stats.commit_objects()
-
- generate_node_stats(volume, 'stats/node')
- cp = NodeRoutes('guid', volume)
+ release = json.load(conn.request('POST', ['context'], bundle, params={'cmd': 'submit', 'initial': True}).raw)
+ announce = next(volume['post'].find(query='1', limit=1)[0]).guid
self.assertEqual({
- 'user': [
- (ts + 1, {'total': 1.0}),
- (ts + 2, {'total': 1.0}),
- (ts + 3, {'total': 1.0}),
- (ts + 4, {'total': 2.0}),
- (ts + 5, {'total': 2.0}),
- (ts + 6, {'total': 2.0}),
- (ts + 7, {'total': 2.0}),
- (ts + 8, {'total': 2.0}),
- (ts + 9, {'total': 2.0}),
- ],
- 'context': [
- (ts + 1, {'total': 1.0, 'released': 0.0, 'failed': 0.0, 'downloaded': 1.0}),
- (ts + 2, {'total': 1.0, 'released': 1.0, 'failed': 0.0, 'downloaded': 1.0}),
- (ts + 3, {'total': 1.0, 'released': 1.0, 'failed': 0.0, 'downloaded': 1.0}),
- (ts + 4, {'total': 2.0, 'released': 3.0, 'failed': 2.0, 'downloaded': 3.0}),
- (ts + 5, {'total': 2.0, 'released': 3.0, 'failed': 2.0, 'downloaded': 3.0}),
- (ts + 6, {'total': 2.0, 'released': 3.0, 'failed': 2.0, 'downloaded': 3.0}),
- (ts + 7, {'total': 2.0, 'released': 3.0, 'failed': 2.0, 'downloaded': 3.0}),
- (ts + 8, {'total': 2.0, 'released': 3.0, 'failed': 3.0, 'downloaded': 3.0}),
- (ts + 9, {'total': 2.0, 'released': 3.0, 'failed': 3.0, 'downloaded': 3.0}),
- ],
- 'post': [
- (ts + 1, {'total': 0.0, 'downloaded': 1.0}),
- (ts + 2, {'total': 0.0, 'downloaded': 1.0}),
- (ts + 3, {'total': 1.0, 'downloaded': 1.0}),
- (ts + 4, {'total': 5.0, 'downloaded': 1.0}),
- (ts + 5, {'total': 6.0, 'downloaded': 1.0}),
- (ts + 6, {'total': 8.0, 'downloaded': 1.0}),
- (ts + 7, {'total': 8.0, 'downloaded': 3.0}),
- (ts + 8, {'total': 8.0, 'downloaded': 3.0}),
- (ts + 9, {'total': 8.0, 'downloaded': 3.0}),
- ],
- },
- call(cp, method='GET', cmd='stats', source=[
- 'user.total',
- 'context.total',
- 'context.released',
- 'context.failed',
- 'context.downloaded',
- 'post.total',
- 'post.downloaded',
- ], start=ts + 1, end=ts + 10))
+ release: {
+ 'seqno': 4,
+ 'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
+ 'value': {
+ 'license': ['Public Domain'],
+ 'announce': announce,
+ 'release': [[1], 0],
+ 'requires': [],
+ 'spec': {'*-*': {'bundle': str(hash(bundle)), 'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
+ 'stability': 'developer',
+ 'unpack_size': len(activity_info) + len(changelog),
+ 'version': '1',
+ },
+ },
+ }, conn.get(['context', 'bundle_id', 'releases']))
+ post = volume['post'][announce]
+ assert tests.UID in post['author']
+ self.assertEqual('notification', post['type'])
self.assertEqual({
- 'downloads': 2,
- 'rating': [1, 1],
- },
- volume['context'].get('context_1').properties(['downloads', 'rating']))
- self.assertEqual({
- 'downloads': 1,
- 'rating': [2, 7],
- },
- volume['context'].get('context_2').properties(['downloads', 'rating']))
- self.assertEqual({
- 'downloads': 2,
- 'rating': [1, 2],
- },
- volume['post'].get('topic_1').properties(['downloads', 'rating']))
- self.assertEqual({
- 'downloads': 1,
- 'rating': [0, 0],
- },
- volume['post'].get('topic_2').properties(['downloads', 'rating']))
-
- def test_generate_node_stats_Deletes(self):
- node.stats_root.value = 'stats'
- stats_node.stats_node.value = True
- stats_node.stats_node_rras.value = ['RRA:AVERAGE:0.5:1:10', 'RRA:AVERAGE:0.5:10:10']
- volume = db.Volume('db', model.RESOURCES)
-
- ts = 1000000000
-
- volume['user'].create({
- 'guid': 'user_1',
- 'ctime': ts + 1,
- 'mtime': ts + 2,
- 'layer': ['deleted'],
- 'name': '',
- })
- volume['context'].create({
- 'guid': 'context_1',
- 'ctime': ts + 1,
- 'mtime': ts + 2,
- 'layer': ['deleted'],
- 'type': 'activity',
- 'title': '',
- 'summary': '',
- 'description': '',
- })
- volume['release'].create({
- 'guid': 'impl_1',
- 'ctime': ts + 1,
- 'mtime': ts + 2,
- 'layer': ['deleted'],
- 'context': 'context_1',
- 'license': ['GPL-3'],
- 'version': '1',
- })
- volume['post'].create({
- 'guid': 'post_1',
- 'ctime': ts + 1,
- 'mtime': ts + 2,
- 'layer': ['deleted'],
- 'context': 'context_1',
- 'type': 'object',
- 'title': '',
- 'message': '',
- })
- volume['report'].create({
- 'guid': 'report_1',
- 'ctime': ts + 1,
- 'mtime': ts + 2,
- 'layer': ['deleted'],
- 'context': 'context_1',
- 'release': 'impl_1',
- 'error': '',
- })
-
- self.override(time, 'time', lambda: ts + 9)
- generate_node_stats(volume, 'stats/node')
- cp = NodeRoutes('guid', volume)
-
+ 'en': 'TestActivitry 1 release',
+ 'es': 'TestActivitry 1 release',
+ 'fr': 'TestActivitry 1 release',
+ }, post['title'])
self.assertEqual({
- 'user': [
- (ts + 1, {'total': 1.0}),
- (ts + 2, {'total': 0.0}),
- (ts + 3, {'total': 0.0}),
- ],
- 'context': [
- (ts + 1, {'total': 1.0}),
- (ts + 2, {'total': 0.0}),
- (ts + 3, {'total': 0.0}),
- ],
- 'post': [
- (ts + 1, {'total': 1.0}),
- (ts + 2, {'total': 0.0}),
- (ts + 3, {'total': 0.0}),
- ],
- },
- call(cp, method='GET', cmd='stats', source=[
- 'user.total',
- 'context.total',
- 'post.total',
- ], start=ts + 1, end=ts + 3))
+ 'en-us': 'LOG',
+ }, post['message'])
def test_AggpropInsertAccess(self):
class Document(db.Resource):
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.READ | ACL.INSERT)
+ @db.stored_property(db.Aggregated, acl=ACL.READ | ACL.INSERT)
def prop1(self, value):
return value
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.READ | ACL.INSERT | ACL.AUTHOR)
+ @db.stored_property(db.Aggregated, acl=ACL.READ | ACL.INSERT | ACL.AUTHOR)
def prop2(self, value):
return value
volume = db.Volume('db', [Document, User])
- volume['user'].create({'guid': tests.UID, 'name': 'user1', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- volume['user'].create({'guid': tests.UID2, 'name': 'user2', 'pubkey': {'blob': StringIO(tests.PUBKEY2)}})
+ cp = NodeRoutes('node', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user1', 'pubkey': tests.PUBKEY})
+ volume['user'].create({'guid': tests.UID2, 'name': 'user2', 'pubkey': tests.PUBKEY2})
- cp = NodeRoutes('node', volume)
guid = call(cp, method='POST', document='document', principal=tests.UID, content={})
self.override(time, 'time', lambda: 0)
- call(cp, method='POST', path=['document', guid, 'prop1'], principal=tests.UID, content={'guid': '1'})
- call(cp, method='POST', path=['document', guid, 'prop1'], principal=tests.UID2, content={'guid': '2'})
+ agg1 = call(cp, method='POST', path=['document', guid, 'prop1'], principal=tests.UID)
+ agg2 = call(cp, method='POST', path=['document', guid, 'prop1'], principal=tests.UID2)
self.assertEqual({
- '1': {'seqno': 4, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
- '2': {'seqno': 5, 'author': {tests.UID2: {'name': 'user2', 'order': 0, 'role': 3}}},
+ agg1: {'seqno': 4, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}, 'value': None},
+ agg2: {'seqno': 5, 'author': {tests.UID2: {'name': 'user2', 'order': 0, 'role': 1}}, 'value': None},
},
call(cp, method='GET', path=['document', guid, 'prop1']))
- call(cp, method='POST', path=['document', guid, 'prop2'], principal=tests.UID, content={'guid': '1'})
- self.assertRaises(http. Forbidden, call, cp, method='POST', path=['document', guid, 'prop2'], principal=tests.UID2, content={'guid': '2'})
+ agg3 = call(cp, method='POST', path=['document', guid, 'prop2'], principal=tests.UID)
+ self.assertRaises(http. Forbidden, call, cp, method='POST', path=['document', guid, 'prop2'], principal=tests.UID2)
self.assertEqual({
- '1': {'seqno': 6, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
+ agg3: {'seqno': 6, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}, 'value': None},
},
call(cp, method='GET', path=['document', guid, 'prop2']))
@@ -1356,64 +694,64 @@ class NodeTest(tests.Test):
class Document(db.Resource):
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.READ | ACL.INSERT | ACL.REMOVE)
+ @db.stored_property(db.Aggregated, acl=ACL.READ | ACL.INSERT | ACL.REMOVE)
def prop1(self, value):
return value
- @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.READ | ACL.INSERT | ACL.REMOVE | ACL.AUTHOR)
+ @db.stored_property(db.Aggregated, acl=ACL.READ | ACL.INSERT | ACL.REMOVE | ACL.AUTHOR)
def prop2(self, value):
return value
volume = db.Volume('db', [Document, User])
- volume['user'].create({'guid': tests.UID, 'name': 'user1', 'pubkey': {'blob': StringIO(tests.PUBKEY)}})
- volume['user'].create({'guid': tests.UID2, 'name': 'user2', 'pubkey': {'blob': StringIO(tests.PUBKEY2)}})
+ cp = NodeRoutes('node', volume=volume)
+ volume['user'].create({'guid': tests.UID, 'name': 'user1', 'pubkey': tests.PUBKEY})
+ volume['user'].create({'guid': tests.UID2, 'name': 'user2', 'pubkey': tests.PUBKEY2})
- cp = NodeRoutes('node', volume)
guid = call(cp, method='POST', document='document', principal=tests.UID, content={})
self.override(time, 'time', lambda: 0)
- call(cp, method='POST', path=['document', guid, 'prop1'], principal=tests.UID, content={'guid': '1', 'probe': True})
- call(cp, method='POST', path=['document', guid, 'prop1'], principal=tests.UID2, content={'guid': '2', 'probe': True})
+ agg1 = call(cp, method='POST', path=['document', guid, 'prop1'], principal=tests.UID, content=True)
+ agg2 = call(cp, method='POST', path=['document', guid, 'prop1'], principal=tests.UID2, content=True)
self.assertEqual({
- '1': {'seqno': 4, 'probe': True, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
- '2': {'seqno': 5, 'probe': True, 'author': {tests.UID2: {'name': 'user2', 'order': 0, 'role': 3}}},
+ agg1: {'seqno': 4, 'value': True, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
+ agg2: {'seqno': 5, 'value': True, 'author': {tests.UID2: {'name': 'user2', 'order': 0, 'role': 1}}},
},
call(cp, method='GET', path=['document', guid, 'prop1']))
- self.assertRaises(http.Forbidden, call, cp, method='DELETE', path=['document', guid, 'prop1', '1'], principal=tests.UID2)
- self.assertRaises(http.Forbidden, call, cp, method='DELETE', path=['document', guid, 'prop1', '2'], principal=tests.UID)
+ self.assertRaises(http.Forbidden, call, cp, method='DELETE', path=['document', guid, 'prop1', agg1], principal=tests.UID2)
+ self.assertRaises(http.Forbidden, call, cp, method='DELETE', path=['document', guid, 'prop1', agg2], principal=tests.UID)
self.assertEqual({
- '1': {'seqno': 4, 'probe': True, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
- '2': {'seqno': 5, 'probe': True, 'author': {tests.UID2: {'name': 'user2', 'order': 0, 'role': 3}}},
+ agg1: {'seqno': 4, 'value': True, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
+ agg2: {'seqno': 5, 'value': True, 'author': {tests.UID2: {'name': 'user2', 'order': 0, 'role': 1}}},
},
call(cp, method='GET', path=['document', guid, 'prop1']))
- call(cp, method='DELETE', path=['document', guid, 'prop1', '1'], principal=tests.UID)
+ call(cp, method='DELETE', path=['document', guid, 'prop1', agg1], principal=tests.UID)
self.assertEqual({
- '1': {'seqno': 6},
- '2': {'seqno': 5, 'probe': True, 'author': {tests.UID2: {'name': 'user2', 'order': 0, 'role': 3}}},
+ agg1: {'seqno': 6, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
+ agg2: {'seqno': 5, 'value': True, 'author': {tests.UID2: {'name': 'user2', 'order': 0, 'role': 1}}},
},
call(cp, method='GET', path=['document', guid, 'prop1']))
- call(cp, method='DELETE', path=['document', guid, 'prop1', '2'], principal=tests.UID2)
+ call(cp, method='DELETE', path=['document', guid, 'prop1', agg2], principal=tests.UID2)
self.assertEqual({
- '1': {'seqno': 6},
- '2': {'seqno': 7},
+ agg1: {'seqno': 6, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
+ agg2: {'seqno': 7, 'author': {tests.UID2: {'name': 'user2', 'order': 0, 'role': 1}}},
},
call(cp, method='GET', path=['document', guid, 'prop1']))
- call(cp, method='POST', path=['document', guid, 'prop2'], principal=tests.UID, content={'guid': '1', 'probe': True})
+ agg3 = call(cp, method='POST', path=['document', guid, 'prop2'], principal=tests.UID, content=True)
self.assertEqual({
- '1': {'seqno': 8, 'probe': True, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
+ agg3: {'seqno': 8, 'value': True, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
},
call(cp, method='GET', path=['document', guid, 'prop2']))
- self.assertRaises(http.Forbidden, call, cp, method='DELETE', path=['document', guid, 'prop2', '1'], principal=tests.UID2)
+ self.assertRaises(http.Forbidden, call, cp, method='DELETE', path=['document', guid, 'prop2', agg3], principal=tests.UID2)
self.assertEqual({
- '1': {'seqno': 8, 'probe': True, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
+ agg3: {'seqno': 8, 'value': True, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
},
call(cp, method='GET', path=['document', guid, 'prop2']))
- call(cp, method='DELETE', path=['document', guid, 'prop2', '1'], principal=tests.UID)
+ call(cp, method='DELETE', path=['document', guid, 'prop2', agg3], principal=tests.UID)
self.assertEqual({
- '1': {'seqno': 9},
+ agg3: {'seqno': 9, 'author': {tests.UID: {'name': 'user1', 'order': 0, 'role': 3}}},
},
call(cp, method='GET', path=['document', guid, 'prop2']))
diff --git a/tests/units/node/obs.py b/tests/units/node/obs.py
index bf43ed6..21b53a0 100755
--- a/tests/units/node/obs.py
+++ b/tests/units/node/obs.py
@@ -39,8 +39,8 @@ class ObsTest(tests.Test):
]))
self.assertEqual([
- {'distributor_id': 'Debian', 'name': 'Debian-6.0', 'arches': ['i586', 'x86_64']},
- {'distributor_id': 'Fedora', 'name': 'Fedora-11', 'arches': ['i586']},
+ {'lsb_id': 'Debian', 'lsb_release': '6.0', 'name': 'Debian-6.0', 'arches': ['i586', 'x86_64']},
+ {'lsb_id': 'Fedora', 'lsb_release': '11', 'name': 'Fedora-11', 'arches': ['i586']},
],
obs.get_repos())
@@ -51,21 +51,10 @@ class ObsTest(tests.Test):
'project': 'base',
'repository': 'repo',
'arch': 'arch',
- 'package': 'pkg1',
+ 'package': ['pkg1', 'pkg2'],
}},
[ '<resolve>',
' <binary name="pygame" url="http://pkg1.prm" arch="arch"/>',
- '</resolve>',
- ],
- ),
- (('GET', ['resolve']),
- {'allowed': (400, 404), 'params': {
- 'project': 'base',
- 'repository': 'repo',
- 'arch': 'arch',
- 'package': 'pkg2',
- }},
- [ '<resolve>',
' <binary name="pygame" url="http://pkg2.prm" arch="arch"/>',
'</resolve>',
],
@@ -122,10 +111,7 @@ class ObsTest(tests.Test):
('http://pkg2-2.prm', ['4']),
]))
- obs.presolve({
- 'Debian': {'binary': [['deb']]},
- 'Fedora': {'binary': [['pkg1', 'pkg2']], 'devel': [['pkg3']]},
- }, '.')
+ obs.presolve(None, ['pkg1', 'pkg2'], '.')
self.assertEqual({
'arch': [
diff --git a/tests/units/node/stats_node.py b/tests/units/node/stats_node.py
deleted file mode 100755
index eab7fb8..0000000
--- a/tests/units/node/stats_node.py
+++ /dev/null
@@ -1,338 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import time
-
-from __init__ import tests
-
-from sugar_network import db, model
-from sugar_network.node.stats_node import Sniffer, stats_node_step
-from sugar_network.toolkit.rrd import Rrd
-from sugar_network.toolkit.router import Request
-
-
-class StatsTest(tests.Test):
-
- def test_InitializeTotals(self):
- volume = db.Volume('local', model.RESOURCES)
-
- stats = Sniffer(volume, 'stats/node')
- self.assertEqual(0, stats._stats['user']['total'])
- self.assertEqual(0, stats._stats['context']['total'])
- self.assertEqual(0, stats._stats['post']['total'])
-
- volume['user'].create({'guid': 'user', 'name': 'user', 'pubkey': ''})
- volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
- volume['post'].create({'guid': 'post', 'context': 'context', 'title': '', 'message': '', 'type': 'update'})
-
- stats = Sniffer(volume, 'stats/node')
- self.assertEqual(1, stats._stats['user']['total'])
- self.assertEqual(1, stats._stats['context']['total'])
- self.assertEqual(1, stats._stats['post']['total'])
-
- def test_POSTs(self):
- volume = db.Volume('local', model.RESOURCES)
- stats = Sniffer(volume, 'stats/node')
-
- request = Request(method='POST', path=['context'])
- request.principal = 'user'
- stats.log(request)
- stats.log(request)
- stats.log(request)
- self.assertEqual(3, stats._stats['context']['total'])
-
- def test_DELETEs(self):
- volume = db.Volume('local', model.RESOURCES)
- stats = Sniffer(volume, 'stats/node')
-
- request = Request(method='DELETE', path=['context'])
- request.principal = 'user'
- stats.log(request)
- stats.log(request)
- stats.log(request)
- self.assertEqual(-3, stats._stats['context']['total'])
-
- def test_Posts(self):
- volume = db.Volume('local', model.RESOURCES)
- stats = Sniffer(volume, 'stats/node')
- volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
- volume['post'].create({'guid': 'topic', 'type': 'update', 'context': 'context', 'title': '', 'message': ''})
-
- request = Request(method='POST', path=['post'])
- request.principal = 'user'
- request.content = {'context': 'context', 'vote': 1, 'type': 'review', 'title': '', 'message': ''}
- stats.log(request)
- self.assertEqual(1, stats._stats['post']['total'])
-
- request = Request(method='POST', path=['post'])
- request.principal = 'user'
- request.content = {'context': 'context', 'vote': 2, 'type': 'review', 'title': '', 'message': ''}
- stats.log(request)
- self.assertEqual(2, stats._stats['post']['total'])
-
- request = Request(method='POST', path=['post'])
- request.principal = 'user'
- request.content = {'topic': 'topic', 'vote': 3, 'type': 'feedback', 'title': '', 'message': ''}
- stats.log(request)
- self.assertEqual(3, stats._stats['post']['total'])
-
- stats.commit_objects()
- self.assertEqual([2, 3], volume['context'].get('context')['rating'])
- self.assertEqual([1, 3], volume['post'].get('topic')['rating'])
-
- def test_ContextDownloaded(self):
- volume = db.Volume('local', model.RESOURCES)
- stats = Sniffer(volume, 'stats/node')
- volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
- volume['release'].create({'guid': 'release', 'context': 'context', 'license': 'GPLv3', 'version': '1', 'date': 0, 'stability': 'stable', 'notes': ''})
-
- request = Request(method='GET', path=['release', 'release', 'fake'])
- request.principal = 'user'
- stats.log(request)
- self.assertEqual(0, stats._stats['context']['downloaded'])
-
- request = Request(method='GET', path=['release', 'release', 'data'])
- request.principal = 'user'
- stats.log(request)
- self.assertEqual(1, stats._stats['context']['downloaded'])
-
- def test_ContextReleased(self):
- volume = db.Volume('local', model.RESOURCES)
- stats = Sniffer(volume, 'stats/node')
- volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
-
- request = Request(method='POST', path=['release'])
- request.principal = 'user'
- request.content = {'context': 'context'}
- stats.log(request)
- self.assertEqual(1, stats._stats['context']['released'])
-
- def test_ContextFailed(self):
- volume = db.Volume('local', model.RESOURCES)
- stats = Sniffer(volume, 'stats/node')
- volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
-
- request = Request(method='POST', path=['report'])
- request.principal = 'user'
- request.content = {'context': 'context'}
- stats.log(request)
- self.assertEqual(1, stats._stats['context']['failed'])
-
- def test_PostDownloaded(self):
- volume = db.Volume('local', model.RESOURCES)
- stats = Sniffer(volume, 'stats/node')
- volume['post'].create({'guid': 'topic', 'type': 'object', 'context': 'context', 'title': '', 'message': ''})
-
- request = Request(method='GET', path=['post', 'topic', 'fake'])
- request.principal = 'user'
- stats.log(request)
- self.assertEqual(0, stats._stats['post']['downloaded'])
-
- request = Request(method='GET', path=['post', 'topic', 'data'])
- request.principal = 'user'
- stats.log(request)
- self.assertEqual(1, stats._stats['post']['downloaded'])
-
- def test_Commit(self):
- volume = db.Volume('local', model.RESOURCES)
- volume['user'].create({'guid': 'user', 'name': 'user', 'pubkey': ''})
- volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
- volume['post'].create({'guid': 'review', 'context': 'context', 'type': 'review', 'title': '', 'message': '', 'vote': 5})
-
- stats = Sniffer(volume, 'stats/node')
- request = Request(method='GET', path=['user', 'user'])
- request.principal = 'user'
- stats.log(request)
- request = Request(method='GET', path=['context', 'context'])
- request.principal = 'user'
- stats.log(request)
- request = Request(method='GET', path=['post', 'review'])
- request.principal = 'user'
- stats.log(request)
-
- self.assertEqual(1, stats._stats['user']['total'])
- self.assertEqual(1, stats._stats['context']['total'])
- self.assertEqual(1, stats._stats['post']['total'])
-
- ts = int(time.time())
- stats.commit(ts)
- stats.commit_objects()
-
- self.assertEqual(1, stats._stats['user']['total'])
- self.assertEqual(1, stats._stats['context']['total'])
- self.assertEqual(1, stats._stats['post']['total'])
-
- self.assertEqual([
- [('post', ts, {
- 'downloaded': 0.0,
- 'total': 1.0,
- })],
- [('user', ts, {
- 'total': 1.0,
- })],
- [('context', ts, {
- 'failed': 0.0,
- 'downloaded': 0.0,
- 'total': 1.0,
- 'released': 0.0,
- })],
- ],
- [[(j.name,) + i for i in j.get(j.last, j.last)] for j in Rrd('stats/node', 1)])
-
- def test_CommitContextStats(self):
- volume = db.Volume('local', model.RESOURCES)
-
- volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
- volume['release'].create({'guid': 'release', 'context': 'context', 'license': 'GPLv3', 'version': '1', 'date': 0, 'stability': 'stable', 'notes': ''})
-
- self.assertEqual(0, volume['context'].get('context')['downloads'])
- self.assertEqual([0, 0], volume['context'].get('context')['rating'])
-
- stats = Sniffer(volume, 'stats/node')
- request = Request(method='GET', path=['release', 'release', 'data'])
- request.principal = 'user'
- stats.log(request)
- request = Request(method='POST', path=['post'])
- request.principal = 'user'
- request.content = {'context': 'context', 'vote': 5, 'type': 'review', 'title': '', 'message': ''}
- stats.log(request)
-
- stats.commit()
- stats.commit_objects()
-
- self.assertEqual(1, volume['context'].get('context')['downloads'])
- self.assertEqual([1, 5], volume['context'].get('context')['rating'])
-
- stats.commit()
- stats.commit_objects()
-
- self.assertEqual(1, volume['context'].get('context')['downloads'])
- self.assertEqual([1, 5], volume['context'].get('context')['rating'])
-
- stats = Sniffer(volume, 'stats/node')
- request = Request(method='GET', path=['release', 'release', 'data'])
- request.principal = 'user'
- stats.log(request)
- request = Request(method='POST', path=['post'])
- request.principal = 'user'
- request.content = {'context': 'context', 'vote': 1, 'type': 'review', 'title': '', 'message': ''}
- stats.log(request)
- stats.commit()
- stats.commit_objects()
-
- self.assertEqual(2, volume['context'].get('context')['downloads'])
- self.assertEqual([2, 6], volume['context'].get('context')['rating'])
-
- def test_CommitTopicStats(self):
- volume = db.Volume('local', model.RESOURCES)
-
- volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
- volume['post'].create({'guid': 'topic', 'type': 'object', 'context': 'context', 'title': '', 'message': ''})
-
- self.assertEqual(0, volume['post'].get('topic')['downloads'])
- self.assertEqual([0, 0], volume['post'].get('topic')['rating'])
-
- stats = Sniffer(volume, 'stats/node')
- request = Request(method='GET', path=['post', 'topic', 'data'])
- request.principal = 'user'
- stats.log(request)
- request = Request(method='POST', path=['post'])
- request.principal = 'user'
- request.content = {'topic': 'topic', 'vote': 5, 'type': 'feedback'}
- stats.log(request)
- stats.commit()
- stats.commit_objects()
-
- self.assertEqual(1, volume['post'].get('topic')['downloads'])
- self.assertEqual([1, 5], volume['post'].get('topic')['rating'])
-
- stats.commit()
- stats.commit_objects()
-
- self.assertEqual(1, volume['post'].get('topic')['downloads'])
- self.assertEqual([1, 5], volume['post'].get('topic')['rating'])
-
- request = Request(method='GET', path=['post', 'topic', 'data'])
- request.principal = 'user'
- stats.log(request)
- request = Request(method='POST', path=['post'])
- request.principal = 'user'
- request.content = {'topic': 'topic', 'vote': 1, 'type': 'feedback'}
- stats.log(request)
- stats.commit()
- stats.commit_objects()
-
- self.assertEqual(2, volume['post'].get('topic')['downloads'])
- self.assertEqual([2, 6], volume['post'].get('topic')['rating'])
-
- def test_Suspend(self):
- stats_node_step.value = 5
- volume = db.Volume('local', model.RESOURCES)
- volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
- volume['release'].create({'guid': 'impl', 'context': 'context', 'license': 'GPLv3', 'version': '1', 'date': 0, 'stability': 'stable', 'notes': ''})
-
- ts = self.ts = 1000000000
- self.override(time, 'time', lambda: self.ts)
-
- stats = Sniffer(volume, 'stats')
- request = Request(method='POST', path=['context'])
- stats.log(request)
- request = Request(method='GET', path=['release', 'impl', 'data'], context='context')
- stats.log(request)
- stats.suspend()
-
- rdb = Rrd('stats', 1)['context']
- self.assertEqual([
- ],
- [i for i in rdb.get(ts, ts + 10)])
-
- stats = Sniffer(volume, 'stats')
- stats.suspend()
-
- rdb = Rrd('stats', 1)['context']
- self.assertEqual([
- ],
- [i for i in rdb.get(ts, ts + 10)])
-
- self.ts += 6
- stats = Sniffer(volume, 'stats')
-
- rdb = Rrd('stats', 1)['context']
- self.assertEqual([
- (ts + 0, {'failed': 0.0, 'downloaded': 0.0, 'total': 0.0, 'released': 0.0}),
- (ts + 5, {'failed': 0.0, 'downloaded': 1.0, 'total': 2.0, 'released': 0.0}),
- ],
- [i for i in rdb.get(ts, ts + 20)])
-
- request = Request(method='POST', path=['context'])
- stats.log(request)
- request = Request(method='GET', path=['release', 'impl', 'data'], context='context')
- stats.log(request)
- request = Request(method='GET', path=['release', 'impl', 'data'], context='context')
- stats.log(request)
- stats.suspend()
-
- stats = Sniffer(volume, 'stats')
- stats.suspend()
-
- rdb = Rrd('stats', 1)['context']
- self.assertEqual([
- (ts + 0, {'failed': 0.0, 'downloaded': 0.0, 'total': 0.0, 'released': 0.0}),
- (ts + 5, {'failed': 0.0, 'downloaded': 1.0, 'total': 2.0, 'released': 0.0}),
- ],
- [i for i in rdb.get(ts, ts + 10)])
-
- self.ts += 6
- stats = Sniffer(volume, 'stats')
-
- rdb = Rrd('stats', 1)['context']
- self.assertEqual([
- (ts + 0, {'failed': 0.0, 'downloaded': 0.0, 'total': 0.0, 'released': 0.0}),
- (ts + 5, {'failed': 0.0, 'downloaded': 1.0, 'total': 2.0, 'released': 0.0}),
- (ts + 10, {'failed': 0.0, 'downloaded': 3.0, 'total': 3.0, 'released': 0.0}),
- ],
- [i for i in rdb.get(ts, ts + 20)])
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/node/sync_online.py b/tests/units/node/sync_online.py
index 7ee6dcb..e2c864a 100755
--- a/tests/units/node/sync_online.py
+++ b/tests/units/node/sync_online.py
@@ -44,11 +44,11 @@ class SyncOnlineTest(tests.Test):
def type(self, value):
return value
- @db.indexed_property(slot=1, prefix='N', full_text=True, localized=True)
+ @db.indexed_property(db.Localized, slot=1, prefix='N', full_text=True)
def title(self, value):
return value
- @db.indexed_property(prefix='D', full_text=True, localized=True)
+ @db.indexed_property(db.Localized, prefix='D', full_text=True)
def message(self, value):
return value
@@ -80,8 +80,8 @@ class SyncOnlineTest(tests.Test):
self.assertEqual([[4, None]], json.load(file('slave/pull.sequence')))
self.assertEqual([[2, None]], json.load(file('slave/push.sequence')))
- guid1 = client.post(['document'], {'context': '', 'message': '1', 'title': '', 'type': 'comment'})
- guid2 = client.post(['document'], {'context': '', 'message': '2', 'title': '', 'type': 'comment'})
+ guid1 = client.post(['document'], {'context': '', 'message': '1', 'title': '', 'type': 'post'})
+ guid2 = client.post(['document'], {'context': '', 'message': '2', 'title': '', 'type': 'post'})
client.post(cmd='online-sync')
self.assertEqual([
@@ -92,7 +92,7 @@ class SyncOnlineTest(tests.Test):
self.assertEqual([[6, None]], json.load(file('slave/pull.sequence')))
self.assertEqual([[4, None]], json.load(file('slave/push.sequence')))
- guid3 = client.post(['document'], {'context': '', 'message': '3', 'title': '', 'type': 'comment'})
+ guid3 = client.post(['document'], {'context': '', 'message': '3', 'title': '', 'type': 'post'})
client.post(cmd='online-sync')
self.assertEqual([
{'guid': guid1, 'message': {'en-us': '1'}},
@@ -128,7 +128,7 @@ class SyncOnlineTest(tests.Test):
client.put(['document', guid1], {'message': 'a'})
client.put(['document', guid2], {'message': 'b'})
client.put(['document', guid3], {'message': 'c'})
- guid4 = client.post(['document'], {'context': '', 'message': 'd', 'title': '', 'type': 'comment'})
+ guid4 = client.post(['document'], {'context': '', 'message': 'd', 'title': '', 'type': 'post'})
client.delete(['document', guid2])
client.post(cmd='online-sync')
self.assertEqual([
@@ -158,8 +158,8 @@ class SyncOnlineTest(tests.Test):
self.assertEqual([[4, None]], json.load(file('slave/pull.sequence')))
self.assertEqual([[2, None]], json.load(file('slave/push.sequence')))
- guid1 = client.post(['document'], {'context': '', 'message': '1', 'title': '', 'type': 'comment'})
- guid2 = client.post(['document'], {'context': '', 'message': '2', 'title': '', 'type': 'comment'})
+ guid1 = client.post(['document'], {'context': '', 'message': '1', 'title': '', 'type': 'post'})
+ guid2 = client.post(['document'], {'context': '', 'message': '2', 'title': '', 'type': 'post'})
slave_client.post(cmd='online-sync')
self.assertEqual([
@@ -170,7 +170,7 @@ class SyncOnlineTest(tests.Test):
self.assertEqual([[6, None]], json.load(file('slave/pull.sequence')))
self.assertEqual([[2, None]], json.load(file('slave/push.sequence')))
- guid3 = client.post(['document'], {'context': '', 'message': '3', 'title': '', 'type': 'comment'})
+ guid3 = client.post(['document'], {'context': '', 'message': '3', 'title': '', 'type': 'post'})
slave_client.post(cmd='online-sync')
self.assertEqual([
{'guid': guid1, 'message': {'en-us': '1'}},
@@ -206,7 +206,7 @@ class SyncOnlineTest(tests.Test):
client.put(['document', guid1], {'message': 'a'})
client.put(['document', guid2], {'message': 'b'})
client.put(['document', guid3], {'message': 'c'})
- guid4 = client.post(['document'], {'context': '', 'message': 'd', 'title': '', 'type': 'comment'})
+ guid4 = client.post(['document'], {'context': '', 'message': 'd', 'title': '', 'type': 'post'})
client.delete(['document', guid2])
slave_client.post(cmd='online-sync')
self.assertEqual([
@@ -252,7 +252,7 @@ class SyncOnlineTest(tests.Test):
self.assertEqual([[4, None]], json.load(file('slave/pull.sequence')))
self.assertEqual([[2, None]], json.load(file('slave/push.sequence')))
- guid = slave.post(['document'], {'context': '', 'message': '1', 'title': '1', 'type': 'comment'})
+ guid = slave.post(['document'], {'context': '', 'message': '1', 'title': '1', 'type': 'post'})
slave.post(cmd='online-sync')
coroutine.sleep(1)
diff --git a/tests/units/node/volume.py b/tests/units/node/volume.py
deleted file mode 100755
index 01e71a7..0000000
--- a/tests/units/node/volume.py
+++ /dev/null
@@ -1,826 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import os
-import time
-import urllib2
-import hashlib
-from cStringIO import StringIO
-
-from __init__ import tests
-
-from sugar_network import db, toolkit, model
-from sugar_network.node.volume import diff, merge
-from sugar_network.node.stats_node import Sniffer
-from sugar_network.node.routes import NodeRoutes
-from sugar_network.toolkit.rrd import Rrd
-from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, Blob, ACL, route
-
-
-current_time = time.time
-
-
-class VolumeTest(tests.Test):
-
- def setUp(self):
- tests.Test.setUp(self)
- self.override(time, 'time', lambda: 0)
- self.override(NodeRoutes, 'authorize', lambda self, user, role: True)
-
- def test_diff(self):
-
- class Document(db.Resource):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- volume = db.Volume('db', [Document])
- cp = NodeRoutes('guid', volume)
-
- guid1 = call(cp, method='POST', document='document', content={'prop': 'a'})
- self.utime('db/document/%s/%s' % (guid1[:2], guid1), 1)
- guid2 = call(cp, method='POST', document='document', content={'prop': 'b'})
- self.utime('db/document/%s/%s' % (guid2[:2], guid2), 2)
-
- in_seq = toolkit.Sequence([[1, None]])
- self.assertEqual([
- {'resource': 'document'},
- {'guid': guid1,
- 'diff': {
- 'guid': {'value': guid1, 'mtime': 1},
- 'mtime': {'value': 0, 'mtime': 1},
- 'ctime': {'value': 0, 'mtime': 1},
- 'prop': {'value': 'a', 'mtime': 1},
- 'author': {'mtime': 1, 'value': {}},
- 'layer': {'mtime': 1, 'value': []},
- 'tags': {'mtime': 1, 'value': []},
- },
- },
- {'guid': guid2,
- 'diff': {
- 'guid': {'value': guid2, 'mtime': 2},
- 'mtime': {'value': 0, 'mtime': 2},
- 'ctime': {'value': 0, 'mtime': 2},
- 'prop': {'value': 'b', 'mtime': 2},
- 'author': {'mtime': 2, 'value': {}},
- 'layer': {'mtime': 2, 'value': []},
- 'tags': {'mtime': 2, 'value': []},
- },
- },
- {'commit': [[1, 2]]},
- ],
- [i for i in diff(volume, in_seq)])
- self.assertEqual([[1, None]], in_seq)
-
- def test_diff_Partial(self):
-
- class Document(db.Resource):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- volume = db.Volume('db', [Document])
- cp = NodeRoutes('guid', volume)
-
- guid1 = call(cp, method='POST', document='document', content={'prop': 'a'})
- self.utime('db/document/%s/%s' % (guid1[:2], guid1), 1)
- guid2 = call(cp, method='POST', document='document', content={'prop': 'b'})
- self.utime('db/document/%s/%s' % (guid2[:2], guid2), 2)
-
- in_seq = toolkit.Sequence([[1, None]])
- patch = diff(volume, in_seq)
- self.assertEqual({'resource': 'document'}, next(patch))
- self.assertEqual(guid1, next(patch)['guid'])
- self.assertEqual({'commit': []}, patch.throw(StopIteration()))
- try:
- next(patch)
- assert False
- except StopIteration:
- pass
-
- patch = diff(volume, in_seq)
- self.assertEqual({'resource': 'document'}, next(patch))
- self.assertEqual(guid1, next(patch)['guid'])
- self.assertEqual(guid2, next(patch)['guid'])
- self.assertEqual({'commit': [[1, 1]]}, patch.throw(StopIteration()))
- try:
- next(patch)
- assert False
- except StopIteration:
- pass
-
- def test_diff_Stretch(self):
-
- class Document(db.Resource):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- volume = db.Volume('db', [Document])
- cp = NodeRoutes('guid', volume)
-
- guid1 = call(cp, method='POST', document='document', content={'prop': 'a'})
- self.utime('db/document/%s/%s' % (guid1[:2], guid1), 1)
- guid2 = call(cp, method='POST', document='document', content={'prop': 'b'})
- volume['document'].delete(guid2)
- guid3 = call(cp, method='POST', document='document', content={'prop': 'c'})
- self.utime('db/document/%s/%s' % (guid3[:2], guid3), 2)
- guid4 = call(cp, method='POST', document='document', content={'prop': 'd'})
- volume['document'].delete(guid4)
- guid5 = call(cp, method='POST', document='document', content={'prop': 'f'})
- self.utime('db/document/%s/%s' % (guid5[:2], guid5), 2)
-
- in_seq = toolkit.Sequence([[1, None]])
- patch = diff(volume, in_seq)
- self.assertEqual({'resource': 'document'}, patch.send(None))
- self.assertEqual(guid1, patch.send(None)['guid'])
- self.assertEqual(guid3, patch.send(None)['guid'])
- self.assertEqual(guid5, patch.send(None)['guid'])
- self.assertEqual({'commit': [[1, 1], [3, 3]]}, patch.throw(StopIteration()))
- try:
- patch.send(None)
- assert False
- except StopIteration:
- pass
-
- patch = diff(volume, in_seq)
- self.assertEqual({'resource': 'document'}, patch.send(None))
- self.assertEqual(guid1, patch.send(None)['guid'])
- self.assertEqual(guid3, patch.send(None)['guid'])
- self.assertEqual(guid5, patch.send(None)['guid'])
- self.assertEqual({'commit': [[1, 5]]}, patch.send(None))
- try:
- patch.send(None)
- assert False
- except StopIteration:
- pass
-
- def test_diff_DoNotStretchContinuesPacket(self):
-
- class Document(db.Resource):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- volume = db.Volume('db', [Document])
- cp = NodeRoutes('guid', volume)
-
- guid1 = call(cp, method='POST', document='document', content={'prop': 'a'})
- volume['document'].delete(guid1)
- guid2 = call(cp, method='POST', document='document', content={'prop': 'b'})
- volume['document'].delete(guid2)
- guid3 = call(cp, method='POST', document='document', content={'prop': 'c'})
- self.utime('db/document/%s/%s' % (guid3[:2], guid3), 2)
- guid4 = call(cp, method='POST', document='document', content={'prop': 'd'})
- volume['document'].delete(guid4)
- guid5 = call(cp, method='POST', document='document', content={'prop': 'f'})
- self.utime('db/document/%s/%s' % (guid5[:2], guid5), 2)
-
- in_seq = toolkit.Sequence([[1, None]])
- patch = diff(volume, in_seq, toolkit.Sequence([[1, 1]]))
- self.assertEqual({'resource': 'document'}, patch.send(None))
- self.assertEqual(guid3, patch.send(None)['guid'])
- self.assertEqual(guid5, patch.send(None)['guid'])
- self.assertEqual({'commit': [[1, 1], [3, 3], [5, 5]]}, patch.send(None))
- try:
- patch.send(None)
- assert False
- except StopIteration:
- pass
-
- def test_diff_TheSameInSeqForAllDocuments(self):
-
- class Document1(db.Resource):
- pass
-
- class Document2(db.Resource):
- pass
-
- class Document3(db.Resource):
- pass
-
- volume = db.Volume('db', [Document1, Document2, Document3])
- cp = NodeRoutes('guid', volume)
-
- guid3 = call(cp, method='POST', document='document1', content={})
- self.utime('db/document/%s/%s' % (guid3[:2], guid3), 3)
- guid2 = call(cp, method='POST', document='document2', content={})
- self.utime('db/document/%s/%s' % (guid2[:2], guid2), 2)
- guid1 = call(cp, method='POST', document='document3', content={})
- self.utime('db/document/%s/%s' % (guid1[:2], guid1), 1)
-
- in_seq = toolkit.Sequence([[1, None]])
- patch = diff(volume, in_seq)
- self.assertEqual({'resource': 'document1'}, patch.send(None))
- self.assertEqual(guid3, patch.send(None)['guid'])
- self.assertEqual({'resource': 'document2'}, patch.send(None))
- self.assertEqual(guid2, patch.send(None)['guid'])
- self.assertEqual({'resource': 'document3'}, patch.send(None))
- self.assertEqual(guid1, patch.send(None)['guid'])
- self.assertEqual({'commit': [[1, 3]]}, patch.send(None))
- try:
- patch.send(None)
- assert False
- except StopIteration:
- pass
-
- def test_merge_Create(self):
-
- class Document1(db.Resource):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- class Document2(db.Resource):
- pass
-
- self.touch(('db/seqno', '100'))
- volume = db.Volume('db', [Document1, Document2])
-
- records = [
- {'resource': 'document1'},
- {'guid': '1', 'diff': {
- 'guid': {'value': '1', 'mtime': 1.0},
- 'ctime': {'value': 2, 'mtime': 2.0},
- 'mtime': {'value': 3, 'mtime': 3.0},
- 'prop': {'value': '4', 'mtime': 4.0},
- }},
- {'resource': 'document2'},
- {'guid': '5', 'diff': {
- 'guid': {'value': '5', 'mtime': 5.0},
- 'ctime': {'value': 6, 'mtime': 6.0},
- 'mtime': {'value': 7, 'mtime': 7.0},
- }},
- {'commit': [[1, 2]]},
- ]
- self.assertEqual(([[1, 2]], [[101, 102]]), merge(volume, records))
-
- self.assertEqual(
- {'guid': '1', 'prop': '4', 'ctime': 2, 'mtime': 3},
- volume['document1'].get('1').properties(['guid', 'ctime', 'mtime', 'prop']))
- self.assertEqual(1, os.stat('db/document1/1/1/guid').st_mtime)
- self.assertEqual(2, os.stat('db/document1/1/1/ctime').st_mtime)
- self.assertEqual(3, os.stat('db/document1/1/1/mtime').st_mtime)
- self.assertEqual(4, os.stat('db/document1/1/1/prop').st_mtime)
-
- self.assertEqual(
- {'guid': '5', 'ctime': 6, 'mtime': 7},
- volume['document2'].get('5').properties(['guid', 'ctime', 'mtime']))
- self.assertEqual(5, os.stat('db/document2/5/5/guid').st_mtime)
- self.assertEqual(6, os.stat('db/document2/5/5/ctime').st_mtime)
- self.assertEqual(7, os.stat('db/document2/5/5/mtime').st_mtime)
-
- def test_merge_Update(self):
-
- class Document(db.Resource):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- self.touch(('db/seqno', '100'))
- volume = db.Volume('db', [Document])
- volume['document'].create({'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1})
- for i in os.listdir('db/document/1/1'):
- os.utime('db/document/1/1/%s' % i, (2, 2))
-
- records = [
- {'resource': 'document'},
- {'guid': '1', 'diff': {'prop': {'value': '2', 'mtime': 1.0}}},
- {'commit': [[1, 1]]},
- ]
- self.assertEqual(([[1, 1]], []), merge(volume, records))
- self.assertEqual(
- {'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1},
- volume['document'].get('1').properties(['guid', 'ctime', 'mtime', 'prop']))
- self.assertEqual(2, os.stat('db/document/1/1/prop').st_mtime)
-
- records = [
- {'resource': 'document'},
- {'guid': '1', 'diff': {'prop': {'value': '3', 'mtime': 2.0}}},
- {'commit': [[2, 2]]},
- ]
- self.assertEqual(([[2, 2]], []), merge(volume, records))
- self.assertEqual(
- {'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1},
- volume['document'].get('1').properties(['guid', 'ctime', 'mtime', 'prop']))
- self.assertEqual(2, os.stat('db/document/1/1/prop').st_mtime)
-
- records = [
- {'resource': 'document'},
- {'guid': '1', 'diff': {'prop': {'value': '4', 'mtime': 3.0}}},
- {'commit': [[3, 3]]},
- ]
- self.assertEqual(([[3, 3]], [[102, 102]]), merge(volume, records))
- self.assertEqual(
- {'guid': '1', 'prop': '4', 'ctime': 1, 'mtime': 1},
- volume['document'].get('1').properties(['guid', 'ctime', 'mtime', 'prop']))
- self.assertEqual(3, os.stat('db/document/1/1/prop').st_mtime)
-
- def test_merge_MultipleCommits(self):
-
- class Document(db.Resource):
-
- @db.stored_property()
- def prop(self, value):
- return value
-
- self.touch(('db/seqno', '100'))
- volume = db.Volume('db', [Document])
-
- def generator():
- for i in [
- {'resource': 'document'},
- {'commit': [[1, 1]]},
- {'guid': '1', 'diff': {
- 'guid': {'value': '1', 'mtime': 1.0},
- 'ctime': {'value': 2, 'mtime': 2.0},
- 'mtime': {'value': 3, 'mtime': 3.0},
- 'prop': {'value': '4', 'mtime': 4.0},
- }},
- {'commit': [[2, 3]]},
- ]:
- yield i
-
- records = generator()
- self.assertEqual(([[1, 3]], [[101, 101]]), merge(volume, records))
- assert volume['document'].exists('1')
-
- def test_merge_UpdateStats(self):
- volume = db.Volume('db', model.RESOURCES)
- cp = NodeRoutes('guid', volume)
- stats = Sniffer(volume, 'stats/node')
-
- records = [
- {'resource': 'context'},
- {'guid': 'context', 'diff': {
- 'guid': {'value': 'context', 'mtime': 1.0},
- 'ctime': {'value': 1, 'mtime': 1.0},
- 'mtime': {'value': 1, 'mtime': 1.0},
- 'type': {'value': ['package'], 'mtime': 1.0},
- 'title': {'value': {}, 'mtime': 1.0},
- 'summary': {'value': {}, 'mtime': 1.0},
- 'description': {'value': {}, 'mtime': 1.0},
- }},
- {'resource': 'post'},
- {'guid': 'topic_1', 'diff': {
- 'guid': {'value': 'topic_1', 'mtime': 1.0},
- 'ctime': {'value': 1, 'mtime': 1.0},
- 'mtime': {'value': 1, 'mtime': 1.0},
- 'type': {'value': 'object', 'mtime': 1.0},
- 'context': {'value': 'context', 'mtime': 1.0},
- 'title': {'value': {}, 'mtime': 1.0},
- 'message': {'value': {}, 'mtime': 1.0},
- 'solution': {'value': 'solution_1', 'mtime': 1.0},
- }},
- {'guid': 'topic_2', 'diff': {
- 'guid': {'value': 'topic_2', 'mtime': 1.0},
- 'ctime': {'value': 1, 'mtime': 1.0},
- 'mtime': {'value': 1, 'mtime': 1.0},
- 'type': {'value': 'object', 'mtime': 1.0},
- 'context': {'value': 'context', 'mtime': 1.0},
- 'title': {'value': {}, 'mtime': 1.0},
- 'message': {'value': {}, 'mtime': 1.0},
- 'solution': {'value': 'solution_2', 'mtime': 1.0},
- }},
- {'guid': 'context_review', 'diff': {
- 'guid': {'value': 'context_review', 'mtime': 1.0},
- 'ctime': {'value': 1, 'mtime': 1.0},
- 'mtime': {'value': 1, 'mtime': 1.0},
- 'context': {'value': 'context', 'mtime': 1.0},
- 'vote': {'value': 1, 'mtime': 1.0},
- 'author': {'mtime': 1, 'value': {}},
- 'layer': {'mtime': 1, 'value': []},
- 'tags': {'mtime': 1, 'value': []},
- 'type': {'value': 'review', 'mtime': 1.0},
- }},
- {'guid': 'topic_review', 'diff': {
- 'guid': {'value': 'topic_review', 'mtime': 1.0},
- 'ctime': {'value': 1, 'mtime': 1.0},
- 'mtime': {'value': 1, 'mtime': 1.0},
- 'context': {'value': 'context', 'mtime': 1.0},
- 'topic': {'value': 'topic_1', 'mtime': 1.0},
- 'vote': {'value': 1, 'mtime': 1.0},
- 'author': {'mtime': 1, 'value': {}},
- 'layer': {'mtime': 1, 'value': []},
- 'tags': {'mtime': 1, 'value': []},
- 'type': {'value': 'feedback', 'mtime': 1.0},
- }},
- {'guid': 'solution_1', 'diff': {
- 'guid': {'value': 'solution_1', 'mtime': 1.0},
- 'ctime': {'value': 1, 'mtime': 1.0},
- 'mtime': {'value': 1, 'mtime': 1.0},
- 'context': {'value': 'context', 'mtime': 1.0},
- 'topic': {'value': 'topic_1', 'mtime': 1.0},
- 'type': {'value': 'answer', 'mtime': 1.0},
- 'title': {'value': {}, 'mtime': 1.0},
- 'message': {'value': {}, 'mtime': 1.0},
- }},
- {'guid': 'solution_2', 'diff': {
- 'guid': {'value': 'solution_2', 'mtime': 1.0},
- 'ctime': {'value': 1, 'mtime': 1.0},
- 'mtime': {'value': 1, 'mtime': 1.0},
- 'context': {'value': 'context', 'mtime': 1.0},
- 'topic': {'value': 'topic_2', 'mtime': 1.0},
- 'type': {'value': 'answer', 'mtime': 1.0},
- 'title': {'value': {}, 'mtime': 1.0},
- 'message': {'value': {}, 'mtime': 1.0},
- }},
- {'resource': 'release'},
- {'guid': 'release', 'diff': {
- 'guid': {'value': 'release', 'mtime': 1.0},
- 'ctime': {'value': 1, 'mtime': 1.0},
- 'mtime': {'value': 1, 'mtime': 1.0},
- 'context': {'value': 'context', 'mtime': 1.0},
- 'license': {'value': ['GPL-3.0'], 'mtime': 1.0},
- 'version': {'value': '1', 'mtime': 1.0},
- 'stability': {'value': 'stable', 'mtime': 1.0},
- 'notes': {'value': {}, 'mtime': 1.0},
- }},
- {'commit': [[1, 1]]},
- ]
- merge(volume, records, stats=stats)
- ts = int(current_time())
- stats.commit(ts)
- stats.commit_objects()
-
- self.assertEqual([
- [('post', ts, {
- 'downloaded': 0.0,
- 'total': 6.0,
- })],
- [('user', ts, {
- 'total': 0.0,
- })],
- [('context', ts, {
- 'failed': 0.0,
- 'downloaded': 0.0,
- 'total': 1.0,
- 'released': 1.0,
- })],
- ],
- [[(j.name,) + i for i in j.get(j.last, j.last)] for j in Rrd('stats/node', 1)])
- self.assertEqual([1, 1], volume['context'].get('context')['rating'])
- self.assertEqual([1, 1], volume['post'].get('topic_1')['rating'])
-
- records = [
- {'resource': 'post'},
- {'guid': 'topic_2', 'diff': {'solution': {'value': '', 'mtime': 2.0}}},
- {'commit': [[2, 2]]},
- ]
- merge(volume, records, stats=stats)
- ts += 1
- stats.commit(ts)
- stats.commit_objects()
-
- self.assertEqual([
- [('post', ts, {
- 'downloaded': 0.0,
- 'total': 6.0,
- })],
- [('user', ts, {
- 'total': 0.0,
- })],
- [('context', ts, {
- 'failed': 0.0,
- 'downloaded': 0.0,
- 'total': 1.0,
- 'released': 1.0,
- })],
- ],
- [[(j.name,) + i for i in j.get(j.last, j.last)] for j in Rrd('stats/node', 1)])
-
- records = [
- {'resource': 'context'},
- {'guid': 'context', 'diff': {'layer': {'value': ['deleted'], 'mtime': 3.0}}},
- {'resource': 'post'},
- {'guid': 'topic_1', 'diff': {'layer': {'value': ['deleted'], 'mtime': 3.0}}},
- {'guid': 'topic_2', 'diff': {'layer': {'value': ['deleted'], 'mtime': 3.0}}},
- {'guid': 'context_review', 'diff': {'layer': {'value': ['deleted'], 'mtime': 3.0}}},
- {'guid': 'topic_review', 'diff': {'layer': {'value': ['deleted'], 'mtime': 3.0}}},
- {'guid': 'solution_1', 'diff': {'layer': {'value': ['deleted'], 'mtime': 3.0}}},
- {'guid': 'solution_2', 'diff': {'layer': {'value': ['deleted'], 'mtime': 3.0}}},
- {'resource': 'release'},
- {'guid': 'release', 'diff': {'layer': {'value': ['deleted'], 'mtime': 3.0}}},
- {'commit': [[3, 3]]},
- ]
- merge(volume, records, stats=stats)
- ts += 1
- stats.commit(ts)
- stats.commit_objects()
-
- self.assertEqual([
- [('post', ts, {
- 'downloaded': 0.0,
- 'total': 0.0,
- })],
- [('user', ts, {
- 'total': 0.0,
- })],
- [('context', ts, {
- 'failed': 0.0,
- 'downloaded': 0.0,
- 'total': 0.0,
- 'released': 1.0,
- })],
- ],
- [[(j.name,) + i for i in j.get(j.last, j.last)] for j in Rrd('stats/node', 1)])
-
- def test_diff_Blobs(self):
-
- class Document(db.Resource):
-
- @db.blob_property()
- def prop(self, value):
- return value
-
- volume = db.Volume('db', [Document])
- cp = NodeRoutes('guid', volume)
-
- guid = call(cp, method='POST', document='document', content={})
- call(cp, method='PUT', document='document', guid=guid, content={'prop': 'payload'})
- self.utime('db', 0)
-
- patch = diff(volume, toolkit.Sequence([[1, None]]))
- self.assertEqual(
- {'resource': 'document'},
- next(patch))
- record = next(patch)
- self.assertEqual('payload', ''.join([i for i in record.pop('blob')]))
- self.assertEqual(
- {'guid': guid, 'blob_size': len('payload'), 'diff': {
- 'prop': {
- 'digest': hashlib.sha1('payload').hexdigest(),
- 'blob_size': len('payload'),
- 'mime_type': 'application/octet-stream',
- 'mtime': 0,
- },
- }},
- record)
- self.assertEqual(
- {'guid': guid, 'diff': {
- 'guid': {'value': guid, 'mtime': 0},
- 'author': {'mtime': 0, 'value': {}},
- 'layer': {'mtime': 0, 'value': []},
- 'tags': {'mtime': 0, 'value': []},
- 'mtime': {'value': 0, 'mtime': 0},
- 'ctime': {'value': 0, 'mtime': 0},
- }},
- next(patch))
- self.assertEqual(
- {'commit': [[1, 2]]},
- next(patch))
- self.assertRaises(StopIteration, next, patch)
-
- def test_diff_BlobUrls(self):
- url = 'http://src.sugarlabs.org/robots.txt'
- blob = urllib2.urlopen(url).read()
-
- class Document(db.Resource):
-
- @db.blob_property()
- def prop(self, value):
- return value
-
- volume = db.Volume('db', [Document])
- cp = NodeRoutes('guid', volume)
-
- guid = call(cp, method='POST', document='document', content={})
- call(cp, method='PUT', document='document', guid=guid, content={'prop': {'url': url}})
- self.utime('db', 1)
-
- self.assertEqual([
- {'resource': 'document'},
- {'guid': guid,
- 'diff': {
- 'guid': {'value': guid, 'mtime': 1},
- 'author': {'mtime': 1, 'value': {}},
- 'layer': {'mtime': 1, 'value': []},
- 'tags': {'mtime': 1, 'value': []},
- 'mtime': {'value': 0, 'mtime': 1},
- 'ctime': {'value': 0, 'mtime': 1},
- 'prop': {'url': url, 'mtime': 1},
- },
- },
- {'commit': [[1, 2]]},
- ],
- [i for i in diff(volume, toolkit.Sequence([[1, None]]))])
-
- patch = diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=True)
- self.assertEqual(
- {'resource': 'document'},
- next(patch))
- record = next(patch)
- self.assertEqual(blob, ''.join([i for i in record.pop('blob')]))
- self.assertEqual(
- {'guid': guid, 'blob_size': len(blob), 'diff': {'prop': {'mtime': 1}}},
- record)
- self.assertEqual(
- {'guid': guid, 'diff': {
- 'guid': {'value': guid, 'mtime': 1},
- 'author': {'mtime': 1, 'value': {}},
- 'layer': {'mtime': 1, 'value': []},
- 'tags': {'mtime': 1, 'value': []},
- 'mtime': {'value': 0, 'mtime': 1},
- 'ctime': {'value': 0, 'mtime': 1},
- }},
- next(patch))
- self.assertEqual(
- {'commit': [[1, 2]]},
- next(patch))
- self.assertRaises(StopIteration, next, patch)
-
- def test_diff_SkipBrokenBlobUrls(self):
-
- class Document(db.Resource):
-
- @db.blob_property()
- def prop(self, value):
- return value
-
- volume = db.Volume('db', [Document])
- cp = NodeRoutes('guid', volume)
-
- guid1 = call(cp, method='POST', document='document', content={})
- call(cp, method='PUT', document='document', guid=guid1, content={'prop': {'url': 'http://foo/bar'}})
- guid2 = call(cp, method='POST', document='document', content={})
- self.utime('db', 1)
-
- self.assertEqual([
- {'resource': 'document'},
- {'guid': guid1,
- 'diff': {
- 'guid': {'value': guid1, 'mtime': 1},
- 'author': {'mtime': 1, 'value': {}},
- 'layer': {'mtime': 1, 'value': []},
- 'tags': {'mtime': 1, 'value': []},
- 'mtime': {'value': 0, 'mtime': 1},
- 'ctime': {'value': 0, 'mtime': 1},
- 'prop': {'url': 'http://foo/bar', 'mtime': 1},
- },
- },
- {'guid': guid2,
- 'diff': {
- 'guid': {'value': guid2, 'mtime': 1},
- 'author': {'mtime': 1, 'value': {}},
- 'layer': {'mtime': 1, 'value': []},
- 'tags': {'mtime': 1, 'value': []},
- 'mtime': {'value': 0, 'mtime': 1},
- 'ctime': {'value': 0, 'mtime': 1},
- },
- },
- {'commit': [[1, 3]]},
- ],
- [i for i in diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=False)])
-
- self.assertEqual([
- {'resource': 'document'},
- {'guid': guid1,
- 'diff': {
- 'guid': {'value': guid1, 'mtime': 1},
- 'author': {'mtime': 1, 'value': {}},
- 'layer': {'mtime': 1, 'value': []},
- 'tags': {'mtime': 1, 'value': []},
- 'mtime': {'value': 0, 'mtime': 1},
- 'ctime': {'value': 0, 'mtime': 1},
- },
- },
- {'guid': guid2,
- 'diff': {
- 'guid': {'value': guid2, 'mtime': 1},
- 'author': {'mtime': 1, 'value': {}},
- 'layer': {'mtime': 1, 'value': []},
- 'tags': {'mtime': 1, 'value': []},
- 'mtime': {'value': 0, 'mtime': 1},
- 'ctime': {'value': 0, 'mtime': 1},
- },
- },
- {'commit': [[1, 3]]},
- ],
- [i for i in diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=True)])
-
- def test_merge_Blobs(self):
-
- class Document(db.Resource):
-
- @db.blob_property()
- def prop(self, value):
- return value
-
- volume = db.Volume('db', [Document])
-
- merge(volume, [
- {'resource': 'document'},
- {'guid': '1', 'diff': {
- 'guid': {'value': '1', 'mtime': 1.0},
- 'ctime': {'value': 2, 'mtime': 2.0},
- 'mtime': {'value': 3, 'mtime': 3.0},
- 'prop': {
- 'blob': StringIO('payload'),
- 'blob_size': len('payload'),
- 'digest': hashlib.sha1('payload').hexdigest(),
- 'mime_type': 'foo/bar',
- 'mtime': 1,
- },
- }},
- {'commit': [[1, 1]]},
- ])
-
- assert volume['document'].exists('1')
- blob = volume['document'].get('1')['prop']
- self.assertEqual(1, blob['mtime'])
- self.assertEqual('foo/bar', blob['mime_type'])
- self.assertEqual(hashlib.sha1('payload').hexdigest(), blob['digest'])
- self.assertEqual(tests.tmpdir + '/db/document/1/1/prop.blob', blob['blob'])
- self.assertEqual('payload', file(blob['blob']).read())
-
- def test_diff_ByLayers(self):
-
- class Context(db.Resource):
- pass
-
- class release(db.Resource):
- pass
-
- class Review(db.Resource):
- pass
-
- volume = db.Volume('db', [Context, release, Review])
- volume['context'].create({'guid': '0', 'ctime': 1, 'mtime': 1, 'layer': ['layer0', 'common']})
- volume['context'].create({'guid': '1', 'ctime': 1, 'mtime': 1, 'layer': 'layer1'})
- volume['release'].create({'guid': '2', 'ctime': 2, 'mtime': 2, 'layer': 'layer2'})
- volume['review'].create({'guid': '3', 'ctime': 3, 'mtime': 3, 'layer': 'layer3'})
-
- volume['context'].update('0', {'tags': '0'})
- volume['context'].update('1', {'tags': '1'})
- volume['release'].update('2', {'tags': '2'})
- volume['review'].update('3', {'tags': '3'})
- self.utime('db', 0)
-
- self.assertEqual(sorted([
- {'resource': 'context'},
- {'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
- {'guid': '1', 'diff': {'tags': {'value': '1', 'mtime': 0}}},
- {'resource': 'release'},
- {'guid': '2', 'diff': {'tags': {'value': '2', 'mtime': 0}}},
- {'resource': 'review'},
- {'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
- {'commit': [[5, 8]]},
- ]),
- sorted([i for i in diff(volume, toolkit.Sequence([[5, None]]))]))
-
- self.assertEqual(sorted([
- {'resource': 'context'},
- {'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
- {'guid': '1', 'diff': {'tags': {'value': '1', 'mtime': 0}}},
- {'resource': 'release'},
- {'resource': 'review'},
- {'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
- {'commit': [[5, 8]]},
- ]),
- sorted([i for i in diff(volume, toolkit.Sequence([[5, None]]), layer='layer1')]))
-
- self.assertEqual(sorted([
- {'resource': 'context'},
- {'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
- {'resource': 'release'},
- {'guid': '2', 'diff': {'tags': {'value': '2', 'mtime': 0}}},
- {'resource': 'review'},
- {'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
- {'commit': [[5, 8]]},
- ]),
- sorted([i for i in diff(volume, toolkit.Sequence([[5, None]]), layer='layer2')]))
-
- self.assertEqual(sorted([
- {'resource': 'context'},
- {'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
- {'resource': 'release'},
- {'resource': 'review'},
- {'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
- {'commit': [[5, 8]]},
- ]),
- sorted([i for i in diff(volume, toolkit.Sequence([[5, None]]), layer='foo')]))
-
-
-def call(routes, method, document=None, guid=None, prop=None, cmd=None, content=None, **kwargs):
- path = []
- if document:
- path.append(document)
- if guid:
- path.append(guid)
- if prop:
- path.append(prop)
- request = Request(method=method, path=path, cmd=cmd, content=content)
- request.update(kwargs)
- request.environ['HTTP_HOST'] = '127.0.0.1'
- router = Router(routes)
- return router.call(request, Response())
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/toolkit/__main__.py b/tests/units/toolkit/__main__.py
index 79b0e5b..68cb254 100644
--- a/tests/units/toolkit/__main__.py
+++ b/tests/units/toolkit/__main__.py
@@ -2,6 +2,7 @@
from __init__ import tests
+from coroutine import *
from http import *
from lsb_release import *
from mountpoints import *
@@ -11,6 +12,7 @@ from options import *
from spec import *
from router import *
from gbus import *
+from i18n import *
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/toolkit/coroutine.py b/tests/units/toolkit/coroutine.py
new file mode 100755
index 0000000..95738d0
--- /dev/null
+++ b/tests/units/toolkit/coroutine.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# sugar-lint: disable
+
+from __init__ import tests
+
+from sugar_network.toolkit.coroutine import Spooler, spawn, sleep
+
+
+class CoroutineTest(tests.Test):
+
+ def test_Spooler_ContinuousFeeding(self):
+ spooler = Spooler()
+ events = []
+
+ def consumer(num):
+ while True:
+ events[num].append(spooler.wait())
+
+ for i in range(10):
+ events.append([])
+ spawn(consumer, i)
+ sleep(.1)
+
+ for i in range(10):
+ spooler.notify_all(i)
+ sleep(.1)
+ self.assertEqual([range(10)] * 10, events)
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/toolkit/i18n.py b/tests/units/toolkit/i18n.py
new file mode 100755
index 0000000..6c4c0ca
--- /dev/null
+++ b/tests/units/toolkit/i18n.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# sugar-lint: disable
+
+import gettext
+
+from __init__ import tests
+
+from sugar_network.toolkit import i18n
+
+
+class I18nTest(tests.Test):
+
+ def test_decode(self):
+ # Fallback to default lang
+ i18n._default_langs = ['default']
+ self.assertEqual('foo', i18n.decode({'lang': 'foo', 'default': 'bar'}, 'lang'))
+ self.assertEqual('bar', i18n.decode({'lang': 'foo', 'default': 'bar'}, 'fake'))
+
+ # Exact accept_language
+ self.assertEqual('', i18n.decode(None, 'lang'))
+ self.assertEqual('foo', i18n.decode('foo', 'lang'))
+ self.assertEqual('foo', i18n.decode({'lang': 'foo', 'fake': 'bar', 'default': 'default'}, 'lang'))
+ self.assertEqual('foo', i18n.decode({'lang': 'foo', 'fake': 'bar', 'default': 'default'}, ['lang', 'fake']))
+ self.assertEqual('bar', i18n.decode({'lang': 'foo', 'fake': 'bar', 'default': 'default'}, ['fake', 'lang']))
+
+ # Last resort
+ self.assertEqual('foo', i18n.decode({'1': 'foo', '2': 'bar'}, 'fake'))
+
+ # Primed accept_language
+ self.assertEqual('foo', i18n.decode({'1': 'foo', '2': 'bar', 'default': 'default'}, '1-a'))
+
+ # Primed i18n value
+ self.assertEqual('bar', i18n.decode({'1-a': 'foo', '1': 'bar', 'default': 'default'}, '1-b'))
+ self.assertEqual('foo', i18n.decode({'1-a': 'foo', '2': 'bar', 'default': 'default'}, '1-b'))
+
+ def test_decode_EnAsTheLastResort(self):
+ i18n._default_langs = ['en-us']
+ self.assertEqual('right', i18n.decode({'a': 'wrong', 'en': 'right'}, 'probe'))
+ self.assertEqual('exact', i18n.decode({'a': 'wrong', 'en': 'right', 'probe': 'exact'}, 'probe'))
+
+ def test_encode(self):
+ self.assertEqual({
+ 'en': 'Delete Log File',
+ 'es': 'Borrar el archivo de registro',
+ 'fr': 'Supprimer le fichier log',
+ }, i18n.encode('Delete Log File'))
+
+ self.assertEqual({
+ 'en': "Error: Can't open file 'probe'\n",
+ 'es': "Error: No se puede abrir el archivo 'probe'\n",
+ 'fr': "Erreur : Ouverture du fichier 'probe' impossible\n",
+ }, i18n.encode("Error: Can't open file '%s'\n", 'probe'))
+
+ self.assertEqual({
+ 'en': "Error: Can't open file '1'\n",
+ 'es': "Error: No se puede abrir el archivo '2'\n",
+ 'fr': "Erreur : Ouverture du fichier '3' impossible\n",
+ }, i18n.encode("Error: Can't open file '%s'\n", {'en': 1, 'es': 2, 'fr': 3}))
+
+ self.assertEqual({
+ 'en': '1 when deleting 5',
+ 'es': '2 borrando 6',
+ 'fr': '3 lors de la suppression de 7',
+ }, i18n.encode('%(error)s when deleting %(file)s', error={'en': 1, 'es': 2, 'fr': 3}, file={'en': 5, 'es': 6, 'fr': 7}))
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/toolkit/router.py b/tests/units/toolkit/router.py
index a9b17f2..3dd1306 100755
--- a/tests/units/toolkit/router.py
+++ b/tests/units/toolkit/router.py
@@ -9,9 +9,10 @@ from cStringIO import StringIO
from __init__ import tests, src_root
-from sugar_network import db, client
-from sugar_network.toolkit.router import Blob, Router, Request, _parse_accept_language, route, fallbackroute, preroute, postroute, _filename
-from sugar_network.toolkit import default_lang, http, coroutine
+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.coroutine import this
+from sugar_network.toolkit import http, coroutine
class RouterTest(tests.Test):
@@ -499,26 +500,44 @@ class RouterTest(tests.Test):
def test_routes_Pre(self):
- class Routes(object):
+ class A(object):
@route('PROBE')
def ok(self, request, response):
return request['probe']
@preroute
- def preroute(self, op, request, response):
- request['probe'] = 'request'
+ def _(self, op, request, response):
+ request['probe'] = '_'
- router = Router(Routes())
+ class B1(A):
+
+ @preroute
+ def z(self, op, request, response):
+ request['probe'] += 'z'
+
+ class B2(object):
+
+ @preroute
+ def f(self, op, request, response):
+ request['probe'] += 'f'
+
+ class C(B1, B2):
+
+ @preroute
+ def a(self, op, request, response):
+ request['probe'] += 'a'
+
+ router = Router(C())
self.assertEqual(
- ['request'],
+ ['_afz'],
[i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/'}, lambda *args: None)])
def test_routes_Post(self):
postroutes = []
- class Routes(object):
+ class A(object):
@route('OK')
def ok(self):
@@ -529,20 +548,51 @@ class RouterTest(tests.Test):
raise Exception('fail')
@postroute
- def postroute(self, request, response, result, exception):
- postroutes.append((result, str(exception)))
+ def _(self, request, response, result, exception):
+ postroutes.append(('_', result, str(exception)))
- router = Router(Routes())
+ class B1(A):
+
+ @postroute
+ def z(self, request, response, result, exception):
+ postroutes.append(('z', result, str(exception)))
+
+ class B2(object):
+
+ @postroute
+ def f(self, request, response, result, exception):
+ postroutes.append(('f', result, str(exception)))
+
+ class C(B1, B2):
+
+ @postroute
+ def a(self, request, response, result, exception):
+ postroutes.append(('a', result, str(exception)))
+
+ router = Router(C())
self.assertEqual(
['ok'],
[i for i in router({'REQUEST_METHOD': 'OK', 'PATH_INFO': '/'}, lambda *args: None)])
- self.assertEqual(('ok', 'None'), postroutes[-1])
+ self.assertEqual([
+ ('_', 'ok', 'None'),
+ ('a', 'ok', 'None'),
+ ('f', 'ok', 'None'),
+ ('z', 'ok', 'None'),
+ ],
+ postroutes)
+ del postroutes[:]
self.assertEqual(
['{"request": "/", "error": "fail"}'],
[i for i in router({'REQUEST_METHOD': 'FAIL', 'PATH_INFO': '/'}, lambda *args: None)])
- self.assertEqual((None, 'fail'), postroutes[-1])
+ self.assertEqual([
+ ('_', None, 'fail'),
+ ('a', None, 'fail'),
+ ('f', None, 'fail'),
+ ('z', None, 'fail'),
+ ],
+ postroutes)
def test_routes_WildcardsAsLastResort(self):
@@ -968,14 +1018,14 @@ class RouterTest(tests.Test):
],
response)
- def test_BlobsRedirects(self):
+ def test_FilesRedirects(self):
URL = 'http://sugarlabs.org'
class CommandsProcessor(object):
@route('GET')
def get(self, response):
- return Blob(url=URL)
+ return toolkit.File(meta={'url': URL})
router = Router(CommandsProcessor())
@@ -1171,33 +1221,18 @@ class RouterTest(tests.Test):
],
response)
- def test_filename(self):
- self.assertEqual('Foo', _filename('foo', None))
- self.assertEqual('Foo-Bar', _filename(['foo', 'bar'], None))
- self.assertEqual('FOO-BaR', _filename([' f o o', ' ba r '], None))
-
- self.assertEqual('12-3', _filename(['/1/2/', '/3/'], None))
-
- self.assertEqual('Foo.png', _filename('foo', 'image/png'))
- self.assertEqual('Foo-Bar.gif', _filename(['foo', 'bar'], 'image/gif'))
- self.assertEqual('Fake', _filename('fake', 'foo/bar'))
-
- self.assertEqual('Eng', _filename({default_lang(): 'eng'}, None))
- self.assertEqual('Eng', _filename([{default_lang(): 'eng'}], None))
- self.assertEqual('Bar-1', _filename([{'lang': 'foo', default_lang(): 'bar'}, '1'], None))
-
- def test_BlobsDisposition(self):
+ def test_FilesDisposition(self):
self.touch(('blob.data', 'value'))
class CommandsProcessor(object):
@route('GET', [], '1')
def cmd1(self, request):
- return Blob(name='foo', blob='blob.data')
+ return toolkit.File('blob.data', {'name': 'foo', 'mime_type': 'application/octet-stream'})
@route('GET', [], cmd='2')
def cmd2(self, request):
- return Blob(filename='foo.bar', blob='blob.data')
+ return toolkit.File('blob.data', {'filename': 'foo.bar'})
router = Router(CommandsProcessor())
@@ -1216,7 +1251,7 @@ class RouterTest(tests.Test):
'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"',
+ 'content-disposition': 'attachment; filename="foo.obj"',
}
],
response)
@@ -1292,7 +1327,6 @@ class RouterTest(tests.Test):
[i for i in reply])
def test_SpawnEventStream(self):
- events = []
class Routes(object):
@@ -1301,8 +1335,10 @@ class RouterTest(tests.Test):
yield {}
yield {'foo': 'bar'}
- def broadcast(self, event):
- events.append(event.copy())
+ events = []
+ def localcast(event):
+ events.append(event.copy())
+ this.localcast = localcast
reply = Router(Routes(), allow_spawn=True)({
'PATH_INFO': '/resource/guid/prop',
@@ -1321,7 +1357,6 @@ class RouterTest(tests.Test):
del events[:]
def test_SpawnEventStreamFailure(self):
- events = []
class Routes(object):
@@ -1332,8 +1367,10 @@ class RouterTest(tests.Test):
yield {'foo': 'bar'}, {'add': 'on'}
raise RuntimeError('error')
- def broadcast(self, event):
- events.append(event.copy())
+ events = []
+ def localcast(event):
+ events.append(event.copy())
+ this.localcast = localcast
reply = Router(Routes(), allow_spawn=True)({
'PATH_INFO': '/',
@@ -1353,7 +1390,6 @@ class RouterTest(tests.Test):
del events[:]
def test_ReadRequestOnEventStreamSpawn(self):
- events = []
class Routes(object):
@@ -1362,8 +1398,10 @@ class RouterTest(tests.Test):
yield {}
yield {'request': request.content}
- def broadcast(self, event):
- events.append(event.copy())
+ events = []
+ def localcast(event):
+ events.append(event.copy())
+ this.localcast = localcast
reply = Router(Routes(), allow_spawn=True)({
'PATH_INFO': '/',
diff --git a/tests/units/toolkit/toolkit.py b/tests/units/toolkit/toolkit.py
index 8c13b84..07ed9c6 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
+from sugar_network.toolkit import Seqno, Sequence, File
class UtilTest(tests.Test):
@@ -421,33 +421,14 @@ class UtilTest(tests.Test):
['d', 'a', 'b', 'c'],
[i for i in stack])
- def test_gettext(self):
- # Fallback to default lang
- toolkit._default_langs = ['default']
- self.assertEqual('foo', toolkit.gettext({'lang': 'foo', 'default': 'bar'}, 'lang'))
- self.assertEqual('bar', toolkit.gettext({'lang': 'foo', 'default': 'bar'}, 'fake'))
-
- # Exact accept_language
- self.assertEqual('', toolkit.gettext(None, 'lang'))
- self.assertEqual('foo', toolkit.gettext('foo', 'lang'))
- self.assertEqual('foo', toolkit.gettext({'lang': 'foo', 'fake': 'bar', 'default': 'default'}, 'lang'))
- self.assertEqual('foo', toolkit.gettext({'lang': 'foo', 'fake': 'bar', 'default': 'default'}, ['lang', 'fake']))
- self.assertEqual('bar', toolkit.gettext({'lang': 'foo', 'fake': 'bar', 'default': 'default'}, ['fake', 'lang']))
-
- # Last resort
- self.assertEqual('foo', toolkit.gettext({'1': 'foo', '2': 'bar'}, 'fake'))
-
- # Primed accept_language
- self.assertEqual('foo', toolkit.gettext({'1': 'foo', '2': 'bar', 'default': 'default'}, '1-a'))
-
- # Primed i18n value
- self.assertEqual('bar', toolkit.gettext({'1-a': 'foo', '1': 'bar', 'default': 'default'}, '1-b'))
- self.assertEqual('foo', toolkit.gettext({'1-a': 'foo', '2': 'bar', 'default': 'default'}, '1-b'))
-
- def test_gettext_EnAsTheLastResort(self):
- toolkit._default_langs = ['en-us']
- self.assertEqual('right', toolkit.gettext({'a': 'wrong', 'en': 'right'}, 'probe'))
- self.assertEqual('exact', toolkit.gettext({'a': 'wrong', 'en': 'right', 'probe': 'exact'}, 'probe'))
+ 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__':