Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/__init__.py79
-rw-r--r--tests/data/node/implementation/im/implementation/data2
-rw-r--r--tests/data/node/implementation/im/implementation/spec1
-rw-r--r--tests/data/node/implementation/im/implementation2/data2
-rw-r--r--tests/data/node/implementation/im/implementation2/spec1
-rwxr-xr-xtests/integration/master_personal.py2
-rwxr-xr-xtests/integration/master_slave.py2
-rwxr-xr-xtests/integration/node_client.py7
-rwxr-xr-xtests/integration/node_packages.py14
-rw-r--r--tests/units/__main__.py2
-rw-r--r--tests/units/client/__main__.py8
-rwxr-xr-xtests/units/client/clones.py14
-rwxr-xr-xtests/units/client/injector.py6
-rwxr-xr-xtests/units/client/journal.py48
-rwxr-xr-xtests/units/client/offline_routes.py (renamed from tests/units/client/offline_commands.py)22
-rwxr-xr-xtests/units/client/online_routes.py (renamed from tests/units/client/online_commands.py)146
-rwxr-xr-xtests/units/client/routes.py (renamed from tests/units/client/commands.py)92
-rwxr-xr-xtests/units/client/server_routes.py (renamed from tests/units/client/server_commands.py)26
-rw-r--r--tests/units/db/__main__.py8
-rwxr-xr-xtests/units/db/commands.py552
-rwxr-xr-xtests/units/db/env.py45
-rwxr-xr-xtests/units/db/index.py45
-rwxr-xr-xtests/units/db/metadata.py125
-rwxr-xr-xtests/units/db/migrate.py5
-rwxr-xr-xtests/units/db/resource.py (renamed from tests/units/db/document.py)55
-rwxr-xr-xtests/units/db/router.py533
-rwxr-xr-xtests/units/db/routes.py1600
-rwxr-xr-xtests/units/db/storage.py3
-rwxr-xr-xtests/units/db/volume.py1223
-rw-r--r--tests/units/model/__init__.py (renamed from tests/units/resources/__init__.py)0
-rw-r--r--tests/units/model/__main__.py (renamed from tests/units/resources/__main__.py)2
-rwxr-xr-xtests/units/model/comment.py (renamed from tests/units/resources/comment.py)14
-rwxr-xr-xtests/units/model/context.py (renamed from tests/units/resources/context.py)0
-rwxr-xr-xtests/units/model/implementation.py (renamed from tests/units/resources/implementation.py)37
-rwxr-xr-xtests/units/model/review.py (renamed from tests/units/resources/review.py)10
-rwxr-xr-xtests/units/model/routes.py92
-rwxr-xr-xtests/units/model/solution.py (renamed from tests/units/resources/solution.py)10
-rw-r--r--tests/units/node/__main__.py1
-rwxr-xr-xtests/units/node/auth.py163
-rwxr-xr-xtests/units/node/files.py61
-rwxr-xr-xtests/units/node/master.py8
-rwxr-xr-xtests/units/node/node.py281
-rwxr-xr-xtests/units/node/stats_node.py146
-rwxr-xr-xtests/units/node/sync_master.py67
-rwxr-xr-xtests/units/node/sync_offline.py40
-rwxr-xr-xtests/units/node/sync_online.py22
-rwxr-xr-xtests/units/node/volume.py302
-rwxr-xr-xtests/units/resources/volume.py444
-rw-r--r--tests/units/toolkit/__main__.py3
-rwxr-xr-xtests/units/toolkit/http.py37
-rwxr-xr-xtests/units/toolkit/router.py1257
-rwxr-xr-xtests/units/toolkit/toolkit.py (renamed from tests/units/toolkit/util.py)68
52 files changed, 3879 insertions, 3854 deletions
diff --git a/tests/__init__.py b/tests/__init__.py
index 84378c6..f4eed96 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -16,19 +16,17 @@ 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, util, Option, pipe
-from sugar_network.db.router import Router
-from sugar_network.client import journal, IPCRouter, commands
-from sugar_network.client.commands import ClientCommands
+from sugar_network.toolkit import coroutine, http, mountpoints, Option, pipe
+from sugar_network.toolkit.router import Router
+from sugar_network.client import journal, routes as client_routes
+from sugar_network.client.routes import ClientRoutes
from sugar_network import db, client, node, toolkit
-from sugar_network.db import env
from sugar_network.client import injector, solver
-from sugar_network.resources.user import User
-from sugar_network.resources.context import Context
-from sugar_network.resources.implementation import Implementation
-from sugar_network.node.master import MasterCommands
-from sugar_network.node import stats_user, stats_node, obs, auth, slave, downloads
-from sugar_network.resources.volume import Volume
+from sugar_network.model.user import User
+from sugar_network.model.context import Context
+from sugar_network.model.implementation import Implementation
+from sugar_network.node.master import MasterRoutes
+from sugar_network.node import stats_user, stats_node, obs, slave, downloads
root = abspath(dirname(__file__))
@@ -84,7 +82,6 @@ class Test(unittest.TestCase):
db.index_flush_threshold.value = 1
node.find_limit.value = 1024
node.data_root.value = tmpdir
- node.static_url.value = None
node.files_root.value = None
node.sync_layers.value = None
db.index_write_queue.value = 10
@@ -96,7 +93,7 @@ class Test(unittest.TestCase):
client.layers.value = None
client.cache_limit.value = 0
client.cache_lifetime.value = 0
- commands._RECONNECT_TIMEOUT = 0
+ client_routes._RECONNECT_TIMEOUT = 0
mountpoints._connects.clear()
mountpoints._found.clear()
mountpoints._COMPLETE_MOUNT_TIMEOUT = .1
@@ -109,7 +106,6 @@ class Test(unittest.TestCase):
obs._client = None
obs._repos = {'base': [], 'presolve': []}
http._RECONNECTION_NUMBER = 0
- auth.reset()
toolkit.cachedir.value = tmpdir + '/tmp'
injector.invalidate_solutions(None)
injector._pms_path = None
@@ -119,12 +115,12 @@ class Test(unittest.TestCase):
pipe._pipe = None
pipe._trace = None
- Volume.RESOURCES = [
- 'sugar_network.resources.user',
- 'sugar_network.resources.context',
- 'sugar_network.resources.artifact',
- 'sugar_network.resources.implementation',
- 'sugar_network.resources.report',
+ db.Volume.model = [
+ 'sugar_network.model.user',
+ 'sugar_network.model.context',
+ 'sugar_network.model.artifact',
+ 'sugar_network.model.implementation',
+ 'sugar_network.model.report',
]
if tmp_root is None:
@@ -146,8 +142,8 @@ class Test(unittest.TestCase):
def tearDown(self):
self.stop_nodes()
- while Volume._flush_pool:
- Volume._flush_pool.pop().close()
+ while db.Volume._flush_pool:
+ db.Volume._flush_pool.pop().close()
while self._overriden:
mod, name, old_handler = self._overriden.pop()
setattr(mod, name, old_handler)
@@ -224,7 +220,7 @@ class Test(unittest.TestCase):
os.utime(join(root, i), (ts, ts))
def zips(self, *items):
- with util.NamedTemporaryFile() as f:
+ with toolkit.NamedTemporaryFile() as f:
bundle = zipfile.ZipFile(f.name, 'w')
for i in items:
if isinstance(i, basestring):
@@ -269,20 +265,21 @@ class Test(unittest.TestCase):
def start_master(self, classes=None):
if classes is None:
classes = [User, Context, Implementation]
- self.node_volume = Volume('master', classes)
- cp = MasterCommands('guid', self.node_volume)
+ self.node_volume = db.Volume('master', classes)
+ cp = MasterRoutes('guid', self.node_volume)
+ r = Router(cp)
self.node = coroutine.WSGIServer(('127.0.0.1', 8888), Router(cp))
coroutine.spawn(self.node.serve_forever)
coroutine.dispatch(.1)
return self.node_volume
- def fork_master(self, classes=None):
+ def fork_master(self, classes=None, routes=MasterRoutes):
if classes is None:
classes = [User, Context, Implementation]
def node():
- volume = Volume('master', classes)
- cp = MasterCommands('guid', volume)
+ volume = db.Volume('master', classes)
+ cp = routes('guid', volume)
node = coroutine.WSGIServer(('127.0.0.1', 8888), Router(cp))
node.serve_forever()
@@ -290,13 +287,13 @@ class Test(unittest.TestCase):
coroutine.sleep(.1)
return pid
- def start_client(self, classes=None):
+ def start_client(self, classes=None, routes=ClientRoutes):
if classes is None:
classes = [User, Context, Implementation]
- volume = Volume('client', classes)
- commands = ClientCommands(volume, client.api_url.value)
+ volume = db.Volume('client', classes)
+ commands = routes(volume, client.api_url.value)
self.client = coroutine.WSGIServer(
- ('127.0.0.1', client.ipc_port.value), IPCRouter(commands))
+ ('127.0.0.1', client.ipc_port.value), Router(commands))
coroutine.spawn(self.client.serve_forever)
coroutine.dispatch()
return volume
@@ -305,11 +302,11 @@ class Test(unittest.TestCase):
if classes is None:
classes = [User, Context, Implementation]
self.start_master(classes)
- volume = Volume('client', classes)
- commands = ClientCommands(volume, client.api_url.value)
+ volume = db.Volume('client', classes)
+ commands = ClientRoutes(volume, client.api_url.value)
self.wait_for_events(commands, event='inline', state='online').wait()
self.client = coroutine.WSGIServer(
- ('127.0.0.1', client.ipc_port.value), IPCRouter(commands))
+ ('127.0.0.1', client.ipc_port.value), Router(commands))
coroutine.spawn(self.client.serve_forever)
coroutine.dispatch()
return volume
@@ -317,10 +314,10 @@ class Test(unittest.TestCase):
def start_offline_client(self, classes=None):
if classes is None:
classes = [User, Context, Implementation]
- volume = Volume('client', classes)
- commands = ClientCommands(volume)
+ volume = db.Volume('client', classes)
+ commands = ClientRoutes(volume)
self.client = coroutine.WSGIServer(
- ('127.0.0.1', client.ipc_port.value), IPCRouter(commands))
+ ('127.0.0.1', client.ipc_port.value), Router(commands))
coroutine.spawn(self.client.serve_forever)
coroutine.dispatch()
return volume
@@ -341,8 +338,8 @@ class Test(unittest.TestCase):
node.find_limit.value = 1024
db.index_write_queue.value = 10
- volume = Volume('remote', classes or [User, Context, Implementation])
- cp = MasterCommands('guid', volume)
+ volume = db.Volume('remote', classes or [User, Context, Implementation])
+ cp = MasterRoutes('guid', volume)
httpd = coroutine.WSGIServer(('127.0.0.1', 8888), Router(cp))
try:
coroutine.joinall([
@@ -380,7 +377,7 @@ class Test(unittest.TestCase):
logging.basicConfig(level=logging.DEBUG,
filename=join(tmpdir, '%s.log' % fork_num),
format='%(asctime)s %(levelname)s %(name)s: %(message)s')
- util.init_logging(10)
+ toolkit.init_logging(10)
sys.stdout.flush()
sys.stderr.flush()
diff --git a/tests/data/node/implementation/im/implementation/data b/tests/data/node/implementation/im/implementation/data
index b933ad2..d8d70ef 100644
--- a/tests/data/node/implementation/im/implementation/data
+++ b/tests/data/node/implementation/im/implementation/data
@@ -1 +1 @@
-{"seqno": 5, "mime_type": "application/octet-stream", "digest": "fdb59f1ebd6ee26a00396747b3a733f4fd274604"} \ No newline at end of file
+{"seqno": 5, "mime_type": "application/octet-stream", "digest": "fdb59f1ebd6ee26a00396747b3a733f4fd274604", "spec": {"*-*": {"commands": {"activity": {"exec": "true"}}, "extract": "Chat.activity"}}} \ No newline at end of file
diff --git a/tests/data/node/implementation/im/implementation/spec b/tests/data/node/implementation/im/implementation/spec
deleted file mode 100644
index c9ec14a..0000000
--- a/tests/data/node/implementation/im/implementation/spec
+++ /dev/null
@@ -1 +0,0 @@
-{"seqno": 3, "value": {"*-*": {"commands": {"activity": {"exec": "true"}}, "extract": "Chat.activity"}}} \ No newline at end of file
diff --git a/tests/data/node/implementation/im/implementation2/data b/tests/data/node/implementation/im/implementation2/data
index b933ad2..c11bbb8 100644
--- a/tests/data/node/implementation/im/implementation2/data
+++ b/tests/data/node/implementation/im/implementation2/data
@@ -1 +1 @@
-{"seqno": 5, "mime_type": "application/octet-stream", "digest": "fdb59f1ebd6ee26a00396747b3a733f4fd274604"} \ No newline at end of file
+{"seqno": 5, "mime_type": "application/octet-stream", "digest": "fdb59f1ebd6ee26a00396747b3a733f4fd274604", "spec": {"*-*": {"commands": {"activity": {"exec": "true"}}, "extract": "Chat.activity", "requires": {"dep1": {}, "dep2": {}, "dep3": {}}}}} \ No newline at end of file
diff --git a/tests/data/node/implementation/im/implementation2/spec b/tests/data/node/implementation/im/implementation2/spec
deleted file mode 100644
index 89f8d50..0000000
--- a/tests/data/node/implementation/im/implementation2/spec
+++ /dev/null
@@ -1 +0,0 @@
-{"seqno": 3, "value": {"*-*": {"commands": {"activity": {"exec": "true"}}, "extract": "Chat.activity", "requires": {"dep1": {}, "dep2": {}, "dep3": {}}}}} \ No newline at end of file
diff --git a/tests/integration/master_personal.py b/tests/integration/master_personal.py
index 718659b..20b5376 100755
--- a/tests/integration/master_personal.py
+++ b/tests/integration/master_personal.py
@@ -15,7 +15,7 @@ from __init__ import tests, src_root
from sugar_network.client import Client, sugar_uid
from sugar_network.toolkit.rrd import Rrd
-from sugar_network.toolkit import util, coroutine
+from sugar_network.toolkit import coroutine
# /tmp might be on tmpfs wich returns 0 bytes for free mem all time
diff --git a/tests/integration/master_slave.py b/tests/integration/master_slave.py
index 946034e..217997e 100755
--- a/tests/integration/master_slave.py
+++ b/tests/integration/master_slave.py
@@ -15,7 +15,7 @@ from __init__ import tests, src_root
from sugar_network.client import Client
from sugar_network.toolkit.rrd import Rrd
-from sugar_network.toolkit import util, coroutine
+from sugar_network.toolkit import coroutine
# /tmp might be on tmpfs wich returns 0 bytes for free mem all time
diff --git a/tests/integration/node_client.py b/tests/integration/node_client.py
index 4d51883..f7981c8 100755
--- a/tests/integration/node_client.py
+++ b/tests/integration/node_client.py
@@ -10,8 +10,9 @@ from os.path import exists, join
from __init__ import tests, src_root
+from sugar_network import toolkit
from sugar_network.client import IPCClient, Client
-from sugar_network.toolkit import coroutine, util
+from sugar_network.toolkit import coroutine
class NodeClientTest(tests.Test):
@@ -20,7 +21,7 @@ class NodeClientTest(tests.Test):
tests.Test.setUp(self)
os.makedirs('mnt')
- util.cptree(src_root + '/tests/data/node', 'node')
+ toolkit.cptree(src_root + '/tests/data/node', 'node')
self.client_pid = None
self.node_pid = self.popen([join(src_root, 'sugar-network-node'), '-F', 'start',
@@ -122,7 +123,7 @@ class NodeClientTest(tests.Test):
if ipc.get(cmd='status')['route'] == 'offline':
self.wait_for_events(ipc, event='inline', state='online').wait()
- result = util.assert_call(cmd, stdin=json.dumps(stdin))
+ result = toolkit.assert_call(cmd, stdin=json.dumps(stdin))
if result and '--porcelain' not in cmd:
result = json.loads(result)
return result
diff --git a/tests/integration/node_packages.py b/tests/integration/node_packages.py
index 0089e3d..e6ef11e 100755
--- a/tests/integration/node_packages.py
+++ b/tests/integration/node_packages.py
@@ -16,10 +16,10 @@ from __init__ import tests, src_root
from sugar_network import db, client
from sugar_network.client import Client, IPCClient
-from sugar_network.db.router import Router, route
from sugar_network.node.obs import obs_url
+from sugar_network.toolkit.router import Router, route, fallbackroute
from sugar_network.toolkit.rrd import Rrd
-from sugar_network.toolkit import util, coroutine
+from sugar_network.toolkit import coroutine
# /tmp might be on tmpfs wich returns 0 bytes for free mem all time
@@ -39,11 +39,10 @@ class NodePackagesSlaveTest(tests.Test):
def test_packages(self):
- class OBS(db.CommandsProcessor):
+ class OBS(object):
- @route('GET', '/build')
+ @fallbackroute('GET', ['build'], mime_type='text/xml')
def build(self, request, response):
- response.content_type = 'text/xml'
if request.path == ['build', 'base']:
return '<directory><entry name="Fedora-14"/></directory>'
elif request.path == ['build', 'base', 'Fedora-14']:
@@ -53,12 +52,11 @@ class NodePackagesSlaveTest(tests.Test):
elif request.path == ['build', 'presolve', 'OLPC-11.3.1']:
return '<directory><entry name="i586"/></directory>'
- @route('GET', '/resolve')
+ @fallbackroute('GET', ['resolve'], mime_type='text/xml')
def resolve(self, request, response):
- response.content_type = 'text/xml'
return '<resolve><binary name="rpm" url="http://127.0.0.1:9999/packages/rpm" arch="arch"/></resolve>'
- @route('GET', '/packages')
+ @fallbackroute('GET', ['packages'], mime_type='text/plain')
def packages(self, request, response):
return 'package_content'
diff --git a/tests/units/__main__.py b/tests/units/__main__.py
index 22664cb..1df3e3e 100644
--- a/tests/units/__main__.py
+++ b/tests/units/__main__.py
@@ -5,7 +5,7 @@ from __init__ import tests
from toolkit.__main__ import *
from db.__main__ import *
from node.__main__ import *
-from resources.__main__ import *
+from model.__main__ import *
from client.__main__ import *
if __name__ == '__main__':
diff --git a/tests/units/client/__main__.py b/tests/units/client/__main__.py
index fd37288..fc1d045 100644
--- a/tests/units/client/__main__.py
+++ b/tests/units/client/__main__.py
@@ -3,12 +3,12 @@
from __init__ import tests
from clones import *
-from commands import *
+from routes import *
from injector import *
from journal import *
-from offline_commands import *
-from online_commands import *
-from server_commands import *
+from offline_routes import *
+from online_routes import *
+from server_routes import *
from solver import *
from cache import *
diff --git a/tests/units/client/clones.py b/tests/units/client/clones.py
index b9178a1..974adca 100755
--- a/tests/units/client/clones.py
+++ b/tests/units/client/clones.py
@@ -8,18 +8,18 @@ from os.path import abspath, lexists, exists
from __init__ import tests
-from sugar_network.resources.user import User
-from sugar_network.resources.context import Context
+from sugar_network import db, model
+from sugar_network.model.user import User
+from sugar_network.model.context import Context
from sugar_network.client import clones
-from sugar_network.toolkit import coroutine, util
-from sugar_network.resources.volume import Volume
+from sugar_network.toolkit import coroutine
class CloneTest(tests.Test):
def setUp(self):
tests.Test.setUp(self)
- self.volume = Volume('local', [User, Context])
+ self.volume = db.Volume('local', [User, Context])
self.job = None
def tearDown(self):
@@ -371,7 +371,7 @@ class CloneTest(tests.Test):
assert not lexists('share/mime/application/x-foo-bar.xml')
def test_Sync(self):
- volume = Volume('client')
+ volume = db.Volume('client', model.RESOURCES)
volume['context'].create({
'guid': 'context1',
'type': 'activity',
@@ -409,7 +409,7 @@ class CloneTest(tests.Test):
self.assertEqual(0, volume['context'].get('context3')['clone'])
def test_SyncByMtime(self):
- volume = Volume('client')
+ volume = db.Volume('client', model.RESOURCES)
volume['context'].create({
'guid': 'context',
'type': 'activity',
diff --git a/tests/units/client/injector.py b/tests/units/client/injector.py
index 256cfa4..c198f81 100755
--- a/tests/units/client/injector.py
+++ b/tests/units/client/injector.py
@@ -17,9 +17,9 @@ from __init__ import tests
from sugar_network.client import journal
from sugar_network.toolkit import coroutine, enforce, pipe as pipe_, lsb_release
from sugar_network.node import obs
-from sugar_network.resources.user import User
-from sugar_network.resources.context import Context
-from sugar_network.resources.implementation import Implementation
+from sugar_network.model.user import User
+from sugar_network.model.context import Context
+from sugar_network.model.implementation import Implementation
from sugar_network.client import IPCClient, packagekit, injector, clones, solver
from sugar_network import client
diff --git a/tests/units/client/journal.py b/tests/units/client/journal.py
index ffb6e4f..fd36a2a 100755
--- a/tests/units/client/journal.py
+++ b/tests/units/client/journal.py
@@ -12,6 +12,7 @@ from __init__ import tests
from sugar_network import db
from sugar_network.client import journal, ipc_port
+from sugar_network.toolkit.router import Request, Response
class JournalTest(tests.Test):
@@ -76,7 +77,7 @@ class JournalTest(tests.Test):
self.assertEqual('data', file(self.ds.get_filename(guid)).read())
def test_Update(self):
- ds = journal.Commands()
+ ds = journal.Routes()
self.touch(('preview', 'preview1'))
ds.journal_update('guid', StringIO('data1'), title='title1', description='description1', preview={'blob': 'preview'})
@@ -97,76 +98,73 @@ class JournalTest(tests.Test):
def test_FindRequest(self):
url = 'http://127.0.0.1:%s/journal/' % ipc_port.value
- ds = journal.Commands()
+ ds = journal.Routes()
ds.journal_update('guid1', StringIO('data1'), title='title1', description='description1', preview=StringIO('preview1'))
ds.journal_update('guid2', StringIO('data2'), title='title2', description='description2', preview=StringIO('preview2'))
ds.journal_update('guid3', StringIO('data3'), title='title3', description='description3', preview=StringIO('preview3'))
- request = db.Request()
+ request = Request(reply=['uid', 'title', 'description', 'preview'])
request.path = ['journal']
- response = db.Response()
+ response = Response()
self.assertEqual([
{'guid': 'guid1', 'title': 'title1', 'description': 'description1', 'preview': url + 'guid1/preview'},
{'guid': 'guid2', 'title': 'title2', 'description': 'description2', 'preview': url + 'guid2/preview'},
{'guid': 'guid3', 'title': 'title3', 'description': 'description3', 'preview': url + 'guid3/preview'},
],
- ds.journal(request, response)['result'])
- self.assertEqual('application/json', response.content_type)
+ ds.journal_find(request, response)['result'])
- request = db.Request(offset=1, limit=1)
+ request = Request(offset=1, limit=1, reply=['uid', 'title', 'description', 'preview'])
request.path = ['journal']
self.assertEqual([
{'guid': 'guid2', 'title': 'title2', 'description': 'description2', 'preview': url + 'guid2/preview'},
],
- ds.journal(request, response)['result'])
+ ds.journal_find(request, response)['result'])
- request = db.Request(query='title3')
+ request = Request(query='title3', reply=['uid', 'title', 'description', 'preview'])
request.path = ['journal']
self.assertEqual([
{'guid': 'guid3', 'title': 'title3', 'description': 'description3', 'preview': url + 'guid3/preview'},
],
- ds.journal(request, response)['result'])
+ ds.journal_find(request, response)['result'])
- request = db.Request(order_by='+title')
+ request = Request(order_by=['+title'], reply=['uid', 'title', 'description', 'preview'])
request.path = ['journal']
self.assertEqual([
{'guid': 'guid3', 'title': 'title3', 'description': 'description3', 'preview': url + 'guid3/preview'},
{'guid': 'guid2', 'title': 'title2', 'description': 'description2', 'preview': url + 'guid2/preview'},
{'guid': 'guid1', 'title': 'title1', 'description': 'description1', 'preview': url + 'guid1/preview'},
],
- ds.journal(request, response)['result'])
+ ds.journal_find(request, response)['result'])
def test_GetRequest(self):
url = 'http://127.0.0.1:%s/journal/' % ipc_port.value
- ds = journal.Commands()
+ ds = journal.Routes()
ds.journal_update('guid1', StringIO('data1'), title='title1', description='description1', preview=StringIO('preview1'))
- request = db.Request()
+ request = Request()
request.path = ['journal', 'guid1']
- response = db.Response()
+ response = Response()
self.assertEqual(
{'guid': 'guid1', 'title': 'title1', 'description': 'description1', 'preview': url + 'guid1/preview'},
- ds.journal(request, response))
- self.assertEqual('application/json', response.content_type)
+ ds.journal_get(request, response))
def test_GetPropRequest(self):
- ds = journal.Commands()
+ ds = journal.Routes()
ds.journal_update('guid1', StringIO('data1'), title='title1', description='description1', preview=StringIO('preview1'))
- request = db.Request()
+ request = Request()
request.path = ['journal', 'guid1', 'title']
- response = db.Response()
- self.assertEqual('title1', ds.journal(request, response))
- self.assertEqual('application/json', response.content_type)
+ response = Response()
+ self.assertEqual('title1', ds.journal_get_prop(request, response))
- request = db.Request()
+ request = Request()
request.path = ['journal', 'guid1', 'preview']
- response = db.Response()
+ response = Response()
self.assertEqual({
'mime_type': 'image/png',
'blob': '.sugar/default/datastore/gu/guid1/metadata/preview',
- }, ds.journal(request, response))
+ }, ds.journal_get_preview(request, response))
self.assertEqual(None, response.content_type)
diff --git a/tests/units/client/offline_commands.py b/tests/units/client/offline_routes.py
index 69d5f2a..ced30d1 100755
--- a/tests/units/client/offline_commands.py
+++ b/tests/units/client/offline_routes.py
@@ -5,21 +5,21 @@ from os.path import exists
from __init__ import tests, src_root
-from sugar_network import client
+from sugar_network import client, model
from sugar_network.client import IPCClient, clones
-from sugar_network.client.commands import ClientCommands
-from sugar_network.client import IPCRouter
-from sugar_network.resources.volume import Volume
+from sugar_network.client.routes import ClientRoutes
+from sugar_network.db import Volume
+from sugar_network.toolkit.router import Router
from sugar_network.toolkit import coroutine, http
-class OfflineCommandsTest(tests.Test):
+class OfflineRoutes(tests.Test):
def setUp(self):
tests.Test.setUp(self)
- self.home_volume = Volume('db')
- commands = ClientCommands(self.home_volume)
- server = coroutine.WSGIServer(('127.0.0.1', client.ipc_port.value), IPCRouter(commands))
+ self.home_volume = Volume('db', model.RESOURCES)
+ commands = ClientRoutes(self.home_volume)
+ server = coroutine.WSGIServer(('127.0.0.1', client.ipc_port.value), Router(commands))
coroutine.spawn(server.serve_forever)
coroutine.dispatch()
@@ -127,9 +127,9 @@ class OfflineCommandsTest(tests.Test):
job.kill()
self.assertEqual([
- {'guid': guid, 'document': 'context', 'event': 'create'},
- {'guid': guid, 'document': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'document': 'context'},
+ {'guid': guid, 'resource': 'context', 'event': 'create'},
+ {'guid': guid, 'resource': 'context', 'event': 'update'},
+ {'guid': guid, 'event': 'delete', 'resource': 'context'},
],
events)
diff --git a/tests/units/client/online_commands.py b/tests/units/client/online_routes.py
index 692fa38..10d9b4b 100755
--- a/tests/units/client/online_commands.py
+++ b/tests/units/client/online_routes.py
@@ -11,24 +11,26 @@ from os.path import exists
from __init__ import tests, src_root
-from sugar_network import client, db
-from sugar_network.client import IPCClient, journal, clones, injector, commands
+from sugar_network import client, db, model
+from sugar_network.client import IPCClient, journal, clones, injector, routes
from sugar_network.toolkit import coroutine, http
from sugar_network.toolkit.spec import Spec
-from sugar_network.client.commands import ClientCommands
-from sugar_network.resources.volume import Volume, Resource
-from sugar_network.resources.user import User
-from sugar_network.resources.context import Context
-from sugar_network.resources.implementation import Implementation
-from sugar_network.resources.artifact import Artifact
+from sugar_network.client.routes import ClientRoutes, Request, Response
+from sugar_network.node.master import MasterRoutes
+from sugar_network.db import Volume, Resource
+from sugar_network.model.user import User
+from sugar_network.model.context import Context
+from sugar_network.model.implementation import Implementation
+from sugar_network.model.artifact import Artifact
+from sugar_network.toolkit.router import route
import requests
-class OnlineCommandsTest(tests.Test):
+class OnlineRoutes(tests.Test):
def test_inline(self):
- cp = ClientCommands(Volume('client'), client.api_url.value)
+ cp = ClientRoutes(Volume('client', model.RESOURCES), client.api_url.value)
assert not cp.inline()
trigger = self.wait_for_events(cp, event='inline', state='online')
@@ -38,8 +40,8 @@ class OnlineCommandsTest(tests.Test):
assert trigger.value is None
assert not cp.inline()
- request = db.Request(method='GET', cmd='whoami')
- cp.call(request)
+ request = Request(method='GET', cmd='whoami')
+ cp.whoami(request, Response())
trigger.wait()
assert cp.inline()
@@ -290,9 +292,9 @@ class OnlineCommandsTest(tests.Test):
kwargs['data'] = data.read()
updates.append((guid, kwargs))
- self.override(journal.Commands, '__init__', lambda *args: None)
- self.override(journal.Commands, 'journal_update', journal_update)
- self.override(journal.Commands, 'journal_delete', lambda self, guid: updates.append((guid,)))
+ self.override(journal.Routes, '__init__', lambda *args: None)
+ self.override(journal.Routes, 'journal_update', journal_update)
+ self.override(journal.Routes, 'journal_delete', lambda self, guid: updates.append((guid,)))
ipc = IPCClient()
@@ -368,9 +370,9 @@ class OnlineCommandsTest(tests.Test):
kwargs['data'] = data.read()
updates.append((guid, kwargs))
- self.override(journal.Commands, '__init__', lambda *args: None)
- self.override(journal.Commands, 'journal_update', journal_update)
- self.override(journal.Commands, 'journal_delete', lambda self, guid: updates.append((guid,)))
+ self.override(journal.Routes, '__init__', lambda *args: None)
+ self.override(journal.Routes, 'journal_update', journal_update)
+ self.override(journal.Routes, 'journal_delete', lambda self, guid: updates.append((guid,)))
ipc = IPCClient()
@@ -497,9 +499,9 @@ class OnlineCommandsTest(tests.Test):
job.kill()
self.assertEqual([
- {'guid': guid, 'document': 'context', 'event': 'create'},
- {'guid': guid, 'document': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'document': 'context'},
+ {'guid': guid, 'resource': 'context', 'event': 'create'},
+ {'guid': guid, 'resource': 'context', 'event': 'update'},
+ {'guid': guid, 'event': 'delete', 'resource': 'context'},
],
events)
del events[:]
@@ -522,9 +524,9 @@ class OnlineCommandsTest(tests.Test):
job.kill()
self.assertEqual([
- {'guid': guid, 'document': 'context', 'event': 'create'},
- {'guid': guid, 'document': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'document': 'context'},
+ {'guid': guid, 'resource': 'context', 'event': 'create'},
+ {'guid': guid, 'resource': 'context', 'event': 'update'},
+ {'guid': guid, 'event': 'delete', 'resource': 'context'},
],
events)
@@ -1097,7 +1099,7 @@ class OnlineCommandsTest(tests.Test):
}})
- trigger = self.wait_for_events(ipc, event='update', document='context', guid=context1)
+ trigger = self.wait_for_events(ipc, event='update', resource='context', guid=context1)
ipc.put(['context', context1], 2, cmd='clone')
trigger.wait()
self.assertEqual(
@@ -1110,7 +1112,7 @@ class OnlineCommandsTest(tests.Test):
'summary': 'summary',
'description': 'description',
})
- trigger = self.wait_for_events(ipc, event='create', document='context', guid=context2)
+ trigger = self.wait_for_events(ipc, event='create', resource='context', guid=context2)
ipc.put(['context', context2], True, cmd='favorite')
trigger.wait()
self.assertEqual(
@@ -1118,59 +1120,63 @@ class OnlineCommandsTest(tests.Test):
ipc.get(['context', context2], reply=['favorite']))
def test_FallbackToLocalSNOnRemoteTransportFails(self):
- local_pid = os.getpid()
- class Document(Resource):
+ class LocalRoutes(routes._LocalRoutes):
- @db.document_command(method='GET', cmd='sleep')
+ @route('GET', cmd='sleep')
def sleep(self):
- if os.getpid() == local_pid:
- return 'local'
- else:
- coroutine.sleep(.5)
- return 'remote'
+ return 'local'
- @db.document_command(method='GET', cmd='yield_raw_and_sleep',
+ @route('GET', cmd='yield_raw_and_sleep',
mime_type='application/octet-stream')
def yield_raw_and_sleep(self):
- if os.getpid() == local_pid:
- yield 'local'
- else:
- for __ in range(33):
- yield "remote\n"
- coroutine.sleep(.5)
- for __ in range(33):
- yield "remote\n"
-
- @db.document_command(method='GET', cmd='yield_json_and_sleep',
+ yield 'local'
+
+ @route('GET', cmd='yield_json_and_sleep',
mime_type='application/json')
def yield_json_and_sleep(self):
- if os.getpid() == local_pid:
- yield '"local"'
- else:
- yield '"'
- yield 'r'
- coroutine.sleep(.5)
- yield 'emote"'
-
- home_volume = self.start_client([User, Document])
+ yield '"local"'
+
+ self.override(routes, '_LocalRoutes', LocalRoutes)
+ home_volume = self.start_client([User])
ipc = IPCClient()
- guid = ipc.post(['document'], {})
- self.assertEqual('local', ipc.get(['document', guid], cmd='sleep'))
- self.assertEqual('local', ipc.get(['document', guid], cmd='yield_raw_and_sleep'))
- self.assertEqual('local', ipc.get(['document', guid], cmd='yield_json_and_sleep'))
+ self.assertEqual('local', ipc.get(cmd='sleep'))
+ self.assertEqual('local', ipc.get(cmd='yield_raw_and_sleep'))
+ self.assertEqual('local', ipc.get(cmd='yield_json_and_sleep'))
+
+ class NodeRoutes(MasterRoutes):
+
+ @route('GET', cmd='sleep')
+ def sleep(self):
+ coroutine.sleep(.5)
+ return 'remote'
+
+ @route('GET', cmd='yield_raw_and_sleep',
+ mime_type='application/octet-stream')
+ def yield_raw_and_sleep(self):
+ for __ in range(33):
+ yield "remote\n"
+ coroutine.sleep(.5)
+ for __ in range(33):
+ yield "remote\n"
- node_pid = self.fork_master([User, Document])
+ @route('GET', cmd='yield_json_and_sleep',
+ mime_type='application/json')
+ def yield_json_and_sleep(self):
+ yield '"'
+ yield 'r'
+ coroutine.sleep(.5)
+ yield 'emote"'
+
+ node_pid = self.fork_master([User], NodeRoutes)
ipc.get(cmd='inline')
self.wait_for_events(ipc, event='inline', state='online').wait()
- guid = ipc.post(['document'], {})
- home_volume['document'].create({'guid': guid})
ts = time.time()
- self.assertEqual('remote', ipc.get(['document', guid], cmd='sleep'))
- self.assertEqual('remote\n' * 66, ipc.get(['document', guid], cmd='yield_raw_and_sleep'))
- self.assertEqual('remote', ipc.get(['document', guid], cmd='yield_json_and_sleep'))
+ self.assertEqual('remote', ipc.get(cmd='sleep'))
+ self.assertEqual('remote\n' * 66, ipc.get(cmd='yield_raw_and_sleep'))
+ self.assertEqual('remote', ipc.get(cmd='yield_json_and_sleep'))
assert time.time() - ts >= 1.5
def kill():
@@ -1178,27 +1184,27 @@ class OnlineCommandsTest(tests.Test):
self.waitpid(node_pid)
coroutine.spawn(kill)
- self.assertEqual('local', ipc.get(['document', guid], cmd='sleep'))
+ self.assertEqual('local', ipc.get(cmd='sleep'))
assert not ipc.get(cmd='inline')
- node_pid = self.fork_master([User, Document])
+ node_pid = self.fork_master([User], NodeRoutes)
ipc.get(cmd='inline')
self.wait_for_events(ipc, event='inline', state='online').wait()
coroutine.spawn(kill)
- self.assertEqual('local', ipc.get(['document', guid], cmd='yield_raw_and_sleep'))
+ self.assertEqual('local', ipc.get(cmd='yield_raw_and_sleep'))
assert not ipc.get(cmd='inline')
- node_pid = self.fork_master([User, Document])
+ node_pid = self.fork_master([User], NodeRoutes)
ipc.get(cmd='inline')
self.wait_for_events(ipc, event='inline', state='online').wait()
coroutine.spawn(kill)
- self.assertEqual('local', ipc.get(['document', guid], cmd='yield_json_and_sleep'))
+ self.assertEqual('local', ipc.get(cmd='yield_json_and_sleep'))
assert not ipc.get(cmd='inline')
def test_ReconnectOnServerFall(self):
- commands._RECONNECT_TIMEOUT = 1
+ routes._RECONNECT_TIMEOUT = 1
node_pid = self.fork_master([User])
self.start_client([User])
diff --git a/tests/units/client/commands.py b/tests/units/client/routes.py
index 691eeea..8ae8d44 100755
--- a/tests/units/client/commands.py
+++ b/tests/units/client/routes.py
@@ -5,25 +5,24 @@ import json
from __init__ import tests
-from sugar_network import db, client
+from sugar_network import db, client, model
from sugar_network.client import journal, injector, IPCClient
-from sugar_network.client.commands import ClientCommands, CachedClientCommands
-from sugar_network.resources.volume import Volume
-from sugar_network.resources.user import User
-from sugar_network.resources.report import Report
-from sugar_network.client import IPCRouter
+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
import requests
-class CommandsTest(tests.Test):
+class RoutesTest(tests.Test):
def test_Hub(self):
- volume = Volume('db')
- cp = ClientCommands(volume)
+ volume = db.Volume('db', model.RESOURCES)
+ cp = ClientRoutes(volume)
server = coroutine.WSGIServer(
- ('127.0.0.1', client.ipc_port.value), IPCRouter(cp))
+ ('127.0.0.1', client.ipc_port.value), Router(cp))
coroutine.spawn(server.serve_forever)
coroutine.dispatch()
@@ -45,13 +44,11 @@ class CommandsTest(tests.Test):
def test_launch(self):
self.override(injector, 'launch', lambda *args, **kwargs: [{'args': args, 'kwargs': kwargs}])
- volume = Volume('db')
- cp = ClientCommands(volume)
-
- self.assertRaises(RuntimeError, cp.launch, 'fake-document', 'app', [])
+ volume = db.Volume('db', model.RESOURCES)
+ cp = ClientRoutes(volume)
trigger = self.wait_for_events(cp, event='launch')
- cp.launch('context', 'app', [])
+ cp.launch(Request(path=['context', 'app']), [])
self.assertEqual(
{'event': 'launch', 'args': ['app', []], 'kwargs': {'color': None, 'activity_id': None, 'uri': None, 'object_id': None}},
trigger.wait())
@@ -59,11 +56,11 @@ class CommandsTest(tests.Test):
def test_launch_ResumeJobject(self):
self.override(injector, 'launch', lambda *args, **kwargs: [{'args': args, 'kwargs': kwargs}])
self.override(journal, 'exists', lambda *args: True)
- volume = Volume('db')
- cp = ClientCommands(volume)
+ volume = db.Volume('db', model.RESOURCES)
+ cp = ClientRoutes(volume)
trigger = self.wait_for_events(cp, event='launch')
- cp.launch('context', 'app', [], object_id='object_id')
+ cp.launch(Request(path=['context', 'app']), [], object_id='object_id')
self.assertEqual(
{'event': 'launch', 'args': ['app', []], 'kwargs': {'color': None, 'activity_id': None, 'uri': None, 'object_id': 'object_id'}},
trigger.wait())
@@ -165,9 +162,9 @@ class CommandsTest(tests.Test):
ipc.get(['context'], reply=['guid', 'title'], favorite=False)['result'])
def test_SetLocalLayerInOffline(self):
- volume = Volume('client')
- cp = ClientCommands(volume, client.api_url.value)
- post = db.Request(method='POST', document='context')
+ volume = db.Volume('client', model.RESOURCES)
+ cp = ClientRoutes(volume, client.api_url.value)
+ post = Request(method='POST', path=['context'])
post.content_type = 'application/json'
post.content = {
'type': 'activity',
@@ -176,22 +173,22 @@ class CommandsTest(tests.Test):
'description': 'description',
}
- guid = cp.call(post)
- self.assertEqual(['public', 'local'], cp.call(db.Request(method='GET', document='context', guid=guid, prop='layer')))
+ guid = call(cp, post)
+ self.assertEqual(['public', 'local'], call(cp, Request(method='GET', path=['context', guid, 'layer'])))
trigger = self.wait_for_events(cp, event='inline', state='online')
node_volume = self.start_master()
- cp.call(db.Request(method='GET', cmd='inline'))
+ call(cp, Request(method='GET', cmd='inline'))
trigger.wait()
- guid = cp.call(post)
- self.assertEqual(['public'], cp.call(db.Request(method='GET', document='context', guid=guid, prop='layer')))
+ guid = call(cp, post)
+ self.assertEqual(['public'], call(cp, Request(method='GET', path=['context', guid, 'layer'])))
def test_CachedClientCommands(self):
- volume = Volume('client')
- cp = CachedClientCommands(volume, client.api_url.value)
+ volume = db.Volume('client', model.RESOURCES)
+ cp = CachedClientRoutes(volume, client.api_url.value)
- post = db.Request(method='POST', document='context')
+ post = Request(method='POST', path=['context'])
post.content_type = 'application/json'
post.content = {
'type': 'activity',
@@ -199,12 +196,12 @@ class CommandsTest(tests.Test):
'summary': 'summary',
'description': 'description',
}
- guid1 = cp.call(post)
- guid2 = cp.call(post)
+ guid1 = call(cp, post)
+ guid2 = call(cp, post)
trigger = self.wait_for_events(cp, event='push')
self.start_master()
- cp.call(db.Request(method='GET', cmd='inline'))
+ call(cp, Request(method='GET', cmd='inline'))
trigger.wait()
self.assertEqual([[3, None]], json.load(file('client/push.sequence')))
@@ -229,7 +226,7 @@ class CommandsTest(tests.Test):
trigger = self.wait_for_events(cp, event='push')
self.start_master()
- cp.call(db.Request(method='GET', cmd='inline'))
+ call(cp, Request(method='GET', cmd='inline'))
trigger.wait()
self.assertEqual([[4, None]], json.load(file('client/push.sequence')))
@@ -245,30 +242,30 @@ class CommandsTest(tests.Test):
self.node_volume['context'].get(guid2)['author'])
def test_CachedClientCommands_WipeReports(self):
- volume = Volume('client')
- cp = CachedClientCommands(volume, client.api_url.value)
+ volume = db.Volume('client', model.RESOURCES)
+ cp = CachedClientRoutes(volume, client.api_url.value)
- post = db.Request(method='POST', document='report')
+ post = Request(method='POST', path=['report'])
post.content_type = 'application/json'
post.content = {
'context': 'context',
'error': 'error',
}
- guid = cp.call(post)
+ guid = call(cp, post)
trigger = self.wait_for_events(cp, event='push')
self.start_master([User, Report])
- cp.call(db.Request(method='GET', cmd='inline'))
+ call(cp, Request(method='GET', cmd='inline'))
trigger.wait()
assert not volume['report'].exists(guid)
assert self.node_volume['report'].exists(guid)
def test_SwitchToOfflineForAbsentOnlineProps(self):
- volume = Volume('client')
- cp = ClientCommands(volume, client.api_url.value)
+ volume = db.Volume('client', model.RESOURCES)
+ cp = ClientRoutes(volume, client.api_url.value)
- post = db.Request(method='POST', document='context')
+ post = Request(method='POST', path=['context'])
post.content_type = 'application/json'
post.content = {
'type': 'activity',
@@ -276,17 +273,22 @@ class CommandsTest(tests.Test):
'summary': 'summary',
'description': 'description',
}
- guid = cp.call(post)
+ guid = call(cp, post)
- self.assertEqual('title', cp.call(db.Request(method='GET', document='context', guid=guid, prop='title')))
+ self.assertEqual('title', call(cp, Request(method='GET', path=['context', guid, 'title'])))
trigger = self.wait_for_events(cp, event='inline', state='online')
self.start_master()
- cp.call(db.Request(method='GET', cmd='inline'))
+ call(cp, Request(method='GET', cmd='inline'))
trigger.wait()
assert not self.node_volume['context'].exists(guid)
- self.assertEqual('title', cp.call(db.Request(method='GET', document='context', guid=guid, prop='title')))
+ self.assertEqual('title', call(cp, Request(method='GET', path=['context', guid, 'title'])))
+
+
+def call(routes, request):
+ router = Router(routes)
+ return router.call(request, Response())
if __name__ == '__main__':
diff --git a/tests/units/client/server_commands.py b/tests/units/client/server_routes.py
index 771d008..bea8f7f 100755
--- a/tests/units/client/server_commands.py
+++ b/tests/units/client/server_routes.py
@@ -7,11 +7,11 @@ from os.path import exists
from __init__ import tests, src_root
-from sugar_network import db, client
+from sugar_network import db, client, model
from sugar_network.client import IPCClient
-from sugar_network.client.commands import ClientCommands
-from sugar_network.client import IPCRouter
-from sugar_network.resources.volume import Volume
+from sugar_network.client.routes import ClientRoutes
+from sugar_network.db import Volume
+from sugar_network.toolkit.router import Router
from sugar_network.toolkit import mountpoints, coroutine
@@ -19,20 +19,20 @@ class ServerCommandsTest(tests.Test):
def start_node(self):
os.makedirs('disk/sugar-network')
- self.node_volume = Volume('db')
- cp = ClientCommands(self.node_volume)
+ self.node_volume = Volume('db', model.RESOURCES)
+ cp = ClientRoutes(self.node_volume)
trigger = self.wait_for_events(cp, event='inline', state='online')
coroutine.spawn(mountpoints.monitor, tests.tmpdir)
trigger.wait()
- server = coroutine.WSGIServer(('127.0.0.1', client.ipc_port.value), IPCRouter(cp))
+ server = coroutine.WSGIServer(('127.0.0.1', client.ipc_port.value), Router(cp))
coroutine.spawn(server.serve_forever)
coroutine.dispatch()
return cp
def test_PopulateNode(self):
os.makedirs('disk/sugar-network')
- volume = Volume('db')
- cp = ClientCommands(volume)
+ volume = Volume('db', model.RESOURCES)
+ cp = ClientRoutes(volume)
assert not cp.inline()
trigger = self.wait_for_events(cp, event='inline', state='online')
@@ -41,8 +41,8 @@ class ServerCommandsTest(tests.Test):
assert cp.inline()
def test_MountNode(self):
- volume = Volume('db')
- cp = ClientCommands(volume)
+ volume = Volume('db', model.RESOURCES)
+ cp = ClientRoutes(volume)
trigger = self.wait_for_events(cp, event='inline', state='online')
mountpoints.populate('.')
@@ -97,8 +97,8 @@ class ServerCommandsTest(tests.Test):
job.kill()
self.assertEqual([
- {'guid': guid, 'document': 'context', 'event': 'create'},
- {'guid': guid, 'document': 'context', 'event': 'update'},
+ {'guid': guid, 'resource': 'context', 'event': 'create'},
+ {'guid': guid, 'resource': 'context', 'event': 'update'},
],
events)
diff --git a/tests/units/db/__main__.py b/tests/units/db/__main__.py
index 70e829a..6dda7ff 100644
--- a/tests/units/db/__main__.py
+++ b/tests/units/db/__main__.py
@@ -2,15 +2,11 @@
from __init__ import tests
-from commands import *
-from document import *
-from env import *
+from resource import *
from index import *
-from metadata import *
from migrate import *
-from router import *
from storage import *
-from volume import *
+from routes import *
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/db/commands.py b/tests/units/db/commands.py
deleted file mode 100755
index da859d5..0000000
--- a/tests/units/db/commands.py
+++ /dev/null
@@ -1,552 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-from cStringIO import StringIO
-
-from __init__ import tests
-
-from sugar_network import db
-from sugar_network.db import env, volume, Volume, Document, \
- property_command, document_command, directory_command, volume_command, \
- Request, BlobProperty, Response, CommandsProcessor, \
- CommandNotFound, to_int, to_list
-from sugar_network.db.router import route
-from sugar_network.toolkit.http import NotFound, Forbidden
-
-
-class CommandsTest(tests.Test):
-
- def test_VolumeCommands(self):
- calls = []
-
- class TestCommandsProcessor(CommandsProcessor):
-
- @volume_command(method='PROBE')
- def command_1(self, **kwargs):
- calls.append(('command_1', kwargs))
-
- @volume_command(method='PROBE', cmd='command_2')
- def command_2(self, **kwargs):
- calls.append(('command_2', kwargs))
-
- cp = TestCommandsProcessor()
-
- self.call(cp, 'PROBE')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', cmd='command_1')
- self.call(cp, 'PROBE', cmd='command_2')
-
- self.assertEqual([
- ('command_1', {}),
- ('command_2', {}),
- ],
- calls)
-
- def test_DirectoryCommands(self):
- calls = []
-
- class TestCommandsProcessor(CommandsProcessor):
-
- @directory_command(method='PROBE')
- def command_1(self, **kwargs):
- calls.append(('command_1', kwargs))
-
- @directory_command(method='PROBE', cmd='command_2')
- def command_2(self, **kwargs):
- calls.append(('command_2', kwargs))
-
- cp = TestCommandsProcessor()
-
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE')
- self.call(cp, 'PROBE', document='testdocument')
- self.call(cp, 'PROBE', document='fakedocument')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', cmd='command_1', document='testdocument')
- self.call(cp, 'PROBE', cmd='command_2', document='testdocument')
- self.call(cp, 'PROBE', cmd='command_2', document='fakedocument')
-
- self.assertEqual([
- ('command_1', {}),
- ('command_1', {}),
- ('command_2', {}),
- ('command_2', {}),
- ],
- calls)
-
- def test_DocumentCommands(self):
- calls = []
-
- class TestCommandsProcessor(CommandsProcessor):
-
- @document_command(method='PROBE')
- def command_1(self, **kwargs):
- calls.append(('command_1', kwargs))
-
- @document_command(method='PROBE', cmd='command_2')
- def command_2(self, **kwargs):
- calls.append(('command_2', kwargs))
-
- class TestDocument(Document):
- pass
-
- volume = Volume(tests.tmpdir, [TestDocument])
- cp = TestCommandsProcessor(volume)
-
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', document='testdocument')
- self.call(cp, 'PROBE', document='testdocument', guid='guid')
- self.call(cp, 'PROBE', document='fakedocument', guid='guid')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', cmd='command_1', document='testdocument', guid='guid')
- self.call(cp, 'PROBE', cmd='command_2', document='testdocument', guid='guid')
- self.call(cp, 'PROBE', cmd='command_2', document='fakedocument', guid='guid')
-
- self.assertEqual([
- ('command_1', {}),
- ('command_1', {}),
- ('command_2', {}),
- ('command_2', {}),
- ],
- calls)
-
- def test_PropertyCommands(self):
- calls = []
-
- class TestCommandsProcessor(CommandsProcessor):
-
- @property_command(method='PROBE')
- def command_1(self, **kwargs):
- calls.append(('command_1', kwargs))
-
- @property_command(method='PROBE', cmd='command_2')
- def command_2(self, **kwargs):
- calls.append(('command_2', kwargs))
-
- class TestDocument(Document):
- pass
-
- volume = Volume(tests.tmpdir, [TestDocument])
- cp = TestCommandsProcessor(volume)
-
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', document='testdocument')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', document='testdocument', guid='guid')
- self.call(cp, 'PROBE', document='testdocument', guid='guid', prop='prop')
- self.call(cp, 'PROBE', document='fakedocument', guid='guid', prop='prop')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', cmd='command_1', document='testdocument', guid='guid', prop='prop')
- self.call(cp, 'PROBE', cmd='command_2', document='testdocument', guid='guid', prop='prop')
- self.call(cp, 'PROBE', cmd='command_2', document='fakedocument', guid='guid', prop='prop')
-
- self.assertEqual([
- ('command_1', {}),
- ('command_1', {}),
- ('command_2', {}),
- ('command_2', {}),
- ],
- calls)
-
- def test_ClassDodcumentCommands(self):
- calls = []
-
- class TestDocument(Document):
-
- @document_command(method='PROBE')
- def command_1(cls, **kwargs):
- calls.append(('command_1', kwargs))
-
- @document_command(method='PROBE', cmd='command_2')
- def command_2(cls, **kwargs):
- calls.append(('command_2', kwargs))
-
- volume = Volume(tests.tmpdir, [TestDocument])
- cp = CommandsProcessor(volume)
-
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', document='testdocument')
- self.assertRaises(NotFound, self.call, cp, 'PROBE', document='testdocument', guid='guid')
- volume['testdocument'].create({'guid': 'guid'})
- self.call(cp, 'PROBE', document='testdocument', guid='guid')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', document='fakedocument', guid='guid')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', cmd='command_1', document='testdocument', guid='guid')
- self.call(cp, 'PROBE', cmd='command_2', document='testdocument', guid='guid')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', cmd='command_2', document='fakedocument', guid='guid')
-
- self.assertEqual([
- ('command_1', {}),
- ('command_2', {}),
- ],
- calls)
-
- def test_ClassPropertyCommands(self):
- calls = []
-
- class TestDocument(Document):
-
- @property_command(method='PROBE')
- def command_1(cls, **kwargs):
- calls.append(('command_1', kwargs))
-
- @property_command(method='PROBE', cmd='command_2')
- def command_2(cls, **kwargs):
- calls.append(('command_2', kwargs))
-
- volume = Volume(tests.tmpdir, [TestDocument])
- cp = CommandsProcessor(volume)
-
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', document='testdocument')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', document='testdocument', prop='prop')
- self.assertRaises(NotFound, self.call, cp, 'PROBE', document='testdocument', guid='guid', prop='prop')
- volume['testdocument'].create({'guid': 'guid'})
- self.call(cp, 'PROBE', document='testdocument', guid='guid', prop='prop')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', document='fakedocument', guid='guid', prop='prop')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', cmd='command_1', document='testdocument', guid='guid', prop='prop')
- self.call(cp, 'PROBE', cmd='command_2', document='testdocument', guid='guid', prop='prop')
- self.assertRaises(CommandNotFound, self.call, cp, 'PROBE', cmd='command_2', document='fakedocument', guid='guid', prop='prop')
-
- self.assertEqual([
- ('command_1', {}),
- ('command_2', {}),
- ],
- calls)
-
- def test_AccessLevel(self):
- calls = []
-
- class TestCommandsProcessor(CommandsProcessor):
-
- @volume_command(method='PROBE', cmd='all')
- def all(self):
- pass
-
- @volume_command(method='PROBE', cmd='system', access_level=env.ACCESS_SYSTEM)
- def system(self):
- pass
-
- @volume_command(method='PROBE', cmd='local', access_level=env.ACCESS_LOCAL)
- def local(self):
- pass
-
- @volume_command(method='PROBE', cmd='remote', access_level=env.ACCESS_REMOTE)
- def remote(self):
- pass
-
- cp = TestCommandsProcessor()
-
- self.call(cp, 'PROBE', cmd='all', access_level=env.ACCESS_REMOTE)
- self.call(cp, 'PROBE', cmd='all', access_level=env.ACCESS_LOCAL)
- self.call(cp, 'PROBE', cmd='all', access_level=env.ACCESS_SYSTEM)
-
- self.call(cp, 'PROBE', cmd='remote', access_level=env.ACCESS_REMOTE)
- self.assertRaises(Forbidden, self.call, cp, 'PROBE', cmd='remote', access_level=env.ACCESS_LOCAL)
- self.assertRaises(Forbidden, self.call, cp, 'PROBE', cmd='remote', access_level=env.ACCESS_SYSTEM)
-
- self.assertRaises(Forbidden, self.call, cp, 'PROBE', cmd='local', access_level=env.ACCESS_REMOTE)
- self.call(cp, 'PROBE', cmd='local', access_level=env.ACCESS_LOCAL)
- self.assertRaises(Forbidden, self.call, cp, 'PROBE', cmd='local', access_level=env.ACCESS_SYSTEM)
-
- self.assertRaises(Forbidden, self.call, cp, 'PROBE', cmd='system', access_level=env.ACCESS_REMOTE)
- self.assertRaises(Forbidden, self.call, cp, 'PROBE', cmd='system', access_level=env.ACCESS_LOCAL)
- self.call(cp, 'PROBE', cmd='system', access_level=env.ACCESS_SYSTEM)
-
- def test_ParentClasses(self):
- calls = []
-
- class Parent(object):
-
- @volume_command(method='PROBE')
- def probe(self):
- return 'probe'
-
- class TestCommandsProcessor(CommandsProcessor, Parent):
- pass
-
- cp = TestCommandsProcessor()
- self.assertEqual('probe', self.call(cp, 'PROBE'))
-
- def test_OverrideInChildClass(self):
- calls = []
-
- class Parent(CommandsProcessor):
-
- @volume_command(method='PROBE')
- def probe(self):
- return 'probe-1'
-
- @volume_command(method='COMMON')
- def common(self):
- return 'common'
-
- class Child(Parent):
-
- @volume_command(method='PROBE')
- def probe(self):
- return 'probe-2'
-
- @volume_command(method='PARTICULAR')
- def particular(self):
- return 'particular'
-
- cp = Child()
- self.assertEqual('probe-2', self.call(cp, 'PROBE'))
- self.assertEqual('common', self.call(cp, 'COMMON'))
- self.assertEqual('particular', self.call(cp, 'PARTICULAR'))
-
- def test_RequestRead(self):
-
- class Stream(object):
-
- def __init__(self, value):
- self.pos = 0
- self.value = value
-
- def read(self, size):
- assert self.pos + size <= len(self.value)
- result = self.value[self.pos:self.pos + size]
- self.pos += size
- return result
-
- request = Request()
- request.content_stream = Stream('123')
- request.content_length = len(request.content_stream.value)
- self.assertEqual('123', request.read())
- self.assertEqual('', request.read())
- self.assertEqual('', request.read(10))
-
- request = Request()
- request.content_stream = Stream('123')
- request.content_length = len(request.content_stream.value)
- self.assertEqual('123', request.read(10))
-
- request = Request()
- request.content_stream = Stream('123')
- request.content_length = len(request.content_stream.value)
- self.assertEqual('1', request.read(1))
- self.assertEqual('2', request.read(1))
- self.assertEqual('3', request.read())
-
- def test_Arguments(self):
-
- class TestCommandsProcessor(CommandsProcessor):
-
- @volume_command(method='PROBE', arguments={'arg_int': to_int, 'arg_list': to_list})
- def probe(self, arg_int=None, arg_list=None):
- return arg_int, arg_list
-
- cp = TestCommandsProcessor()
-
- self.assertEqual((None, None), self.call(cp, 'PROBE'))
- self.assertEqual((-1, [-2, None]), self.call(cp, 'PROBE', arg_int=-1, arg_list=[-2, None]))
- self.assertEqual((4, [' foo', ' bar ', ' ']), self.call(cp, 'PROBE', arg_int='4', arg_list=' foo, bar , '))
- self.assertEqual((None, ['foo']), self.call(cp, 'PROBE', arg_list='foo'))
- self.assertEqual((None, []), self.call(cp, 'PROBE', arg_list=''))
- self.assertEqual((None, [' ']), self.call(cp, 'PROBE', arg_list=' '))
- self.assertEqual((0, None), self.call(cp, 'PROBE', arg_int=''))
- self.assertRaises(RuntimeError, self.call, cp, 'PROBE', arg_int=' ')
- self.assertRaises(RuntimeError, self.call, cp, 'PROBE', arg_int='foo')
-
- def test_PassKwargs(self):
-
- class TestCommandsProcessor(CommandsProcessor):
-
- @volume_command(method='PROBE')
- def probe(self, arg, request, response, **kwargs):
- return arg, dict(request), dict(response), kwargs
-
- cp = TestCommandsProcessor()
-
- self.assertEqual(
- (None, {'method': 'PROBE'}, {}, {}),
- self.call(cp, 'PROBE'))
- self.assertEqual(
- (1, {'method': 'PROBE', 'arg': 1}, {}, {}),
- self.call(cp, 'PROBE', arg=1))
- self.assertEqual(
- (None, {'method': 'PROBE', 'foo': 'bar'}, {}, {}),
- self.call(cp, 'PROBE', foo='bar'))
- self.assertEqual(
- (-2, {'method': 'PROBE', 'foo': 'bar', 'arg': -2}, {}, {}),
- self.call(cp, 'PROBE', foo='bar', arg=-2))
-
- def test_PrePost(self):
-
- class ParentCommandsProcessor(CommandsProcessor):
-
- @db.volume_command_pre(method='PROBE')
- def command_pre1(self, request):
- request['probe'].append('pre1')
-
- @db.volume_command_pre(method='PROBE')
- def command_pre2(self, request):
- request['probe'].append('pre2')
-
- @db.volume_command_post(method='PROBE')
- def command_post1(self, request, response, result):
- request['probe'].append('post1')
- response['probe'].append('post1')
- return result + 1
-
- @db.volume_command_post(method='PROBE')
- def command_post2(self, request, response, result):
- request['probe'].append('post2')
- response['probe'].append('post2')
- return result + 1
-
- class TestCommandsProcessor(ParentCommandsProcessor):
-
- @db.volume_command_pre(method='PROBE')
- def command_pre3(self, request):
- request['probe'].append('pre3')
-
- @db.volume_command_pre(method='PROBE')
- def command_pre4(self, request):
- request['probe'].append('pre4')
-
- @db.volume_command(method='PROBE')
- def command(self, request):
- request['probe'].append('cmd')
- response['probe'].append('cmd')
- return 1
-
- @db.volume_command_post(method='PROBE')
- def command_post3(self, request, response, result):
- request['probe'].append('post3')
- response['probe'].append('post3')
- return result + 1
-
- @db.volume_command_post(method='PROBE')
- def command_post4(self, request, response, result):
- request['probe'].append('post4')
- response['probe'].append('post4')
- return result + 1
-
- cp = TestCommandsProcessor()
-
- request = db.Request(method='PROBE', probe=[])
- response = db.Response(probe=[])
- self.assertEqual(5, cp.call(request, response))
- self.assertEqual(['pre1', 'pre2', 'pre3', 'pre4', 'cmd', 'post1', 'post2', 'post3', 'post4'], request['probe'])
- self.assertEqual(['cmd', 'post1', 'post2', 'post3', 'post4'], response['probe'])
-
- def test_PrePostCallbackLess(self):
-
- class TestCommandsProcessor(CommandsProcessor):
-
- @db.volume_command_pre(method='PROBE')
- def command_pre(self, request):
- request['probe'].append('pre')
-
- def super_call(self, request, response):
- request['probe'].append('cmd')
- response['probe'].append('cmd')
- return 1
-
- @db.volume_command_post(method='PROBE')
- def command_post(self, request, response, result):
- request['probe'].append('post')
- response['probe'].append('post')
- return result + 1
-
- cp = TestCommandsProcessor()
-
- request = db.Request(method='PROBE', probe=[])
- response = db.Response(probe=[])
- self.assertEqual(2, cp.call(request, response))
- self.assertEqual(['pre', 'cmd', 'post'], request['probe'])
- self.assertEqual(['cmd', 'post'], response['probe'])
-
- def test_SubCall(self):
-
- class TestCommandsProcessor(CommandsProcessor):
-
- @db.volume_command(method='PROBE')
- def command1(self, request):
- return request.call('PROBE', cmd='command2')
-
- @db.volume_command(method='PROBE')
- def command2(self, request):
- return {'access_level': request.access_level, 'accept_language': request.accept_language}
-
- cp = TestCommandsProcessor()
-
- request = db.Request(method='PROBE')
- request.access_level = -1
- request.accept_language = 'foo'
- self.assertEqual({
- 'access_level': -1,
- 'accept_language': 'foo',
- },
- cp.call(request, db.Response()))
-
- def test_Routes(self):
- calls = []
-
- class BaseRoutes(CommandsProcessor):
-
- @route('GET', '/foo')
- def route1(self, request, response):
- return 'route1'
-
- class Routes(BaseRoutes):
-
- @route('PUT', '/foo')
- def route2(self, request, response):
- return 'route2'
-
- @route('GET', '/bar')
- def route3(self, request, response):
- return 'route3'
-
- def call(self, request, response):
- try:
- return CommandsProcessor.call(self, request, response)
- except CommandNotFound:
- return 'default'
-
- cp = Routes()
- request = Request()
-
- request.path = []
- request['method'] = 'GET'
- self.assertEqual('default', cp.call(request, db.Response()))
-
- request.path = ['foo']
- request['method'] = 'GET'
- self.assertEqual('route1', cp.call(request, db.Response()))
-
- request.path = ['foo']
- request['method'] = 'PUT'
- self.assertEqual('route2', cp.call(request, db.Response()))
-
- request.path = ['foo']
- request['method'] = 'POST'
- self.assertEqual('default', cp.call(request, db.Response()))
-
- request.path = ['bar', 'foo', 'probe']
- request['method'] = 'GET'
- self.assertEqual('route3', cp.call(request, db.Response()))
-
- def call(self, cp, method, document=None, guid=None, prop=None,
- access_level=env.ACCESS_REMOTE, **kwargs):
-
- class TestRequest(Request):
-
- content_stream = None
- content_length = 0
-
- request = TestRequest(**kwargs)
- request['method'] = method
- request.access_level = access_level
- if document:
- request['document'] = document
- if guid:
- request['guid'] = guid
- if prop:
- request['prop'] = prop
- if 'content_stream' in request:
- request.content_stream = request.pop('content_stream')
- request.content_length = len(request.content_stream.getvalue())
-
- self.response = Response()
- return cp.call(request, self.response)
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/db/env.py b/tests/units/db/env.py
deleted file mode 100755
index 953271e..0000000
--- a/tests/units/db/env.py
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import copy
-from os.path import exists
-
-from __init__ import tests
-
-from sugar_network import toolkit
-from sugar_network.db import env
-
-
-class EnvTest(tests.Test):
-
- def test_gettext(self):
- # Fallback to default lang
- toolkit._default_lang = 'default'
- self.assertEqual('foo', env.gettext({'lang': 'foo', 'default': 'bar'}, 'lang'))
- self.assertEqual('bar', env.gettext({'lang': 'foo', 'default': 'bar'}, 'fake'))
-
- # Exact accept_language
- self.assertEqual('', env.gettext(None, 'lang'))
- self.assertEqual('foo', env.gettext('foo', 'lang'))
- self.assertEqual('foo', env.gettext({'lang': 'foo', 'fake': 'bar', 'default': 'default'}, 'lang'))
- self.assertEqual('foo', env.gettext({'lang': 'foo', 'fake': 'bar', 'default': 'default'}, ['lang', 'fake']))
- self.assertEqual('bar', env.gettext({'lang': 'foo', 'fake': 'bar', 'default': 'default'}, ['fake', 'lang']))
-
- # Last resort
- self.assertEqual('foo', env.gettext({'1': 'foo', '2': 'bar'}, 'fake'))
-
- # Primed accept_language
- self.assertEqual('foo', env.gettext({'1': 'foo', '2': 'bar', 'default': 'default'}, '1-a'))
-
- # Primed i18n value
- self.assertEqual('bar', env.gettext({'1-a': 'foo', '1': 'bar', 'default': 'default'}, '1-b'))
- self.assertEqual('foo', env.gettext({'1-a': 'foo', '2': 'bar', 'default': 'default'}, '1-b'))
-
- def test_gettext_EnAsTheLastResort(self):
- toolkit._default_lang = 'en-us'
- self.assertEqual('right', env.gettext({'a': 'wrong', 'en': 'right'}, 'probe'))
- self.assertEqual('exact', env.gettext({'a': 'wrong', 'en': 'right', 'probe': 'exact'}, 'probe'))
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/db/index.py b/tests/units/db/index.py
index b94675a..9b7d130 100755
--- a/tests/units/db/index.py
+++ b/tests/units/db/index.py
@@ -11,9 +11,11 @@ from os.path import exists
from __init__ import tests
from sugar_network import toolkit
-from sugar_network.db import index, env
-from sugar_network.db.metadata import Metadata, IndexedProperty, GUID_PREFIX
+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.directory import _Query
+from sugar_network.toolkit.router import ACL
from sugar_network.toolkit import coroutine
@@ -69,8 +71,8 @@ class IndexTest(tests.Test):
([], 0),
db._find(reply=['key']))
- def test_IndexByReprcast(self):
- db = Index({'key': IndexedProperty('key', 1, 'K', reprcast=lambda x: "foo" + x)})
+ def test_IndexByFmt(self):
+ db = Index({'key': IndexedProperty('key', 1, 'K', fmt=lambda x: "foo" + x)})
db.store('1', {'key': 'bar'})
@@ -87,7 +89,7 @@ class IndexTest(tests.Test):
[],
db._find(key='fake', reply=['key'])[0])
- def test_IndexByReprcastGenerator(self):
+ def test_IndexByFmtGenerator(self):
def iterate(value):
if value != 'fake':
@@ -95,7 +97,7 @@ class IndexTest(tests.Test):
yield 'bar'
yield value
- db = Index({'key': IndexedProperty('key', 1, 'K', reprcast=iterate)})
+ db = Index({'key': IndexedProperty('key', 1, 'K', fmt=iterate)})
db.store('1', {'key': 'value'})
self.assertEqual(
@@ -497,7 +499,7 @@ class IndexTest(tests.Test):
db = Index({}, lambda: commits.append(True))
coroutine.dispatch()
- env.index_flush_threshold.value = 1
+ index.index_flush_threshold.value = 1
db.store('1', {})
coroutine.dispatch()
db.store('2', {})
@@ -510,7 +512,7 @@ class IndexTest(tests.Test):
del commits[:]
db = Index({}, lambda: commits.append(True))
coroutine.dispatch()
- env.index_flush_threshold.value = 2
+ index.index_flush_threshold.value = 2
db.store('4', {})
coroutine.dispatch()
db.store('5', {})
@@ -525,8 +527,8 @@ class IndexTest(tests.Test):
db.close()
def test_FlushTimeout(self):
- env.index_flush_threshold.value = 0
- env.index_flush_timeout.value = 1
+ index.index_flush_threshold.value = 0
+ index.index_flush_timeout.value = 1
commits = []
@@ -557,7 +559,7 @@ class IndexTest(tests.Test):
self.assertEqual(2, len(commits))
def test_DoNotMissImmediateCommitEvent(self):
- env.index_flush_threshold.value = 1
+ index.index_flush_threshold.value = 1
commits = []
db = Index({}, lambda: commits.append(True))
@@ -748,6 +750,25 @@ class IndexTest(tests.Test):
]),
db._find(prop=['a', '-b', 'c'], reply=['guid'])[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)])
+
+ 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)])
+
+ prop = Property('prop', fmt=lambda x: x.keys())
+ self.assertEqual(['a', '2'], [i for i in _fmt_prop_value(prop, {'a': 1, 2: 'b'})])
+
class Index(index.IndexWriter):
@@ -759,7 +780,7 @@ class Index(index.IndexWriter):
metadata = Metadata(Index)
metadata.update(props)
metadata['guid'] = IndexedProperty('guid',
- permissions=env.ACCESS_CREATE | env.ACCESS_READ, slot=0,
+ acl=ACL.CREATE | ACL.READ, slot=0,
prefix=GUID_PREFIX)
index.IndexWriter.__init__(self, tests.tmpdir + '/index', metadata, *args)
diff --git a/tests/units/db/metadata.py b/tests/units/db/metadata.py
deleted file mode 100755
index 64c08db..0000000
--- a/tests/units/db/metadata.py
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-from __init__ import tests
-
-from sugar_network.db.metadata import Property
-
-
-class MetadataTest(tests.Test):
-
- def test_Property_decode(self):
- prop = Property('prop', typecast=int)
- self.assertEqual(1, prop.decode(1))
- self.assertEqual(1, prop.decode(1.1))
- self.assertEqual(1, prop.decode('1'))
- self.assertRaises(ValueError, prop.decode, '1.0')
- self.assertRaises(ValueError, prop.decode, '')
- self.assertRaises(ValueError, prop.decode, None)
-
- prop = Property('prop', typecast=float)
- self.assertEqual(1.0, prop.decode(1))
- self.assertEqual(1.1, prop.decode(1.1))
- self.assertEqual(1.0, prop.decode('1'))
- self.assertEqual(1.1, prop.decode('1.1'))
- self.assertRaises(ValueError, prop.decode, '')
- self.assertRaises(ValueError, prop.decode, None)
-
- prop = Property('prop', typecast=bool)
- self.assertEqual(False, prop.decode(0))
- self.assertEqual(True, prop.decode(1))
- self.assertEqual(True, prop.decode(1.1))
- self.assertEqual(True, prop.decode('1'))
- self.assertEqual(True, prop.decode('A'))
- self.assertEqual(False, prop.decode(''))
- self.assertRaises(ValueError, prop.decode, None)
-
- prop = Property('prop', typecast=[int])
- self.assertEqual((1,), prop.decode(1))
- self.assertRaises(ValueError, prop.decode, None)
- self.assertRaises(ValueError, prop.decode, '')
- self.assertEqual((), prop.decode([]))
- self.assertEqual((123,), prop.decode('123'))
- self.assertRaises(ValueError, prop.decode, 'a')
- self.assertEqual((123, 4, 5), prop.decode(['123', 4, 5.6]))
-
- prop = Property('prop', typecast=[1, 2])
- self.assertRaises(ValueError, prop.decode, 0)
- self.assertRaises(ValueError, prop.decode, None)
- self.assertRaises(ValueError, prop.decode, '')
- self.assertRaises(ValueError, prop.decode, 'A')
- self.assertEqual(1, prop.decode(1))
- self.assertEqual(2, prop.decode(2))
-
- prop = Property('prop', typecast=[[True, False, 'probe']])
- self.assertRaises(ValueError, prop.decode, None)
- self.assertEqual((0, ), prop.decode(0))
- self.assertRaises(ValueError, prop.decode, 'A')
- self.assertEqual((True, ), prop.decode(True))
- self.assertEqual((False, ), prop.decode(False))
- self.assertRaises(ValueError, prop.decode, [3])
- self.assertRaises(ValueError, prop.decode, ['A'])
- self.assertRaises(ValueError, prop.decode, '')
- self.assertEqual((), prop.decode([]))
- self.assertEqual((True,), prop.decode([True]))
- self.assertEqual((False,), prop.decode([False]))
- self.assertEqual((True, False, True), prop.decode([True, False, True]))
- self.assertEqual((True, False, 'probe'), prop.decode([True, False, 'probe']))
- self.assertRaises(ValueError, prop.decode, [True, None])
-
- prop = Property('prop', typecast=[str])
- self.assertEqual(('',), prop.decode(''))
- self.assertEqual(('',), prop.decode(['']))
- self.assertEqual((), prop.decode([]))
-
- prop = Property('prop', typecast=[])
- self.assertRaises(ValueError, prop.decode, None)
- self.assertEqual(('',), prop.decode(''))
- self.assertEqual(('',), prop.decode(['']))
- self.assertEqual((), prop.decode([]))
- self.assertEqual(('0',), prop.decode(0))
- self.assertEqual(('',), prop.decode(''))
- self.assertEqual(('foo',), prop.decode('foo'))
-
- prop = Property('prop', typecast=[['A', 'B', 'C']])
- self.assertRaises(ValueError, prop.decode, '')
- self.assertRaises(ValueError, prop.decode, [''])
- self.assertEqual((), prop.decode([]))
- self.assertEqual(('A', 'B', 'C'), prop.decode(['A', 'B', 'C']))
- self.assertRaises(ValueError, prop.decode, ['a'])
- self.assertRaises(ValueError, prop.decode, ['A', 'x'])
-
- prop = Property('prop', typecast=[frozenset(['A', 'B', 'C'])])
- self.assertEqual(('A', 'B', 'C'), prop.decode(['A', 'B', 'C']))
-
- prop = Property('prop', typecast=lambda x: x + 1)
- self.assertEqual(1, prop.decode(0))
-
- def test_Property_to_string(self):
- prop = Property('prop', typecast=int)
- self.assertEqual(['0'], prop.to_string(0))
- self.assertEqual(['1'], prop.to_string(1))
-
- prop = Property('prop', typecast=float)
- self.assertEqual(['0'], prop.to_string(0))
- self.assertEqual(['1.1'], prop.to_string(1.1))
-
- prop = Property('prop', typecast=bool)
- self.assertEqual(['1'], prop.to_string(True))
- self.assertEqual(['0'], prop.to_string(False))
-
- prop = Property('prop', typecast=[int])
- self.assertEqual(['0', '1'], prop.to_string([0, 1]))
-
- prop = Property('prop', typecast=[1, 2])
- self.assertEqual(['2', '1'], prop.to_string([2, 1]))
-
- prop = Property('prop', typecast=[[True, 0, 'probe']])
- self.assertEqual(['probe', '1', '0'], prop.to_string(['probe', True, 0]))
-
- prop = Property('prop', reprcast=lambda x: x.keys())
- self.assertEqual(['a', '2'], prop.to_string({'a': 1, 2: 'b'}))
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/db/migrate.py b/tests/units/db/migrate.py
index 89e75c8..773a45d 100755
--- a/tests/units/db/migrate.py
+++ b/tests/units/db/migrate.py
@@ -8,7 +8,6 @@ from os.path import exists, lexists
from __init__ import tests
from sugar_network import db
-from sugar_network.db import document, env
from sugar_network.db import directory as directory_
from sugar_network.db.directory import Directory
from sugar_network.db.index import IndexWriter
@@ -18,7 +17,7 @@ class MigrateTest(tests.Test):
def test_MissedProps(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(prefix='P')
def prop1(self, value):
@@ -52,7 +51,7 @@ class MigrateTest(tests.Test):
def test_ConvertToJson(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(prefix='P', default='value')
def prop(self, value):
diff --git a/tests/units/db/document.py b/tests/units/db/resource.py
index e25ee29..ed37664 100755
--- a/tests/units/db/document.py
+++ b/tests/units/db/resource.py
@@ -18,18 +18,19 @@ import gobject
from __init__ import tests
from sugar_network import db
-from sugar_network.db import document, storage, env, index
+from sugar_network.db import storage, index
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.util import Sequence
+from sugar_network.toolkit.router import ACL
+from sugar_network.toolkit import Sequence
-class DocumentTest(tests.Test):
+class ResourceTest(tests.Test):
def test_ActiveProperty_Slotted(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def slotted(self, value):
@@ -54,7 +55,7 @@ class DocumentTest(tests.Test):
def test_ActiveProperty_SlottedIUnique(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop_1(self, value):
@@ -68,7 +69,7 @@ class DocumentTest(tests.Test):
def test_ActiveProperty_Terms(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(prefix='T')
def term(self, value):
@@ -94,7 +95,7 @@ class DocumentTest(tests.Test):
def test_ActiveProperty_TermsUnique(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(prefix='P')
def prop_1(self, value):
@@ -108,7 +109,7 @@ class DocumentTest(tests.Test):
def test_ActiveProperty_FullTextSearch(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(full_text=False, slot=1)
def no(self, value):
@@ -129,7 +130,7 @@ class DocumentTest(tests.Test):
def test_update(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop_1(self, value):
@@ -153,7 +154,7 @@ class DocumentTest(tests.Test):
def test_delete(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(prefix='P')
def prop(self, value):
@@ -186,7 +187,7 @@ class DocumentTest(tests.Test):
def test_populate(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
@@ -232,7 +233,7 @@ class DocumentTest(tests.Test):
def test_populate_IgnoreBadDocuments(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
@@ -273,7 +274,7 @@ class DocumentTest(tests.Test):
def test_create_with_guid(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
@@ -293,7 +294,7 @@ class DocumentTest(tests.Test):
def test_seqno(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
@@ -333,7 +334,7 @@ class DocumentTest(tests.Test):
def test_diff(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
@@ -434,9 +435,9 @@ class DocumentTest(tests.Test):
def test_diff_IgnoreCalcProps(self):
- class Document(document.Document):
+ class Document(db.Resource):
- @db.indexed_property(slot=1, permissions=db.ACCESS_PUBLIC | db.ACCESS_CALC)
+ @db.indexed_property(slot=1, acl=ACL.PUBLIC | ACL.CALC)
def prop(self, value):
return value
@@ -465,7 +466,7 @@ class DocumentTest(tests.Test):
def test_diff_Exclude(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
@@ -499,7 +500,7 @@ class DocumentTest(tests.Test):
URL = 'http://src.sugarlabs.org/robots.txt'
URL_content = urllib2.urlopen(URL).read()
- class Document(document.Document):
+ class Document(db.Resource):
@db.blob_property()
def blob(self, value):
@@ -528,7 +529,7 @@ class DocumentTest(tests.Test):
def test_diff_Filter(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(prefix='P')
def prop(self, value):
@@ -555,7 +556,7 @@ class DocumentTest(tests.Test):
def test_diff_GroupBy(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1, prefix='P')
def prop(self, value):
@@ -584,7 +585,7 @@ class DocumentTest(tests.Test):
def test_merge_New(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
@@ -650,7 +651,7 @@ class DocumentTest(tests.Test):
def test_merge_Update(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.blob_property()
def blob(self, value):
@@ -729,7 +730,7 @@ class DocumentTest(tests.Test):
def test_merge_SeqnoLessMode(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
@@ -788,7 +789,7 @@ class DocumentTest(tests.Test):
def test_merge_AvoidCalculatedBlobs(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.blob_property()
def blob(self, value):
@@ -810,7 +811,7 @@ class DocumentTest(tests.Test):
def test_merge_Blobs(self):
- class Document(document.Document):
+ class Document(db.Resource):
@db.blob_property()
def blob(self, value):
@@ -847,7 +848,7 @@ class DocumentTest(tests.Test):
def test_wipe(self):
- class Document(document.Document):
+ class Document(db.Resource):
pass
directory = Directory(tests.tmpdir, Document, IndexWriter)
diff --git a/tests/units/db/router.py b/tests/units/db/router.py
deleted file mode 100755
index 5147c71..0000000
--- a/tests/units/db/router.py
+++ /dev/null
@@ -1,533 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import re
-import os
-import time
-import json
-import urllib2
-import hashlib
-import tempfile
-from email.utils import formatdate
-from cStringIO import StringIO
-from os.path import exists
-
-from __init__ import tests, src_root
-
-from sugar_network import db, node, static, toolkit
-from sugar_network.db.router import Router, _Request, _parse_accept_language, route, _filename
-from sugar_network.toolkit import util, default_lang, http
-from sugar_network.resources.user import User
-from sugar_network.resources.volume import Volume, Resource
-from sugar_network import client as local
-
-
-class RouterTest(tests.Test):
-
- def test_StreamedResponse(self):
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command()
- def get_stream(self, response):
- return StringIO('stream')
-
- cp = CommandsProcessor()
- router = Router(cp)
-
- response = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- },
- lambda *args: None)
- self.assertEqual('stream', ''.join([i for i in response]))
-
- def test_EmptyResponse(self):
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command(cmd='1', mime_type='application/octet-stream')
- def get_binary(self, response):
- pass
-
- @db.volume_command(cmd='2', mime_type='application/json')
- def get_json(self, response):
- pass
-
- @db.volume_command(cmd='3')
- def no_get(self, response):
- pass
-
- cp = CommandsProcessor()
- router = Router(cp)
-
- response = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'QUERY_STRING': 'cmd=1',
- },
- lambda *args: None)
- self.assertEqual('', ''.join([i for i in response]))
-
- response = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'QUERY_STRING': 'cmd=2',
- },
- lambda *args: None)
- self.assertEqual('null', ''.join([i for i in response]))
-
- response = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'QUERY_STRING': 'cmd=3',
- },
- lambda *args: None)
- self.assertEqual('', ''.join([i for i in response]))
-
- def test_StatusWOResult(self):
-
- class Status(http.Status):
- status = '001 Status'
- headers = {'status-header': 'value'}
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command(method='GET')
- def get(self, response):
- raise Status('Status-Error')
-
- router = Router(CommandsProcessor())
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- error = json.dumps({'request': '/', 'error': 'Status-Error'})
- self.assertEqual(error, ''.join([i for i in reply]))
- self.assertEqual([
- '001 Status',
- {'content-length': str(len(error)), 'content-type': 'application/json', 'status-header': 'value'},
- ],
- response)
-
- def test_StatusWResult(self):
-
- class Status(http.Status):
- status = '001 Status'
- headers = {'status-header': 'value'}
- result = 'result'
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command(method='GET')
- def get(self, response):
- raise Status('Status-Error')
-
- router = Router(CommandsProcessor())
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- error = 'result'
- self.assertEqual(error, ''.join([i for i in reply]))
- self.assertEqual([
- '001 Status',
- {'content-length': str(len(error)), 'status-header': 'value'},
- ],
- response)
-
- def test_StatusPass(self):
-
- class StatusPass(http.StatusPass):
- status = '001 StatusPass'
- headers = {'statuspass-header': 'value'}
- result = 'result'
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command(method='GET')
- def get(self, response):
- raise StatusPass('Status-Error')
-
- router = Router(CommandsProcessor())
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- error = ''
- self.assertEqual(error, ''.join([i for i in reply]))
- self.assertEqual([
- '001 StatusPass',
- {'content-length': str(len(error)), 'statuspass-header': 'value'},
- ],
- response)
-
- def test_BlobsRedirects(self):
- URL = 'http://sugarlabs.org'
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command(method='GET')
- def get(self, response):
- return db.PropertyMetadata(url=URL)
-
- router = Router(CommandsProcessor())
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- error = ''
- self.assertEqual(error, ''.join([i for i in reply]))
- self.assertEqual([
- '303 See Other',
- {'content-length': '0', 'location': URL},
- ],
- response)
-
- def test_LastModified(self):
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command(method='GET')
- def get(self, request):
- request.response.last_modified = 10
- return 'ok'
-
- router = Router(CommandsProcessor())
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = 'ok'
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '200 OK',
- {'last-modified': formatdate(10, localtime=False, usegmt=True), 'content-length': str(len(result))},
- ],
- response)
-
- def test_IfModifiedSince(self):
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command(method='GET')
- def get(self, request):
- if not request.if_modified_since or request.if_modified_since >= 10:
- return 'ok'
- else:
- raise http.NotModified()
-
- router = Router(CommandsProcessor())
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = 'ok'
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '200 OK',
- {'content-length': str(len(result))},
- ],
- response)
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'HTTP_IF_MODIFIED_SINCE': formatdate(11, localtime=False, usegmt=True),
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = 'ok'
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '200 OK',
- {'content-length': str(len(result))},
- ],
- response)
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'HTTP_IF_MODIFIED_SINCE': formatdate(9, localtime=False, usegmt=True),
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = ''
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '304 Not Modified',
- {'content-length': str(len(result))},
- ],
- response)
-
- def test_Request_MultipleQueryArguments(self):
- request = _Request({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'QUERY_STRING': 'a1=v1&a2=v2&a1=v3&a3=v4&a1=v5&a3=v6',
- })
- self.assertEqual(
- {'a1': ['v1', 'v3', 'v5'], 'a2': 'v2', 'a3': ['v4', 'v6'], 'method': 'GET'},
- request)
-
- def test_Register_UrlPath(self):
- self.assertEqual(
- [],
- _Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': ''}).path)
- self.assertEqual(
- [],
- _Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/'}).path)
- self.assertEqual(
- ['foo'],
- _Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': 'foo'}).path)
- self.assertEqual(
- ['foo', 'bar'],
- _Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': 'foo/bar'}).path)
- self.assertEqual(
- ['foo', 'bar'],
- _Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/foo/bar/'}).path)
- self.assertEqual(
- ['foo', 'bar'],
- _Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': '///foo////bar////'}).path)
-
- def test_Request_FailOnRelativePaths(self):
- self.assertRaises(RuntimeError, _Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '..'})
- self.assertRaises(RuntimeError, _Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/..'})
- self.assertRaises(RuntimeError, _Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/../'})
- self.assertRaises(RuntimeError, _Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '../bar'})
- self.assertRaises(RuntimeError, _Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/foo/../bar'})
- self.assertRaises(RuntimeError, _Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/foo/..'})
-
- def test_parse_accept_language(self):
- self.assertEqual(
- ['ru', 'en', 'es'],
- _parse_accept_language(' ru , en , es'))
- self.assertEqual(
- ['ru', 'en', 'es'],
- _parse_accept_language(' en;q=.4 , ru, es;q=0.1'))
- self.assertEqual(
- ['ru', 'en', 'es'],
- _parse_accept_language('ru;q=1,en;q=1,es;q=0.5'))
- self.assertEqual(
- ['ru-ru', 'es-br'],
- _parse_accept_language('ru-RU,es_BR'))
-
- def test_StaticFiles(self):
- router = Router(db.CommandsProcessor())
- 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_StaticFilesIfModifiedSince(self):
- router = Router(db.CommandsProcessor())
- local_path = src_root + '/sugar_network/static/httpdocs/images/missing.png'
- mtime = os.stat(local_path).st_mtime
-
- response = []
- reply = router({
- 'PATH_INFO': '/static/images/missing.png',
- 'REQUEST_METHOD': 'GET',
- 'HTTP_IF_MODIFIED_SINCE': formatdate(mtime - 1, localtime=False, usegmt=True),
- },
- 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(mtime, localtime=False, usegmt=True),
- 'content-length': str(len(result)),
- 'content-type': 'image/png',
- 'content-disposition': 'attachment; filename="missing.png"',
- }
- ],
- response)
-
- response = []
- reply = router({
- 'PATH_INFO': '/static/images/missing.png',
- 'REQUEST_METHOD': 'GET',
- 'HTTP_IF_MODIFIED_SINCE': formatdate(mtime, localtime=False, usegmt=True),
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = ''
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '304 Not Modified',
- {'content-length': str(len(result))},
- ],
- response)
-
- response = []
- reply = router({
- 'PATH_INFO': '/static/images/missing.png',
- 'REQUEST_METHOD': 'GET',
- 'HTTP_IF_MODIFIED_SINCE': formatdate(mtime + 1, localtime=False, usegmt=True),
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = ''
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '304 Not Modified',
- {'content-length': str(len(result))},
- ],
- response)
-
- def test_JsonpCallback(self):
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command(method='GET')
- def get(self, request):
- return 'ok'
-
- router = Router(CommandsProcessor())
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'QUERY_STRING': 'callback=foo',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = 'foo("ok");'
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '200 OK',
- {'content-length': str(len(result))},
- ],
- 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('Foo-3', _filename(['foo', 3], 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):
- self.touch(('blob.data', 'value'))
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.volume_command(method='GET', cmd='1')
- def cmd1(self, request):
- return db.PropertyMetadata(name='foo', blob='blob.data')
-
- @db.volume_command(method='GET', cmd='2')
- def cmd2(self, request):
- return db.PropertyMetadata(filename='foo.bar', blob='blob.data')
-
- router = Router(CommandsProcessor())
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'QUERY_STRING': 'cmd=1',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = 'value'
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '200 OK',
- {
- 'last-modified': formatdate(os.stat('blob.data').st_mtime, localtime=False, usegmt=True),
- 'content-length': str(len(result)),
- 'content-type': 'application/octet-stream',
- 'content-disposition': 'attachment; filename="Foo.obj"',
- }
- ],
- response)
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'GET',
- 'QUERY_STRING': 'cmd=2',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- result = 'value'
- self.assertEqual(result, ''.join([i for i in reply]))
- self.assertEqual([
- '200 OK',
- {
- 'last-modified': formatdate(os.stat('blob.data').st_mtime, localtime=False, usegmt=True),
- 'content-length': str(len(result)),
- 'content-type': 'application/octet-stream',
- 'content-disposition': 'attachment; filename="foo.bar"',
- }
- ],
- response)
-
- def test_DoNotOverrideContentLengthForHEAD(self):
-
- class CommandsProcessor(db.CommandsProcessor):
-
- @db.route('HEAD', '/')
- def head(self, request, response):
- response.content_length = 100
-
- router = Router(CommandsProcessor())
-
- response = []
- reply = router({
- 'PATH_INFO': '/',
- 'REQUEST_METHOD': 'HEAD',
- },
- lambda status, headers: response.extend([status, dict(headers)]))
- self.assertEqual([], [i for i in reply])
- self.assertEqual([
- '200 OK',
- {'content-length': '100'},
- ],
- response)
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/db/routes.py b/tests/units/db/routes.py
new file mode 100755
index 0000000..3d2d7f1
--- /dev/null
+++ b/tests/units/db/routes.py
@@ -0,0 +1,1600 @@
+#!/usr/bin/env python
+# sugar-lint: disable
+
+import os
+import sys
+import time
+import shutil
+import hashlib
+from cStringIO import StringIO
+from email.message import Message
+from email.utils import formatdate
+from os.path import dirname, join, abspath, exists
+
+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
+
+
+class RoutesTest(tests.Test):
+
+ def test_PostDefaults(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(default='default')
+ def w_default(self, value):
+ return value
+
+ @db.stored_property()
+ def wo_default(self, value):
+ return value
+
+ @db.indexed_property(slot=1, default='not_stored_default')
+ def not_stored_default(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [Document], lambda event: None)
+
+ self.assertRaises(RuntimeError, self.call, 'POST', ['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']))
+
+ def test_Populate(self):
+ self.touch(
+ ('document/1/1/guid', '{"value": "1"}'),
+ ('document/1/1/ctime', '{"value": 1}'),
+ ('document/1/1/mtime', '{"value": 1}'),
+ ('document/1/1/seqno', '{"value": 0}'),
+
+ ('document/2/2/guid', '{"value": "2"}'),
+ ('document/2/2/ctime', '{"value": 2}'),
+ ('document/2/2/mtime', '{"value": 2}'),
+ ('document/2/2/seqno', '{"value": 0}'),
+ )
+
+ 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
+ self.assertEqual(
+ sorted(['1', '2']),
+ sorted([i.guid for i in volume['document'].find()[0]]))
+
+ shutil.rmtree('document/index')
+
+ 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
+ self.assertEqual(
+ sorted(['1', '2']),
+ sorted([i.guid for i in volume['document'].find()[0]]))
+
+ def test_Commands(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, default='')
+ def localized_prop(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ self.volume['testdocument'].create({'guid': 'guid'})
+
+ self.assertEqual({
+ 'total': 1,
+ 'result': [
+ {'guid': 'guid', 'prop': ''},
+ ],
+ },
+ self.call('GET', path=['testdocument'], reply=['guid', 'prop']))
+
+ guid_1 = self.call('POST', path=['testdocument'], content={'prop': 'value_1'})
+ assert guid_1
+ guid_2 = self.call('POST', path=['testdocument'], content={'prop': 'value_2'})
+ assert guid_2
+
+ self.assertEqual(
+ sorted([
+ {'guid': 'guid', 'prop': ''},
+ {'guid': guid_1, 'prop': 'value_1'},
+ {'guid': guid_2, 'prop': 'value_2'},
+ ]),
+ sorted(self.call('GET', path=['testdocument'], reply=['guid', 'prop'])['result']))
+
+ self.call('PUT', path=['testdocument', guid_1], content={'prop': 'value_3'})
+
+ self.assertEqual(
+ sorted([
+ {'guid': 'guid', 'prop': ''},
+ {'guid': guid_1, 'prop': 'value_3'},
+ {'guid': guid_2, 'prop': 'value_2'},
+ ]),
+ sorted(self.call('GET', path=['testdocument'], reply=['guid', 'prop'])['result']))
+
+ self.call('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']))
+
+ self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid_2])
+
+ self.assertEqual(
+ {'guid': guid_1, 'prop': 'value_3'},
+ self.call('GET', path=['testdocument', guid_1], reply=['guid', 'prop']))
+
+ self.assertEqual(
+ 'value_3',
+ self.call('GET', path=['testdocument', guid_1, 'prop']))
+
+ def test_SetBLOBs(self):
+
+ class TestDocument(db.Resource):
+
+ @db.blob_property()
+ def blob(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'], content='blob1')
+ self.assertEqual('blob1', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+
+ self.call('PUT', path=['testdocument', guid, 'blob'], content_stream=StringIO('blob2'))
+ self.assertEqual('blob2', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+
+ self.call('PUT', path=['testdocument', guid, 'blob'], content=None)
+ self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob'])
+
+ def test_SetBLOBsByMeta(self):
+
+ class TestDocument(db.Resource):
+
+ @db.blob_property(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={})
+
+ self.assertRaises(RuntimeError, self.call, 'PUT', path=['testdocument', guid, 'blob'],
+ content={}, content_type='application/json')
+ self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob'])
+
+ self.touch('file')
+ self.assertRaises(RuntimeError, self.call, 'PUT', path=['testdocument', guid, 'blob'],
+ content={'blob': 'file'}, content_type='application/json')
+ self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob'])
+
+ 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'])
+ assert 'bar' not in blob
+
+ def test_RemoveBLOBs(self):
+
+ class TestDocument(db.Resource):
+
+ @db.blob_property(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={'blob': 'blob'})
+
+ self.assertEqual('blob', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+
+ self.call('PUT', path=['testdocument', guid, 'blob'])
+ self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob'])
+
+ def test_RemoveTempBLOBFilesOnFails(self):
+
+ class TestDocument(db.Resource):
+
+ @db.blob_property(mime_type='default')
+ def blob(self, value):
+ return value
+
+ @blob.setter
+ def blob(self, value):
+ raise RuntimeError()
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ guid = self.call('POST', path=['testdocument'], content={})
+
+ self.assertRaises(RuntimeError, self.call, 'PUT', path=['testdocument', guid, 'blob'], content='probe')
+ self.assertEqual(0, len(os.listdir('tmp')))
+
+ def test_SetBLOBsWithMimeType(self):
+
+ class TestDocument(db.Resource):
+
+ @db.blob_property(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={})
+
+ 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)
+
+ 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)
+
+ def test_GetBLOBs(self):
+
+ class TestDocument(db.Resource):
+
+ @db.blob_property()
+ def blob(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'], content='blob')
+
+ blob_path = tests.tmpdir + '/testdocument/%s/%s/blob' % (guid[:2], guid)
+ blob_meta = {
+ 'seqno': 2,
+ 'blob': blob_path + '.blob',
+ 'blob_size': 4,
+ 'digest': hashlib.sha1('blob').hexdigest(),
+ 'mime_type': 'application/octet-stream',
+ 'mtime': int(os.stat(blob_path).st_mtime),
+ }
+
+ self.assertEqual('blob', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+
+ self.assertEqual(
+ {'guid': guid, 'blob': 'http://localhost/testdocument/%s/blob' % guid},
+ self.call('GET', path=['testdocument', guid], reply=['guid', 'blob'], host='localhost'))
+
+ self.assertEqual([
+ {'guid': guid, 'blob': 'http://localhost/testdocument/%s/blob' % guid},
+ ],
+ self.call('GET', path=['testdocument'], reply=['guid', 'blob'], host='localhost')['result'])
+
+ def test_GetBLOBsByUrls(self):
+
+ class TestDocument(db.Resource):
+
+ @db.blob_property()
+ def blob(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ guid = self.call('POST', path=['testdocument'], content={})
+
+ self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob'])
+ self.assertEqual(
+ {'blob': 'http://127.0.0.1/testdocument/%s/blob' % guid},
+ self.call('GET', path=['testdocument', guid], reply=['blob'], host='127.0.0.1'))
+ self.assertEqual([
+ {'blob': 'http://127.0.0.1/testdocument/%s/blob' % guid},
+ ],
+ self.call('GET', path=['testdocument'], reply=['blob'], host='127.0.0.1')['result'])
+
+ self.call('PUT', path=['testdocument', guid, 'blob'], content='file')
+ self.assertEqual('file', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read())
+ self.assertEqual(
+ {'blob': 'http://127.0.0.1/testdocument/%s/blob' % guid},
+ self.call('GET', path=['testdocument', guid], reply=['blob'], host='127.0.0.1'))
+ self.assertEqual([
+ {'blob': 'http://127.0.0.1/testdocument/%s/blob' % guid},
+ ],
+ self.call('GET', path=['testdocument'], reply=['blob'], host='127.0.0.1')['result'])
+
+ self.call('PUT', path=['testdocument', guid, 'blob'], content={'url': 'http://foo'},
+ content_type='application/json')
+ self.assertEqual('http://foo', self.call('GET', path=['testdocument', guid, 'blob'])['url'])
+ self.assertEqual(
+ {'blob': 'http://foo'},
+ self.call('GET', path=['testdocument', guid], reply=['blob'], host='127.0.0.1'))
+ self.assertEqual([
+ {'blob': 'http://foo'},
+ ],
+ self.call('GET', path=['testdocument'], reply=['blob'], 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()
+ def blob(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+
+ 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'])
+ self.assertEqual(
+ {'blob': 'http://localhost/testdocument/%s/blob' % guid},
+ self.call('GET', path=['testdocument', guid], reply=['blob'], host='localhost'))
+
+ def test_Command_ReplyForGET(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, 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'})
+
+ self.assertEqual(
+ ['guid', 'prop'],
+ self.call('GET', path=['testdocument', guid], reply=['guid', 'prop']).keys())
+
+ self.assertEqual(
+ ['guid'],
+ self.call('GET', path=['testdocument'])['result'][0].keys())
+
+ self.assertEqual(
+ sorted(['guid', 'prop']),
+ sorted(self.call('GET', path=['testdocument'], reply=['prop', 'guid'])['result'][0].keys()))
+
+ self.assertEqual(
+ sorted(['prop']),
+ sorted(self.call('GET', path=['testdocument'], reply=['prop'])['result'][0].keys()))
+
+ def test_DecodeBeforeSetting(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, typecast=int)
+ def prop(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+
+ guid = self.call('POST', path=['testdocument'], content={'prop': '-1'})
+ self.assertEqual(-1, self.call('GET', path=['testdocument', guid, 'prop']))
+
+ def test_LocalizedSet(self):
+ toolkit._default_lang = 'en'
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, 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(0, 100, 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(0, 100, localized_prop='value_raw2')[0]])
+
+ 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(0, 100, localized_prop='value_ru')[0]])
+
+ self.call('PUT', path=['testdocument', guid], accept_language=['en'], content={'localized_prop': 'value_en'})
+ self.assertEqual({'ru': 'value_ru', 'en': 'value_en'}, directory.get(guid)['localized_prop'])
+ self.assertEqual(
+ [guid],
+ [i.guid for i in directory.find(0, 100, localized_prop='value_ru')[0]])
+ self.assertEqual(
+ [guid],
+ [i.guid for i in directory.find(0, 100, localized_prop='value_en')[0]])
+
+ def test_LocalizedGet(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, default='')
+ def localized_prop(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ directory = self.volume['testdocument']
+
+ guid = self.call('POST', path=['testdocument'], content={
+ 'localized_prop': {
+ 'ru': 'value_ru',
+ 'es': 'value_es',
+ 'en': 'value_en',
+ },
+ })
+
+ toolkit._default_lang = 'en'
+
+ self.assertEqual(
+ {'localized_prop': 'value_en'},
+ self.call('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']))
+ self.assertEqual(
+ 'value_ru',
+ self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['ru', 'es']))
+ self.assertEqual(
+ [{'localized_prop': 'value_ru'}],
+ self.call('GET', path=['testdocument'], accept_language=['foo', 'ru', 'es'], reply=['localized_prop'])['result'])
+
+ self.assertEqual(
+ {'localized_prop': 'value_ru'},
+ self.call('GET', path=['testdocument', guid], accept_language=['ru-RU'], reply=['localized_prop']))
+ self.assertEqual(
+ 'value_ru',
+ self.call('GET', path=['testdocument', guid, 'localized_prop'], 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'])
+
+ self.assertEqual(
+ {'localized_prop': 'value_es'},
+ self.call('GET', path=['testdocument', guid], accept_language=['es'], reply=['localized_prop']))
+ self.assertEqual(
+ 'value_es',
+ self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['es', 'ru']))
+ self.assertEqual(
+ [{'localized_prop': 'value_es'}],
+ self.call('GET', path=['testdocument'], accept_language=['foo', 'es', 'ru'], reply=['localized_prop'])['result'])
+
+ self.assertEqual(
+ {'localized_prop': 'value_en'},
+ self.call('GET', path=['testdocument', guid], accept_language=['fr'], reply=['localized_prop']))
+ self.assertEqual(
+ 'value_en',
+ self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['fr', 'za']))
+ self.assertEqual(
+ [{'localized_prop': 'value_en'}],
+ self.call('GET', path=['testdocument'], accept_language=['foo', 'fr', 'za'], reply=['localized_prop'])['result'])
+
+ toolkit._default_lang = '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']))
+ self.assertEqual(
+ 'value_%s' % fallback_lang,
+ self.call('GET', path=['testdocument', guid, 'localized_prop'], 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'])
+
+ def test_OpenByModuleName(self):
+ self.touch(
+ ('foo/bar.py', [
+ 'from sugar_network import db',
+ 'class Bar(db.Resource): pass',
+ ]),
+ ('foo/__init__.py', ''),
+ )
+ sys.path.insert(0, '.')
+
+ volume = db.Volume('.', ['foo.bar'], lambda event: None)
+ assert exists('bar/index')
+ volume['bar'].find()
+ volume.close()
+
+ def test_Command_GetBlobSetByUrl(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.blob_property()
+ def blob(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, 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')
+
+ self.assertEqual(
+ 'http://sugarlabs.org',
+ self.call('GET', path=['testdocument', guid, 'blob'])['url'])
+
+ def test_on_create(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, default='')
+ def localized_prop(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+
+ 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)
+
+ def test_on_create_Override(self):
+
+ class Routes(db.Routes):
+
+ def on_create(self, request, props, event):
+ props['prop'] = 'overriden'
+ db.Routes.on_create(self, request, props, event)
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, default='')
+ def localized_prop(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+
+ guid = self.call('POST', ['testdocument'], content={'prop': 'foo'}, routes=Routes)
+ self.assertEqual('overriden', self.volume['testdocument'].get(guid)['prop'])
+
+ self.call('PUT', ['testdocument', guid], content={'prop': 'bar'}, routes=Routes)
+ self.assertEqual('bar', self.volume['testdocument'].get(guid)['prop'])
+
+ def test_on_update(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, 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']
+
+ time.sleep(1)
+
+ self.call('PUT', path=['testdocument', guid], content={'prop': 'probe'})
+ assert self.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):
+ props['prop'] = 'overriden'
+ db.Routes.on_update(self, request, props, event)
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, default='')
+ def localized_prop(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+
+ guid = self.call('POST', ['testdocument'], content={'prop': 'foo'}, routes=Routes)
+ self.assertEqual('foo', self.volume['testdocument'].get(guid)['prop'])
+
+ self.call('PUT', ['testdocument', guid], content={'prop': 'bar'}, routes=Routes)
+ self.assertEqual('overriden', self.volume['testdocument'].get(guid)['prop'])
+
+ def __test_DoNotPassGuidsForCreate(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.indexed_property(prefix='L', localized=True, 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={})
+ assert guid
+
+ def test_seqno(self):
+
+ class Document1(db.Resource):
+ pass
+
+ class Document2(db.Resource):
+ pass
+
+ volume = db.Volume(tests.tmpdir, [Document1, Document2], lambda event: None)
+
+ assert not exists('seqno')
+ self.assertEqual(0, volume.seqno.value)
+
+ volume['document1'].create({'guid': '1'})
+ self.assertEqual(1, volume['document1'].get('1')['seqno'])
+ volume['document2'].create({'guid': '1'})
+ self.assertEqual(2, volume['document2'].get('1')['seqno'])
+ volume['document1'].create({'guid': '2'})
+ self.assertEqual(3, volume['document1'].get('2')['seqno'])
+ volume['document2'].create({'guid': '2'})
+ self.assertEqual(4, volume['document2'].get('2')['seqno'])
+
+ 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)
+ self.assertEqual(4, volume.seqno.value)
+
+ def test_Events(self):
+ db.index_flush_threshold.value = 0
+ db.index_flush_timeout.value = 0
+
+ class Document1(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ pass
+
+ class Document2(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ pass
+
+ @db.blob_property()
+ def blob(self, value):
+ return value
+
+ self.touch(
+ ('document1/1/1/guid', '{"value": "1"}'),
+ ('document1/1/1/ctime', '{"value": 1}'),
+ ('document1/1/1/mtime', '{"value": 1}'),
+ ('document1/1/1/prop', '{"value": ""}'),
+ ('document1/1/1/seqno', '{"value": 0}'),
+ )
+
+ events = []
+ volume = db.Volume(tests.tmpdir, [Document1, Document2], lambda event: events.append(event))
+ 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[:]
+
+ volume['document1'].create({'guid': 'guid1'})
+ volume['document2'].create({'guid': 'guid2'})
+ self.assertEqual([
+ {'event': 'create', 'resource': 'document1', 'guid': 'guid1'},
+ {'event': 'create', 'resource': 'document2', 'guid': 'guid2'},
+ ],
+ events)
+ del events[:]
+
+ volume['document1'].update('guid1', {'prop': 'foo'})
+ volume['document2'].update('guid2', {'prop': 'bar'})
+ self.assertEqual([
+ {'event': 'update', 'resource': 'document1', 'guid': 'guid1'},
+ {'event': 'update', 'resource': 'document2', 'guid': 'guid2'},
+ ],
+ events)
+ del events[:]
+
+ volume['document1'].delete('guid1')
+ self.assertEqual([
+ {'event': 'delete', 'resource': 'document1', 'guid': 'guid1'},
+ ],
+ events)
+ del events[:]
+
+ volume['document1'].commit()
+ mtime1 = int(os.stat('document1/index/mtime').st_mtime)
+ volume['document2'].commit()
+ mtime2 = int(os.stat('document2/index/mtime').st_mtime)
+
+ self.assertEqual([
+ {'event': 'commit', 'resource': 'document1', 'mtime': mtime1},
+ {'event': 'commit', 'resource': 'document2', 'mtime': mtime2},
+ ],
+ events)
+
+ def test_PermissionsNoWrite(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='', acl=ACL.READ)
+ def prop(self, value):
+ pass
+
+ @db.blob_property(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={})
+
+ 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')
+
+ def test_BlobsWritePermissions(self):
+
+ class TestDocument(db.Resource):
+
+ @db.blob_property(acl=ACL.CREATE | ACL.WRITE)
+ def blob1(self, value):
+ return value
+
+ @db.blob_property(acl=ACL.CREATE)
+ def blob2(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], 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 = 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_')
+
+ def test_properties_OverrideGet(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='1')
+ def prop1(self, value):
+ return value
+
+ @db.indexed_property(slot=2, default='2')
+ def prop2(self, value):
+ return -1
+
+ @db.blob_property()
+ 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={})
+ self.touch(('new-blob', 'new-blob'))
+ self.call('PUT', path=['testdocument', guid, 'blob'], content='old-blob')
+
+ self.assertEqual(
+ 'new-blob',
+ self.call('GET', path=['testdocument', guid, 'blob'])['blob'])
+ self.assertEqual(
+ '1',
+ self.call('GET', path=['testdocument', guid, 'prop1']))
+ self.assertEqual(
+ -1,
+ self.call('GET', path=['testdocument', guid, 'prop2']))
+ self.assertEqual(
+ {'prop1': '1', 'prop2': -1},
+ self.call('GET', path=['testdocument', guid], reply=['prop1', 'prop2']))
+
+ def test_properties_OverrideSet(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='1')
+ def prop(self, value):
+ return value
+
+ @prop.setter
+ def prop(self, value):
+ return '_%s' % value
+
+ @db.blob_property()
+ def blob1(self, meta):
+ return meta
+
+ @blob1.setter
+ def blob1(self, value):
+ return Blob({'url': file(value['blob']).read()})
+
+ @db.blob_property()
+ def blob2(self, meta):
+ return meta
+
+ @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
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ guid = self.call('POST', path=['testdocument'], content={})
+
+ self.assertEqual('_1', self.call('GET', path=['testdocument', guid, 'prop']))
+ self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob1'])
+
+ 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'])
+
+ 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'])
+
+ self.call('PUT', path=['testdocument', guid, 'blob1'], content='blob_url')
+ self.assertEqual('blob_url', self.call('GET', path=['testdocument', guid, 'blob1'])['url'])
+
+ guid = self.call('POST', path=['testdocument'], content={'blob2': 'foo'})
+ self.assertEqual(' foo ', file(self.call('GET', path=['testdocument', guid, 'blob2'])['blob']).read())
+
+ self.call('PUT', path=['testdocument', guid, 'blob2'], content='bar')
+ self.assertEqual(' bar ', file(self.call('GET', path=['testdocument', guid, 'blob2'])['blob']).read())
+
+ def test_properties_CallSettersAtTheEnd(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, typecast=int)
+ def prop1(self, value):
+ return value
+
+ @prop1.setter
+ def prop1(self, value):
+ return self['prop3'] + value
+
+ @db.indexed_property(slot=2, typecast=int)
+ def prop2(self, value):
+ return value
+
+ @prop2.setter
+ def prop2(self, value):
+ return self['prop3'] - value
+
+ @db.indexed_property(slot=3, typecast=int)
+ 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']))
+
+ def test_properties_PopulateRequiredPropsInSetters(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, typecast=int)
+ def prop1(self, value):
+ return value
+
+ @prop1.setter
+ def prop1(self, value):
+ self['prop2'] = value + 1
+ return value
+
+ @db.indexed_property(slot=2, typecast=int)
+ 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 + '!')
+
+ 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())
+
+ def test_Group(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1)
+ def prop(self, value):
+ return value
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+
+ self.call('POST', path=['testdocument'], content={'prop': 1})
+ self.call('POST', path=['testdocument'], content={'prop': 2})
+ self.call('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']))
+
+ def test_CallSetterEvenIfThereIsNoCreatePermissions(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, acl=ACL.READ, default=0)
+ def prop(self, value):
+ return value
+
+ @prop.setter
+ def prop(self, value):
+ return value + 1
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+
+ self.assertRaises(http.Forbidden, self.call, 'POST', path=['testdocument'], content={'prop': 1})
+
+ guid = self.call('POST', path=['testdocument'], content={})
+ self.assertEqual(1, self.call('GET', path=['testdocument', guid, 'prop']))
+
+ def test_ReturnDefualtsForMissedProps(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='default')
+ 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'})
+
+ self.assertEqual(
+ [{'prop': 'set'}],
+ self.call('GET', path=['testdocument'], reply='prop')['result'])
+ self.assertEqual(
+ {'prop': 'set'},
+ self.call('GET', path=['testdocument', guid], reply='prop'))
+ self.assertEqual(
+ 'set',
+ self.call('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'])
+ self.assertEqual(
+ {'prop': 'default'},
+ self.call('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']))
+
+ def test_prop_meta(self):
+
+ class TestDocument(db.Resource):
+
+ @db.indexed_property(slot=1, default='')
+ def prop(self, value):
+ return value
+
+ @db.blob_property()
+ def blob1(self, value):
+ return value
+
+ @db.blob_property()
+ def blob2(self, value):
+ return value
+
+ @blob2.setter
+ def blob2(self, value):
+ return {'url': 'http://new', 'foo': 'bar', 'blob_size': 100}
+
+ self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None)
+ guid = self.call('POST', ['testdocument'], content = {'prop': 'prop', 'blob1': 'blob', 'blob2': ''})
+
+ assert self.call('HEAD', ['testdocument', guid, 'prop']) is None
+ meta = self.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')
+ meta['url'] = 'http://localhost/testdocument/%s/blob1' % guid
+ 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)
+
+ def test_DefaultAuthor(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])
+
+ guid = self.call('POST', ['document'], content={}, principal='user')
+ self.assertEqual(
+ [{'name': 'user', 'role': 2}],
+ self.call('GET', ['document', guid, 'author']))
+ self.assertEqual(
+ {'user': {'role': 2, 'order': 0}},
+ self.volume['document'].get(guid)['author'])
+
+ self.volume['user'].create({'guid': 'user', 'color': '', 'pubkey': '', 'name': 'User'})
+
+ guid = self.call('POST', ['document'], content={}, principal='user')
+ self.assertEqual(
+ [{'guid': 'user', 'name': 'User', 'role': 3}],
+ self.call('GET', ['document', guid, 'author']))
+ self.assertEqual(
+ {'user': {'name': 'User', 'role': 3, 'order': 0}},
+ self.volume['document'].get(guid)['author'])
+
+ def test_FindByAuthor(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': 'user1', 'color': '', 'pubkey': '', 'name': 'UserName1'})
+ self.volume['user'].create({'guid': 'user2', 'color': '', 'pubkey': '', 'name': 'User Name2'})
+ self.volume['user'].create({'guid': 'user3', 'color': '', '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')
+
+ self.assertEqual(sorted([
+ {'guid': guid1},
+ ]),
+ self.call('GET', ['document'], author='UserName1')['result'])
+
+ self.assertEqual(sorted([
+ {'guid': guid1},
+ ]),
+ sorted(self.call('GET', ['document'], query='author:UserName')['result']))
+ self.assertEqual(sorted([
+ {'guid': guid1},
+ {'guid': guid2},
+ {'guid': guid3},
+ ]),
+ sorted(self.call('GET', ['document'], query='author:User')['result']))
+ self.assertEqual(sorted([
+ {'guid': guid2},
+ {'guid': guid3},
+ ]),
+ sorted(self.call('GET', ['document'], query='author:Name')['result']))
+
+ def test_PreserveAuthorsOrder(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': 'user1', 'color': '', 'pubkey': '', 'name': 'User1'})
+ self.volume['user'].create({'guid': 'user2', 'color': '', 'pubkey': '', 'name': 'User2'})
+ self.volume['user'].create({'guid': 'user3', 'color': '', '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)
+
+ 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']))
+ 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'])
+
+ self.call('PUT', ['document', guid], cmd='userdel', user='user2', principal='user1')
+ self.call('PUT', ['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']))
+ 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'])
+
+ self.call('PUT', ['document', guid], cmd='userdel', user='user2', principal='user1')
+ self.call('PUT', ['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']))
+ 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'])
+
+ self.call('PUT', ['document', guid], cmd='userdel', user='user3', principal='user1')
+ self.call('PUT', ['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']))
+ 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_AddUser(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': 'user1', 'color': '', 'pubkey': '', 'name': 'User1'})
+ self.volume['user'].create({'guid': 'user2', 'color': '', 'pubkey': '', 'name': 'User2'})
+
+ guid = self.call('POST', ['document'], content={}, principal='user1')
+ self.assertEqual([
+ {'guid': 'user1', 'name': 'User1', 'role': 3},
+ ],
+ self.call('GET', ['document', guid, 'author']))
+ self.assertEqual({
+ 'user1': {'name': 'User1', 'role': 3, 'order': 0},
+ },
+ self.volume['document'].get(guid)['author'])
+
+ self.call('PUT', ['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']))
+ self.assertEqual({
+ 'user1': {'name': 'User1', 'role': 3, 'order': 0},
+ 'user2': {'name': 'User2', 'role': 3, 'order': 1},
+ },
+ self.volume['document'].get(guid)['author'])
+
+ self.call('PUT', ['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']))
+ 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'])
+
+ self.call('PUT', ['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']))
+ 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'])
+
+ def test_UpdateAuthor(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': 'user1', 'color': '', 'pubkey': '', 'name': 'User1'})
+ guid = self.call('POST', ['document'], content={}, principal='user1')
+
+ self.call('PUT', ['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']))
+ self.assertEqual({
+ 'user1': {'name': 'User1', 'role': 3, 'order': 0},
+ 'User2': {'role': 0, 'order': 1},
+ },
+ self.volume['document'].get(guid)['author'])
+
+ self.call('PUT', ['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']))
+ self.assertEqual({
+ 'user1': {'name': 'User1', 'role': 1, 'order': 0},
+ 'User2': {'role': 0, 'order': 1},
+ },
+ self.volume['document'].get(guid)['author'])
+
+ self.call('PUT', ['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']))
+ self.assertEqual({
+ 'user1': {'name': 'User1', 'role': 1, 'order': 0},
+ 'User2': {'role': 2, 'order': 1},
+ },
+ self.volume['document'].get(guid)['author'])
+
+ def test_DelUser(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': 'user1', 'color': '', 'pubkey': '', 'name': 'User1'})
+ self.volume['user'].create({'guid': 'user2', 'color': '', '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')
+ self.assertEqual([
+ {'guid': 'user1', 'name': 'User1', 'role': 3},
+ {'guid': 'user2', 'name': 'User2', 'role': 1},
+ {'name': 'User3', 'role': 0},
+ ],
+ self.call('GET', ['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'])
+
+ # 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.call('PUT', ['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']))
+ self.assertEqual({
+ 'user2': {'name': 'User2', 'role': 1, 'order': 1},
+ 'User3': {'role': 0, 'order': 2},
+ },
+ self.volume['document'].get(guid)['author'])
+
+ self.call('PUT', ['document', guid], cmd='userdel', user='User3', principal='user2')
+ self.assertEqual([
+ {'guid': 'user2', 'name': 'User2', 'role': 1},
+ ],
+ self.call('GET', ['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))
+
+ 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:
+ request = Request({
+ 'REQUEST_METHOD': method,
+ 'PATH_INFO': '/'.join([''] + path),
+ 'HTTP_ACCEPT_LANGUAGE': ','.join(accept_language or []),
+ 'HTTP_HOST': host,
+ 'wsgi.input': content_stream,
+ })
+ request.cmd = cmd
+ request.content = content
+ request.content_type = content_type
+ if request.content_stream is not None:
+ request.content_length = len(request.content_stream.getvalue())
+ request.update(kwargs)
+ request.principal = principal
+ router = Router(routes(self.volume))
+ self.response = Response()
+ return router._call(request, self.response)
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/db/storage.py b/tests/units/db/storage.py
index 149ed03..6eb62e5 100755
--- a/tests/units/db/storage.py
+++ b/tests/units/db/storage.py
@@ -11,11 +11,10 @@ from os.path import exists
from __init__ import tests
-from sugar_network.db import env
from sugar_network.db.metadata import Metadata, StoredProperty
from sugar_network.db.metadata import BlobProperty
from sugar_network.db.storage import Storage
-from sugar_network.toolkit import BUFFER_SIZE, util
+from sugar_network.toolkit import BUFFER_SIZE
class StorageTest(tests.Test):
diff --git a/tests/units/db/volume.py b/tests/units/db/volume.py
deleted file mode 100755
index b968069..0000000
--- a/tests/units/db/volume.py
+++ /dev/null
@@ -1,1223 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import os
-import sys
-import time
-import shutil
-import hashlib
-from cStringIO import StringIO
-from email.message import Message
-from email.utils import formatdate
-from os.path import dirname, join, abspath, exists
-
-src_root = abspath(dirname(__file__))
-
-from __init__ import tests
-
-from sugar_network import db, toolkit
-from sugar_network.db import env
-from sugar_network.db.volume import VolumeCommands
-from sugar_network.toolkit import coroutine, http, util
-
-
-class VolumeTest(tests.Test):
-
- def setUp(self):
- tests.Test.setUp(self)
- self.response = db.Response()
-
- def test_PostDefaults(self):
-
- class Document(db.Document):
-
- @db.stored_property(default='default')
- def w_default(self, value):
- return value
-
- @db.stored_property()
- def wo_default(self, value):
- return value
-
- @db.indexed_property(slot=1, default='not_stored_default')
- def not_stored_default(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [Document])
-
- self.assertRaises(RuntimeError, self.call, 'POST', document='document', content={})
-
- guid = self.call('POST', document='document', content={'wo_default': 'wo_default'})
- self.assertEqual('default', self.call('GET', document='document', guid=guid, prop='w_default'))
- self.assertEqual('wo_default', self.call('GET', document='document', guid=guid, prop='wo_default'))
- self.assertEqual('not_stored_default', self.call('GET', document='document', guid=guid, prop='not_stored_default'))
-
- def test_Populate(self):
- self.touch(
- ('document/1/1/guid', '{"value": "1"}'),
- ('document/1/1/ctime', '{"value": 1}'),
- ('document/1/1/mtime', '{"value": 1}'),
- ('document/1/1/seqno', '{"value": 0}'),
-
- ('document/2/2/guid', '{"value": "2"}'),
- ('document/2/2/ctime', '{"value": 2}'),
- ('document/2/2/mtime', '{"value": 2}'),
- ('document/2/2/seqno', '{"value": 0}'),
- )
-
- class Document(db.Document):
- pass
-
- with db.Volume(tests.tmpdir, [Document]) as volume:
- for cls in volume.values():
- for __ in cls.populate():
- pass
- self.assertEqual(
- sorted(['1', '2']),
- sorted([i.guid for i in volume['document'].find()[0]]))
-
- shutil.rmtree('document/index')
-
- class Document(db.Document):
- pass
-
- with db.Volume(tests.tmpdir, [Document]) as volume:
- for cls in volume.values():
- for __ in cls.populate():
- pass
- self.assertEqual(
- sorted(['1', '2']),
- sorted([i.guid for i in volume['document'].find()[0]]))
-
- def test_Commands(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- self.volume['testdocument'].create({'guid': 'guid'})
-
- self.assertEqual({
- 'total': 1,
- 'result': [
- {'guid': 'guid', 'prop': ''},
- ],
- },
- self.call('GET', document='testdocument', reply=['guid', 'prop']))
-
- guid_1 = self.call('POST', document='testdocument', content={'prop': 'value_1'})
- assert guid_1
- guid_2 = self.call('POST', document='testdocument', content={'prop': 'value_2'})
- assert guid_2
-
- self.assertEqual(
- sorted([
- {'guid': 'guid', 'prop': ''},
- {'guid': guid_1, 'prop': 'value_1'},
- {'guid': guid_2, 'prop': 'value_2'},
- ]),
- sorted(self.call('GET', document='testdocument', reply=['guid', 'prop'])['result']))
-
- self.call('PUT', document='testdocument', guid=guid_1, content={'prop': 'value_3'})
-
- self.assertEqual(
- sorted([
- {'guid': 'guid', 'prop': ''},
- {'guid': guid_1, 'prop': 'value_3'},
- {'guid': guid_2, 'prop': 'value_2'},
- ]),
- sorted(self.call('GET', document='testdocument', reply=['guid', 'prop'])['result']))
-
- self.call('DELETE', document='testdocument', guid=guid_2)
-
- self.assertEqual(
- sorted([
- {'guid': 'guid', 'prop': ''},
- {'guid': guid_1, 'prop': 'value_3'},
- ]),
- sorted(self.call('GET', document='testdocument', reply=['guid', 'prop'])['result']))
-
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid_2)
-
- self.assertEqual(
- {'guid': guid_1, 'prop': 'value_3'},
- self.call('GET', document='testdocument', guid=guid_1, reply=['guid', 'prop']))
-
- self.assertEqual(
- 'value_3',
- self.call('GET', document='testdocument', guid=guid_1, prop='prop'))
-
- def test_SetBLOBs(self):
-
- class TestDocument(db.Document):
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content='blob1')
- self.assertEqual('blob1', file(self.call('GET', document='testdocument', guid=guid, prop='blob')['blob']).read())
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content_stream=StringIO('blob2'))
- self.assertEqual('blob2', file(self.call('GET', document='testdocument', guid=guid, prop='blob')['blob']).read())
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content=None)
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid, prop='blob')
-
- def test_SetBLOBsByMeta(self):
-
- class TestDocument(db.Document):
-
- @db.blob_property(mime_type='default')
- def blob(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
-
- self.assertRaises(RuntimeError, self.call, 'PUT', document='testdocument', guid=guid, prop='blob',
- content={}, content_type='application/json')
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid, prop='blob')
-
- self.touch('file')
- self.assertRaises(RuntimeError, self.call, 'PUT', document='testdocument', guid=guid, prop='blob',
- content={'blob': 'file'}, content_type='application/json')
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid, prop='blob')
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob',
- content={'url': 'foo', 'bar': 'probe'}, content_type='application/json')
- blob = self.call('GET', document='testdocument', guid=guid, prop='blob')
- self.assertEqual('foo', blob['url'])
- assert 'bar' not in blob
-
- def test_RemoveBLOBs(self):
-
- class TestDocument(db.Document):
-
- @db.blob_property(mime_type='default')
- def blob(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={'blob': 'blob'})
-
- self.assertEqual('blob', file(self.call('GET', document='testdocument', guid=guid, prop='blob')['blob']).read())
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob')
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid, prop='blob')
-
- def test_RemoveTempBLOBFilesOnFails(self):
-
- class TestDocument(db.Document):
-
- @db.blob_property(mime_type='default')
- def blob(self, value):
- return value
-
- @blob.setter
- def blob(self, value):
- raise RuntimeError()
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
-
- self.assertRaises(RuntimeError, self.call, 'PUT', document='testdocument', guid=guid, prop='blob', content='probe')
- self.assertEqual(0, len(os.listdir('tmp')))
-
- def test_SetBLOBsWithMimeType(self):
-
- class TestDocument(db.Document):
-
- @db.blob_property(mime_type='default')
- def blob(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content='blob1')
- self.assertEqual('default', self.call('GET', document='testdocument', guid=guid, prop='blob')['mime_type'])
- self.assertEqual('default', self.response.content_type)
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content='blob1', content_type='foo')
- self.assertEqual('foo', self.call('GET', document='testdocument', guid=guid, prop='blob')['mime_type'])
- self.assertEqual('foo', self.response.content_type)
-
- def test_GetBLOBs(self):
-
- class TestDocument(db.Document):
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content='blob')
-
- blob_path = tests.tmpdir + '/testdocument/%s/%s/blob' % (guid[:2], guid)
- blob_meta = {
- 'seqno': 2,
- 'blob': blob_path + '.blob',
- 'blob_size': 4,
- 'digest': hashlib.sha1('blob').hexdigest(),
- 'mime_type': 'application/octet-stream',
- 'mtime': int(os.stat(blob_path).st_mtime),
- }
-
- self.assertEqual('blob', file(self.call('GET', document='testdocument', guid=guid, prop='blob')['blob']).read())
-
- self.assertEqual(
- {'guid': guid, 'blob': blob_meta},
- self.call('GET', document='testdocument', guid=guid, reply=['guid', 'blob']))
-
- self.assertEqual([
- {'guid': guid, 'blob': blob_meta},
- ],
- self.call('GET', document='testdocument', reply=['guid', 'blob'])['result'])
-
- def test_GetBLOBsByUrls(self):
-
- class TestDocument(db.Document):
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
-
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid, prop='blob')
- self.assertEqual(
- {'blob': 'http://127.0.0.1/testdocument/%s/blob' % guid},
- self.call('GET', document='testdocument', guid=guid, reply=['blob'], static_prefix='http://127.0.0.1'))
- self.assertEqual([
- {'blob': 'http://127.0.0.1/testdocument/%s/blob' % guid},
- ],
- self.call('GET', document='testdocument', reply=['blob'], static_prefix='http://127.0.0.1')['result'])
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content='file')
- self.assertEqual('file', file(self.call('GET', document='testdocument', guid=guid, prop='blob')['blob']).read())
- self.assertEqual(
- {'blob': 'http://127.0.0.1/testdocument/%s/blob' % guid},
- self.call('GET', document='testdocument', guid=guid, reply=['blob'], static_prefix='http://127.0.0.1'))
- self.assertEqual([
- {'blob': 'http://127.0.0.1/testdocument/%s/blob' % guid},
- ],
- self.call('GET', document='testdocument', reply=['blob'], static_prefix='http://127.0.0.1')['result'])
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content={'url': 'http://foo'},
- content_type='application/json')
- self.assertEqual('http://foo', self.call('GET', document='testdocument', guid=guid, prop='blob')['url'])
- self.assertEqual(
- {'blob': 'http://foo'},
- self.call('GET', document='testdocument', guid=guid, reply=['blob'], static_prefix='http://127.0.0.1'))
- self.assertEqual([
- {'blob': 'http://foo'},
- ],
- self.call('GET', document='testdocument', reply=['blob'], static_prefix='http://127.0.0.1')['result'])
-
- def test_CommandsGetAbsentBlobs(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
-
- guid = self.call('POST', document='testdocument', content={'prop': 'value'})
- self.assertEqual('value', self.call('GET', document='testdocument', guid=guid, prop='prop'))
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid, prop='blob')
- self.assertEqual(
- {'blob': db.PropertyMetadata()},
- self.call('GET', document='testdocument', guid=guid, reply=['blob']))
-
- def test_Command_ReplyForGET(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={'prop': 'value'})
-
- self.assertEqual(
- ['guid', 'prop'],
- self.call('GET', document='testdocument', guid=guid, reply=['guid', 'prop']).keys())
-
- self.assertEqual(
- ['guid'],
- self.call('GET', document='testdocument')['result'][0].keys())
-
- self.assertEqual(
- sorted(['guid', 'prop']),
- sorted(self.call('GET', document='testdocument', reply=['prop', 'guid'])['result'][0].keys()))
-
- self.assertEqual(
- sorted(['prop']),
- sorted(self.call('GET', document='testdocument', reply=['prop'])['result'][0].keys()))
-
- def test_DecodeBeforeSetting(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, typecast=int)
- def prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
-
- guid = self.call(method='POST', document='testdocument', content={'prop': '-1'})
- self.assertEqual(-1, self.call(method='GET', document='testdocument', guid=guid, prop='prop'))
-
- def test_LocalizedSet(self):
- toolkit._default_lang = 'en'
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- 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(0, 100, 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(0, 100, localized_prop='value_raw2')[0]])
-
- guid = self.call('POST', document='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(0, 100, localized_prop='value_ru')[0]])
-
- self.call('PUT', document='testdocument', guid=guid, accept_language=['en'], content={'localized_prop': 'value_en'})
- self.assertEqual({'ru': 'value_ru', 'en': 'value_en'}, directory.get(guid)['localized_prop'])
- self.assertEqual(
- [guid],
- [i.guid for i in directory.find(0, 100, localized_prop='value_ru')[0]])
- self.assertEqual(
- [guid],
- [i.guid for i in directory.find(0, 100, localized_prop='value_en')[0]])
-
- def test_LocalizedGet(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- directory = self.volume['testdocument']
-
- guid = self.call('POST', document='testdocument', content={
- 'localized_prop': {
- 'ru': 'value_ru',
- 'es': 'value_es',
- 'en': 'value_en',
- },
- })
-
- toolkit._default_lang = 'en'
-
- self.assertEqual(
- {'localized_prop': 'value_en'},
- self.call('GET', document='testdocument', guid=guid, reply=['localized_prop']))
- self.assertEqual(
- {'localized_prop': 'value_ru'},
- self.call('GET', document='testdocument', guid=guid, accept_language=['ru'], reply=['localized_prop']))
- self.assertEqual(
- 'value_ru',
- self.call('GET', document='testdocument', guid=guid, accept_language=['ru', 'es'], prop='localized_prop'))
- self.assertEqual(
- [{'localized_prop': 'value_ru'}],
- self.call('GET', document='testdocument', accept_language=['foo', 'ru', 'es'], reply=['localized_prop'])['result'])
-
- self.assertEqual(
- {'localized_prop': 'value_ru'},
- self.call('GET', document='testdocument', guid=guid, accept_language=['ru-RU'], reply=['localized_prop']))
- self.assertEqual(
- 'value_ru',
- self.call('GET', document='testdocument', guid=guid, accept_language=['ru-RU', 'es'], prop='localized_prop'))
- self.assertEqual(
- [{'localized_prop': 'value_ru'}],
- self.call('GET', document='testdocument', accept_language=['foo', 'ru-RU', 'es'], reply=['localized_prop'])['result'])
-
- self.assertEqual(
- {'localized_prop': 'value_es'},
- self.call('GET', document='testdocument', guid=guid, accept_language=['es'], reply=['localized_prop']))
- self.assertEqual(
- 'value_es',
- self.call('GET', document='testdocument', guid=guid, accept_language=['es', 'ru'], prop='localized_prop'))
- self.assertEqual(
- [{'localized_prop': 'value_es'}],
- self.call('GET', document='testdocument', accept_language=['foo', 'es', 'ru'], reply=['localized_prop'])['result'])
-
- self.assertEqual(
- {'localized_prop': 'value_en'},
- self.call('GET', document='testdocument', guid=guid, accept_language=['fr'], reply=['localized_prop']))
- self.assertEqual(
- 'value_en',
- self.call('GET', document='testdocument', guid=guid, accept_language=['fr', 'za'], prop='localized_prop'))
- self.assertEqual(
- [{'localized_prop': 'value_en'}],
- self.call('GET', document='testdocument', accept_language=['foo', 'fr', 'za'], reply=['localized_prop'])['result'])
-
- toolkit._default_lang = 'foo'
- fallback_lang = sorted(['ru', 'es', 'en'])[0]
-
- self.assertEqual(
- {'localized_prop': 'value_%s' % fallback_lang},
- self.call('GET', document='testdocument', guid=guid, accept_language=['fr'], reply=['localized_prop']))
- self.assertEqual(
- 'value_%s' % fallback_lang,
- self.call('GET', document='testdocument', guid=guid, accept_language=['fr', 'za'], prop='localized_prop'))
- self.assertEqual(
- [{'localized_prop': 'value_%s' % fallback_lang}],
- self.call('GET', document='testdocument', accept_language=['foo', 'fr', 'za'], reply=['localized_prop'])['result'])
-
- def test_OpenByModuleName(self):
- self.touch(
- ('foo/bar.py', [
- 'from sugar_network import db',
- 'class Bar(db.Document): pass',
- ]),
- ('foo/__init__.py', ''),
- )
- sys.path.insert(0, '.')
-
- volume = db.Volume('.', ['foo.bar'])
- assert exists('bar/index')
- volume['bar'].find()
- volume.close()
-
- def test_Command_GetBlobSetByUrl(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
- self.call('PUT', document='testdocument', guid=guid, prop='blob', url='http://sugarlabs.org')
-
- self.assertEqual(
- 'http://sugarlabs.org',
- self.call('GET', document='testdocument', guid=guid, prop='blob')['url'])
-
- def test_on_create(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
-
- ts = int(time.time())
- guid = self.call(method='POST', document='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)
-
- def test_on_create_Override(self):
-
- class Commands(VolumeCommands):
-
- def on_create(self, request, props, event):
- props['prop'] = 'overriden'
- VolumeCommands.on_create(self, request, props, event)
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- volume = db.Volume(tests.tmpdir, [TestDocument])
- cp = Commands(volume)
-
- request = db.Request(method='POST', document='testdocument')
- request.content = {'prop': 'foo'}
- guid = cp.call(request, db.Response())
- self.assertEqual('overriden', volume['testdocument'].get(guid)['prop'])
-
- request = db.Request(method='PUT', document='testdocument', guid=guid)
- request.content = {'prop': 'bar'}
- cp.call(request, db.Response())
- self.assertEqual('bar', volume['testdocument'].get(guid)['prop'])
-
- def test_on_update(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call(method='POST', document='testdocument', content={})
- prev_mtime = self.volume['testdocument'].get(guid)['mtime']
-
- time.sleep(1)
-
- self.call(method='PUT', document='testdocument', guid=guid, content={'prop': 'probe'})
- assert self.volume['testdocument'].get(guid)['mtime'] - prev_mtime >= 1
-
- def test_on_update_Override(self):
-
- class Commands(VolumeCommands):
-
- def on_update(self, request, props, event):
- props['prop'] = 'overriden'
- VolumeCommands.on_update(self, request, props, event)
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- volume = db.Volume(tests.tmpdir, [TestDocument])
- cp = Commands(volume)
-
- request = db.Request(method='POST', document='testdocument')
- request.content = {'prop': 'foo'}
- guid = cp.call(request, db.Response())
- self.assertEqual('foo', volume['testdocument'].get(guid)['prop'])
-
- request = db.Request(method='PUT', document='testdocument', guid=guid)
- request.content = {'prop': 'bar'}
- cp.call(request, db.Response())
- self.assertEqual('overriden', volume['testdocument'].get(guid)['prop'])
-
- def __test_DoNotPassGuidsForCreate(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.indexed_property(prefix='L', localized=True, default='')
- def localized_prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- self.assertRaises(http.Forbidden, self.call, method='POST', document='testdocument', content={'guid': 'foo'})
- guid = self.call(method='POST', document='testdocument', content={})
- assert guid
-
- def test_seqno(self):
-
- class Document1(db.Document):
- pass
-
- class Document2(db.Document):
- pass
-
- volume = db.Volume(tests.tmpdir, [Document1, Document2])
-
- assert not exists('seqno')
- self.assertEqual(0, volume.seqno.value)
-
- volume['document1'].create({'guid': '1'})
- self.assertEqual(1, volume['document1'].get('1')['seqno'])
- volume['document2'].create({'guid': '1'})
- self.assertEqual(2, volume['document2'].get('1')['seqno'])
- volume['document1'].create({'guid': '2'})
- self.assertEqual(3, volume['document1'].get('2')['seqno'])
- volume['document2'].create({'guid': '2'})
- self.assertEqual(4, volume['document2'].get('2')['seqno'])
-
- self.assertEqual(4, volume.seqno.value)
- assert not exists('seqno')
- volume.seqno.commit()
- assert exists('seqno')
- volume = db.Volume(tests.tmpdir, [Document1, Document2])
- self.assertEqual(4, volume.seqno.value)
-
- def test_Events(self):
- env.index_flush_threshold.value = 0
- env.index_flush_timeout.value = 0
-
- class Document1(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- pass
-
- class Document2(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- pass
-
- @db.blob_property()
- def blob(self, value):
- return value
-
- self.touch(
- ('document1/1/1/guid', '{"value": "1"}'),
- ('document1/1/1/ctime', '{"value": 1}'),
- ('document1/1/1/mtime', '{"value": 1}'),
- ('document1/1/1/prop', '{"value": ""}'),
- ('document1/1/1/seqno', '{"value": 0}'),
- )
-
- events = []
- volume = db.Volume(tests.tmpdir, [Document1, Document2])
- volume.connect(lambda event: events.append(event))
-
- volume.populate()
- mtime = int(os.stat('document1/index/mtime').st_mtime)
- self.assertEqual([
- {'event': 'commit', 'document': 'document1', 'mtime': mtime},
- {'event': 'populate', 'document': 'document1', 'mtime': mtime},
- ],
- events)
- del events[:]
-
- volume['document1'].create({'guid': 'guid1'})
- volume['document2'].create({'guid': 'guid2'})
- self.assertEqual([
- {'event': 'create', 'document': 'document1', 'guid': 'guid1'},
- {'event': 'create', 'document': 'document2', 'guid': 'guid2'},
- ],
- events)
- del events[:]
-
- volume['document1'].update('guid1', {'prop': 'foo'})
- volume['document2'].update('guid2', {'prop': 'bar'})
- self.assertEqual([
- {'event': 'update', 'document': 'document1', 'guid': 'guid1'},
- {'event': 'update', 'document': 'document2', 'guid': 'guid2'},
- ],
- events)
- del events[:]
-
- volume['document1'].delete('guid1')
- self.assertEqual([
- {'event': 'delete', 'document': 'document1', 'guid': 'guid1'},
- ],
- events)
- del events[:]
-
- volume['document1'].commit()
- mtime1 = int(os.stat('document1/index/mtime').st_mtime)
- volume['document2'].commit()
- mtime2 = int(os.stat('document2/index/mtime').st_mtime)
-
- self.assertEqual([
- {'event': 'commit', 'document': 'document1', 'mtime': mtime1},
- {'event': 'commit', 'document': 'document2', 'mtime': mtime2},
- ],
- events)
-
- def test_PermissionsNoWrite(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='', permissions=db.ACCESS_READ)
- def prop(self, value):
- pass
-
- @db.blob_property(permissions=db.ACCESS_READ)
- def blob(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
-
- self.assertRaises(http.Forbidden, self.call, 'POST', document='testdocument', content={'prop': 'value'})
- self.assertRaises(http.Forbidden, self.call, 'PUT', document='testdocument', guid=guid, content={'prop': 'value'})
- self.assertRaises(http.Forbidden, self.call, 'PUT', document='testdocument', guid=guid, content={'blob': 'value'})
- self.assertRaises(http.Forbidden, self.call, 'PUT', document='testdocument', guid=guid, prop='prop', content='value')
- self.assertRaises(http.Forbidden, self.call, 'PUT', document='testdocument', guid=guid, prop='blob', content='value')
-
- def test_BlobsWritePermissions(self):
-
- class TestDocument(db.Document):
-
- @db.blob_property(permissions=db.ACCESS_CREATE | db.ACCESS_WRITE)
- def blob1(self, value):
- return value
-
- @db.blob_property(permissions=db.ACCESS_CREATE)
- def blob2(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
-
- guid = self.call('POST', document='testdocument', content={})
- self.call('PUT', document='testdocument', guid=guid, content={'blob1': 'value1', 'blob2': 'value2'})
- self.call('PUT', document='testdocument', guid=guid, content={'blob1': 'value1'})
- self.assertRaises(http.Forbidden, self.call, 'PUT', document='testdocument', guid=guid, content={'blob2': 'value2_'})
-
- guid = self.call('POST', document='testdocument', content={})
- self.call('PUT', document='testdocument', guid=guid, prop='blob1', content='value1')
- self.call('PUT', document='testdocument', guid=guid, prop='blob2', content='value2')
- self.call('PUT', document='testdocument', guid=guid, prop='blob1', content='value1_')
- self.assertRaises(http.Forbidden, self.call, 'PUT', document='testdocument', guid=guid, prop='blob2', content='value2_')
-
- def test_properties_OverrideGet(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='1')
- def prop1(self, value):
- return value
-
- @db.indexed_property(slot=2, default='2')
- def prop2(self, value):
- return -1
-
- @db.blob_property()
- def blob(self, meta):
- meta['blob'] = 'new-blob'
- return meta
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
- self.touch(('new-blob', 'new-blob'))
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content='old-blob')
-
- self.assertEqual(
- 'new-blob',
- self.call('GET', document='testdocument', guid=guid, prop='blob')['blob'])
- self.assertEqual(
- '1',
- self.call('GET', document='testdocument', guid=guid, prop='prop1'))
- self.assertEqual(
- -1,
- self.call('GET', document='testdocument', guid=guid, prop='prop2'))
- self.assertEqual(
- {'prop1': '1', 'prop2': -1},
- self.call('GET', document='testdocument', guid=guid, reply=['prop1', 'prop2']))
-
- def test_properties_OverrideSet(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='1')
- def prop(self, value):
- return value
-
- @prop.setter
- def prop(self, value):
- return '_%s' % value
-
- @db.blob_property()
- def blob1(self, meta):
- return meta
-
- @blob1.setter
- def blob1(self, value):
- return db.PropertyMetadata(url=file(value['blob']).read())
-
- @db.blob_property()
- def blob2(self, meta):
- return meta
-
- @blob2.setter
- def blob2(self, value):
- with util.NamedTemporaryFile(delete=False) as f:
- f.write(' %s ' % file(value['blob']).read())
- value['blob'] = f.name
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={})
-
- self.assertEqual('_1', self.call('GET', document='testdocument', guid=guid, prop='prop'))
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid, prop='blob1')
-
- self.call('PUT', document='testdocument', guid=guid, prop='prop', content='2')
- self.assertEqual('_2', self.call('GET', document='testdocument', guid=guid, prop='prop'))
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid, prop='blob1')
-
- self.call('PUT', document='testdocument', guid=guid, content={'prop': 3})
- self.assertEqual('_3', self.call('GET', document='testdocument', guid=guid, prop='prop'))
- self.assertRaises(http.NotFound, self.call, 'GET', document='testdocument', guid=guid, prop='blob1')
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob1', content='blob_url')
- self.assertEqual('blob_url', self.call('GET', document='testdocument', guid=guid, prop='blob1')['url'])
-
- guid = self.call('POST', document='testdocument', content={'blob2': 'foo'})
- self.assertEqual(' foo ', file(self.call('GET', document='testdocument', guid=guid, prop='blob2')['blob']).read())
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob2', content='bar')
- self.assertEqual(' bar ', file(self.call('GET', document='testdocument', guid=guid, prop='blob2')['blob']).read())
-
- def test_properties_CallSettersAtTheEnd(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, typecast=int)
- def prop1(self, value):
- return value
-
- @prop1.setter
- def prop1(self, value):
- return self['prop3'] + value
-
- @db.indexed_property(slot=2, typecast=int)
- def prop2(self, value):
- return value
-
- @prop2.setter
- def prop2(self, value):
- return self['prop3'] - value
-
- @db.indexed_property(slot=3, typecast=int)
- def prop3(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={'prop1': 1, 'prop2': 2, 'prop3': 3})
- self.assertEqual(4, self.call('GET', document='testdocument', guid=guid, prop='prop1'))
- self.assertEqual(1, self.call('GET', document='testdocument', guid=guid, prop='prop2'))
-
- def test_properties_PopulateRequiredPropsInSetters(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, typecast=int)
- def prop1(self, value):
- return value
-
- @prop1.setter
- def prop1(self, value):
- self['prop2'] = value + 1
- return value
-
- @db.indexed_property(slot=2, typecast=int)
- 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])
- guid = self.call('POST', document='testdocument', content={'prop1': 1})
- self.assertEqual(1, self.call('GET', document='testdocument', guid=guid, prop='prop1'))
- self.assertEqual(2, self.call('GET', document='testdocument', guid=guid, prop='prop2'))
-
- def test_properties_PopulateRequiredPropsInBlobSetter(self):
-
- class TestDocument(db.Document):
-
- @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])
- guid = self.call('POST', document='testdocument', content={'blob': ''})
- self.assertEqual(1, self.call('GET', document='testdocument', guid=guid, prop='prop1'))
- self.assertEqual(2, self.call('GET', document='testdocument', guid=guid, prop='prop2'))
-
- def test_SubCall(self):
-
- class TestDocument(db.Document):
-
- @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 util.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', document='testdocument', guid=self.guid, prop='blob', content=value + '!')
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
-
- guid = self.call('POST', document='testdocument', content={'blob': '0'})
- coroutine.dispatch()
- self.assertEqual('0!', file(self.call('GET', document='testdocument', guid=guid, prop='blob')['blob']).read())
-
- self.call('PUT', document='testdocument', guid=guid, prop='blob', content='1')
- coroutine.dispatch()
- self.assertEqual('0!1!', file(self.call('GET', document='testdocument', guid=guid, prop='blob')['blob']).read())
-
- def test_Group(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
-
- self.call('POST', document='testdocument', content={'prop': 1})
- self.call('POST', document='testdocument', content={'prop': 2})
- self.call('POST', document='testdocument', content={'prop': 1})
-
- self.assertEqual(
- sorted([{'prop': 1}, {'prop': 2}]),
- sorted(self.call('GET', document='testdocument', reply='prop', group_by='prop')['result']))
-
- def test_CallSetterEvenIfThereIsNoCreatePermissions(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, permissions=db.ACCESS_READ, default=0)
- def prop(self, value):
- return value
-
- @prop.setter
- def prop(self, value):
- return value + 1
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
-
- self.assertRaises(http.Forbidden, self.call, 'POST', document='testdocument', content={'prop': 1})
-
- guid = self.call('POST', document='testdocument', content={})
- self.assertEqual(1, self.call('GET', document='testdocument', guid=guid, prop='prop'))
-
- def test_ReturnDefualtsForMissedProps(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='default')
- def prop(self, value):
- return value
-
- self.volume = db.Volume(tests.tmpdir, [TestDocument])
- guid = self.call('POST', document='testdocument', content={'prop': 'set'})
-
- self.assertEqual(
- [{'prop': 'set'}],
- self.call('GET', document='testdocument', reply='prop')['result'])
- self.assertEqual(
- {'prop': 'set'},
- self.call('GET', document='testdocument', guid=guid, reply='prop'))
- self.assertEqual(
- 'set',
- self.call('GET', document='testdocument', guid=guid, prop='prop'))
-
- os.unlink('testdocument/%s/%s/prop' % (guid[:2], guid))
-
- self.assertEqual(
- [{'prop': 'default'}],
- self.call('GET', document='testdocument', reply='prop')['result'])
- self.assertEqual(
- {'prop': 'default'},
- self.call('GET', document='testdocument', guid=guid, reply='prop'))
- self.assertEqual(
- 'default',
- self.call('GET', document='testdocument', guid=guid, prop='prop'))
-
- def test_PopulateNonDefualtPropsInSetters(self):
-
- class TestDocument(db.Document):
-
- @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])
-
- self.assertRaises(RuntimeError, self.call, 'POST', document='testdocument', content={})
-
- guid = self.call('POST', document='testdocument', content={'prop2': 'value2'})
- self.assertEqual('value2', self.call('GET', document='testdocument', guid=guid, prop='prop1'))
-
- def test_prop_meta(self):
-
- class TestDocument(db.Document):
-
- @db.indexed_property(slot=1, default='')
- def prop(self, value):
- return value
-
- @db.blob_property()
- def blob1(self, value):
- return value
-
- @db.blob_property()
- def blob2(self, value):
- return value
-
- @blob2.setter
- def blob2(self, value):
- return {'url': 'http://new', 'foo': 'bar', 'blob_size': 100}
-
- volume = db.Volume(tests.tmpdir, [TestDocument])
- cp = VolumeCommands(volume)
-
- request = db.Request(method='POST', document='testdocument')
- request.content = {'prop': 'prop', 'blob1': 'blob', 'blob2': ''}
- guid = cp.call(request, db.Response())
-
- request = db.Request(method='HEAD', document='testdocument', guid=guid, prop='prop')
- response = db.Response()
- assert cp.call(request, response) is None
- meta = volume['testdocument'].get(guid).meta('prop')
- meta.pop('value')
- self.assertEqual(meta, response.meta)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified)
-
- request = db.Request(method='HEAD', document='testdocument', guid=guid, prop='blob1')
- request.static_prefix = 'http://localhost'
- request.path = ['path']
- response = db.Response()
- assert cp.call(request, response) is None
- meta = volume['testdocument'].get(guid).meta('blob1')
- meta.pop('blob')
- meta['url'] = 'http://localhost/path'
- self.assertEqual(meta, response.meta)
- self.assertEqual(len('blob'), response.content_length)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified)
-
- request = db.Request(method='HEAD', document='testdocument', guid=guid, prop='blob2')
- response = db.Response()
- assert cp.call(request, response) is None
- meta = volume['testdocument'].get(guid).meta('blob2')
- self.assertEqual(meta, response.meta)
- self.assertEqual(100, response.content_length)
- self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified)
-
- def call(self, method, document=None, guid=None, prop=None,
- accept_language=None, content=None, content_stream=None,
- content_type=None, if_modified_since=None, static_prefix=None,
- **kwargs):
-
- class TestRequest(db.Request):
-
- content_stream = None
- content_length = 0
-
- request = TestRequest(**kwargs)
- request.static_prefix = static_prefix
- request.content = content
- request.content_stream = content_stream
- request.content_type = content_type
- request.accept_language = accept_language
- request.if_modified_since = if_modified_since
- request['method'] = method
- if document:
- request['document'] = document
- if guid:
- request['guid'] = guid
- if prop:
- request['prop'] = prop
- if request.content_stream is not None:
- request.content_length = len(request.content_stream.getvalue())
-
- self.response = db.Response()
- cp = VolumeCommands(self.volume)
- return cp.call(request, self.response)
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/resources/__init__.py b/tests/units/model/__init__.py
index 345c327..345c327 100644
--- a/tests/units/resources/__init__.py
+++ b/tests/units/model/__init__.py
diff --git a/tests/units/resources/__main__.py b/tests/units/model/__main__.py
index 4444f07..6d8e563 100644
--- a/tests/units/resources/__main__.py
+++ b/tests/units/model/__main__.py
@@ -7,7 +7,7 @@ from context import *
from implementation import *
from review import *
from solution import *
-from volume import *
+from routes import *
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/resources/comment.py b/tests/units/model/comment.py
index 9c89517..7cf23b9 100755
--- a/tests/units/resources/comment.py
+++ b/tests/units/model/comment.py
@@ -4,13 +4,13 @@
from __init__ import tests
from sugar_network.client import Client
-from sugar_network.resources.user import User
-from sugar_network.resources.context import Context
-from sugar_network.resources.review import Review
-from sugar_network.resources.feedback import Feedback
-from sugar_network.resources.solution import Solution
-from sugar_network.resources.comment import Comment
-from sugar_network.resources.implementation import Implementation
+from sugar_network.model.user import User
+from sugar_network.model.context import Context
+from sugar_network.model.review import Review
+from sugar_network.model.feedback import Feedback
+from sugar_network.model.solution import Solution
+from sugar_network.model.comment import Comment
+from sugar_network.model.implementation import Implementation
from sugar_network.toolkit import http
diff --git a/tests/units/resources/context.py b/tests/units/model/context.py
index d8c5628..d8c5628 100755
--- a/tests/units/resources/context.py
+++ b/tests/units/model/context.py
diff --git a/tests/units/resources/implementation.py b/tests/units/model/implementation.py
index 176051c..a3afd4b 100755
--- a/tests/units/resources/implementation.py
+++ b/tests/units/model/implementation.py
@@ -8,64 +8,61 @@ import xapian
from __init__ import tests
from sugar_network import db
-from sugar_network.db.router import Router, route
-from sugar_network.resources import implementation
-from sugar_network.resources.volume import Volume
-from sugar_network.resources.implementation import _encode_version, Implementation
-from sugar_network.node.commands import NodeCommands
+from sugar_network.model import implementation
+from sugar_network.model.implementation import _fmt_version, Implementation
from sugar_network.client import IPCClient
from sugar_network.toolkit import http, coroutine
class ImplementationTest(tests.Test):
- def test_encode_version(self):
+ def test_fmt_version(self):
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''5''000')),
- _encode_version('1'))
+ _fmt_version('1'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0002''0000''5''000')),
- _encode_version('1.2'))
+ _fmt_version('1.2'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0020''0300''5''000')),
- _encode_version('1.20.300'))
+ _fmt_version('1.20.300'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0020''0300''5''000')),
- _encode_version('1.20.300.4444'))
+ _fmt_version('1.20.300.4444'))
self.assertEqual(
xapian.sortable_serialise(eval('1''9999''0000''5''000')),
- _encode_version('10001.99999.10000'))
+ _fmt_version('10001.99999.10000'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''3''000')),
- _encode_version('1-pre'))
+ _fmt_version('1-pre'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''4''000')),
- _encode_version('1-rc'))
+ _fmt_version('1-rc'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''5''000')),
- _encode_version('1-'))
+ _fmt_version('1-'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''6''000')),
- _encode_version('1-r'))
+ _fmt_version('1-r'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''3''001')),
- _encode_version('1-pre1'))
+ _fmt_version('1-pre1'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''4''002')),
- _encode_version('1-rc2'))
+ _fmt_version('1-rc2'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''6''003')),
- _encode_version('1-r3'))
+ _fmt_version('1-r3'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''6''000')),
- _encode_version('1-r-2-3'))
+ _fmt_version('1-r-2-3'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''6''001')),
- _encode_version('1-r1.2-3'))
+ _fmt_version('1-r1.2-3'))
def test_WrongAuthor(self):
self.start_online_client()
diff --git a/tests/units/resources/review.py b/tests/units/model/review.py
index c5cd30a..0e50f5a 100755
--- a/tests/units/resources/review.py
+++ b/tests/units/model/review.py
@@ -4,11 +4,11 @@
from __init__ import tests
from sugar_network.client import Client
-from sugar_network.resources.user import User
-from sugar_network.resources.context import Context
-from sugar_network.resources.review import Review
-from sugar_network.resources.artifact import Artifact
-from sugar_network.resources.implementation import Implementation
+from sugar_network.model.user import User
+from sugar_network.model.context import Context
+from sugar_network.model.review import Review
+from sugar_network.model.artifact import Artifact
+from sugar_network.model.implementation import Implementation
class ReviewTest(tests.Test):
diff --git a/tests/units/model/routes.py b/tests/units/model/routes.py
new file mode 100755
index 0000000..dd5bcb3
--- /dev/null
+++ b/tests/units/model/routes.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+# sugar-lint: disable
+
+import os
+import json
+import time
+from email.utils import formatdate
+from os.path import exists
+
+from __init__ import tests, src_root
+
+from sugar_network import db, model
+from sugar_network.model.user import User
+from sugar_network.toolkit.router import Router
+from sugar_network.toolkit import coroutine
+
+
+class RoutesTest(tests.Test):
+
+ def test_StaticFiles(self):
+ router = Router(model.Routes())
+ 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):
+
+ @db.indexed_property(slot=1)
+ def prop(self, value):
+ return value
+
+ routes = model.Routes()
+ volume = db.Volume('db', [Document], routes.broadcast)
+ events = []
+
+ def read_events():
+ for event in routes.subscribe(event='!commit'):
+ if not event.strip():
+ continue
+ assert event.startswith('data: ')
+ assert event.endswith('\n\n')
+ event = json.loads(event[6:])
+ events.append(event)
+
+ job = coroutine.spawn(read_events)
+ coroutine.dispatch()
+ volume['document'].create({'guid': 'guid', 'prop': 'value1'})
+ coroutine.dispatch()
+ volume['document'].update('guid', {'prop': 'value2'})
+ coroutine.dispatch()
+ volume['document'].delete('guid')
+ coroutine.dispatch()
+ volume['document'].commit()
+ coroutine.sleep(.5)
+ job.kill()
+
+ self.assertEqual([
+ {'guid': 'guid', 'resource': 'document', 'event': 'create'},
+ {'guid': 'guid', 'resource': 'document', 'event': 'update'},
+ {'guid': 'guid', 'event': 'delete', 'resource': u'document'},
+ ],
+ events)
+
+ def test_SubscribeWithPong(self):
+ routes = model.Routes()
+ for event in routes.subscribe(ping=True):
+ break
+ self.assertEqual('data: {"event": "pong"}\n\n', event)
+
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/resources/solution.py b/tests/units/model/solution.py
index a56ccfa..dafb5a7 100755
--- a/tests/units/resources/solution.py
+++ b/tests/units/model/solution.py
@@ -4,11 +4,11 @@
from __init__ import tests
from sugar_network.client import Client
-from sugar_network.resources.user import User
-from sugar_network.resources.context import Context
-from sugar_network.resources.feedback import Feedback
-from sugar_network.resources.solution import Solution
-from sugar_network.resources.implementation import Implementation
+from sugar_network.model.user import User
+from sugar_network.model.context import Context
+from sugar_network.model.feedback import Feedback
+from sugar_network.model.solution import Solution
+from sugar_network.model.implementation import Implementation
class SolutionTest(tests.Test):
diff --git a/tests/units/node/__main__.py b/tests/units/node/__main__.py
index 4ab7386..ac37315 100644
--- a/tests/units/node/__main__.py
+++ b/tests/units/node/__main__.py
@@ -2,7 +2,6 @@
from __init__ import tests
-from auth import *
from downloads import *
from files import *
from master import *
diff --git a/tests/units/node/auth.py b/tests/units/node/auth.py
deleted file mode 100755
index f445f3c..0000000
--- a/tests/units/node/auth.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import os
-import json
-
-from __init__ import tests
-
-from sugar_network import db, client
-from sugar_network.node import auth
-from sugar_network.client import IPCClient, Client
-from sugar_network.resources.user import User
-from sugar_network.toolkit import http, enforce
-
-
-class AuthTest(tests.Test):
-
- def test_Config(self):
- self.touch(('authorization.conf', [
- '[user_1]',
- 'role_1 = True',
- '[user_2]',
- 'role_2 = False',
- ]))
-
- request = db.Request()
- request.principal = 'user_1'
- self.assertEqual(True, auth.try_validate(request, 'role_1'))
- auth.validate(request, 'role_1')
-
- request.principal = 'user_2'
- self.assertEqual(False, auth.try_validate(request, 'role_2'))
- self.assertRaises(http.Forbidden, auth.validate, request, 'role_2')
-
- request.principal = 'user_3'
- self.assertEqual(False, auth.try_validate(request, 'role_1'))
- self.assertEqual(False, auth.try_validate(request, 'role_2'))
- self.assertRaises(http.Forbidden, auth.validate, request, 'role_1')
- self.assertRaises(http.Forbidden, auth.validate, request, 'role_2')
-
- def test_FullWriteForRoot(self):
- conn = Client()
-
- self.start_master()
- conn.post(['context'], {
- 'guid': 'guid',
- 'type': 'package',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.assertNotEqual('probe', conn.get(['context', 'guid', 'title']))
- self.stop_nodes()
-
- self.touch((
- 'master/context/gu/guid/author',
- json.dumps({"seqno": 1, "value": {"fake": {"role": 3}}}),
- ))
-
- self.start_master()
- self.assertRaises(http.Forbidden, conn.put, ['context', 'guid'], {'title': 'probe'})
-
- self.touch(('authorization.conf', [
- '[%s]' % tests.UID,
- 'root = True',
- ]))
- auth.reset()
- conn.put(['context', 'guid'], {'title': 'probe'})
- self.assertEqual('probe', conn.get(['context', 'guid', 'title']))
-
- def test_Anonymous(self):
- conn = http.Client(client.api_url.value)
-
- props = {'guid': 'guid',
- 'type': 'package',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- }
- self.start_master()
-
- self.assertRaises(RuntimeError, conn.post, ['context'], props)
-
- self.touch(('authorization.conf', [
- '[anonymous]',
- 'user = True',
- ]))
- auth.reset()
- conn.post(['context'], props)
- self.assertEqual('title', conn.get(['context', 'guid', 'title']))
- self.assertEqual([], conn.get(['context', 'guid', 'author']))
-
- self.stop_nodes()
- self.touch((
- 'master/context/gu/guid/author',
- json.dumps({"seqno": 1, "value": {"fake": {"role": 3}}}),
- ))
- self.start_master()
-
- auth.reset()
- self.assertRaises(http.Forbidden, conn.put, ['context', 'guid'], {'title': 'probe'})
-
- self.touch(('authorization.conf', [
- '[anonymous]',
- 'user = True',
- 'root = True',
- ]))
- auth.reset()
- conn.put(['context', 'guid'], {'title': 'probe'})
- self.assertEqual('probe', conn.get(['context', 'guid', 'title']))
- self.assertEqual([{'name': 'fake', 'role': 3}], conn.get(['context', 'guid', 'author']))
-
- def test_LiveUpdate(self):
- conn = http.Client(client.api_url.value)
-
- props = {'guid': 'guid',
- 'type': 'package',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- }
- self.start_master()
-
- self.touch(('authorization.conf', ''))
- os.utime('authorization.conf', (1, 1))
- self.assertRaises(RuntimeError, conn.post, ['context'], props)
-
- self.touch(('authorization.conf', [
- '[anonymous]',
- 'user = True',
- ]))
- os.utime('authorization.conf', (2, 2))
- conn.post(['context'], props)
- self.assertEqual([], conn.get(['context', 'guid', 'author']))
-
- self.touch(('authorization.conf', ''))
- os.utime('authorization.conf', (3, 3))
- self.assertRaises(RuntimeError, conn.post, ['context'], props)
-
- def test_DefaultAuthorization(self):
-
- class Document(db.Document):
-
- @db.document_command(method='GET', cmd='probe1',
- mime_type='application/json')
- def probe1(cls, directory):
- return 'ok1'
-
- @db.document_command(method='GET', cmd='probe2',
- permissions=db.ACCESS_AUTH, mime_type='application/json')
- def probe2(cls, directory):
- return 'ok2'
-
- self.start_master([User, Document])
- conn = Client()
-
- guid = conn.post(['document'], {})
- self.assertEqual('ok1', conn.get(['document', guid], cmd='probe1'))
- self.assertEqual('ok2', conn.get(['document', guid], cmd='probe2'))
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/node/files.py b/tests/units/node/files.py
index 2676aa9..111b7a8 100755
--- a/tests/units/node/files.py
+++ b/tests/units/node/files.py
@@ -11,7 +11,6 @@ from cStringIO import StringIO
from __init__ import tests
from sugar_network import db, toolkit
-from sugar_network.toolkit import util
from sugar_network.node import files
@@ -27,14 +26,14 @@ class FilesTest(tests.Test):
return str(self.uuid)
def test_Index_Populate(self):
- seqno = util.Seqno('seqno')
+ seqno = toolkit.Seqno('seqno')
seeder = files.Index('files', 'index', seqno)
os.utime('files', (1, 1))
assert seeder.sync()
assert not seeder.sync()
- in_seq = util.Sequence([[1, None]])
+ in_seq = toolkit.Sequence([[1, None]])
self.assertEqual(
[{'op': 'commit', 'sequence': []}],
[i for i in seeder.diff(in_seq)])
@@ -48,7 +47,7 @@ class FilesTest(tests.Test):
os.utime('files', (1, 1))
assert not seeder.sync()
- in_seq = util.Sequence([[1, None]])
+ in_seq = toolkit.Sequence([[1, None]])
self.assertEqual(
[{'op': 'commit', 'sequence': []}],
[i for i in seeder.diff(in_seq)])
@@ -59,7 +58,7 @@ class FilesTest(tests.Test):
os.utime('files', (2, 2))
assert seeder.sync()
- in_seq = util.Sequence([[1, None]])
+ in_seq = toolkit.Sequence([[1, None]])
self.assertEqual(sorted([
{'op': 'commit', 'sequence': [[1, 3]]},
{'op': 'update', 'blob_size': 1, 'blob': '1', 'path': '1'},
@@ -79,14 +78,14 @@ class FilesTest(tests.Test):
json.load(file('index')))
assert not seeder.sync()
- in_seq = util.Sequence([[4, None]])
+ in_seq = toolkit.Sequence([[4, None]])
self.assertEqual(
[{'op': 'commit', 'sequence': []}],
[i for i in seeder.diff(in_seq)])
self.assertEqual(3, seqno.value)
def test_Index_SelectiveDiff(self):
- seqno = util.Seqno('seqno')
+ seqno = toolkit.Seqno('seqno')
seeder = files.Index('files', 'index', seqno)
self.touch(('files/1', '1'))
@@ -96,7 +95,7 @@ class FilesTest(tests.Test):
self.touch(('files/5', '5'))
self.utime('files', 1)
- in_seq = util.Sequence([[2, 2], [4, 10], [20, None]])
+ in_seq = toolkit.Sequence([[2, 2], [4, 10], [20, None]])
self.assertEqual(sorted([
{'op': 'commit', 'sequence': [[2, 5]]},
{'op': 'update', 'blob_size': 1, 'blob': '2', 'path': '2'},
@@ -106,7 +105,7 @@ class FilesTest(tests.Test):
sorted(files_diff(seeder, in_seq)))
def test_Index_PartialDiff(self):
- seqno = util.Seqno('seqno')
+ seqno = toolkit.Seqno('seqno')
seeder = files.Index('files', 'index', seqno)
self.touch(('files/1', '1'))
@@ -114,7 +113,7 @@ class FilesTest(tests.Test):
self.touch(('files/3', '3'))
self.utime('files', 1)
- in_seq = util.Sequence([[1, None]])
+ in_seq = toolkit.Sequence([[1, None]])
diff = seeder.diff(in_seq)
record = next(diff)
record['blob'] = ''.join([i for i in record['blob']])
@@ -133,7 +132,7 @@ class FilesTest(tests.Test):
self.assertRaises(StopIteration, diff.next)
def test_Index_diff_Stretch(self):
- seqno = util.Seqno('seqno')
+ seqno = toolkit.Seqno('seqno')
seeder = files.Index('files', 'index', seqno)
self.touch(('files/1', '1'))
@@ -141,7 +140,7 @@ class FilesTest(tests.Test):
self.touch(('files/3', '3'))
self.utime('files', 1)
- in_seq = util.Sequence([[1, 1], [3, None]])
+ in_seq = toolkit.Sequence([[1, 1], [3, None]])
diff = seeder.diff(in_seq)
record = next(diff)
record['blob'] = ''.join([i for i in record['blob']])
@@ -153,7 +152,7 @@ class FilesTest(tests.Test):
self.assertRaises(StopIteration, diff.next)
def test_Index_diff_DoNotStretchContinuesPacket(self):
- seqno = util.Seqno('seqno')
+ seqno = toolkit.Seqno('seqno')
seeder = files.Index('files', 'index', seqno)
self.touch(('files/1', '1'))
@@ -161,8 +160,8 @@ class FilesTest(tests.Test):
self.touch(('files/3', '3'))
self.utime('files', 1)
- in_seq = util.Sequence([[1, 1], [3, None]])
- diff = seeder.diff(in_seq, util.Sequence([[1, 1]]))
+ in_seq = toolkit.Sequence([[1, 1], [3, None]])
+ diff = seeder.diff(in_seq, toolkit.Sequence([[1, 1]]))
record = next(diff)
record['blob'] = ''.join([i for i in record['blob']])
self.assertEqual({'op': 'update', 'blob_size': 1, 'blob': '1', 'path': '1'}, record)
@@ -173,7 +172,7 @@ class FilesTest(tests.Test):
self.assertRaises(StopIteration, diff.next)
def test_Index_DiffUpdatedFiles(self):
- seqno = util.Seqno('seqno')
+ seqno = toolkit.Seqno('seqno')
seeder = files.Index('files', 'index', seqno)
self.touch(('files/1', '1'))
@@ -182,7 +181,7 @@ class FilesTest(tests.Test):
self.utime('files', 1)
os.utime('files', (1, 1))
- for __ in seeder.diff(util.Sequence([[1, None]])):
+ for __ in seeder.diff(toolkit.Sequence([[1, None]])):
pass
self.assertEqual(3, seqno.value)
@@ -190,7 +189,7 @@ class FilesTest(tests.Test):
self.assertEqual(
[{'op': 'commit', 'sequence': []}],
- [i for i in seeder.diff(util.Sequence([[4, None]]))])
+ [i for i in seeder.diff(toolkit.Sequence([[4, None]]))])
self.assertEqual(3, seqno.value)
os.utime('files', (3, 3))
@@ -199,7 +198,7 @@ class FilesTest(tests.Test):
{'op': 'update', 'blob_size': 1, 'blob': '2', 'path': '2'},
{'op': 'commit', 'sequence': [[4, 4]]},
]),
- sorted(files_diff(seeder, util.Sequence([[4, None]]))))
+ sorted(files_diff(seeder, toolkit.Sequence([[4, None]]))))
self.assertEqual(4, seqno.value)
os.utime('files/1', (4, 4))
@@ -211,7 +210,7 @@ class FilesTest(tests.Test):
{'op': 'update', 'blob_size': 1, 'blob': '3', 'path': '3'},
{'op': 'commit', 'sequence': [[5, 6]]},
]),
- sorted(files_diff(seeder, util.Sequence([[5, None]]))))
+ sorted(files_diff(seeder, toolkit.Sequence([[5, None]]))))
self.assertEqual(6, seqno.value)
self.assertEqual(sorted([
@@ -220,11 +219,11 @@ class FilesTest(tests.Test):
{'op': 'update', 'blob_size': 1, 'blob': '3', 'path': '3'},
{'op': 'commit', 'sequence': [[1, 6]]},
]),
- sorted(files_diff(seeder, util.Sequence([[1, None]]))))
+ sorted(files_diff(seeder, toolkit.Sequence([[1, None]]))))
self.assertEqual(6, seqno.value)
def test_Index_DiffCreatedFiles(self):
- seqno = util.Seqno('seqno')
+ seqno = toolkit.Seqno('seqno')
seeder = files.Index('files', 'index', seqno)
self.touch(('files/1', '1'))
@@ -233,7 +232,7 @@ class FilesTest(tests.Test):
self.utime('files', 1)
os.utime('files', (1, 1))
- for __ in seeder.diff(util.Sequence([[1, None]])):
+ for __ in seeder.diff(toolkit.Sequence([[1, None]])):
pass
self.assertEqual(3, seqno.value)
@@ -243,7 +242,7 @@ class FilesTest(tests.Test):
self.assertEqual(
[{'op': 'commit', 'sequence': []}],
- [i for i in seeder.diff(util.Sequence([[4, None]]))])
+ [i for i in seeder.diff(toolkit.Sequence([[4, None]]))])
self.assertEqual(3, seqno.value)
os.utime('files/4', (2, 2))
@@ -253,7 +252,7 @@ class FilesTest(tests.Test):
{'op': 'update', 'blob_size': 1, 'blob': '4', 'path': '4'},
{'op': 'commit', 'sequence': [[4, 4]]},
]),
- sorted(files_diff(seeder, util.Sequence([[4, None]]))))
+ sorted(files_diff(seeder, toolkit.Sequence([[4, None]]))))
self.assertEqual(4, seqno.value)
self.touch(('files/5', '5'))
@@ -267,11 +266,11 @@ class FilesTest(tests.Test):
{'op': 'update', 'blob_size': 1, 'blob': '6', 'path': '6'},
{'op': 'commit', 'sequence': [[5, 6]]},
]),
- sorted(files_diff(seeder, util.Sequence([[5, None]]))))
+ sorted(files_diff(seeder, toolkit.Sequence([[5, None]]))))
self.assertEqual(6, seqno.value)
def test_Index_DiffDeletedFiles(self):
- seqno = util.Seqno('seqno')
+ seqno = toolkit.Seqno('seqno')
seeder = files.Index('files', 'index', seqno)
self.touch(('files/1', '1'))
@@ -280,7 +279,7 @@ class FilesTest(tests.Test):
self.utime('files', 1)
os.utime('files', (1, 1))
- for __ in seeder.diff(util.Sequence([[1, None]])):
+ for __ in seeder.diff(toolkit.Sequence([[1, None]])):
pass
self.assertEqual(3, seqno.value)
@@ -294,7 +293,7 @@ class FilesTest(tests.Test):
{'op': 'delete', 'path': '2'},
{'op': 'commit', 'sequence': [[1, 4]]},
]),
- sorted(files_diff(seeder, util.Sequence([[1, None]]))))
+ sorted(files_diff(seeder, toolkit.Sequence([[1, None]]))))
self.assertEqual(4, seqno.value)
os.unlink('files/1')
@@ -308,7 +307,7 @@ class FilesTest(tests.Test):
{'op': 'delete', 'path': '3'},
{'op': 'commit', 'sequence': [[1, 6]]},
]),
- sorted([i for i in seeder.diff(util.Sequence([[1, None]]))]))
+ sorted([i for i in seeder.diff(toolkit.Sequence([[1, None]]))]))
self.assertEqual(6, seqno.value)
assert not seeder.sync()
@@ -318,7 +317,7 @@ class FilesTest(tests.Test):
{'op': 'delete', 'path': '3'},
{'op': 'commit', 'sequence': [[1, 6]]},
]),
- sorted([i for i in seeder.diff(util.Sequence([[1, None]]))]))
+ sorted([i for i in seeder.diff(toolkit.Sequence([[1, None]]))]))
self.assertEqual(6, seqno.value)
def test_merge_Updated(self):
diff --git a/tests/units/node/master.py b/tests/units/node/master.py
index 242e159..f5dbc1b 100755
--- a/tests/units/node/master.py
+++ b/tests/units/node/master.py
@@ -153,7 +153,7 @@ class MasterTest(tests.Test):
events = []
def read_events():
for event in ipc.subscribe():
- if event.get('document') == 'implementation':
+ if event.get('resource') == 'implementation':
events.append(event)
job = coroutine.spawn(read_events)
@@ -174,7 +174,7 @@ class MasterTest(tests.Test):
})
coroutine.sleep(.5)
self.assertEqual([
- {'event': 'populate', 'document': 'implementation', 'mtime': int(os.stat('master/implementation/index/mtime').st_mtime)},
+ {'event': 'populate', 'resource': 'implementation', 'mtime': int(os.stat('master/implementation/index/mtime').st_mtime)},
],
events)
self.assertEqual({
@@ -189,7 +189,7 @@ class MasterTest(tests.Test):
events = []
def read_events():
for event in ipc.subscribe():
- if event.get('document') == 'implementation':
+ if event.get('resource') == 'implementation':
events.append(event)
job = coroutine.spawn(read_events)
@@ -205,7 +205,7 @@ class MasterTest(tests.Test):
ipc.put(['context', guid, 'dependencies'], ['foo'])
coroutine.sleep(.1)
self.assertEqual([
- {'event': 'populate', 'document': 'implementation', 'mtime': int(os.stat('master/implementation/index/mtime').st_mtime)},
+ {'event': 'populate', 'resource': 'implementation', 'mtime': int(os.stat('master/implementation/index/mtime').st_mtime)},
],
events)
diff --git a/tests/units/node/node.py b/tests/units/node/node.py
index a1bb46b..85dcff3 100755
--- a/tests/units/node/node.py
+++ b/tests/units/node/node.py
@@ -10,22 +10,22 @@ from os.path import exists
from __init__ import tests
-from sugar_network import db, node
+from sugar_network import db, node, model
from sugar_network.client import Client
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.commands import NodeCommands
-from sugar_network.node.master import MasterCommands
-from sugar_network.resources.volume import Volume, Resource
-from sugar_network.resources.user import User
-from sugar_network.resources.context import Context
-from sugar_network.resources.implementation import Implementation
-from sugar_network.resources.review import Review
-from sugar_network.resources.feedback import Feedback
-from sugar_network.resources.artifact import Artifact
-from sugar_network.resources.solution import Solution
-from sugar_network.resources.user import 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.implementation import Implementation
+from sugar_network.model.review import Review
+from sugar_network.model.feedback import Feedback
+from sugar_network.model.artifact import Artifact
+from sugar_network.model.solution import Solution
+from sugar_network.model.user import User
+from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, Blob, ACL, route
class NodeTest(tests.Test):
@@ -37,8 +37,8 @@ class NodeTest(tests.Test):
stats_user.stats_user_rras.value = ['RRA:AVERAGE:0.5:1:100']
def test_UserStats(self):
- volume = Volume('db')
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', model.RESOURCES)
+ cp = NodeRoutes('guid', volume)
call(cp, method='POST', document='user', principal=tests.UID, content={
'name': 'user',
@@ -110,8 +110,8 @@ class NodeTest(tests.Test):
for i in range(100):
rrd['user'].put({'total': i}, ts + i)
- volume = Volume('db', [User, Context, Review, Feedback, Solution, Artifact])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', model.RESOURCES)
+ cp = NodeRoutes('guid', volume)
self.assertEqual({
'user': [
@@ -134,10 +134,11 @@ class NodeTest(tests.Test):
cp.stats(ts, ts + 12, 3, ['user.total']))
def test_HandleDeletes(self):
- volume = Volume('db')
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', model.RESOURCES)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = NodeRoutes('guid', volume)
- guid = call(cp, method='POST', document='context', principal='principal', content={
+ guid = call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
'title': 'title',
'summary': 'summary',
@@ -154,43 +155,44 @@ class NodeTest(tests.Test):
call(cp, method='GET', document='context', guid=guid, reply=['guid', 'title', 'layer']))
self.assertEqual(['public'], volume['context'].get(guid)['layer'])
+ def subscribe():
+ for event in cp.subscribe():
+ events.append(json.loads(event[6:]))
events = []
- volume.connect(lambda event: events.append(event))
- call(cp, method='DELETE', document='context', guid=guid, principal='principal')
+ coroutine.spawn(subscribe)
coroutine.dispatch()
+ call(cp, method='DELETE', document='context', guid=guid, principal=tests.UID)
+ 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', 'document': 'context', 'guid': guid},
- {'event': 'commit', 'document': 'context', 'mtime': int(os.stat('db/context/index/mtime').st_mtime)},
- ],
- events)
+ self.assertEqual({'event': 'delete', 'resource': 'context', 'guid': guid}, events[0])
def test_SimulateDeleteEvents(self):
- volume = Volume('db')
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', model.RESOURCES)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = NodeRoutes('guid', volume)
- guid = call(cp, method='POST', document='context', principal='principal', content={
+ guid = call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
'title': 'title',
'summary': 'summary',
'description': 'description',
})
+ def subscribe():
+ for event in cp.subscribe():
+ events.append(json.loads(event[6:]))
events = []
- volume.connect(lambda event: events.append(event))
- call(cp, method='PUT', document='context', guid=guid, principal='principal', content={'layer': ['deleted']})
+ coroutine.spawn(subscribe)
coroutine.dispatch()
- self.assertEqual([
- {'event': 'delete', 'document': 'context', 'guid': guid},
- {'event': 'commit', 'document': 'context', 'mtime': int(os.stat('db/context/index/mtime').st_mtime)},
- ],
- events)
+ 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 test_RegisterUser(self):
- cp = NodeCommands('guid', Volume('db', [User]))
+ cp = NodeRoutes('guid', db.Volume('db', [User]))
guid = call(cp, method='POST', document='user', principal='fake', content={
'name': 'user',
@@ -203,50 +205,57 @@ class NodeTest(tests.Test):
self.assertEqual('user', call(cp, method='GET', document='user', guid=tests.UID, prop='name'))
def test_UnauthorizedCommands(self):
+ volume = db.Volume('db', model.RESOURCES)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
- class Document(Resource):
+ class Routes(NodeRoutes):
- @db.document_command(method='GET', cmd='probe1',
- permissions=db.ACCESS_AUTH)
+ @route('GET', [None, None], cmd='probe1', acl=ACL.AUTH)
def probe1(self, directory):
pass
- @db.document_command(method='GET', cmd='probe2')
+ @route('GET', [None, None], cmd='probe2')
def probe2(self, directory):
pass
- cp = NodeCommands('guid', Volume('db', [User, Document]))
- guid = call(cp, method='POST', document='document', principal='user', content={})
+ class Document(db.Resource):
+ pass
+
+ cp = Routes('guid', 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)
- call(cp, method='GET', cmd='probe1', document='document', guid=guid, principal='user')
+ call(cp, method='GET', cmd='probe1', document='document', guid=guid, principal=tests.UID)
call(cp, method='GET', cmd='probe2', document='document', guid=guid)
def test_ForbiddenCommands(self):
- class Document(Resource):
+ class Routes(NodeRoutes):
- @db.document_command(method='GET', cmd='probe1',
- permissions=db.ACCESS_AUTHOR)
+ @route('GET', [None, None], cmd='probe1', acl=ACL.AUTHOR)
def probe1(self):
pass
- @db.document_command(method='GET', cmd='probe2')
+ @route('GET', [None, None], cmd='probe2')
def probe2(self):
pass
- class User(db.Document):
+ class Document(db.Resource):
pass
- cp = NodeCommands('guid', Volume('db', [User, Document]))
- guid = call(cp, method='POST', document='document', principal='principal', content={})
+ volume = db.Volume('db', [User, Document])
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = Routes('guid', volume)
+
+ guid = call(cp, method='POST', document='document', principal=tests.UID, content={})
self.assertRaises(http.Forbidden, call, cp, method='GET', cmd='probe1', document='document', guid=guid)
- self.assertRaises(http.Forbidden, call, cp, method='GET', cmd='probe1', document='document', guid=guid, principal='fake')
- call(cp, method='GET', cmd='probe1', document='document', guid=guid, principal='principal')
+ self.assertRaises(http.Unauthorized, call, cp, method='GET', cmd='probe1', document='document', guid=guid, principal='fake')
+ call(cp, method='GET', cmd='probe1', document='document', guid=guid, principal=tests.UID)
call(cp, method='GET', cmd='probe2', document='document', guid=guid)
def test_ForbiddenCommandsForUserResource(self):
- cp = NodeCommands('guid', Volume('db', [User]))
+ cp = NodeRoutes('guid', db.Volume('db', [User]))
call(cp, method='POST', document='user', principal='fake', content={
'name': 'user1',
@@ -258,39 +267,134 @@ class NodeTest(tests.Test):
self.assertEqual('user1', call(cp, method='GET', document='user', guid=tests.UID, prop='name'))
self.assertRaises(http.Unauthorized, call, cp, method='PUT', document='user', guid=tests.UID, content={'name': 'user2'})
- self.assertRaises(http.Forbidden, call, cp, method='PUT', document='user', guid=tests.UID, principal='fake', content={'name': 'user2'})
+ self.assertRaises(http.Unauthorized, call, cp, method='PUT', document='user', guid=tests.UID, principal='fake', content={'name': 'user2'})
call(cp, method='PUT', document='user', guid=tests.UID, principal=tests.UID, content={'name': 'user2'})
self.assertEqual('user2', call(cp, method='GET', document='user', guid=tests.UID, prop='name'))
+ def test_authorize_Config(self):
+ self.touch(('authorization.conf', [
+ '[%s]' % tests.UID,
+ 'root = True',
+ ]))
+
+ class Routes(NodeRoutes):
+
+ @route('PROBE', acl=ACL.SUPERUSER)
+ def probe(self):
+ return 'ok'
+
+ volume = db.Volume('db', [User])
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ volume['user'].create({'guid': tests.UID2, 'name': 'test', 'color': '', 'pubkey': tests.PUBKEY2})
+ cp = Routes('guid', volume)
+
+ self.assertRaises(http.Forbidden, call, cp, method='PROBE')
+ self.assertRaises(http.Forbidden, call, cp, method='PROBE', principal=tests.UID2)
+ self.assertEqual('ok', call(cp, method='PROBE', principal=tests.UID))
+
+ def test_authorize_FullWriteForRoot(self):
+ self.touch(('authorization.conf', [
+ '[%s]' % tests.UID2,
+ 'root = True',
+ ]))
+
+ class Routes(NodeRoutes):
+
+ @route('PROBE', [None, None], acl=ACL.AUTHOR)
+ def probe(self):
+ pass
+
+ class Document(db.Resource):
+ pass
+
+ volume = db.Volume('db', [User, Document])
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ volume['user'].create({'guid': tests.UID2, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY2})
+ cp = Routes('guid', volume)
+
+ guid = call(cp, method='POST', document='document', principal=tests.UID, content={})
+
+ call(cp, 'PROBE', document='document', guid=guid, principal=tests.UID)
+ call(cp, 'PROBE', document='document', guid=guid, principal=tests.UID2)
+
+ def test_authorize_LiveConfigUpdates(self):
+
+ class Routes(NodeRoutes):
+
+ @route('PROBE', acl=ACL.SUPERUSER)
+ def probe(self):
+ pass
+
+ volume = db.Volume('db', [User])
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = Routes('guid', volume)
+
+ self.assertRaises(http.Forbidden, call, cp, 'PROBE', principal=tests.UID)
+ self.touch(('authorization.conf', [
+ '[%s]' % tests.UID,
+ 'root = True',
+ ]))
+ call(cp, 'PROBE', principal=tests.UID)
+
+ def test_authorize_Anonymous(self):
+
+ class Routes(NodeRoutes):
+
+ @route('PROBE1', acl=ACL.AUTH)
+ def probe1(self, request):
+ pass
+
+ @route('PROBE2', acl=ACL.SUPERUSER)
+ def probe2(self, request):
+ pass
+
+ volume = db.Volume('db', [User])
+ cp = Routes('guid', volume)
+
+ self.assertRaises(http.Unauthorized, call, cp, 'PROBE1')
+ self.assertRaises(http.Forbidden, call, cp, 'PROBE2')
+
+ self.touch(('authorization.conf', [
+ '[anonymous]',
+ 'user = True',
+ 'root = True',
+ ]))
+ call(cp, 'PROBE1')
+ call(cp, 'PROBE2')
+
def test_SetUser(self):
- cp = NodeCommands('guid', Volume('db'))
+ volume = db.Volume('db', model.RESOURCES)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = NodeRoutes('guid', volume)
- guid = call(cp, method='POST', document='context', principal='principal', content={
+ guid = call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
'title': 'title',
'summary': 'summary',
'description': 'description',
})
self.assertEqual(
- [{'name': 'principal', 'role': 2}],
+ [{'guid': tests.UID, 'name': 'user', 'role': 3}],
call(cp, method='GET', document='context', guid=guid, prop='author'))
def test_find_MaxLimit(self):
- cp = NodeCommands('guid', Volume('db'))
+ volume = db.Volume('db', model.RESOURCES)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = NodeRoutes('guid', volume)
- call(cp, method='POST', document='context', principal='principal', content={
+ call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
'title': 'title1',
'summary': 'summary',
'description': 'description',
})
- call(cp, method='POST', document='context', principal='principal', content={
+ call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
'title': 'title2',
'summary': 'summary',
'description': 'description',
})
- call(cp, method='POST', document='context', principal='principal', content={
+ call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
'title': 'title3',
'summary': 'summary',
@@ -305,10 +409,11 @@ class NodeTest(tests.Test):
self.assertEqual(1, len(call(cp, method='GET', document='context', limit=1024)['result']))
def test_DeletedDocuments(self):
- volume = Volume('db')
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', model.RESOURCES)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = NodeRoutes('guid', volume)
- guid = call(cp, method='POST', document='context', principal='principal', content={
+ guid = call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
'title': 'title1',
'summary': 'summary',
@@ -325,9 +430,10 @@ class NodeTest(tests.Test):
def test_CreateGUID(self):
# TODO Temporal security hole, see TODO
- volume2 = Volume('db2')
- cp2 = MasterCommands('guid', volume2)
- call(cp2, method='POST', document='context', principal='principal', content={
+ volume = db.Volume('db', model.RESOURCES)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = NodeRoutes('guid', volume)
+ call(cp, method='POST', document='context', principal=tests.UID, content={
'guid': 'foo',
'type': 'activity',
'title': 'title',
@@ -336,12 +442,14 @@ class NodeTest(tests.Test):
})
self.assertEqual(
{'guid': 'foo', 'title': 'title'},
- call(cp2, method='GET', document='context', guid='foo', reply=['guid', 'title']))
+ call(cp, method='GET', document='context', guid='foo', reply=['guid', 'title']))
def test_CreateMalformedGUID(self):
- cp = MasterCommands('guid', Volume('db2'))
+ volume = db.Volume('db', model.RESOURCES)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = MasterRoutes('guid', volume)
- self.assertRaises(RuntimeError, call, cp, method='POST', document='context', principal='principal', content={
+ self.assertRaises(RuntimeError, call, cp, method='POST', document='context', principal=tests.UID, content={
'guid': '!?',
'type': 'activity',
'title': 'title',
@@ -350,16 +458,18 @@ class NodeTest(tests.Test):
})
def test_FailOnExistedGUID(self):
- cp = MasterCommands('guid', Volume('db2'))
+ volume = db.Volume('db', model.RESOURCES)
+ volume['user'].create({'guid': tests.UID, 'name': 'user', 'color': '', 'pubkey': tests.PUBKEY})
+ cp = MasterRoutes('guid', volume)
- guid = call(cp, method='POST', document='context', principal='principal', content={
+ guid = call(cp, method='POST', document='context', principal=tests.UID, content={
'type': 'activity',
'title': 'title',
'summary': 'summary',
'description': 'description',
})
- self.assertRaises(RuntimeError, call, cp, method='POST', document='context', principal='principal', content={
+ self.assertRaises(RuntimeError, call, cp, method='POST', document='context', principal=tests.UID, content={
'guid': guid,
'type': 'activity',
'title': 'title',
@@ -550,16 +660,23 @@ class NodeTest(tests.Test):
self.assertEqual(len(activity_info), data.get('unpack_size'))
-
-
-
-
-def call(cp, principal=None, content=None, **kwargs):
- request = db.Request(**kwargs)
- request.principal = principal
+def call(routes, method, document=None, guid=None, prop=None, principal=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)
+ request.update(kwargs)
+ request.cmd = cmd
request.content = content
request.environ = {'HTTP_HOST': '127.0.0.1'}
- return cp.call(request, db.Response())
+ if principal:
+ request.environ['HTTP_X_SN_LOGIN'] = principal
+ router = Router(routes)
+ return router.call(request, Response())
if __name__ == '__main__':
diff --git a/tests/units/node/stats_node.py b/tests/units/node/stats_node.py
index 607a380..2fa9446 100755
--- a/tests/units/node/stats_node.py
+++ b/tests/units/node/stats_node.py
@@ -5,25 +5,19 @@ import time
from __init__ import tests
-from sugar_network.toolkit.rrd import Rrd
+from sugar_network import db, model
from sugar_network.node.stats_node import stats_node_step, Sniffer
-from sugar_network.resources.user import User
-from sugar_network.resources.context import Context
-from sugar_network.resources.implementation import Implementation
-from sugar_network.resources.review import Review
-from sugar_network.resources.feedback import Feedback
-from sugar_network.resources.artifact import Artifact
-from sugar_network.resources.solution import Solution
-from sugar_network.resources.volume import Volume
+from sugar_network.toolkit.rrd import Rrd
+from sugar_network.toolkit.router import Request
class StatsTest(tests.Test):
- def test_DoNotLogAnonymouses(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ def ___test_DoNotLogAnonymouses(self):
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
- request = db.Request(method='GET', document='context', guid='guid')
+ request = Request(method='GET', path=['context', 'guid'])
stats.log(request)
self.assertEqual(0, stats._stats['context'].viewed)
@@ -32,20 +26,20 @@ class StatsTest(tests.Test):
self.assertEqual(1, stats._stats['context'].viewed)
def test_DoNotLogCmds(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
- request = db.Request(method='GET', document='context', guid='guid', cmd='probe')
+ request = Request(method='GET', path=['context', 'guid'], cmd='probe')
request.principal = 'user'
stats.log(request)
self.assertEqual(0, stats._stats['context'].viewed)
- del request['cmd']
+ request.cmd = None
stats.log(request)
self.assertEqual(1, stats._stats['context'].viewed)
def test_InitializeTotals(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
self.assertEqual(0, stats._stats['user'].total)
@@ -74,10 +68,10 @@ class StatsTest(tests.Test):
self.assertEqual(1, stats._stats['artifact'].total)
def test_POSTs(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
- request = db.Request(method='POST', document='context')
+ request = Request(method='POST', path=['context'])
request.principal = 'user'
stats.log(request)
stats.log(request)
@@ -88,10 +82,10 @@ class StatsTest(tests.Test):
self.assertEqual(0, stats._stats['context'].deleted)
def test_PUTs(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
- request = db.Request(method='PUT', document='context', guid='guid')
+ request = Request(method='PUT', path=['context', 'guid'])
request.principal = 'user'
stats.log(request)
stats.log(request)
@@ -102,10 +96,10 @@ class StatsTest(tests.Test):
self.assertEqual(0, stats._stats['context'].deleted)
def test_DELETEs(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
- request = db.Request(method='DELETE', document='context')
+ request = Request(method='DELETE', path=['context'])
request.principal = 'user'
stats.log(request)
stats.log(request)
@@ -116,29 +110,29 @@ class StatsTest(tests.Test):
self.assertEqual(3, stats._stats['context'].deleted)
def test_GETs(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
- request = db.Request(method='GET', document='user')
+ request = Request(method='GET', path=['user'])
request.principal = 'user'
stats.log(request)
self.assertEqual(0, stats._stats['user'].viewed)
def test_GETsDocument(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
- request = db.Request(method='GET', document='user', guid='user')
+ request = Request(method='GET', path=['user', 'user'])
request.principal = 'user'
stats.log(request)
self.assertEqual(1, stats._stats['user'].viewed)
def test_FeedbackSolutions(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
volume['feedback'].create({'guid': 'guid', 'context': 'context', 'type': 'idea', 'title': '', 'content': ''})
- request = db.Request(method='PUT', document='feedback', guid='guid')
+ request = Request(method='PUT', path=['feedback', 'guid'])
request.principal = 'user'
request.content = {}
stats.log(request)
@@ -162,51 +156,51 @@ class StatsTest(tests.Test):
self.assertEqual(0, stats._stats['feedback'].solutions)
def test_Comments(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
volume['solution'].create({'guid': 'solution', 'context': 'context', 'feedback': 'feedback', 'content': ''})
volume['feedback'].create({'guid': 'feedback', 'context': 'context', 'type': 'idea', 'title': '', 'content': ''})
volume['review'].create({'guid': 'review', 'context': 'context', 'title': '', 'content': '', 'rating': 5})
- request = db.Request(method='POST', document='comment')
+ request = Request(method='POST', path=['comment'])
request.principal = 'user'
request.content = {'solution': 'solution'}
stats.log(request)
self.assertEqual(1, stats._stats['solution'].commented)
- request = db.Request(method='POST', document='comment')
+ request = Request(method='POST', path=['comment'])
request.principal = 'user'
request.content = {'feedback': 'feedback'}
stats.log(request)
self.assertEqual(1, stats._stats['feedback'].commented)
- request = db.Request(method='POST', document='comment')
+ request = Request(method='POST', path=['comment'])
request.principal = 'user'
request.content = {'review': 'review'}
stats.log(request)
self.assertEqual(1, stats._stats['review'].commented)
def test_Reviewes(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
volume['artifact'].create({'guid': 'artifact', 'type': 'instance', 'context': 'context', 'title': '', 'description': ''})
- request = db.Request(method='POST', document='review')
+ request = Request(method='POST', path=['review'])
request.principal = 'user'
request.content = {'context': 'context', 'rating': 0}
stats.log(request)
self.assertEqual(1, stats._stats['context'].reviewed)
self.assertEqual(0, stats._stats['artifact'].reviewed)
- request = db.Request(method='POST', document='review')
+ request = Request(method='POST', path=['review'])
request.principal = 'user'
request.content = {'context': 'context', 'artifact': '', 'rating': 0}
stats.log(request)
self.assertEqual(2, stats._stats['context'].reviewed)
self.assertEqual(0, stats._stats['artifact'].reviewed)
- request = db.Request(method='POST', document='review')
+ request = Request(method='POST', path=['review'])
request.principal = 'user'
request.content = {'artifact': 'artifact', 'rating': 0}
stats.log(request)
@@ -214,55 +208,55 @@ class StatsTest(tests.Test):
self.assertEqual(1, stats._stats['artifact'].reviewed)
def test_ContextDownloaded(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact, Implementation])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
volume['implementation'].create({'guid': 'implementation', 'context': 'context', 'license': 'GPLv3', 'version': '1', 'date': 0, 'stability': 'stable', 'notes': ''})
- request = db.Request(method='GET', document='implementation', guid='implementation', prop='fake')
+ request = Request(method='GET', path=['implementation', 'implementation', 'fake'])
request.principal = 'user'
stats.log(request)
self.assertEqual(0, stats._stats['context'].downloaded)
- request = db.Request(method='GET', document='implementation', guid='implementation', prop='data')
+ request = Request(method='GET', path=['implementation', 'implementation', 'data'])
request.principal = 'user'
stats.log(request)
self.assertEqual(1, stats._stats['context'].downloaded)
def test_ContextReleased(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact, Implementation])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
- request = db.Request(method='POST', document='implementation')
+ request = Request(method='POST', path=['implementation'])
request.principal = 'user'
request.content = {'context': 'context'}
stats.log(request)
self.assertEqual(1, stats._stats['context'].released)
def test_ContextFailed(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact, Implementation])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
- request = db.Request(method='POST', document='report')
+ 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_ContextActive(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact, Implementation])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
- request = db.Request(method='PUT', document='context', guid='1')
+ request = Request(method='PUT', path=['context', '1'])
request.principal = 'user'
stats.log(request)
self.assertEqual(
['1'],
stats._stats['context'].active.keys())
- request = db.Request(method='GET', document='artifact', context='2')
+ request = Request(method='GET', path=['artifact'], context='2')
request.principal = 'user'
stats.log(request)
self.assertEqual(
@@ -270,7 +264,7 @@ class StatsTest(tests.Test):
stats._stats['context'].active.keys())
volume['artifact'].create({'guid': 'artifact', 'type': 'instance', 'context': '3', 'title': '', 'description': ''})
- request = db.Request(method='GET', document='review', artifact='artifact')
+ request = Request(method='GET', path=['review'], artifact='artifact')
request.principal = 'user'
stats.log(request)
self.assertEqual(
@@ -278,21 +272,21 @@ class StatsTest(tests.Test):
sorted(stats._stats['context'].active.keys()))
volume['feedback'].create({'guid': 'feedback', 'context': '4', 'type': 'idea', 'title': '', 'content': ''})
- request = db.Request(method='GET', document='solution', feedback='feedback')
+ request = Request(method='GET', path=['solution'], feedback='feedback')
request.principal = 'user'
stats.log(request)
self.assertEqual(
['1', '2', '3', '4'],
sorted(stats._stats['context'].active.keys()))
- request = db.Request(method='GET', document='context', guid='5')
+ request = Request(method='GET', path=['context', '5'])
request.principal = 'user'
stats.log(request)
self.assertEqual(
['1', '2', '3', '4', '5'],
sorted(stats._stats['context'].active.keys()))
- request = db.Request(method='POST', document='report')
+ request = Request(method='POST', path=['report'])
request.principal = 'user'
request.content = {'context': '6'}
stats.log(request)
@@ -301,7 +295,7 @@ class StatsTest(tests.Test):
sorted(stats._stats['context'].active.keys()))
volume['solution'].create({'guid': 'solution', 'context': '7', 'feedback': 'feedback', 'content': ''})
- request = db.Request(method='POST', document='comment')
+ request = Request(method='POST', path=['comment'])
request.principal = 'user'
request.content = {'solution': 'solution'}
stats.log(request)
@@ -310,10 +304,10 @@ class StatsTest(tests.Test):
sorted(stats._stats['context'].active.keys()))
def test_UserActive(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact, Implementation])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
- request = db.Request(method='GET', document='user')
+ request = Request(method='GET', path=['user'])
request.principal = '1'
stats.log(request)
self.assertEqual(
@@ -323,7 +317,7 @@ class StatsTest(tests.Test):
set([]),
stats._stats['user'].effective)
- request = db.Request(method='POST', document='user')
+ request = Request(method='POST', path=['user'])
request.principal = '2'
stats.log(request)
self.assertEqual(
@@ -334,17 +328,17 @@ class StatsTest(tests.Test):
stats._stats['user'].effective)
def test_ArtifactDownloaded(self):
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
stats = Sniffer(volume)
volume['artifact'].create({'guid': 'artifact', 'type': 'instance', 'context': 'context', 'title': '', 'description': ''})
- request = db.Request(method='GET', document='artifact', guid='artifact', prop='fake')
+ request = Request(method='GET', path=['artifact', 'artifact', 'fake'])
request.principal = 'user'
stats.log(request)
self.assertEqual(0, stats._stats['artifact'].viewed)
self.assertEqual(0, stats._stats['artifact'].downloaded)
- request = db.Request(method='GET', document='artifact', guid='artifact', prop='data')
+ request = Request(method='GET', path=['artifact', 'artifact', 'data'])
request.principal = 'user'
stats.log(request)
self.assertEqual(0, stats._stats['artifact'].viewed)
@@ -352,7 +346,7 @@ class StatsTest(tests.Test):
def test_Commit(self):
stats_node_step.value = 1
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact])
+ volume = db.Volume('local', model.RESOURCES)
volume['user'].create({'guid': 'user', 'name': 'user', 'color': '', 'pubkey': ''})
volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
volume['review'].create({'guid': 'review', 'context': 'context', 'title': '', 'content': '', 'rating': 5})
@@ -361,22 +355,22 @@ class StatsTest(tests.Test):
volume['artifact'].create({'guid': 'artifact', 'type': 'instance', 'context': 'context', 'title': '', 'description': ''})
stats = Sniffer(volume)
- request = db.Request(method='GET', document='user', guid='user')
+ request = Request(method='GET', path=['user', 'user'])
request.principal = 'user'
stats.log(request)
- request = db.Request(method='GET', document='context', guid='context')
+ request = Request(method='GET', path=['context', 'context'])
request.principal = 'user'
stats.log(request)
- request = db.Request(method='GET', document='review', guid='review')
+ request = Request(method='GET', path=['review', 'review'])
request.principal = 'user'
stats.log(request)
- request = db.Request(method='GET', document='feedback', guid='feedback')
+ request = Request(method='GET', path=['feedback', 'feedback'])
request.principal = 'user'
stats.log(request)
- request = db.Request(method='GET', document='solution', guid='solution')
+ request = Request(method='GET', path=['solution', 'solution'])
request.principal = 'user'
stats.log(request)
- request = db.Request(method='GET', document='artifact', guid='artifact')
+ request = Request(method='GET', path=['artifact', 'artifact'])
request.principal = 'user'
stats.log(request)
@@ -474,11 +468,11 @@ class StatsTest(tests.Test):
'released': 0.0,
})],
],
- [[(db.name,) + i for i in db.get(db.first, db.last)] for db in Rrd('stats/node', 1)])
+ [[(j.name,) + i for i in j.get(j.last, j.last)] for j in Rrd('stats/node', 1)])
def test_CommitContextStats(self):
stats_node_step.value = 1
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact, Implementation])
+ volume = db.Volume('local', model.RESOURCES)
volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
volume['implementation'].create({'guid': 'implementation', 'context': 'context', 'license': 'GPLv3', 'version': '1', 'date': 0, 'stability': 'stable', 'notes': ''})
@@ -488,14 +482,14 @@ class StatsTest(tests.Test):
self.assertEqual(0, volume['context'].get('context')['rating'])
stats = Sniffer(volume)
- request = db.Request(method='GET', document='implementation', guid='implementation', prop='data')
+ request = Request(method='GET', path=['implementation', 'implementation', 'data'])
request.principal = 'user'
stats.log(request)
- request = db.Request(method='POST', document='review')
+ request = Request(method='POST', path=['review'])
request.principal = 'user'
request.content = {'context': 'context', 'rating': 5}
stats.log(request)
- request = db.Request(method='POST', document='review')
+ request = Request(method='POST', path=['review'])
request.principal = 'user'
request.content = {'artifact': 'artifact', 'rating': 5}
stats.log(request)
@@ -510,10 +504,10 @@ class StatsTest(tests.Test):
self.assertEqual(5, volume['context'].get('context')['rating'])
stats = Sniffer(volume)
- request = db.Request(method='GET', document='implementation', guid='implementation', prop='data')
+ request = Request(method='GET', path=['implementation', 'implementation', 'data'])
request.principal = 'user'
stats.log(request)
- request = db.Request(method='POST', document='review')
+ request = Request(method='POST', path=['review'])
request.principal = 'user'
request.content = {'context': 'context', 'rating': 1}
stats.log(request)
@@ -524,7 +518,7 @@ class StatsTest(tests.Test):
def test_CommitArtifactStats(self):
stats_node_step.value = 1
- volume = Volume('local', [User, Context, Review, Feedback, Solution, Artifact, Implementation])
+ volume = db.Volume('local', model.RESOURCES)
volume['context'].create({'guid': 'context', 'type': 'activity', 'title': '', 'summary': '', 'description': ''})
volume['artifact'].create({'guid': 'artifact', 'type': 'instance', 'context': 'context', 'title': '', 'description': ''})
@@ -533,10 +527,10 @@ class StatsTest(tests.Test):
self.assertEqual(0, volume['artifact'].get('artifact')['rating'])
stats = Sniffer(volume)
- request = db.Request(method='GET', document='artifact', guid='artifact', prop='data')
+ request = Request(method='GET', path=['artifact', 'artifact', 'data'])
request.principal = 'user'
stats.log(request)
- request = db.Request(method='POST', document='review')
+ request = Request(method='POST', path=['review'])
request.principal = 'user'
request.content = {'artifact': 'artifact', 'rating': 5}
stats.log(request)
@@ -550,10 +544,10 @@ class StatsTest(tests.Test):
self.assertEqual([1, 5], volume['artifact'].get('artifact')['reviews'])
self.assertEqual(5, volume['artifact'].get('artifact')['rating'])
- request = db.Request(method='GET', document='artifact', guid='artifact', prop='data')
+ request = Request(method='GET', path=['artifact', 'artifact', 'data'])
request.principal = 'user'
stats.log(request)
- request = db.Request(method='POST', document='review')
+ request = Request(method='POST', path=['review'])
request.principal = 'user'
request.content = {'artifact': 'artifact', 'rating': 1}
stats.log(request)
diff --git a/tests/units/node/sync_master.py b/tests/units/node/sync_master.py
index e137f6e..c946396 100755
--- a/tests/units/node/sync_master.py
+++ b/tests/units/node/sync_master.py
@@ -18,10 +18,11 @@ from __init__ import tests
from sugar_network.db.directory import Directory
from sugar_network import db, node, toolkit
from sugar_network.node import sync
-from sugar_network.node.master import MasterCommands
-from sugar_network.resources.volume import Volume
-from sugar_network.toolkit import coroutine, util
+from sugar_network.node.master import MasterRoutes
+from sugar_network.db.volume import Volume
+from sugar_network.toolkit import coroutine
from sugar_network.toolkit.rrd import Rrd
+from sugar_network.toolkit.router import Response
class statvfs(object):
@@ -40,7 +41,7 @@ class SyncMasterTest(tests.Test):
self.override(os, 'statvfs', lambda *args: statvfs())
statvfs.f_bfree = 999999999
- class Document(db.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1, default='')
def prop(self, value):
@@ -48,7 +49,7 @@ class SyncMasterTest(tests.Test):
node.files_root.value = 'sync'
self.volume = Volume('master', [Document])
- self.master = MasterCommands('127.0.0.1:8888', self.volume)
+ self.master = MasterRoutes('127.0.0.1:8888', self.volume)
def next_uuid(self):
self.uuid += 1
@@ -58,7 +59,7 @@ class SyncMasterTest(tests.Test):
request = Request()
for chunk in sync.encode([
('diff', None, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 1},
'ctime': {'value': 1, 'mtime': 1},
@@ -78,7 +79,7 @@ class SyncMasterTest(tests.Test):
response.seek(0)
self.assertEqual([
({'packet': 'ack', 'ack': [[1, 1]], 'src': '127.0.0.1:8888', 'sequence': [[1, 1]], 'dst': None}, []),
- ({'packet': 'diff', 'src': '127.0.0.1:8888'}, [{'document': 'document'}, {'commit': []}]),
+ ({'packet': 'diff', 'src': '127.0.0.1:8888'}, [{'resource': 'document'}, {'commit': []}]),
],
[(packet.props, [i for i in packet]) for packet in sync.decode(response)])
@@ -86,7 +87,7 @@ class SyncMasterTest(tests.Test):
for chunk in sync.encode([
('pull', {'sequence': [[1, None]]}, None),
('diff', None, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '2', 'diff': {
'guid': {'value': '2', 'mtime': 2},
'ctime': {'value': 2, 'mtime': 2},
@@ -106,7 +107,7 @@ class SyncMasterTest(tests.Test):
self.assertEqual([
({'packet': 'ack', 'ack': [[2, 2]], 'src': '127.0.0.1:8888', 'sequence': [[2, 2]], 'dst': None}, []),
({'packet': 'diff', 'src': '127.0.0.1:8888'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 1},
'ctime': {'value': 1, 'mtime': 1},
@@ -143,7 +144,7 @@ class SyncMasterTest(tests.Test):
request = Request()
for chunk in sync.package_encode([
('diff', None, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 1},
'ctime': {'value': 1, 'mtime': 1},
@@ -161,7 +162,7 @@ class SyncMasterTest(tests.Test):
request.content_stream.write(chunk)
request.content_stream.seek(0)
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.push(request, response):
reply.write(chunk)
@@ -186,7 +187,7 @@ class SyncMasterTest(tests.Test):
('pull', {'sequence': [[1, None]]}, None),
('files_pull', {'sequence': [[1, None]]}, None),
('diff', None, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '2', 'diff': {
'guid': {'value': '2', 'mtime': 2},
'ctime': {'value': 2, 'mtime': 2},
@@ -204,7 +205,7 @@ class SyncMasterTest(tests.Test):
request.content_stream.write(chunk)
request.content_stream.seek(0)
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.push(request, response):
reply.write(chunk)
@@ -235,7 +236,7 @@ class SyncMasterTest(tests.Test):
], dst='127.0.0.1:8888'):
request.content_stream.write(chunk)
request.content_stream.seek(0)
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.push(request, response):
reply.write(chunk)
@@ -259,7 +260,7 @@ class SyncMasterTest(tests.Test):
], dst='127.0.0.1:8888'):
request.content_stream.write(chunk)
request.content_stream.seek(0)
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.push(request, response):
reply.write(chunk)
@@ -281,7 +282,7 @@ class SyncMasterTest(tests.Test):
for chunk in sync.package_encode([
('pull', {'sequence': [[1, None]]}, None),
('diff', None, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 1},
'ctime': {'value': 1, 'mtime': 1},
@@ -294,7 +295,7 @@ class SyncMasterTest(tests.Test):
request.content_stream.write(chunk)
request.content_stream.seek(0)
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.push(request, response):
reply.write(chunk)
@@ -322,7 +323,7 @@ class SyncMasterTest(tests.Test):
request = Request()
request.environ['HTTP_COOKIE'] = 'sugar_network_pull=%s' % \
base64.b64encode(json.dumps([('pull', None, [[1, None]]), ('files_pull', None, [[1, None]])]))
- response = db.Response()
+ response = Response()
self.assertEqual(None, self.master.pull(request, response))
self.assertEqual([
'sugar_network_pull=%s; Max-Age=3600; HttpOnly' % \
@@ -336,14 +337,14 @@ class SyncMasterTest(tests.Test):
request = Request()
request.environ['HTTP_COOKIE'] = response.get('set-cookie')[0]
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.pull(request, response):
reply.write(chunk)
reply.seek(0)
self.assertEqual([
({'packet': 'diff'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'prop': {'value': '1', 'mtime': 0},
'guid': {'value': '1', 'mtime': 0},
@@ -371,7 +372,7 @@ class SyncMasterTest(tests.Test):
request = Request()
request.environ['HTTP_COOKIE'] = response.get('set-cookie')[0]
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.pull(request, response):
reply.write(chunk)
@@ -401,7 +402,7 @@ class SyncMasterTest(tests.Test):
request = Request()
request.environ['HTTP_COOKIE'] = 'sugar_network_pull=%s' % \
base64.b64encode(json.dumps([('pull', None, [[1, None]])]))
- response = db.Response()
+ response = Response()
self.assertEqual(None, self.master.pull(request, response))
self.assertEqual([
'sugar_network_pull=%s; Max-Age=3600; HttpOnly' % \
@@ -416,7 +417,7 @@ class SyncMasterTest(tests.Test):
request = Request()
request.environ['HTTP_COOKIE'] = response.get('set-cookie')[0]
- response = db.Response()
+ response = Response()
self.assertEqual(None, self.master.pull(request, response))
self.assertEqual([
'sugar_network_pull=unset_sugar_network_pull; Max-Age=0; HttpOnly',
@@ -438,7 +439,7 @@ class SyncMasterTest(tests.Test):
}
request = Request()
- response = db.Response()
+ response = Response()
self.assertEqual(None, self.master.pull(request, response))
self.assertEqual([
'sugar_network_pull=%s; Max-Age=3600; HttpOnly' % \
@@ -452,7 +453,7 @@ class SyncMasterTest(tests.Test):
request = Request()
request.environ['HTTP_COOKIE'] = response.get('set-cookie')[0]
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.pull(request, response):
reply.write(chunk)
@@ -472,7 +473,7 @@ class SyncMasterTest(tests.Test):
request = Request()
request.environ['HTTP_COOKIE'] = response.get('set-cookie')[0]
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.pull(request, response):
reply.write(chunk)
@@ -496,7 +497,7 @@ class SyncMasterTest(tests.Test):
('pull', {'src': '2', 'sequence': [[2, None]], 'layer': '2'}, None),
('pull', {'src': '2', 'sequence': [[22, None]], 'layer': '2'}, None),
('diff', {'src': '3'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 1},
'ctime': {'value': 1, 'mtime': 1},
@@ -506,7 +507,7 @@ class SyncMasterTest(tests.Test):
{'commit': [[1, 1]]},
]),
('diff', {'src': '3'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '2', 'diff': {
'guid': {'value': '2', 'mtime': 2},
'ctime': {'value': 2, 'mtime': 2},
@@ -519,7 +520,7 @@ class SyncMasterTest(tests.Test):
request.content_stream.write(chunk)
request.content_stream.seek(0)
- response = db.Response()
+ response = Response()
reply = StringIO()
for chunk in self.master.push(request, response):
reply.write(chunk)
@@ -548,7 +549,7 @@ class SyncMasterTest(tests.Test):
'sugar_network_pull': base64.b64encode(json.dumps([('pull', None, [[1, None]])])),
'sugar_network_sent': base64.b64encode(json.dumps({'slave': [[2, 2]]})),
}
- response = db.Response()
+ response = Response()
self.assertEqual(None, self.master.pull(request, response))
self.assertEqual([
'sugar_network_pull=%s; Max-Age=3600; HttpOnly' % \
@@ -568,7 +569,7 @@ class SyncMasterTest(tests.Test):
reply.seek(0)
self.assertEqual([
({'packet': 'diff'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'prop': {'value': '1', 'mtime': 0},
'guid': {'value': '1', 'mtime': 0},
@@ -596,7 +597,7 @@ class SyncMasterTest(tests.Test):
'sugar_network_pull': base64.b64encode(json.dumps([('pull', None, [[1, None]])])),
'sugar_network_sent': base64.b64encode(json.dumps({'slave': [[2, 2]], 'other': []})),
}
- response = db.Response()
+ response = Response()
self.assertEqual(None, self.master.pull(request, response))
self.assertEqual([
'sugar_network_pull=%s; Max-Age=3600; HttpOnly' % \
@@ -616,7 +617,7 @@ class SyncMasterTest(tests.Test):
reply.seek(0)
self.assertEqual([
({'packet': 'diff'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'prop': {'value': '1', 'mtime': 0},
'guid': {'value': '1', 'mtime': 0},
diff --git a/tests/units/node/sync_offline.py b/tests/units/node/sync_offline.py
index 752ff93..f3b7111 100755
--- a/tests/units/node/sync_offline.py
+++ b/tests/units/node/sync_offline.py
@@ -15,9 +15,9 @@ from sugar_network import db, node, toolkit
from sugar_network.toolkit.rrd import Rrd
from sugar_network.client import api_url
from sugar_network.node import sync, stats_user, files_root
-from sugar_network.node.slave import SlaveCommands
-from sugar_network.resources.volume import Volume
-from sugar_network.toolkit import coroutine, util
+from sugar_network.node.slave import SlaveRoutes
+from sugar_network.db import Volume
+from sugar_network.toolkit import coroutine
class statvfs(object):
@@ -44,12 +44,12 @@ class SyncOfflineTest(tests.Test):
def test_FailOnFullDump(self):
- class Document(db.Document):
+ class Document(db.Resource):
pass
volume = Volume('node', [Document])
- util.ensure_key('node/key')
- cp = SlaveCommands('node/key', volume)
+ toolkit.ensure_key('node/key')
+ cp = SlaveRoutes('node/key', volume)
node.sync_layers.value = None
self.assertRaises(RuntimeError, cp.offline_sync, tests.tmpdir + '/mnt')
@@ -62,12 +62,12 @@ class SyncOfflineTest(tests.Test):
def test_Export(self):
- class Document(db.Document):
+ class Document(db.Resource):
pass
volume = Volume('node', [Document])
- util.ensure_key('node/key')
- cp = SlaveCommands('node/key', volume)
+ toolkit.ensure_key('node/key')
+ cp = SlaveRoutes('node/key', volume)
stats_user.stats_user.value = True
volume['document'].create({'guid': '1', 'prop': 'value1', 'ctime': 1, 'mtime': 1})
@@ -83,7 +83,7 @@ class SyncOfflineTest(tests.Test):
self.assertEqual([
({'packet': 'diff', 'src': cp.guid, 'dst': '127.0.0.1:8888', 'api_url': 'http://127.0.0.1:8888', 'session': '1', 'filename': '2.sneakernet'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 0},
'ctime': {'value': 1, 'mtime': 0},
@@ -111,15 +111,15 @@ class SyncOfflineTest(tests.Test):
def test_ContinuesExport(self):
payload = ''.join([str(uuid.uuid4()) for i in xrange(5000)])
- class Document(db.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
return value
volume = Volume('node', [Document])
- util.ensure_key('node/key')
- cp = SlaveCommands('node/key', volume)
+ toolkit.ensure_key('node/key')
+ cp = SlaveRoutes('node/key', volume)
stats_user.stats_user.value = True
volume['document'].create({'guid': '1', 'prop': payload, 'ctime': 1, 'mtime': 1})
@@ -136,7 +136,7 @@ class SyncOfflineTest(tests.Test):
self.assertEqual([
({'packet': 'diff', 'src': cp.guid, 'dst': '127.0.0.1:8888', 'api_url': 'http://127.0.0.1:8888', 'session': '1', 'filename': '2.sneakernet'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 0},
'ctime': {'value': 1, 'mtime': 0},
@@ -156,7 +156,7 @@ class SyncOfflineTest(tests.Test):
self.assertEqual([
({'packet': 'diff', 'src': cp.guid, 'dst': '127.0.0.1:8888', 'api_url': 'http://127.0.0.1:8888', 'session': '1', 'filename': '3.sneakernet'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '2', 'diff': {
'guid': {'value': '2', 'mtime': 0},
'ctime': {'value': 2, 'mtime': 0},
@@ -179,7 +179,7 @@ class SyncOfflineTest(tests.Test):
self.assertEqual([
({'packet': 'diff', 'src': cp.guid, 'dst': '127.0.0.1:8888', 'api_url': 'http://127.0.0.1:8888', 'session': '4', 'filename': '5.sneakernet'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 0},
'ctime': {'value': 1, 'mtime': 0},
@@ -205,19 +205,19 @@ class SyncOfflineTest(tests.Test):
sorted([(packet.props, [i for i in packet]) for packet in sync.sneakernet_decode('3')]))
def test_Import(self):
- class Document(db.Document):
+ class Document(db.Resource):
pass
volume = Volume('node', [Document])
- util.ensure_key('node/key')
- cp = SlaveCommands('node/key', volume)
+ toolkit.ensure_key('node/key')
+ cp = SlaveRoutes('node/key', volume)
stats_user.stats_user.value = True
files_root.value = 'files'
ts = int(time.time())
sync.sneakernet_encode([
('diff', {'src': '127.0.0.1:8888'}, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 0},
'ctime': {'value': 1, 'mtime': 0},
diff --git a/tests/units/node/sync_online.py b/tests/units/node/sync_online.py
index 9f978e8..c8bf5f8 100755
--- a/tests/units/node/sync_online.py
+++ b/tests/units/node/sync_online.py
@@ -7,16 +7,16 @@ from os.path import exists
from __init__ import tests
-from sugar_network import db
-from sugar_network.db.router import Router
+from sugar_network import db, toolkit
from sugar_network.client import Client, api_url
from sugar_network.node import sync, stats_user, files_root
-from sugar_network.node.master import MasterCommands
-from sugar_network.node.slave import SlaveCommands
-from sugar_network.resources.volume import Volume
-from sugar_network.resources.user import User
-from sugar_network.resources.feedback import Feedback
-from sugar_network.toolkit import util, coroutine
+from sugar_network.node.master import MasterRoutes
+from sugar_network.node.slave import SlaveRoutes
+from sugar_network.db.volume import Volume
+from sugar_network.model.user import User
+from sugar_network.model.feedback import Feedback
+from sugar_network.toolkit.router import Router
+from sugar_network.toolkit import coroutine
class SyncOnlineTest(tests.Test):
@@ -42,14 +42,14 @@ class SyncOnlineTest(tests.Test):
files_root.value = 'master/files'
self.master_volume = Volume('master', [User, Document])
- self.master_server = coroutine.WSGIServer(('127.0.0.1', 9000), Router(MasterCommands('127.0.0.1:9000', self.master_volume)))
+ self.master_server = coroutine.WSGIServer(('127.0.0.1', 9000), Router(MasterRoutes('127.0.0.1:9000', self.master_volume)))
coroutine.spawn(self.master_server.serve_forever)
coroutine.dispatch()
files_root.value = 'slave/files'
self.slave_volume = Volume('slave', [User, Document])
- util.ensure_key('slave/node')
- self.slave_server = coroutine.WSGIServer(('127.0.0.1', 9001), Router(SlaveCommands('slave/node', self.slave_volume)))
+ toolkit.ensure_key('slave/node')
+ self.slave_server = coroutine.WSGIServer(('127.0.0.1', 9001), Router(SlaveRoutes('slave/node', self.slave_volume)))
coroutine.spawn(self.slave_server.serve_forever)
coroutine.dispatch()
diff --git a/tests/units/node/volume.py b/tests/units/node/volume.py
index 15772e1..9a3a113 100755
--- a/tests/units/node/volume.py
+++ b/tests/units/node/volume.py
@@ -9,18 +9,11 @@ from cStringIO import StringIO
from __init__ import tests
-from sugar_network import db
+from sugar_network import db, toolkit, model
from sugar_network.node.volume import diff, merge
from sugar_network.node.stats_node import stats_node_step, Sniffer
-from sugar_network.node.commands import NodeCommands
-from sugar_network.resources.user import User
-from sugar_network.resources.volume import Volume, Resource
-from sugar_network.resources.review import Review
-from sugar_network.resources.context import Context
-from sugar_network.resources.artifact import Artifact
-from sugar_network.resources.feedback import Feedback
-from sugar_network.resources.solution import Solution
-from sugar_network.toolkit import util
+from sugar_network.node.routes import NodeRoutes
+from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, Blob, ACL, route
class VolumeTest(tests.Test):
@@ -28,32 +21,36 @@ 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.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
return value
- volume = Volume('db', [Document])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
- guid1 = call(cp, method='POST', document='document', principal='principal', content={'prop': 'a'})
+ 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', principal='principal', content={'prop': 'b'})
+ guid2 = call(cp, method='POST', document='document', content={'prop': 'b'})
self.utime('db/document/%s/%s' % (guid2[:2], guid2), 2)
- in_seq = util.Sequence([[1, None]])
+ in_seq = toolkit.Sequence([[1, None]])
self.assertEqual([
- {'document': 'document'},
+ {'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': ['public']},
+ 'tags': {'mtime': 1, 'value': []},
},
},
{'guid': guid2,
@@ -62,6 +59,9 @@ class VolumeTest(tests.Test):
'mtime': {'value': 0, 'mtime': 2},
'ctime': {'value': 0, 'mtime': 2},
'prop': {'value': 'b', 'mtime': 2},
+ 'author': {'mtime': 2, 'value': {}},
+ 'layer': {'mtime': 2, 'value': ['public']},
+ 'tags': {'mtime': 2, 'value': []},
},
},
{'commit': [[1, 2]]},
@@ -71,23 +71,23 @@ class VolumeTest(tests.Test):
def test_diff_Partial(self):
- class Document(db.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
return value
- volume = Volume('db', [Document])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
- guid1 = call(cp, method='POST', document='document', principal='principal', content={'prop': 'a'})
+ 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', principal='principal', content={'prop': 'b'})
+ guid2 = call(cp, method='POST', document='document', content={'prop': 'b'})
self.utime('db/document/%s/%s' % (guid2[:2], guid2), 2)
- in_seq = util.Sequence([[1, None]])
+ in_seq = toolkit.Sequence([[1, None]])
patch = diff(volume, in_seq)
- self.assertEqual({'document': 'document'}, next(patch))
+ self.assertEqual({'resource': 'document'}, next(patch))
self.assertEqual(guid1, next(patch)['guid'])
self.assertEqual({'commit': []}, patch.throw(StopIteration()))
try:
@@ -97,7 +97,7 @@ class VolumeTest(tests.Test):
pass
patch = diff(volume, in_seq)
- self.assertEqual({'document': 'document'}, next(patch))
+ 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()))
@@ -109,29 +109,29 @@ class VolumeTest(tests.Test):
def test_diff_Stretch(self):
- class Document(db.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
return value
- volume = Volume('db', [Document])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
- guid1 = call(cp, method='POST', document='document', principal='principal', content={'prop': 'a'})
+ 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', principal='principal', content={'prop': 'b'})
+ guid2 = call(cp, method='POST', document='document', content={'prop': 'b'})
volume['document'].delete(guid2)
- guid3 = call(cp, method='POST', document='document', principal='principal', content={'prop': 'c'})
+ 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', principal='principal', content={'prop': 'd'})
+ guid4 = call(cp, method='POST', document='document', content={'prop': 'd'})
volume['document'].delete(guid4)
- guid5 = call(cp, method='POST', document='document', principal='principal', content={'prop': 'f'})
+ guid5 = call(cp, method='POST', document='document', content={'prop': 'f'})
self.utime('db/document/%s/%s' % (guid5[:2], guid5), 2)
- in_seq = util.Sequence([[1, None]])
+ in_seq = toolkit.Sequence([[1, None]])
patch = diff(volume, in_seq)
- self.assertEqual({'document': 'document'}, patch.send(None))
+ 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'])
@@ -143,7 +143,7 @@ class VolumeTest(tests.Test):
pass
patch = diff(volume, in_seq)
- self.assertEqual({'document': 'document'}, patch.send(None))
+ 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'])
@@ -156,29 +156,29 @@ class VolumeTest(tests.Test):
def test_diff_DoNotStretchContinuesPacket(self):
- class Document(db.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
return value
- volume = Volume('db', [Document])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
- guid1 = call(cp, method='POST', document='document', principal='principal', content={'prop': 'a'})
+ guid1 = call(cp, method='POST', document='document', content={'prop': 'a'})
volume['document'].delete(guid1)
- guid2 = call(cp, method='POST', document='document', principal='principal', content={'prop': 'b'})
+ guid2 = call(cp, method='POST', document='document', content={'prop': 'b'})
volume['document'].delete(guid2)
- guid3 = call(cp, method='POST', document='document', principal='principal', content={'prop': 'c'})
+ 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', principal='principal', content={'prop': 'd'})
+ guid4 = call(cp, method='POST', document='document', content={'prop': 'd'})
volume['document'].delete(guid4)
- guid5 = call(cp, method='POST', document='document', principal='principal', content={'prop': 'f'})
+ guid5 = call(cp, method='POST', document='document', content={'prop': 'f'})
self.utime('db/document/%s/%s' % (guid5[:2], guid5), 2)
- in_seq = util.Sequence([[1, None]])
- patch = diff(volume, in_seq, util.Sequence([[1, 1]]))
- self.assertEqual({'document': 'document'}, patch.send(None))
+ 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))
@@ -190,32 +190,32 @@ class VolumeTest(tests.Test):
def test_diff_TheSameInSeqForAllDocuments(self):
- class Document1(db.Document):
+ class Document1(db.Resource):
pass
- class Document2(db.Document):
+ class Document2(db.Resource):
pass
- class Document3(db.Document):
+ class Document3(db.Resource):
pass
- volume = Volume('db', [Document1, Document2, Document3])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', [Document1, Document2, Document3])
+ cp = NodeRoutes('guid', volume)
- guid3 = call(cp, method='POST', document='document1', principal='principal', content={})
+ 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', principal='principal', content={})
+ 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', principal='principal', content={})
+ guid1 = call(cp, method='POST', document='document3', content={})
self.utime('db/document/%s/%s' % (guid1[:2], guid1), 1)
- in_seq = util.Sequence([[1, None]])
+ in_seq = toolkit.Sequence([[1, None]])
patch = diff(volume, in_seq)
- self.assertEqual({'document': 'document1'}, patch.send(None))
+ self.assertEqual({'resource': 'document1'}, patch.send(None))
self.assertEqual(guid3, patch.send(None)['guid'])
- self.assertEqual({'document': 'document2'}, patch.send(None))
+ self.assertEqual({'resource': 'document2'}, patch.send(None))
self.assertEqual(guid2, patch.send(None)['guid'])
- self.assertEqual({'document': 'document3'}, patch.send(None))
+ self.assertEqual({'resource': 'document3'}, patch.send(None))
self.assertEqual(guid1, patch.send(None)['guid'])
self.assertEqual({'commit': [[1, 3]]}, patch.send(None))
try:
@@ -226,27 +226,27 @@ class VolumeTest(tests.Test):
def test_merge_Create(self):
- class Document1(db.Document):
+ class Document1(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
return value
- class Document2(db.Document):
+ class Document2(db.Resource):
pass
self.touch(('db/seqno', '100'))
- volume = Volume('db', [Document1, Document2])
+ volume = db.Volume('db', [Document1, Document2])
records = [
- {'document': 'document1'},
+ {'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},
}},
- {'document': 'document2'},
+ {'resource': 'document2'},
{'guid': '5', 'diff': {
'guid': {'value': '5', 'mtime': 5.0},
'ctime': {'value': 6, 'mtime': 6.0},
@@ -273,20 +273,20 @@ class VolumeTest(tests.Test):
def test_merge_Update(self):
- class Document(db.Document):
+ class Document(db.Resource):
@db.indexed_property(slot=1)
def prop(self, value):
return value
self.touch(('db/seqno', '100'))
- volume = Volume('db', [Document])
+ 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 = [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {'prop': {'value': '2', 'mtime': 1.0}}},
{'commit': [[1, 1]]},
]
@@ -297,7 +297,7 @@ class VolumeTest(tests.Test):
self.assertEqual(2, os.stat('db/document/1/1/prop').st_mtime)
records = [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {'prop': {'value': '3', 'mtime': 2.0}}},
{'commit': [[2, 2]]},
]
@@ -308,7 +308,7 @@ class VolumeTest(tests.Test):
self.assertEqual(2, os.stat('db/document/1/1/prop').st_mtime)
records = [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {'prop': {'value': '4', 'mtime': 3.0}}},
{'commit': [[3, 3]]},
]
@@ -320,15 +320,15 @@ class VolumeTest(tests.Test):
def test_merge_MultipleCommits(self):
- class Document(db.Document):
+ class Document(db.Resource):
pass
self.touch(('db/seqno', '100'))
- volume = Volume('db', [Document])
+ volume = db.Volume('db', [Document])
def generator():
for i in [
- {'document': 'document'},
+ {'resource': 'document'},
{'commit': [[1, 1]]},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 1.0},
@@ -346,18 +346,18 @@ class VolumeTest(tests.Test):
def test_merge_UpdateReviewStats(self):
stats_node_step.value = 1
- volume = Volume('db', [User, Context, Review, Feedback, Solution, Artifact])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', model.RESOURCES)
+ cp = NodeRoutes('guid', volume)
stats = Sniffer(volume)
- context = call(cp, method='POST', document='context', principal='principal', content={
+ context = call(cp, method='POST', document='context', content={
'guid': 'context',
'type': 'package',
'title': 'title',
'summary': 'summary',
'description': 'description',
})
- artifact = call(cp, method='POST', document='artifact', principal='principal', content={
+ artifact = call(cp, method='POST', document='artifact', content={
'guid': 'artifact',
'type': 'instance',
'context': context,
@@ -366,7 +366,7 @@ class VolumeTest(tests.Test):
})
records = [
- {'document': 'review'},
+ {'resource': 'review'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 1.0},
'ctime': {'value': 1, 'mtime': 1.0},
@@ -374,6 +374,9 @@ class VolumeTest(tests.Test):
'context': {'value': context, 'mtime': 1.0},
'artifact': {'value': artifact, 'mtime': 4.0},
'rating': {'value': 1, 'mtime': 1.0},
+ 'author': {'mtime': 1, 'value': {}},
+ 'layer': {'mtime': 1, 'value': ['public']},
+ 'tags': {'mtime': 1, 'value': []},
}},
{'guid': '2', 'diff': {
'guid': {'value': '2', 'mtime': 2.0},
@@ -381,6 +384,9 @@ class VolumeTest(tests.Test):
'mtime': {'value': 2, 'mtime': 2.0},
'context': {'value': context, 'mtime': 2.0},
'rating': {'value': 2, 'mtime': 2.0},
+ 'author': {'mtime': 2, 'value': {}},
+ 'layer': {'mtime': 2, 'value': ['public']},
+ 'tags': {'mtime': 2, 'value': []},
}},
{'commit': [[1, 2]]},
]
@@ -394,22 +400,22 @@ class VolumeTest(tests.Test):
def test_diff_Blobs(self):
- class Document(Resource):
+ class Document(db.Resource):
@db.blob_property()
def prop(self, value):
return value
- volume = Volume('db', [User, Document])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
- guid = call(cp, method='POST', document='document', principal='principal', content={})
- call(cp, method='PUT', document='document', guid=guid, principal='principal', content={'prop': 'payload'})
+ 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, util.Sequence([[1, None]]))
+ patch = diff(volume, toolkit.Sequence([[1, None]]))
self.assertEqual(
- {'document': 'document'},
+ {'resource': 'document'},
next(patch))
record = next(patch)
self.assertEqual('payload', ''.join([i for i in record.pop('blob')]))
@@ -426,7 +432,7 @@ class VolumeTest(tests.Test):
self.assertEqual(
{'guid': guid, 'diff': {
'guid': {'value': guid, 'mtime': 0},
- 'author': {'value': {'principal': {'order': 0, 'role': 2}}, 'mtime': 0},
+ 'author': {'mtime': 0, 'value': {}},
'layer': {'mtime': 0, 'value': ['public']},
'tags': {'mtime': 0, 'value': []},
'mtime': {'value': 0, 'mtime': 0},
@@ -434,9 +440,6 @@ class VolumeTest(tests.Test):
}},
next(patch))
self.assertEqual(
- {'document': 'user'},
- next(patch))
- self.assertEqual(
{'commit': [[1, 2]]},
next(patch))
self.assertRaises(StopIteration, next, patch)
@@ -445,25 +448,25 @@ class VolumeTest(tests.Test):
url = 'http://src.sugarlabs.org/robots.txt'
blob = urllib2.urlopen(url).read()
- class Document(Resource):
+ class Document(db.Resource):
@db.blob_property()
def prop(self, value):
return value
- volume = Volume('db', [User, Document])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
- guid = call(cp, method='POST', document='document', principal='principal', content={})
- call(cp, method='PUT', document='document', guid=guid, principal='principal', content={'prop': {'url': url}})
+ 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([
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': guid,
'diff': {
'guid': {'value': guid, 'mtime': 1},
- 'author': {'value': {'principal': {'order': 0, 'role': 2}}, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
'layer': {'mtime': 1, 'value': ['public']},
'tags': {'mtime': 1, 'value': []},
'mtime': {'value': 0, 'mtime': 1},
@@ -471,14 +474,13 @@ class VolumeTest(tests.Test):
'prop': {'url': url, 'mtime': 1},
},
},
- {'document': 'user'},
{'commit': [[1, 2]]},
],
- [i for i in diff(volume, util.Sequence([[1, None]]))])
+ [i for i in diff(volume, toolkit.Sequence([[1, None]]))])
- patch = diff(volume, util.Sequence([[1, None]]), fetch_blobs=True)
+ patch = diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=True)
self.assertEqual(
- {'document': 'document'},
+ {'resource': 'document'},
next(patch))
record = next(patch)
self.assertEqual(blob, ''.join([i for i in record.pop('blob')]))
@@ -488,7 +490,7 @@ class VolumeTest(tests.Test):
self.assertEqual(
{'guid': guid, 'diff': {
'guid': {'value': guid, 'mtime': 1},
- 'author': {'value': {'principal': {'order': 0, 'role': 2}}, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
'layer': {'mtime': 1, 'value': ['public']},
'tags': {'mtime': 1, 'value': []},
'mtime': {'value': 0, 'mtime': 1},
@@ -496,35 +498,32 @@ class VolumeTest(tests.Test):
}},
next(patch))
self.assertEqual(
- {'document': 'user'},
- next(patch))
- self.assertEqual(
{'commit': [[1, 2]]},
next(patch))
self.assertRaises(StopIteration, next, patch)
def test_diff_SkipBrokenBlobUrls(self):
- class Document(Resource):
+ class Document(db.Resource):
@db.blob_property()
def prop(self, value):
return value
- volume = Volume('db', [User, Document])
- cp = NodeCommands('guid', volume)
+ volume = db.Volume('db', [Document])
+ cp = NodeRoutes('guid', volume)
- guid1 = call(cp, method='POST', document='document', principal='principal', content={})
- call(cp, method='PUT', document='document', guid=guid1, principal='principal', content={'prop': {'url': 'http://foo/bar'}})
- guid2 = call(cp, method='POST', document='document', principal='principal', content={})
+ 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([
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': guid1,
'diff': {
'guid': {'value': guid1, 'mtime': 1},
- 'author': {'value': {'principal': {'order': 0, 'role': 2}}, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
'layer': {'mtime': 1, 'value': ['public']},
'tags': {'mtime': 1, 'value': []},
'mtime': {'value': 0, 'mtime': 1},
@@ -535,24 +534,23 @@ class VolumeTest(tests.Test):
{'guid': guid2,
'diff': {
'guid': {'value': guid2, 'mtime': 1},
- 'author': {'value': {'principal': {'order': 0, 'role': 2}}, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
'layer': {'mtime': 1, 'value': ['public']},
'tags': {'mtime': 1, 'value': []},
'mtime': {'value': 0, 'mtime': 1},
'ctime': {'value': 0, 'mtime': 1},
},
},
- {'document': 'user'},
{'commit': [[1, 3]]},
],
- [i for i in diff(volume, util.Sequence([[1, None]]), fetch_blobs=False)])
+ [i for i in diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=False)])
self.assertEqual([
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': guid1,
'diff': {
'guid': {'value': guid1, 'mtime': 1},
- 'author': {'value': {'principal': {'order': 0, 'role': 2}}, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
'layer': {'mtime': 1, 'value': ['public']},
'tags': {'mtime': 1, 'value': []},
'mtime': {'value': 0, 'mtime': 1},
@@ -562,30 +560,29 @@ class VolumeTest(tests.Test):
{'guid': guid2,
'diff': {
'guid': {'value': guid2, 'mtime': 1},
- 'author': {'value': {'principal': {'order': 0, 'role': 2}}, 'mtime': 1},
+ 'author': {'mtime': 1, 'value': {}},
'layer': {'mtime': 1, 'value': ['public']},
'tags': {'mtime': 1, 'value': []},
'mtime': {'value': 0, 'mtime': 1},
'ctime': {'value': 0, 'mtime': 1},
},
},
- {'document': 'user'},
{'commit': [[1, 3]]},
],
- [i for i in diff(volume, util.Sequence([[1, None]]), fetch_blobs=True)])
+ [i for i in diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=True)])
def test_merge_Blobs(self):
- class Document(db.Document):
+ class Document(db.Resource):
@db.blob_property()
def prop(self, value):
return value
- volume = Volume('db', [Document])
+ volume = db.Volume('db', [Document])
merge(volume, [
- {'document': 'document'},
+ {'resource': 'document'},
{'guid': '1', 'diff': {
'guid': {'value': '1', 'mtime': 1.0},
'ctime': {'value': 2, 'mtime': 2.0},
@@ -611,16 +608,16 @@ class VolumeTest(tests.Test):
def test_diff_ByLayers(self):
- class Context(Resource):
+ class Context(db.Resource):
pass
- class Implementation(Resource):
+ class Implementation(db.Resource):
pass
- class Review(Resource):
+ class Review(db.Resource):
pass
- volume = Volume('db', [Context, Implementation, Review])
+ volume = db.Volume('db', [Context, Implementation, 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['implementation'].create({'guid': '2', 'ctime': 2, 'mtime': 2, 'layer': 'layer2'})
@@ -633,56 +630,65 @@ class VolumeTest(tests.Test):
self.utime('db', 0)
self.assertEqual(sorted([
- {'document': 'context'},
+ {'resource': 'context'},
{'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
{'guid': '1', 'diff': {'tags': {'value': '1', 'mtime': 0}}},
- {'document': 'implementation'},
+ {'resource': 'implementation'},
{'guid': '2', 'diff': {'tags': {'value': '2', 'mtime': 0}}},
- {'document': 'review'},
+ {'resource': 'review'},
{'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
{'commit': [[5, 8]]},
]),
- sorted([i for i in diff(volume, util.Sequence([[5, None]]))]))
+ sorted([i for i in diff(volume, toolkit.Sequence([[5, None]]))]))
self.assertEqual(sorted([
- {'document': 'context'},
+ {'resource': 'context'},
{'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
{'guid': '1', 'diff': {'tags': {'value': '1', 'mtime': 0}}},
- {'document': 'implementation'},
- {'document': 'review'},
+ {'resource': 'implementation'},
+ {'resource': 'review'},
{'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
{'commit': [[5, 8]]},
]),
- sorted([i for i in diff(volume, util.Sequence([[5, None]]), layer='layer1')]))
+ sorted([i for i in diff(volume, toolkit.Sequence([[5, None]]), layer='layer1')]))
self.assertEqual(sorted([
- {'document': 'context'},
+ {'resource': 'context'},
{'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
- {'document': 'implementation'},
+ {'resource': 'implementation'},
{'guid': '2', 'diff': {'tags': {'value': '2', 'mtime': 0}}},
- {'document': 'review'},
+ {'resource': 'review'},
{'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
{'commit': [[5, 8]]},
]),
- sorted([i for i in diff(volume, util.Sequence([[5, None]]), layer='layer2')]))
+ sorted([i for i in diff(volume, toolkit.Sequence([[5, None]]), layer='layer2')]))
self.assertEqual(sorted([
- {'document': 'context'},
+ {'resource': 'context'},
{'guid': '0', 'diff': {'tags': {'value': '0', 'mtime': 0}}},
- {'document': 'implementation'},
- {'document': 'review'},
+ {'resource': 'implementation'},
+ {'resource': 'review'},
{'guid': '3', 'diff': {'tags': {'value': '3', 'mtime': 0}}},
{'commit': [[5, 8]]},
]),
- sorted([i for i in diff(volume, util.Sequence([[5, None]]), layer='foo')]))
-
-
-def call(cp, principal=None, content=None, **kwargs):
- request = db.Request(**kwargs)
- request.principal = principal
+ 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)
+ request.update(kwargs)
+ request.cmd = cmd
request.content = content
request.environ = {'HTTP_HOST': '127.0.0.1'}
- return cp.call(request, db.Response())
+ router = Router(routes)
+ return router.call(request, Response())
if __name__ == '__main__':
diff --git a/tests/units/resources/volume.py b/tests/units/resources/volume.py
deleted file mode 100755
index 687f9c8..0000000
--- a/tests/units/resources/volume.py
+++ /dev/null
@@ -1,444 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import os
-import json
-import time
-from os.path import exists
-
-from __init__ import tests
-
-from sugar_network import db, node
-from sugar_network.resources.volume import Volume, Resource, Commands
-from sugar_network.resources.user import User
-from sugar_network.toolkit import coroutine, util
-
-
-class VolumeTest(tests.Test):
-
- def test_Subscribe(self):
-
- class Document(Resource):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- volume = Volume('db', [Document])
- cp = TestCommands(volume)
- events = []
-
- def read_events():
- for event in cp.subscribe(event='!commit'):
- if not event.strip():
- continue
- assert event.startswith('data: ')
- assert event.endswith('\n\n')
- event = json.loads(event[6:])
- events.append(event)
-
- job = coroutine.spawn(read_events)
- coroutine.dispatch()
- volume['document'].create({'guid': 'guid', 'prop': 'value1'})
- coroutine.dispatch()
- volume['document'].update('guid', {'prop': 'value2'})
- coroutine.dispatch()
- volume['document'].delete('guid')
- coroutine.dispatch()
- volume['document'].commit()
- coroutine.sleep(.5)
- job.kill()
-
- self.assertEqual([
- {'guid': 'guid', 'document': 'document', 'event': 'create'},
- {'guid': 'guid', 'document': 'document', 'event': 'update'},
- {'guid': 'guid', 'event': 'delete', 'document': u'document'},
- ],
- events)
-
- def test_SubscribeWithPong(self):
- volume = Volume('db', [])
- cp = TestCommands(volume)
-
- for event in cp.subscribe(ping=True):
- break
- self.assertEqual('data: {"event": "pong"}\n\n', event)
-
- def __test_SubscribeCondition(self):
-
- class Document(Resource):
-
- @db.indexed_property(slot=1)
- def prop(self, value):
- return value
-
- volume = Volume('db', [Document])
- cp = TestCommands(volume)
- events = []
-
- def read_events():
- for event in cp.subscribe(db.Request(), db.Response(), only_commits=True):
- if not event.strip():
- continue
- assert event.startswith('data: ')
- assert event.endswith('\n\n')
- event = json.loads(event[6:])
- events.append(event)
-
- job = coroutine.spawn(read_events)
- coroutine.dispatch()
- volume['document'].create({'guid': 'guid', 'prop': 'value1'})
- coroutine.dispatch()
- volume['document'].update('guid', {'prop': 'value2'})
- coroutine.dispatch()
- volume['document'].delete('guid')
- coroutine.dispatch()
- volume['document'].commit()
- coroutine.sleep(.5)
- job.kill()
-
- self.assertEqual([
- {'document': 'document', 'event': 'commit'},
- {'document': 'document', 'event': 'commit'},
- {'document': 'document', 'event': 'commit'},
- ],
- events)
-
- def test_Populate(self):
- self.touch(
- ('db/context/1/1/guid', json.dumps({"value": "1"})),
- ('db/context/1/1/ctime', json.dumps({"value": 1})),
- ('db/context/1/1/mtime', json.dumps({"value": 1})),
- ('db/context/1/1/seqno', json.dumps({"value": 0})),
- ('db/context/1/1/type', json.dumps({"value": "activity"})),
- ('db/context/1/1/title', json.dumps({"value": {}})),
- ('db/context/1/1/summary', json.dumps({"value": {}})),
- ('db/context/1/1/description', json.dumps({"value": {}})),
- )
-
- volume = Volume('db')
- cp = TestCommands(volume)
- assert exists('db/context/index')
-
- def test_DefaultAuthor(self):
-
- class Document(Resource):
- pass
-
- volume = Volume('db', [User, Document])
- cp = TestCommands(volume)
-
- guid = call(cp, method='POST', document='document', content={}, principal='user')
- self.assertEqual(
- [{'name': 'user', 'role': 2}],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual(
- {'user': {'role': 2, 'order': 0}},
- volume['document'].get(guid)['author'])
-
- volume['user'].create({'guid': 'user', 'color': '', 'pubkey': '', 'name': 'User'})
-
- guid = call(cp, method='POST', document='document', content={}, principal='user')
- self.assertEqual(
- [{'guid': 'user', 'name': 'User', 'role': 3}],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual(
- {'user': {'name': 'User', 'role': 3, 'order': 0}},
- volume['document'].get(guid)['author'])
-
- def test_FindByAuthor(self):
-
- class Document(Resource):
- pass
-
- volume = Volume('db', [User, Document])
- cp = TestCommands(volume)
-
- volume['user'].create({'guid': 'user1', 'color': '', 'pubkey': '', 'name': 'UserName1'})
- volume['user'].create({'guid': 'user2', 'color': '', 'pubkey': '', 'name': 'User Name2'})
- volume['user'].create({'guid': 'user3', 'color': '', 'pubkey': '', 'name': 'User Name 3'})
-
- guid1 = call(cp, method='POST', document='document', content={}, principal='user1')
- guid2 = call(cp, method='POST', document='document', content={}, principal='user2')
- guid3 = call(cp, method='POST', document='document', content={}, principal='user3')
-
- self.assertEqual(sorted([
- {'guid': guid1},
- ]),
- call(cp, method='GET', document='document', author='UserName1')['result'])
-
- self.assertEqual(sorted([
- {'guid': guid1},
- ]),
- sorted(call(cp, method='GET', document='document', query='author:UserName')['result']))
- self.assertEqual(sorted([
- {'guid': guid1},
- {'guid': guid2},
- {'guid': guid3},
- ]),
- sorted(call(cp, method='GET', document='document', query='author:User')['result']))
- self.assertEqual(sorted([
- {'guid': guid2},
- {'guid': guid3},
- ]),
- sorted(call(cp, method='GET', document='document', query='author:Name')['result']))
-
- def test_PreserveAuthorsOrder(self):
-
- class Document(Resource):
- pass
-
- volume = Volume('db', [User, Document])
- cp = TestCommands(volume)
-
- volume['user'].create({'guid': 'user1', 'color': '', 'pubkey': '', 'name': 'User1'})
- volume['user'].create({'guid': 'user2', 'color': '', 'pubkey': '', 'name': 'User2'})
- volume['user'].create({'guid': 'user3', 'color': '', 'pubkey': '', 'name': 'User3'})
-
- guid = call(cp, method='POST', document='document', content={}, principal='user1')
- call(cp, method='PUT', document='document', guid=guid, cmd='useradd', user='user2', role=0)
- call(cp, method='PUT', document='document', guid=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},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 3, 'order': 0},
- 'user2': {'name': 'User2', 'role': 1, 'order': 1},
- 'user3': {'name': 'User3', 'role': 1, 'order': 2},
- },
- volume['document'].get(guid)['author'])
-
- call(cp, method='PUT', document='document', guid=guid, cmd='userdel', user='user2', principal='user1')
- call(cp, method='PUT', document='document', guid=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},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 3, 'order': 0},
- 'user3': {'name': 'User3', 'role': 1, 'order': 2},
- 'user2': {'name': 'User2', 'role': 1, 'order': 3},
- },
- volume['document'].get(guid)['author'])
-
- call(cp, method='PUT', document='document', guid=guid, cmd='userdel', user='user2', principal='user1')
- call(cp, method='PUT', document='document', guid=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},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 3, 'order': 0},
- 'user3': {'name': 'User3', 'role': 1, 'order': 2},
- 'user2': {'name': 'User2', 'role': 1, 'order': 3},
- },
- volume['document'].get(guid)['author'])
-
- call(cp, method='PUT', document='document', guid=guid, cmd='userdel', user='user3', principal='user1')
- call(cp, method='PUT', document='document', guid=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},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 3, 'order': 0},
- 'user2': {'name': 'User2', 'role': 1, 'order': 3},
- 'user3': {'name': 'User3', 'role': 1, 'order': 4},
- },
- volume['document'].get(guid)['author'])
-
- def test_AddUser(self):
-
- class Document(Resource):
- pass
-
- volume = Volume('db', [User, Document])
- cp = TestCommands(volume)
-
- volume['user'].create({'guid': 'user1', 'color': '', 'pubkey': '', 'name': 'User1'})
- volume['user'].create({'guid': 'user2', 'color': '', 'pubkey': '', 'name': 'User2'})
-
- guid = call(cp, method='POST', document='document', content={}, principal='user1')
- self.assertEqual([
- {'guid': 'user1', 'name': 'User1', 'role': 3},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 3, 'order': 0},
- },
- volume['document'].get(guid)['author'])
-
- call(cp, method='PUT', document='document', guid=guid, cmd='useradd', user='user2', role=2)
- self.assertEqual([
- {'guid': 'user1', 'name': 'User1', 'role': 3},
- {'guid': 'user2', 'name': 'User2', 'role': 3},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 3, 'order': 0},
- 'user2': {'name': 'User2', 'role': 3, 'order': 1},
- },
- volume['document'].get(guid)['author'])
-
- call(cp, method='PUT', document='document', guid=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},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 3, 'order': 0},
- 'user2': {'name': 'User2', 'role': 3, 'order': 1},
- 'User3': {'role': 2, 'order': 2},
- },
- volume['document'].get(guid)['author'])
-
- call(cp, method='PUT', document='document', guid=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},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='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},
- },
- volume['document'].get(guid)['author'])
-
- def test_UpdateAuthor(self):
-
- class Document(Resource):
- pass
-
- volume = Volume('db', [User, Document])
- cp = TestCommands(volume)
-
- volume['user'].create({'guid': 'user1', 'color': '', 'pubkey': '', 'name': 'User1'})
- guid = call(cp, method='POST', document='document', content={}, principal='user1')
-
- call(cp, method='PUT', document='document', guid=guid, cmd='useradd', user='User2', role=0)
- self.assertEqual([
- {'guid': 'user1', 'name': 'User1', 'role': 3},
- {'name': 'User2', 'role': 0},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 3, 'order': 0},
- 'User2': {'role': 0, 'order': 1},
- },
- volume['document'].get(guid)['author'])
-
- call(cp, method='PUT', document='document', guid=guid, cmd='useradd', user='user1', role=0)
- self.assertEqual([
- {'guid': 'user1', 'name': 'User1', 'role': 1},
- {'name': 'User2', 'role': 0},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 1, 'order': 0},
- 'User2': {'role': 0, 'order': 1},
- },
- volume['document'].get(guid)['author'])
-
- call(cp, method='PUT', document='document', guid=guid, cmd='useradd', user='User2', role=2)
- self.assertEqual([
- {'guid': 'user1', 'name': 'User1', 'role': 1},
- {'name': 'User2', 'role': 2},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 1, 'order': 0},
- 'User2': {'role': 2, 'order': 1},
- },
- volume['document'].get(guid)['author'])
-
- def test_DelUser(self):
-
- class Document(Resource):
- pass
-
- volume = Volume('db', [User, Document])
- cp = TestCommands(volume)
-
- volume['user'].create({'guid': 'user1', 'color': '', 'pubkey': '', 'name': 'User1'})
- volume['user'].create({'guid': 'user2', 'color': '', 'pubkey': '', 'name': 'User2'})
- guid = call(cp, method='POST', document='document', content={}, principal='user1')
- call(cp, method='PUT', document='document', guid=guid, cmd='useradd', user='user2')
- call(cp, method='PUT', document='document', guid=guid, cmd='useradd', user='User3')
- self.assertEqual([
- {'guid': 'user1', 'name': 'User1', 'role': 3},
- {'guid': 'user2', 'name': 'User2', 'role': 1},
- {'name': 'User3', 'role': 0},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user1': {'name': 'User1', 'role': 3, 'order': 0},
- 'user2': {'name': 'User2', 'role': 1, 'order': 1},
- 'User3': {'role': 0, 'order': 2},
- },
- volume['document'].get(guid)['author'])
-
- # Do not remove yourself
- self.assertRaises(RuntimeError, call, cp, method='PUT', document='document', guid=guid, cmd='userdel', user='user1', principal='user1')
- self.assertRaises(RuntimeError, call, cp, method='PUT', document='document', guid=guid, cmd='userdel', user='user2', principal='user2')
-
- call(cp, method='PUT', document='document', guid=guid, cmd='userdel', user='user1', principal='user2')
- self.assertEqual([
- {'guid': 'user2', 'name': 'User2', 'role': 1},
- {'name': 'User3', 'role': 0},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user2': {'name': 'User2', 'role': 1, 'order': 1},
- 'User3': {'role': 0, 'order': 2},
- },
- volume['document'].get(guid)['author'])
-
- call(cp, method='PUT', document='document', guid=guid, cmd='userdel', user='User3', principal='user2')
- self.assertEqual([
- {'guid': 'user2', 'name': 'User2', 'role': 1},
- ],
- call(cp, method='GET', document='document', guid=guid, prop='author'))
- self.assertEqual({
- 'user2': {'name': 'User2', 'role': 1, 'order': 1},
- },
- volume['document'].get(guid)['author'])
-
-
-class TestCommands(db.VolumeCommands, Commands):
-
- def __init__(self, volume):
- db.VolumeCommands.__init__(self, volume)
- Commands.__init__(self)
- self.volume.connect(self.broadcast)
-
-
-def call(cp, principal=None, content=None, **kwargs):
- request = db.Request(**kwargs)
- request.principal = principal
- request.content = content
- request.environ = {'HTTP_HOST': '127.0.0.1'}
- request.commands = cp
- return cp.call(request, db.Response())
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/toolkit/__main__.py b/tests/units/toolkit/__main__.py
index 9871e6b..841711e 100644
--- a/tests/units/toolkit/__main__.py
+++ b/tests/units/toolkit/__main__.py
@@ -6,9 +6,10 @@ from http import *
from lsb_release import *
from mountpoints import *
from rrd import *
-from util import *
+from toolkit import *
from options import *
from spec import *
+from router import *
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/toolkit/http.py b/tests/units/toolkit/http.py
index f1fe10e..4117cbc 100755
--- a/tests/units/toolkit/http.py
+++ b/tests/units/toolkit/http.py
@@ -6,8 +6,8 @@ import select
from __init__ import tests
-from sugar_network import db, client as local
-from sugar_network.db import router
+from sugar_network import client as local
+from sugar_network.toolkit.router import route, Router, Request
from sugar_network.toolkit import coroutine, http
@@ -15,18 +15,17 @@ class HTTPTest(tests.Test):
def test_Subscribe(self):
- class CommandsProcessor(db.CommandsProcessor):
+ class CommandsProcessor(object):
events = []
- @router.route('GET', '/')
+ @route('GET', cmd='subscribe')
def subscribe(self, request, response):
- assert request.get('cmd') == 'subscribe'
while CommandsProcessor.events:
- coroutine.sleep(.3)
+ coroutine.sleep(.1)
yield CommandsProcessor.events.pop(0) + '\n'
- self.server = coroutine.WSGIServer(('127.0.0.1', local.ipc_port.value), router.Router(CommandsProcessor()))
+ self.server = coroutine.WSGIServer(('127.0.0.1', local.ipc_port.value), Router(CommandsProcessor()))
coroutine.spawn(self.server.serve_forever)
coroutine.dispatch()
client = http.Client('http://127.0.0.1:%s' % local.ipc_port.value)
@@ -57,29 +56,33 @@ class HTTPTest(tests.Test):
def test_call_ReturnStream(self):
- class Commands(db.CommandsProcessor):
+ class Commands(object):
- @db.volume_command(method='GET', cmd='f1', mime_type='application/json')
+ @route('GET', cmd='f1', mime_type='application/json')
def f1(self):
yield json.dumps('result')
- @db.volume_command(method='GET', cmd='f2', mime_type='foo/bar')
+ @route('GET', cmd='f2', mime_type='foo/bar')
def f2(self):
yield json.dumps('result')
- self.server = coroutine.WSGIServer(('127.0.0.1', local.ipc_port.value), router.Router(Commands()))
+ self.server = coroutine.WSGIServer(('127.0.0.1', local.ipc_port.value), Router(Commands()))
coroutine.spawn(self.server.serve_forever)
coroutine.dispatch()
client = http.Client('http://127.0.0.1:%s' % local.ipc_port.value)
- request = db.Request()
- request['method'] = 'GET'
- request['cmd'] = 'f1'
+ request = Request({
+ 'REQUEST_METHOD': 'GET',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'cmd=f1',
+ })
self.assertEqual('result', client.call(request))
- request = db.Request()
- request['method'] = 'GET'
- request['cmd'] = 'f2'
+ request = Request({
+ 'REQUEST_METHOD': 'GET',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'cmd=f2',
+ })
self.assertEqual('result', json.load(client.call(request)))
diff --git a/tests/units/toolkit/router.py b/tests/units/toolkit/router.py
new file mode 100755
index 0000000..32e26f3
--- /dev/null
+++ b/tests/units/toolkit/router.py
@@ -0,0 +1,1257 @@
+#!/usr/bin/env python
+# sugar-lint: disable
+
+import os
+import json
+from email.utils import formatdate
+from cStringIO import StringIO
+
+from __init__ import tests, src_root
+
+from sugar_network import db
+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
+
+
+class RouterTest(tests.Test):
+
+ def test_routes_Exact(self):
+
+ class Routes(object):
+
+ @route('PROBE')
+ def command_1(self):
+ return 'command_1'
+
+ @route('PROBE', cmd='command_2')
+ def command_2(self):
+ return 'command_2'
+
+ @route('PROBE', ['resource'])
+ def command_3(self):
+ return 'command_3'
+
+ @route('PROBE', ['resource'], cmd='command_4')
+ def command_4(self):
+ return 'command_4'
+
+ @route('PROBE', ['resource', 'guid'])
+ def command_5(self):
+ return 'command_5'
+
+ @route('PROBE', ['resource', 'guid'], cmd='command_6')
+ def command_6(self):
+ return 'command_6'
+
+ @route('PROBE', ['resource', 'guid', 'prop'])
+ def command_7(self):
+ return 'command_7'
+
+ @route('PROBE', ['resource', 'guid', 'prop'], cmd='command_8')
+ def command_8(self):
+ return 'command_8'
+
+ router = Router(Routes())
+ status = []
+
+ self.assertEqual(
+ ['command_1'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': '',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_1')))]), status[-1])
+
+ self.assertEqual(
+ ['command_2'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'cmd=command_2',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_2')))]), status[-1])
+
+ self.assertEqual(
+ ['command_3'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource',
+ 'QUERY_STRING': '',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_3')))]), status[-1])
+
+ self.assertEqual(
+ ['command_4'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource',
+ 'QUERY_STRING': 'cmd=command_4',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_4')))]), status[-1])
+
+ self.assertEqual(
+ ['command_5'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource/guid',
+ 'QUERY_STRING': '',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_5')))]), status[-1])
+
+ self.assertEqual(
+ ['command_6'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource/guid',
+ 'QUERY_STRING': 'cmd=command_6',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_6')))]), status[-1])
+
+ self.assertEqual(
+ ['command_7'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource/guid/prop',
+ 'QUERY_STRING': '',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_7')))]), status[-1])
+
+ self.assertEqual(
+ ['command_8'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource/guid/prop',
+ 'QUERY_STRING': 'cmd=command_8',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_8')))]), status[-1])
+
+ self.assertEqual(
+ ['{"request": "/*/*/*", "error": "Path not found"}'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/*/*/*'}, lambda *args: None)])
+ self.assertEqual(
+ ['{"request": "/*", "error": "Path not found"}'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/*'}, lambda *args: None)])
+ self.assertEqual(
+ ['{"request": "/?cmd=*", "error": "No such operation"}'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/', 'QUERY_STRING': 'cmd=*'}, lambda *args: None)])
+ self.assertEqual(
+ ['{"request": "/", "error": "No such operation"}'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/'}, lambda *args: None)])
+
+ def test_routes_TailWildcards(self):
+
+ class Routes(object):
+
+ @route('PROBE', ['resource', 'guid', None])
+ def command_1(self):
+ return 'command_1'
+
+ @route('PROBE', ['resource', 'guid', None], cmd='command_2')
+ def command_2(self):
+ return 'command_2'
+
+ @route('PROBE', ['resource', None, None])
+ def command_3(self):
+ return 'command_3'
+
+ @route('PROBE', ['resource', None, None], cmd='command_4')
+ def command_4(self):
+ return 'command_4'
+
+ @route('PROBE', [None, None, None])
+ def command_5(self):
+ return 'command_5'
+
+ @route('PROBE', [None, None, None], cmd='command_6')
+ def command_6(self):
+ return 'command_6'
+
+ router = Router(Routes())
+ status = []
+
+ self.assertEqual(
+ ['command_1'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource/guid/*',
+ 'QUERY_STRING': '',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_1')))]), status[-1])
+
+ self.assertEqual(
+ ['command_2'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource/guid/*',
+ 'QUERY_STRING': 'cmd=command_2',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_2')))]), status[-1])
+
+ self.assertEqual(
+ ['command_3'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource/guid2/prop',
+ 'QUERY_STRING': '',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_3')))]), status[-1])
+
+ self.assertEqual(
+ ['command_4'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource/guid2/prop',
+ 'QUERY_STRING': 'cmd=command_4',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_4')))]), status[-1])
+
+ self.assertEqual(
+ ['command_5'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/*/guid/prop',
+ 'QUERY_STRING': '',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_5')))]), status[-1])
+
+ self.assertEqual(
+ ['command_6'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/*/guid/prop',
+ 'QUERY_STRING': 'cmd=command_6',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_6')))]), status[-1])
+
+ self.assertEqual(
+ ['{"request": "/", "error": "Path not found"}'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/'}, lambda *args: None)])
+ self.assertEqual(
+ ['{"request": "/*/*/*?cmd=*", "error": "No such operation"}'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/*/*/*', 'QUERY_STRING': 'cmd=*'}, lambda *args: None)])
+ self.assertEqual(
+ ['{"request": "/*/*/*", "error": "No such operation"}'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/*/*/*'}, lambda *args: None)])
+
+ def test_routes_FreeWildcards(self):
+
+ class Routes(object):
+
+ @route('PROBE', ['resource1', None, 'prop1'])
+ def command_1(self):
+ return 'command_1'
+
+ @route('PROBE', ['resource1', None, 'prop1'], cmd='command_2')
+ def command_2(self):
+ return 'command_2'
+
+ @route('PROBE', [None, None, 'prop2'])
+ def command_3(self):
+ return 'command_3'
+
+ @route('PROBE', [None, None, 'prop2'], cmd='command_4')
+ def command_4(self):
+ return 'command_4'
+
+ router = Router(Routes())
+ status = []
+
+ self.assertEqual(
+ ['command_1'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource1/*/prop1',
+ 'QUERY_STRING': '',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_1')))]), status[-1])
+
+ self.assertEqual(
+ ['command_2'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/resource1/*/prop1',
+ 'QUERY_STRING': 'cmd=command_2',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_2')))]), status[-1])
+
+ self.assertEqual(
+ ['command_3'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/*/*/prop2',
+ 'QUERY_STRING': '',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_3')))]), status[-1])
+
+ self.assertEqual(
+ ['command_4'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/*/*/prop2',
+ 'QUERY_STRING': 'cmd=command_4',
+ }, lambda *args: status.append(args))])
+ self.assertEqual(('200 OK', [('content-length', str(len('command_4')))]), status[-1])
+
+ self.assertEqual(
+ ['{"request": "/*/*/prop3", "error": "Path not found"}'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/*/*/prop3'}, lambda *args: None)])
+ self.assertEqual(
+ ['{"request": "/*/*/prop2", "error": "No such operation"}'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/*/*/prop2'}, lambda *args: None)])
+
+ self.assertEqual(
+ ['{"request": "/", "error": "Path not found"}'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/'}, lambda *args: None)])
+ self.assertEqual(
+ ['{"request": "/*/*/*?cmd=*", "error": "Path not found"}'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/*/*/*', 'QUERY_STRING': 'cmd=*'}, lambda *args: None)])
+ self.assertEqual(
+ ['{"request": "/*/*/prop2", "error": "No such operation"}'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/*/*/prop2'}, lambda *args: None)])
+
+ def test_routes_Fallback(self):
+
+ class Routes(object):
+
+ @fallbackroute()
+ def fallback(self):
+ return 'fallback'
+
+ @fallbackroute('PROBE2')
+ def fallback2(self):
+ return 'fallback2'
+
+ @route('PROBE', ['exists'])
+ def exists(self):
+ return 'exists'
+
+ router = Router(Routes())
+ status = []
+
+ self.assertEqual(
+ ['exists'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/exists'}, lambda *args: None)])
+ self.assertEqual(
+ ['fallback'],
+ [i for i in router({'REQUEST_METHOD': 'PUT', 'PATH_INFO': '/'}, lambda *args: None)])
+ self.assertEqual(
+ ['fallback'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/*'}, lambda *args: None)])
+ self.assertEqual(
+ ['fallback'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/*/*/*'}, lambda *args: None)])
+
+ self.assertEqual(
+ ['fallback2'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE2', 'PATH_INFO': '/'}, lambda *args: None)])
+ self.assertEqual(
+ ['fallback2'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE2', 'PATH_INFO': '/*/*/*'}, lambda *args: None)])
+ self.assertEqual(
+ ['fallback'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE3', 'PATH_INFO': '/*/*/*/*/*'}, lambda *args: None)])
+
+ def test_routes_FallbackForCommands(self):
+
+ class Routes(object):
+
+ @fallbackroute()
+ def fallback(self):
+ return 'fallback'
+
+ @fallbackroute('PROBE1', ['raise', 'fail'])
+ def fallback2(self):
+ return 'fallback2'
+
+ @route('PROBE2', [None, None])
+ def exists(self):
+ return 'exists'
+
+ @route('PROBE3', [None, None], cmd='CMD')
+ def exists2(self):
+ return 'exists2'
+
+ router = Router(Routes())
+
+ self.assertEqual(
+ ['fallback'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE3', 'PATH_INFO': '/raise/fail', 'QUERY_STRING': 'cmd=FOO'}, lambda *args: None)])
+
+ def test_routes_FallbackAndRegularRouteOnTheSameLevel(self):
+
+ class Routes(object):
+
+ @fallbackroute()
+ def fallback(self):
+ return 'fallback'
+
+ @route('PROBE')
+ def exists(self):
+ return 'exists'
+
+ router = Router(Routes())
+ status = []
+
+ self.assertEqual(
+ ['exists'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/'}, lambda *args: None)])
+ self.assertEqual(
+ ['fallback'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/'}, lambda *args: None)])
+
+ def test_routes_CheckFallbacksBeforeWildecards(self):
+
+ class Routes(object):
+
+ @fallbackroute('PROBE', ['static'])
+ def fallback(self):
+ return 'fallback'
+
+ @route('PROBE', [None])
+ def wildcards(self):
+ return 'wildcards'
+
+ router = Router(Routes())
+ status = []
+
+ self.assertEqual(
+ ['fallback'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/static'}, lambda *args: None)])
+ self.assertEqual(
+ ['wildcards'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/foo'}, lambda *args: None)])
+
+ def test_routes_FallbackForTailedPaths(self):
+
+ class Routes(object):
+
+ @fallbackroute('PROBE', ['static'])
+ def fallback(self, request):
+ return '/'.join(request.path)
+
+ router = Router(Routes())
+ status = []
+
+ self.assertEqual(
+ ['static'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/static'}, lambda *args: None)])
+ self.assertEqual(
+ ['static/foo'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/static/foo'}, lambda *args: None)])
+ self.assertEqual(
+ ['static/foo/bar'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/static/foo/bar'}, lambda *args: None)])
+
+ def test_routes_ParentClasses(self):
+ calls = []
+
+ class Parent(object):
+
+ @route('PROBE')
+ def probe(self):
+ return 'probe'
+
+ class Child(Parent):
+ pass
+
+ router = Router(Child())
+
+ self.assertEqual(
+ ['probe'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/'}, lambda *args: None)])
+
+ def test_routes_OverrideInChildClass(self):
+ calls = []
+
+ class Parent(object):
+
+ @route('PROBE')
+ def probe(self):
+ return 'probe-1'
+
+ @route('COMMON')
+ def common(self):
+ return 'common'
+
+ class Child(Parent):
+
+ @route('PROBE')
+ def probe(self):
+ return 'probe-2'
+
+ @route('PARTICULAR')
+ def particular(self):
+ return 'particular'
+
+ router = Router(Child())
+
+ self.assertEqual(
+ ['probe-2'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/'}, lambda *args: None)])
+ self.assertEqual(
+ ['common'],
+ [i for i in router({'REQUEST_METHOD': 'COMMON', 'PATH_INFO': '/'}, lambda *args: None)])
+ self.assertEqual(
+ ['particular'],
+ [i for i in router({'REQUEST_METHOD': 'PARTICULAR', 'PATH_INFO': '/'}, lambda *args: None)])
+
+ def test_routes_Pre(self):
+
+ class Routes(object):
+
+ @route('PROBE')
+ def ok(self, request, response):
+ return request['probe']
+
+ @preroute
+ def preroute(self, op, request):
+ request['probe'] = 'request'
+
+ router = Router(Routes())
+
+ self.assertEqual(
+ ['request'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/'}, lambda *args: None)])
+
+ def test_routes_Post(self):
+ postroutes = []
+
+ class Routes(object):
+
+ @route('OK')
+ def ok(self):
+ return 'ok'
+
+ @route('FAIL')
+ def fail(self, request, response):
+ raise Exception('fail')
+
+ @postroute
+ def postroute(self, request, response, result, exception):
+ postroutes.append((result, str(exception)))
+
+ router = Router(Routes())
+
+ self.assertEqual(
+ ['ok'],
+ [i for i in router({'REQUEST_METHOD': 'OK', 'PATH_INFO': '/'}, lambda *args: None)])
+ self.assertEqual(('ok', 'None'), postroutes[-1])
+
+ self.assertEqual(
+ ['{"request": "/", "error": "fail"}'],
+ [i for i in router({'REQUEST_METHOD': 'FAIL', 'PATH_INFO': '/'}, lambda *args: None)])
+ self.assertEqual((None, 'fail'), postroutes[-1])
+
+ def test_routes_WildcardsAsLastResort(self):
+
+ class Routes(object):
+
+ @route('PROBE', ['exists'])
+ def exists(self):
+ return 'exists'
+
+ @route('PROBE', ['exists', 'deep'])
+ def exists_deep(self):
+ return 'exists/deep'
+
+ @route('GET', [None])
+ def wildcards(self):
+ return '*'
+
+ @route('GET', [None, None])
+ def wildcards_deep(self):
+ return '*/*'
+
+ router = Router(Routes())
+ status = []
+
+ self.assertEqual(
+ ['exists'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/exists'}, lambda *args: None)])
+ self.assertEqual(
+ ['exists/deep'],
+ [i for i in router({'REQUEST_METHOD': 'PROBE', 'PATH_INFO': '/exists/deep'}, lambda *args: None)])
+ self.assertEqual(
+ ['*'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/exists'}, lambda *args: None)])
+ self.assertEqual(
+ ['*/*'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/exists/deep'}, lambda *args: None)])
+ self.assertEqual(
+ ['*'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/foo'}, lambda *args: None)])
+ self.assertEqual(
+ ['*/*'],
+ [i for i in router({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/foo/bar'}, lambda *args: None)])
+
+ def test_Request_Read(self):
+
+ class Stream(object):
+
+ def __init__(self, value):
+ self.pos = 0
+ self.value = value
+
+ def read(self, size):
+ assert self.pos + size <= len(self.value)
+ result = self.value[self.pos:self.pos + size]
+ self.pos += size
+ return result
+
+ request = Request({'PATH_INFO': '/', 'REQUEST_METHOD': 'GET', 'wsgi.input': Stream('123')})
+ request.content_length = len(request.content_stream.value)
+ self.assertEqual('123', request.read())
+ self.assertEqual('', request.read())
+ self.assertEqual('', request.read(10))
+
+ request = Request({'PATH_INFO': '/', 'REQUEST_METHOD': 'GET', 'wsgi.input': Stream('123')})
+ request.content_length = len(request.content_stream.value)
+ self.assertEqual('123', request.read(10))
+
+ request = Request({'PATH_INFO': '/', 'REQUEST_METHOD': 'GET', 'wsgi.input': Stream('123')})
+ request.content_length = len(request.content_stream.value)
+ self.assertEqual('1', request.read(1))
+ self.assertEqual('2', request.read(1))
+ self.assertEqual('3', request.read())
+
+ def test_IntArguments(self):
+
+ class Routes(object):
+
+ @route('PROBE', arguments={'arg': int})
+ def probe(self, arg):
+ return json.dumps(arg)
+
+ router = Router(Routes())
+
+ self.assertEqual(
+ ['null'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['-1'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=-1',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['2'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=1&arg=2',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['0'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['null'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ }, lambda *args: None)])
+
+ def test_BoolArguments(self):
+
+ class Routes(object):
+
+ @route('PROBE', arguments={'arg': bool})
+ def probe(self, arg):
+ return json.dumps(arg)
+
+ router = Router(Routes())
+
+ self.assertEqual(
+ ['null'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['true'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=1',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['true'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=on',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['true'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=true',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['false'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=foo',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['true'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['true'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['null'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ }, lambda *args: None)])
+
+ def test_ListArguments(self):
+
+ class Routes(object):
+
+ @route('PROBE', arguments={'arg': list})
+ def probe(self, arg):
+ return json.dumps(arg)
+
+ router = Router(Routes())
+
+ self.assertEqual(
+ ['null'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['["a1"]'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=a1',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['["a1", "a2"]'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=a1,a2',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['["a1", "a2", "a3"]'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=a1&arg=a2&arg=a3',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['[]'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'arg=',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['null'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ }, lambda *args: None)])
+
+ def test_ArgumentDefaults(self):
+
+ class Routes(object):
+
+ @route('PROBE', arguments={'a1': -1, 'a2': False, 'a3': [None]}, mime_type='application/json')
+ def probe(self, a1, a2, a3):
+ return (a1, a2, a3)
+
+ router = Router(Routes())
+
+ self.assertEqual(
+ ['[-1, false, [null]]'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['[1, true, ["3", "4"]]'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'a1=1&a2=1&a3=3,4',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['[0, true, []]'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': 'a1=&a2=&a3=',
+ }, lambda *args: None)])
+ self.assertEqual(
+ ['[-1, false, [null]]'],
+ [i for i in router({
+ 'REQUEST_METHOD': 'PROBE',
+ 'PATH_INFO': '/',
+ }, lambda *args: None)])
+
+ def test_StreamedResponse(self):
+
+ class CommandsProcessor(object):
+
+ @route('GET')
+ def get_stream(self, response):
+ return StringIO('stream')
+
+ router = Router(CommandsProcessor())
+
+ response = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ },
+ lambda *args: None)
+ self.assertEqual('stream', ''.join([i for i in response]))
+
+ def test_EmptyResponse(self):
+
+ class CommandsProcessor(object):
+
+ @route('GET', [], '1', mime_type='application/octet-stream')
+ def get_binary(self, response):
+ pass
+
+ @route('GET', [], '2', mime_type='application/json')
+ def get_json(self, response):
+ pass
+
+ @route('GET', [], '3')
+ def no_get(self, response):
+ pass
+
+ router = Router(CommandsProcessor())
+
+ response = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ 'QUERY_STRING': 'cmd=1',
+ },
+ lambda *args: None)
+ self.assertEqual('', ''.join([i for i in response]))
+
+ response = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ 'QUERY_STRING': 'cmd=2',
+ },
+ lambda *args: None)
+ self.assertEqual('null', ''.join([i for i in response]))
+
+ response = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ 'QUERY_STRING': 'cmd=3',
+ },
+ lambda *args: None)
+ self.assertEqual('', ''.join([i for i in response]))
+
+ def test_StatusWOResult(self):
+
+ class Status(http.Status):
+ status = '001 Status'
+ headers = {'status-header': 'value'}
+
+ class CommandsProcessor(object):
+
+ @route('GET')
+ def get(self, response):
+ raise Status('Status-Error')
+
+ router = Router(CommandsProcessor())
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ error = json.dumps({'request': '/', 'error': 'Status-Error'})
+ self.assertEqual(error, ''.join([i for i in reply]))
+ self.assertEqual([
+ '001 Status',
+ {'content-length': str(len(error)), 'content-type': 'application/json', 'status-header': 'value'},
+ ],
+ response)
+
+ def test_ErrorInHEAD(self):
+
+ class Status(http.Status):
+ status = '001 Status'
+
+ class CommandsProcessor(object):
+
+ @route('HEAD')
+ def get(self, response):
+ raise Status('Status-Error')
+
+ router = Router(CommandsProcessor())
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'HEAD',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ self.assertEqual('', ''.join([i for i in reply]))
+ self.assertEqual([
+ '001 Status',
+ {'X-SN-error': '"Status-Error"'},
+ ],
+ response)
+
+ def test_StatusPass(self):
+
+ class StatusPass(http.StatusPass):
+ status = '001 StatusPass'
+ headers = {'statuspass-header': 'value'}
+ result = 'result'
+
+ class CommandsProcessor(object):
+
+ @route('GET')
+ def get(self, response):
+ raise StatusPass('Status-Error')
+
+ router = Router(CommandsProcessor())
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ error = ''
+ self.assertEqual(error, ''.join([i for i in reply]))
+ self.assertEqual([
+ '001 StatusPass',
+ {'content-length': str(len(error)), 'statuspass-header': 'value'},
+ ],
+ response)
+
+ def test_BlobsRedirects(self):
+ URL = 'http://sugarlabs.org'
+
+ class CommandsProcessor(object):
+
+ @route('GET')
+ def get(self, response):
+ return Blob(url=URL)
+
+ router = Router(CommandsProcessor())
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ error = ''
+ self.assertEqual(error, ''.join([i for i in reply]))
+ self.assertEqual([
+ '303 See Other',
+ {'content-length': '0', 'location': URL},
+ ],
+ response)
+
+ def test_LastModified(self):
+
+ class CommandsProcessor(object):
+
+ @route('GET')
+ def get(self, request, response):
+ response.last_modified = 10
+ return 'ok'
+
+ router = Router(CommandsProcessor())
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ result = 'ok'
+ self.assertEqual(result, ''.join([i for i in reply]))
+ self.assertEqual([
+ '200 OK',
+ {'last-modified': formatdate(10, localtime=False, usegmt=True), 'content-length': str(len(result))},
+ ],
+ response)
+
+ def test_IfModifiedSince(self):
+
+ class CommandsProcessor(object):
+
+ @route('GET')
+ def get(self, request):
+ if not request.if_modified_since or request.if_modified_since >= 10:
+ return 'ok'
+ else:
+ raise http.NotModified()
+
+ router = Router(CommandsProcessor())
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ result = 'ok'
+ self.assertEqual(result, ''.join([i for i in reply]))
+ self.assertEqual([
+ '200 OK',
+ {'content-length': str(len(result))},
+ ],
+ response)
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ 'HTTP_IF_MODIFIED_SINCE': formatdate(11, localtime=False, usegmt=True),
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ result = 'ok'
+ self.assertEqual(result, ''.join([i for i in reply]))
+ self.assertEqual([
+ '200 OK',
+ {'content-length': str(len(result))},
+ ],
+ response)
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ 'HTTP_IF_MODIFIED_SINCE': formatdate(9, localtime=False, usegmt=True),
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ result = ''
+ self.assertEqual(result, ''.join([i for i in reply]))
+ self.assertEqual([
+ '304 Not Modified',
+ {'content-length': str(len(result))},
+ ],
+ response)
+
+ def test_Request_MultipleQueryArguments(self):
+ request = Request({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ 'QUERY_STRING': 'a1=v1&a2=v2&a1=v3&a3=v4&a1=v5&a3=v6',
+ })
+ self.assertEqual(
+ {'a1': ['v1', 'v3', 'v5'], 'a2': 'v2', 'a3': ['v4', 'v6']},
+ dict(request))
+
+ def test_Register_UrlPath(self):
+ self.assertEqual(
+ [],
+ Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': ''}).path)
+ self.assertEqual(
+ [],
+ Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/'}).path)
+ self.assertEqual(
+ ['foo'],
+ Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': 'foo'}).path)
+ self.assertEqual(
+ ['foo', 'bar'],
+ Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': 'foo/bar'}).path)
+ self.assertEqual(
+ ['foo', 'bar'],
+ Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': '/foo/bar/'}).path)
+ self.assertEqual(
+ ['foo', 'bar'],
+ Request({'REQUEST_METHOD': 'GET', 'PATH_INFO': '///foo////bar////'}).path)
+
+ def test_Request_FailOnRelativePaths(self):
+ self.assertRaises(RuntimeError, Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '..'})
+ self.assertRaises(RuntimeError, Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/..'})
+ self.assertRaises(RuntimeError, Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/../'})
+ self.assertRaises(RuntimeError, Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '../bar'})
+ self.assertRaises(RuntimeError, Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/foo/../bar'})
+ self.assertRaises(RuntimeError, Request, {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/foo/..'})
+
+ def test_Request_EmptyArguments(self):
+ request = Request({'QUERY_STRING': 'a&b&c', 'PATH_INFO': '/', 'REQUEST_METHOD': 'GET'})
+ self.assertEqual('', request['a'])
+ self.assertEqual('', request['b'])
+ self.assertEqual('', request['c'])
+
+ def test_Request_UpdateQueryOnSets(self):
+ request = Request({'QUERY_STRING': 'a&b=2&c', 'PATH_INFO': '/', 'REQUEST_METHOD': 'GET'})
+ self.assertEqual('a&b=2&c', request.query)
+
+ request['a'] = 'a'
+ self.assertEqual('a=a&c=&b=2', request.query)
+
+ request['b'] = 'b'
+ self.assertEqual('a=a&c=&b=b', request.query)
+
+ request['c'] = 'c'
+ self.assertEqual('a=a&c=c&b=b', request.query)
+
+ def test_parse_accept_language(self):
+ self.assertEqual(
+ ['ru', 'en', 'es'],
+ _parse_accept_language(' ru , en , es'))
+ self.assertEqual(
+ ['ru', 'en', 'es'],
+ _parse_accept_language(' en;q=.4 , ru, es;q=0.1'))
+ self.assertEqual(
+ ['ru', 'en', 'es'],
+ _parse_accept_language('ru;q=1,en;q=1,es;q=0.5'))
+ self.assertEqual(
+ ['ru-ru', 'es-br'],
+ _parse_accept_language('ru-RU,es_BR'))
+
+ def test_JsonpCallback(self):
+
+ class CommandsProcessor(object):
+
+ @route('GET')
+ def get(self, request):
+ return 'ok'
+
+ router = Router(CommandsProcessor())
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ 'QUERY_STRING': 'callback=foo',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ result = 'foo("ok");'
+ self.assertEqual(result, ''.join([i for i in reply]))
+ self.assertEqual([
+ '200 OK',
+ {'content-length': str(len(result))},
+ ],
+ 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('Foo-3', _filename(['foo', 3], 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):
+ self.touch(('blob.data', 'value'))
+
+ class CommandsProcessor(object):
+
+ @route('GET', [], '1')
+ def cmd1(self, request):
+ return Blob(name='foo', blob='blob.data')
+
+ @route('GET', [], cmd='2')
+ def cmd2(self, request):
+ return Blob(filename='foo.bar', blob='blob.data')
+
+ router = Router(CommandsProcessor())
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ 'QUERY_STRING': 'cmd=1',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ result = 'value'
+ self.assertEqual(result, ''.join([i for i in reply]))
+ self.assertEqual([
+ '200 OK',
+ {
+ 'last-modified': formatdate(os.stat('blob.data').st_mtime, localtime=False, usegmt=True),
+ 'content-length': str(len(result)),
+ 'content-type': 'application/octet-stream',
+ 'content-disposition': 'attachment; filename="Foo.obj"',
+ }
+ ],
+ response)
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'GET',
+ 'QUERY_STRING': 'cmd=2',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ result = 'value'
+ self.assertEqual(result, ''.join([i for i in reply]))
+ self.assertEqual([
+ '200 OK',
+ {
+ 'last-modified': formatdate(os.stat('blob.data').st_mtime, localtime=False, usegmt=True),
+ 'content-length': str(len(result)),
+ 'content-type': 'application/octet-stream',
+ 'content-disposition': 'attachment; filename="foo.bar"',
+ }
+ ],
+ response)
+
+ def test_DoNotOverrideContentLengthForHEAD(self):
+
+ class CommandsProcessor(object):
+
+ @route('HEAD', [])
+ def head(self, request, response):
+ response.content_length = 100
+
+ router = Router(CommandsProcessor())
+
+ response = []
+ reply = router({
+ 'PATH_INFO': '/',
+ 'REQUEST_METHOD': 'HEAD',
+ },
+ lambda status, headers: response.extend([status, dict(headers)]))
+ self.assertEqual([], [i for i in reply])
+ self.assertEqual([
+ '200 OK',
+ {'content-length': '100'},
+ ],
+ response)
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/toolkit/util.py b/tests/units/toolkit/toolkit.py
index ada713d..b901583 100755
--- a/tests/units/toolkit/util.py
+++ b/tests/units/toolkit/toolkit.py
@@ -7,8 +7,8 @@ from cStringIO import StringIO
from __init__ import tests
-from sugar_network.toolkit import util
-from sugar_network.toolkit.util import Seqno, Sequence
+from sugar_network import toolkit
+from sugar_network.toolkit import Seqno, Sequence
class UtilTest(tests.Test):
@@ -350,7 +350,7 @@ class UtilTest(tests.Test):
result = []
stream = StringIO(string)
while True:
- line = util.readline(stream)
+ line = toolkit.readline(stream)
if not line:
break
result.append(line)
@@ -364,39 +364,39 @@ class UtilTest(tests.Test):
self.assertEqual([' \n', ' b \n'], readlines(' \n b \n'))
def test_Pool(self):
- stack = util.Pool()
+ stack = toolkit.Pool()
stack.add('a')
stack.add('b')
stack.add('c')
- self.assertEqual(util.Pool.QUEUED, stack.get_state('a'))
- self.assertEqual(util.Pool.QUEUED, stack.get_state('b'))
- self.assertEqual(util.Pool.QUEUED, stack.get_state('c'))
+ self.assertEqual(toolkit.Pool.QUEUED, stack.get_state('a'))
+ self.assertEqual(toolkit.Pool.QUEUED, stack.get_state('b'))
+ self.assertEqual(toolkit.Pool.QUEUED, stack.get_state('c'))
self.assertEqual(
- [('c', util.Pool.ACTIVE), ('b', util.Pool.ACTIVE), ('a', util.Pool.ACTIVE)],
+ [('c', toolkit.Pool.ACTIVE), ('b', toolkit.Pool.ACTIVE), ('a', toolkit.Pool.ACTIVE)],
[(i, stack.get_state(i)) for i in stack])
self.assertEqual(
[],
[i for i in stack])
- self.assertEqual(util.Pool.PASSED, stack.get_state('a'))
- self.assertEqual(util.Pool.PASSED, stack.get_state('b'))
- self.assertEqual(util.Pool.PASSED, stack.get_state('c'))
+ self.assertEqual(toolkit.Pool.PASSED, stack.get_state('a'))
+ self.assertEqual(toolkit.Pool.PASSED, stack.get_state('b'))
+ self.assertEqual(toolkit.Pool.PASSED, stack.get_state('c'))
stack.rewind()
- self.assertEqual(util.Pool.QUEUED, stack.get_state('a'))
- self.assertEqual(util.Pool.QUEUED, stack.get_state('b'))
- self.assertEqual(util.Pool.QUEUED, stack.get_state('c'))
+ self.assertEqual(toolkit.Pool.QUEUED, stack.get_state('a'))
+ self.assertEqual(toolkit.Pool.QUEUED, stack.get_state('b'))
+ self.assertEqual(toolkit.Pool.QUEUED, stack.get_state('c'))
self.assertEqual(
['c', 'b', 'a'],
[i for i in stack])
stack.add('c')
- self.assertEqual(util.Pool.QUEUED, stack.get_state('c'))
+ self.assertEqual(toolkit.Pool.QUEUED, stack.get_state('c'))
self.assertEqual(
- [('c', util.Pool.ACTIVE)],
+ [('c', toolkit.Pool.ACTIVE)],
[(i, stack.get_state(i)) for i in stack])
- self.assertEqual(util.Pool.PASSED, stack.get_state('c'))
+ self.assertEqual(toolkit.Pool.PASSED, stack.get_state('c'))
stack.add('b')
stack.add('a')
@@ -410,17 +410,45 @@ class UtilTest(tests.Test):
[i for i in stack])
stack.add('d')
- self.assertEqual(util.Pool.QUEUED, stack.get_state('d'))
+ self.assertEqual(toolkit.Pool.QUEUED, stack.get_state('d'))
self.assertEqual(
- [('d', util.Pool.ACTIVE)],
+ [('d', toolkit.Pool.ACTIVE)],
[(i, stack.get_state(i)) for i in stack])
- self.assertEqual(util.Pool.PASSED, stack.get_state('d'))
+ self.assertEqual(toolkit.Pool.PASSED, stack.get_state('d'))
stack.rewind()
self.assertEqual(
['d', 'a', 'b', 'c'],
[i for i in stack])
+ def test_gettext(self):
+ # Fallback to default lang
+ toolkit._default_lang = '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_lang = 'en-us'
+ self.assertEqual('right', toolkit.gettext({'a': 'wrong', 'en': 'right'}, 'probe'))
+ self.assertEqual('exact', toolkit.gettext({'a': 'wrong', 'en': 'right', 'probe': 'exact'}, 'probe'))
+
if __name__ == '__main__':
tests.main()