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__.py72
-rw-r--r--tests/units/client/__main__.py3
-rwxr-xr-xtests/units/client/injector.py12
-rwxr-xr-xtests/units/client/journal.py10
-rwxr-xr-xtests/units/client/offline_routes.py560
-rwxr-xr-xtests/units/client/online_routes.py1611
-rwxr-xr-xtests/units/client/routes.py1242
-rwxr-xr-xtests/units/client/server_routes.py226
-rwxr-xr-xtests/units/db/resource.py35
-rwxr-xr-xtests/units/db/routes.py93
-rwxr-xr-xtests/units/db/volume.py51
-rwxr-xr-xtests/units/model/context.py88
-rwxr-xr-xtests/units/model/model.py9
-rwxr-xr-xtests/units/model/post.py1
-rwxr-xr-xtests/units/model/routes.py3
-rwxr-xr-xtests/units/node/master.py8
-rwxr-xr-xtests/units/node/model.py2
-rwxr-xr-xtests/units/node/node.py83
-rwxr-xr-xtests/units/node/slave.py2
-rwxr-xr-xtests/units/toolkit/router.py1
-rwxr-xr-xtests/units/toolkit/toolkit.py6
21 files changed, 1285 insertions, 2833 deletions
diff --git a/tests/__init__.py b/tests/__init__.py
index 1f5118c..386616a 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -22,14 +22,17 @@ coroutine.inject()
from sugar_network.toolkit import http, mountpoints, Option, gbus, i18n, languages, parcel
from sugar_network.toolkit.router import Router, Request
from sugar_network.toolkit.coroutine import this
-#from sugar_network.client import IPCConnection, journal, routes as client_routes
-#from sugar_network.client.routes import ClientRoutes, _Auth
+from sugar_network.client import IPCConnection, journal, routes as client_routes, model as client_model
+from sugar_network.client.injector import Injector
+from sugar_network.client.routes import ClientRoutes, _Auth
from sugar_network import db, client, node, toolkit, model
from sugar_network.model.user import User
from sugar_network.model.context import Context
+from sugar_network.node.model import Context as MasterContext
+from sugar_network.node.model import User as MasterUser
from sugar_network.model.post import Post
from sugar_network.node.master import MasterRoutes
-from sugar_network.node import obs, slave
+from sugar_network.node import obs, slave, master
from requests import adapters
@@ -91,13 +94,12 @@ class Test(unittest.TestCase):
client.api.value = 'http://127.0.0.1:7777'
client.mounts_root.value = None
client.ipc_port.value = 5555
- client.layers.value = None
client.cache_limit.value = 0
client.cache_limit_percent.value = 0
client.cache_lifetime.value = 0
client.keyfile.value = join(root, 'data', UID)
- #client_routes._RECONNECT_TIMEOUT = 0
- #journal._ds_root = tmpdir + '/datastore'
+ client_routes._RECONNECT_TIMEOUT = 0
+ journal._ds_root = tmpdir + '/datastore'
mountpoints._connects.clear()
mountpoints._found.clear()
mountpoints._COMPLETE_MOUNT_TIMEOUT = .1
@@ -114,11 +116,11 @@ class Test(unittest.TestCase):
'sugar_network.model.report',
]
- #if tmp_root is None:
- # self.override(_Auth, 'profile', lambda self: {
- # 'name': 'test',
- # 'pubkey': PUBKEY,
- # })
+ if tmp_root is None:
+ self.override(_Auth, 'profile', lambda self: {
+ 'name': 'test',
+ 'pubkey': PUBKEY,
+ })
os.makedirs('tmp')
@@ -131,6 +133,7 @@ class Test(unittest.TestCase):
this.volume = None
this.call = None
this.broadcast = lambda x: x
+ this.injector = None
def tearDown(self):
self.stop_nodes()
@@ -153,6 +156,11 @@ class Test(unittest.TestCase):
self.assertEqual(0, self.waitpid(pid))
coroutine.shutdown()
+ def stop_master(self):
+ while self.forks:
+ pid = self.forks.pop()
+ self.assertEqual(0, self.waitpid(pid))
+
def waitpid(self, pid, sig=signal.SIGTERM, ignore_status=False):
if pid in self.forks:
self.forks.remove(pid)
@@ -258,7 +266,7 @@ class Test(unittest.TestCase):
def start_master(self, classes=None, routes=MasterRoutes):
if classes is None:
- classes = [User, Context, Post]
+ classes = master.RESOURCES
#self.touch(('master/etc/private/node', file(join(root, 'data', NODE_UID)).read()))
self.node_volume = db.Volume('master', classes)
self.node_routes = routes(volume=self.node_volume)
@@ -272,7 +280,7 @@ class Test(unittest.TestCase):
def fork_master(self, classes=None, routes=MasterRoutes):
if classes is None:
- classes = [User, Context]
+ classes = master.RESOURCES
def node():
volume = db.Volume('master', classes)
@@ -284,12 +292,11 @@ class Test(unittest.TestCase):
return pid
def start_client(self, classes=None, routes=None):
- if classes is None:
- classes = [User, Context]
if routes is None:
routes = ClientRoutes
- volume = db.Volume('client', classes)
- self.client_routes = routes(volume, client.api.value)
+ volume = db.Volume('client', classes or client_model.RESOURCES)
+ self.client_routes = routes(volume)
+ self.client_routes.connect(client.api.value)
self.client = coroutine.WSGIServer(
('127.0.0.1', client.ipc_port.value), Router(self.client_routes))
coroutine.spawn(self.client.serve_forever)
@@ -298,29 +305,34 @@ class Test(unittest.TestCase):
return volume
def start_online_client(self, classes=None):
- if classes is None:
- classes = [User, Context]
- self.start_master(classes)
- volume = db.Volume('client', classes)
- self.client_routes = ClientRoutes(volume, client.api.value)
+ self.fork_master(classes)
+ this.injector = Injector('client/cache')
+ home_volume = db.Volume('client', classes or client_model.RESOURCES)
+ self.client_routes = ClientRoutes(home_volume)
+ self.client_routes.connect(client.api.value)
self.wait_for_events(self.client_routes, event='inline', state='online').wait()
self.client = coroutine.WSGIServer(
('127.0.0.1', client.ipc_port.value), Router(self.client_routes))
coroutine.spawn(self.client.serve_forever)
coroutine.dispatch()
- this.volume = volume
- return volume
+ this.volume = home_volume
+ return home_volume
def start_offline_client(self, resources=None):
- self.home_volume = db.Volume('db', resources or model.RESOURCES)
- self.client_routes = ClientRoutes(self.home_volume)
+ this.injector = Injector('client/cache')
+ home_volume = db.Volume('client', resources or client_model.RESOURCES)
+ self.client_routes = ClientRoutes(home_volume)
server = coroutine.WSGIServer(('127.0.0.1', client.ipc_port.value), Router(self.client_routes))
coroutine.spawn(server.serve_forever)
coroutine.dispatch()
- this.volume = self.home_volume
- return IPCConnection()
-
- def wait_for_events(self, cp, **condition):
+ this.volume = home_volume
+ return home_volume
+
+ def wait_for_events(self, cp=None, **condition):
+ if cp is None:
+ cp = self.client_routes
+ if hasattr(cp, 'inline') and not cp.inline():
+ cp.connect(client.api.value)
trigger = coroutine.AsyncResult()
def waiter(trigger):
diff --git a/tests/units/client/__main__.py b/tests/units/client/__main__.py
index 5d48161..fcc26a6 100644
--- a/tests/units/client/__main__.py
+++ b/tests/units/client/__main__.py
@@ -4,9 +4,6 @@ from __init__ import tests
from journal import *
from routes import *
-from offline_routes import *
-from online_routes import *
-from server_routes import *
from injector import *
from packagekit import *
diff --git a/tests/units/client/injector.py b/tests/units/client/injector.py
index 4b12fe2..ec88975 100755
--- a/tests/units/client/injector.py
+++ b/tests/units/client/injector.py
@@ -12,8 +12,9 @@ from os.path import exists, join, basename
from __init__ import tests
from sugar_network import db, client
-from sugar_network.client import Connection, keyfile, api, packagekit, injector as injector_
+from sugar_network.client import Connection, keyfile, api, packagekit, injector as injector_, model
from sugar_network.client.injector import _PreemptivePool, Injector
+from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import http, lsb_release
@@ -398,7 +399,7 @@ class InjectorTest(tests.Test):
activity_bundle = self.zips(('topdir/activity/activity.info', activity_info))
release = conn.upload(['context'], activity_bundle, cmd='submit', initial=True)
- self.assertRaises(RuntimeError, injector._solve, 'context', 'stable')
+ self.assertRaises(http.ServiceUnavailable, injector._solve, 'context', 'stable')
def test_solve_ReuseCachedSolution(self):
volume = self.start_master()
@@ -514,7 +515,7 @@ class InjectorTest(tests.Test):
self.assertEqual([client.api.value, 'stable', 0], json.load(file('client/solutions/context'))[:-1])
os.unlink('client/solutions/context')
- self.assertRaises(RuntimeError, injector._solve, 'context', 'stable')
+ self.assertRaises(http.ServiceUnavailable, injector._solve, 'context', 'stable')
def test_download_SetExecPermissions(self):
volume = self.start_master()
@@ -575,6 +576,7 @@ class InjectorTest(tests.Test):
],
[i for i in injector.checkin('context')])
+ self.assertEqual(['checkin'], this.volume['context']['context']['pins'])
self.assertEqual(activity_info, file(join('client', 'releases', release, 'activity', 'activity.info')).read())
self.assertEqual([client.api.value, 'stable', 0, {
'context': {
@@ -626,6 +628,7 @@ class InjectorTest(tests.Test):
},
json.load(file('client/checkins')))
self.assertEqual(0, injector._pool._du)
+ self.assertEqual(['checkin'], this.volume['context']['context']['pins'])
assert injector.checkout('context')
assert exists(join('client', 'releases', release))
@@ -633,6 +636,7 @@ class InjectorTest(tests.Test):
},
json.load(file('client/checkins')))
self.assertEqual(len(activity_info), injector._pool._du)
+ self.assertEqual([], this.volume['context']['context']['pins'])
for __ in injector.checkin('context'):
pass
@@ -642,6 +646,7 @@ class InjectorTest(tests.Test):
},
json.load(file('client/checkins')))
self.assertEqual(0, injector._pool._du)
+ self.assertEqual(['checkin'], this.volume['context']['context']['pins'])
assert injector.checkout('context')
assert not injector.checkout('context')
@@ -651,6 +656,7 @@ class InjectorTest(tests.Test):
},
json.load(file('client/checkins')))
self.assertEqual(len(activity_info), injector._pool._du)
+ self.assertEqual([], this.volume['context']['context']['pins'])
def test_checkin_Refresh(self):
volume = self.start_master()
diff --git a/tests/units/client/journal.py b/tests/units/client/journal.py
index 30c67f8..bae636b 100755
--- a/tests/units/client/journal.py
+++ b/tests/units/client/journal.py
@@ -161,10 +161,14 @@ class JournalTest(tests.Test):
request = Request()
request.path = ['journal', 'guid1', 'preview']
response = Response()
+ blob = ds.journal_get_preview(request, response)
self.assertEqual({
- 'mime_type': 'image/png',
- 'blob': '.sugar/default/datastore/gu/guid1/metadata/preview',
- }, ds.journal_get_preview(request, response))
+ 'content-type': 'image/png',
+ },
+ dict(blob))
+ self.assertEqual(
+ '.sugar/default/datastore/gu/guid1/metadata/preview',
+ blob.path)
self.assertEqual(None, response.content_type)
diff --git a/tests/units/client/offline_routes.py b/tests/units/client/offline_routes.py
deleted file mode 100755
index c8ac58c..0000000
--- a/tests/units/client/offline_routes.py
+++ /dev/null
@@ -1,560 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import json
-import hashlib
-from cStringIO import StringIO
-from zipfile import ZipFile
-from os.path import exists
-
-from __init__ import tests, src_root
-
-from sugar_network import client, model
-from sugar_network.client import IPCConnection, releases, packagekit
-from sugar_network.client.routes import ClientRoutes
-from sugar_network.model.user import User
-from sugar_network.model.report import Report
-from sugar_network.toolkit.router import Router
-from sugar_network.toolkit import coroutine, http, lsb_release
-
-
-class OfflineRoutes(tests.Test):
-
- def setUp(self, fork_num=0):
- tests.Test.setUp(self, fork_num)
- self.override(releases, '_activity_id_new', lambda: 'activity_id')
-
- def test_whoami(self):
- ipc = self.start_offline_client()
-
- self.assertEqual(
- {'guid': tests.UID, 'roles': [], 'route': 'offline'},
- ipc.get(cmd='whoami'))
-
- def test_Events(self):
- ipc = self.start_offline_client()
- events = []
-
- def read_events():
- for event in ipc.subscribe(event='!commit'):
- events.append(event)
- job = coroutine.spawn(read_events)
- coroutine.dispatch()
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- ipc.put(['context', guid], {
- 'title': 'title_2',
- })
- ipc.delete(['context', guid])
- coroutine.sleep(.1)
- job.kill()
-
- self.assertEqual([
- {'guid': guid, 'resource': 'context', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'resource': 'context'},
- ],
- events)
-
- def test_Feeds(self):
- ipc = self.start_offline_client()
-
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl1 = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- self.home_volume['release'].update(impl1, {'data': {
- 'spec': {'*-*': {}},
- }})
- impl2 = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '2',
- 'stability': 'stable',
- 'notes': '',
- })
- self.home_volume['release'].update(impl2, {'data': {
- 'spec': {'*-*': {
- 'requires': {
- 'dep1': {},
- 'dep2': {'restrictions': [['1', '2']]},
- 'dep3': {'restrictions': [[None, '2']]},
- 'dep4': {'restrictions': [['3', None]]},
- },
- }},
- }})
-
- self.assertEqual({
- 'releases': [
- {
- 'version': '1',
- 'stability': 'stable',
- 'guid': impl1,
- 'license': ['GPLv3+'],
- 'layer': ['local'],
- 'author': {},
- 'ctime': self.home_volume['release'].get(impl1).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {'spec': {'*-*': {}}},
- },
- {
- 'version': '2',
- 'stability': 'stable',
- 'guid': impl2,
- 'license': ['GPLv3+'],
- 'layer': ['local'],
- 'author': {},
- 'ctime': self.home_volume['release'].get(impl2).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'spec': {'*-*': {
- 'requires': {
- 'dep1': {},
- 'dep2': {'restrictions': [['1', '2']]},
- 'dep3': {'restrictions': [[None, '2']]},
- 'dep4': {'restrictions': [['3', None]]},
- },
- }},
- },
- },
- ],
- },
- ipc.get(['context', context], cmd='feed'))
-
- def test_BLOBs(self):
- ipc = self.start_offline_client()
-
- guid = ipc.post(['context'], {
- 'type': 'package',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- blob = 'logo_blob'
- ipc.request('PUT', ['context', guid, 'logo'], blob)
-
- self.assertEqual(
- blob,
- ipc.request('GET', ['context', guid, 'logo']).content)
- self.assertEqual({
- 'logo': {
- 'url': 'http://127.0.0.1:5555/context/%s/logo' % guid,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'image/png',
- },
- },
- ipc.get(['context', guid], reply=['logo']))
- self.assertEqual([{
- 'logo': {
- 'url': 'http://127.0.0.1:5555/context/%s/logo' % guid,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'image/png',
- },
- }],
- ipc.get(['context'], reply=['logo'])['result'])
-
- self.assertEqual(
- file(src_root + '/sugar_network/static/httpdocs/images/package.png').read(),
- ipc.request('GET', ['context', guid, 'icon']).content)
- self.assertEqual({
- 'icon': {
- 'url': 'http://127.0.0.1:5555/static/images/package.png',
- 'mime_type': 'image/png',
- },
- },
- ipc.get(['context', guid], reply=['icon']))
- self.assertEqual([{
- 'icon': {
- 'url': 'http://127.0.0.1:5555/static/images/package.png',
- 'mime_type': 'image/png',
- },
- }],
- ipc.get(['context'], reply=['icon'])['result'])
-
- def test_favorite(self):
- ipc = self.start_offline_client()
- events = []
-
- def read_events():
- for event in ipc.subscribe(event='!commit'):
- events.append(event)
- coroutine.spawn(read_events)
- coroutine.dispatch()
-
- context1 = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title1',
- 'summary': 'summary',
- 'description': 'description',
- })
- context2 = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title2',
- 'summary': 'summary',
- 'description': 'description',
- })
-
- self.assertEqual(
- sorted([]),
- sorted(ipc.get(['context'], layer='favorite')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='local')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': context1, 'layer': ['local']}, {'guid': context2, 'layer': ['local']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['local']}, ipc.get(['context', context1], reply='layer'))
- self.assertEqual(['local'], ipc.get(['context', context1, 'layer']))
- self.assertEqual({'layer': ['local']}, ipc.get(['context', context2], reply='layer'))
- self.assertEqual(['local'], ipc.get(['context', context2, 'layer']))
-
- del events[:]
- ipc.put(['context', context1], True, cmd='favorite')
- coroutine.sleep(.1)
-
- self.assertEqual(
- {'guid': context1, 'resource': 'context', 'event': 'update'},
- events[-1])
- self.assertEqual(
- sorted([{'guid': context1}]),
- sorted(ipc.get(['context'], layer='favorite')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='local')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': context1, 'layer': ['favorite', 'local']}, {'guid': context2, 'layer': ['local']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['favorite', 'local']}, ipc.get(['context', context1], reply='layer'))
- self.assertEqual(['favorite', 'local'], ipc.get(['context', context1, 'layer']))
- self.assertEqual({'layer': ['local']}, ipc.get(['context', context2], reply='layer'))
- self.assertEqual(['local'], ipc.get(['context', context2, 'layer']))
-
- del events[:]
- ipc.put(['context', context2], True, cmd='favorite')
- coroutine.sleep(.1)
-
- self.assertEqual(
- {'guid': context2, 'resource': 'context', 'event': 'update'},
- events[-1])
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='favorite')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='local')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': context1, 'layer': ['favorite', 'local']}, {'guid': context2, 'layer': ['favorite', 'local']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['favorite', 'local']}, ipc.get(['context', context1], reply='layer'))
- self.assertEqual(['favorite', 'local'], ipc.get(['context', context1, 'layer']))
- self.assertEqual({'layer': ['favorite', 'local']}, ipc.get(['context', context2], reply='layer'))
- self.assertEqual(['favorite', 'local'], ipc.get(['context', context2, 'layer']))
-
- del events[:]
- ipc.put(['context', context1], False, cmd='favorite')
- coroutine.sleep(.1)
-
- self.assertEqual(
- {'guid': context1, 'resource': 'context', 'event': 'update'},
- events[-1])
- self.assertEqual(
- sorted([{'guid': context2}]),
- sorted(ipc.get(['context'], layer='favorite')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='local')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': context1, 'layer': ['local']}, {'guid': context2, 'layer': ['favorite', 'local']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['local']}, ipc.get(['context', context1], reply='layer'))
- self.assertEqual(['local'], ipc.get(['context', context1, 'layer']))
- self.assertEqual({'layer': ['favorite', 'local']}, ipc.get(['context', context2], reply='layer'))
- self.assertEqual(['favorite', 'local'], ipc.get(['context', context2, 'layer']))
-
- def test_launch_Activity(self):
- local = self.start_online_client()
- ipc = IPCConnection()
-
- activity_info = '\n'.join([
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = bundle_id',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ])
- blob = self.zips(['TestActivity/activity/activity.info', activity_info])
- impl = ipc.upload(['release'], StringIO(blob), cmd='submit', initial=True)
-
- ipc.put(['context', 'bundle_id'], True, cmd='clone')
- solution = [{
- 'guid': impl,
- 'context': 'bundle_id',
- 'license': ['Public Domain'],
- 'stability': 'stable',
- 'version': '1',
- 'path': tests.tmpdir + '/client/release/%s/%s/data.blob' % (impl[:2], impl),
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'unpack_size': len(activity_info),
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'application/vnd.olpc-sugar',
- 'spec': {'*-*': {'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
- },
- }]
- assert local['release'].exists(impl)
- self.assertEqual(
- [client.api.value, ['stable'], solution],
- json.load(file('solutions/bu/bundle_id')))
-
- self.node.stop()
- coroutine.sleep(.1)
-
- log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id.log'
- self.assertEqual([
- {'event': 'launch', 'foo': 'bar', 'activity_id': 'activity_id'},
- {'event': 'exec', 'activity_id': 'activity_id'},
- {'event': 'exit', 'activity_id': 'activity_id'},
- ],
- [i for i in ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')])
- assert local['release'].exists(impl)
- self.assertEqual(
- [client.api.value, ['stable'], solution],
- json.load(file('solutions/bu/bundle_id')))
-
- def test_ServiceUnavailableWhileSolving(self):
- ipc = self.start_offline_client()
-
- self.assertEqual([
- {'event': 'failure', 'activity_id': 'activity_id', 'exception': 'ServiceUnavailable', 'error': "Resource 'foo' does not exist in 'context'"},
- ],
- [i for i in ipc.get(['context', 'foo'], cmd='launch')])
-
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.assertEqual([
- {'event': 'launch', 'activity_id': 'activity_id'},
- {'event': 'failure', 'activity_id': 'activity_id', 'exception': 'ServiceUnavailable',
- 'stability': ['stable'],
- 'logs': [
- tests.tmpdir + '/.sugar/default/logs/shell.log',
- tests.tmpdir + '/.sugar/default/logs/sugar-network-client.log',
- ],
- 'error': """\
-Can't find all required implementations:
-- %s -> (problem)
- No known implementations at all""" % context},
- ],
- [i for i in ipc.get(['context', context], cmd='launch')])
-
- impl = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'layer': ['origin'],
- })
- self.home_volume['release'].update(impl, {'data': {
- 'spec': {
- '*-*': {
- 'commands': {'activity': {'exec': 'true'}},
- 'requires': {'dep': {}},
- },
- },
- }})
- self.assertEqual([
- {'event': 'launch', 'activity_id': 'activity_id'},
- {'event': 'failure', 'activity_id': 'activity_id', 'exception': 'ServiceUnavailable',
- 'stability': ['stable'],
- 'logs': [
- tests.tmpdir + '/.sugar/default/logs/shell.log',
- tests.tmpdir + '/.sugar/default/logs/sugar-network-client.log',
- ],
- 'error': """\
-Can't find all required implementations:
-- %s -> 1 (%s)
-- dep -> (problem)
- No known implementations at all""" % (context, impl)},
- ],
- [i for i in ipc.get(['context', context], cmd='launch')])
- assert not exists('solutions/%s/%s' % (context[:2], context))
-
- def test_ServiceUnavailableWhileInstalling(self):
- ipc = self.start_offline_client()
-
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'layer': ['origin'],
- })
- self.home_volume['release'].update(impl, {'data': {
- 'spec': {
- '*-*': {
- 'commands': {'activity': {'exec': 'true'}},
- 'requires': {'dep': {}},
- },
- },
- }})
- ipc.post(['context'], {
- 'guid': 'dep',
- 'type': 'package',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- 'aliases': {
- lsb_release.distributor_id(): {
- 'status': 'success',
- 'binary': [['dep.bin']],
- },
- },
- })
-
- def resolve(names):
- return dict([(i, {'name': i, 'pk_id': i, 'version': '0', 'arch': '*', 'installed': False}) for i in names])
- self.override(packagekit, 'resolve', resolve)
-
- self.assertEqual([
- {'event': 'launch', 'activity_id': 'activity_id'},
- {'event': 'failure', 'activity_id': 'activity_id', 'exception': 'ServiceUnavailable', 'error': 'Installation is not available in offline',
- 'stability': ['stable'],
- 'solution': [
- { 'guid': impl,
- 'context': context,
- 'license': ['GPLv3+'],
- 'stability': 'stable',
- 'version': '1',
- 'layer': ['origin', 'local'],
- 'author': {},
- 'ctime': self.home_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'spec': {'*-*': {'commands': {'activity': {'exec': 'true'}}, 'requires': {'dep': {}}}},
- },
- },
- { 'guid': 'dep',
- 'context': 'dep',
- 'install': [{'arch': '*', 'installed': False, 'name': 'dep.bin', 'pk_id': 'dep.bin', 'version': '0'}],
- 'license': None,
- 'stability': 'packaged',
- 'version': '0',
- },
- ],
- 'logs': [
- tests.tmpdir + '/.sugar/default/logs/shell.log',
- tests.tmpdir + '/.sugar/default/logs/sugar-network-client.log',
- ],
- },
- ],
- [i for i in ipc.get(['context', context], cmd='launch')])
-
- def test_NoAuthors(self):
- ipc = self.start_offline_client()
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.assertEqual(
- {},
- self.home_volume['context'].get(guid)['author'])
- self.assertEqual(
- [],
- ipc.get(['context', guid, 'author']))
-
- def test_HandleDeletes(self):
- ipc = self.start_offline_client()
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
-
- guid_path = 'db/context/%s/%s' % (guid[:2], guid)
- assert exists(guid_path)
-
- ipc.delete(['context', guid])
- self.assertRaises(http.NotFound, ipc.get, ['context', guid])
- assert not exists(guid_path)
-
- def test_SubmitReport(self):
- ipc = self.home_volume = self.start_offline_client()
-
- self.touch(
- ['file1', 'content1'],
- ['file2', 'content2'],
- ['file3', 'content3'],
- )
- events = [i for i in ipc.post(['report'], {'context': 'context', 'error': 'error', 'logs': [
- tests.tmpdir + '/file1',
- tests.tmpdir + '/file2',
- tests.tmpdir + '/file3',
- ]}, cmd='submit')]
- self.assertEqual('done', events[-1]['event'])
- guid = events[-1]['guid']
-
- self.assertEqual({
- 'context': 'context',
- 'error': 'error',
- },
- ipc.get(['report', guid], reply=['context', 'error']))
- zipfile = ZipFile('db/report/%s/%s/data.blob' % (guid[:2], guid))
- self.assertEqual('content1', zipfile.read('file1'))
- self.assertEqual('content2', zipfile.read('file2'))
- self.assertEqual('content3', zipfile.read('file3'))
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/client/online_routes.py b/tests/units/client/online_routes.py
deleted file mode 100755
index 50df2ec..0000000
--- a/tests/units/client/online_routes.py
+++ /dev/null
@@ -1,1611 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import os
-import json
-import time
-import copy
-import shutil
-import zipfile
-import hashlib
-from zipfile import ZipFile
-from cStringIO import StringIO
-from os.path import exists, lexists, basename
-
-from __init__ import tests, src_root
-
-from sugar_network import client, db, model
-from sugar_network.client import IPCConnection, journal, routes, releases
-from sugar_network.toolkit import coroutine, http
-from sugar_network.toolkit.spec import Spec
-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.report import Report
-from sugar_network.model.context import Context
-from sugar_network.model.release import Release
-from sugar_network.model.post import Post
-from sugar_network.toolkit.router import route
-from sugar_network.toolkit import Option
-
-import requests
-
-
-class OnlineRoutes(tests.Test):
-
- def setUp(self, fork_num=0):
- tests.Test.setUp(self, fork_num)
- self.override(releases, '_activity_id_new', lambda: 'activity_id')
-
- def test_whoami(self):
- self.start_online_client()
- ipc = IPCConnection()
-
- self.assertEqual(
- {'guid': tests.UID, 'roles': [], 'route': 'proxy'},
- ipc.get(cmd='whoami'))
-
- def test_Events(self):
- local_volume = self.start_online_client()
- ipc = IPCConnection()
- events = []
-
- def read_events():
- for event in ipc.subscribe(event='!commit'):
- events.append(event)
- coroutine.spawn(read_events)
- coroutine.dispatch()
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- ipc.put(['context', guid], {
- 'title': 'title_2',
- })
- coroutine.sleep(.1)
- ipc.delete(['context', guid])
- coroutine.sleep(.1)
-
- self.assertEqual([
- {'guid': tests.UID, 'resource': 'user', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'resource': 'context'},
- ],
- events)
- del events[:]
-
- guid = self.node_volume['context'].create({
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.node_volume['context'].update(guid, {
- 'title': 'title_2',
- })
- coroutine.sleep(.1)
- self.node_volume['context'].delete(guid)
- coroutine.sleep(.1)
-
- self.assertEqual([
- {'guid': guid, 'resource': 'context', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'resource': 'context'},
- ],
- events)
- del events[:]
-
- guid = local_volume['context'].create({
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- local_volume['context'].update(guid, {
- 'title': 'title_2',
- })
- coroutine.sleep(.1)
- local_volume['context'].delete(guid)
- coroutine.sleep(.1)
-
- self.assertEqual([], events)
-
- self.node.stop()
- coroutine.sleep(.1)
- del events[:]
-
- guid = local_volume['context'].create({
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- local_volume['context'].update(guid, {
- 'title': 'title_2',
- })
- coroutine.sleep(.1)
- local_volume['context'].delete(guid)
- coroutine.sleep(.1)
-
- self.assertEqual([
- {'guid': guid, 'resource': 'context', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'resource': 'context'},
- ],
- events)
- del events[:]
-
- def test_Feeds(self):
- self.start_online_client()
- ipc = IPCConnection()
-
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl1 = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- self.node_volume['release'].update(impl1, {'data': {
- 'spec': {'*-*': {}},
- }})
- impl2 = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '2',
- 'stability': 'stable',
- 'notes': '',
- })
- self.node_volume['release'].update(impl2, {'data': {
- 'spec': {'*-*': {
- 'requires': {
- 'dep1': {},
- 'dep2': {'restrictions': [['1', '2']]},
- 'dep3': {'restrictions': [[None, '2']]},
- 'dep4': {'restrictions': [['3', None]]},
- },
- }},
- 'blob_size': 1,
- 'unpack_size': 2,
- 'mime_type': 'foo',
- }})
-
- self.assertEqual({
- 'releases': [
- {
- 'version': '1',
- 'stability': 'stable',
- 'guid': impl1,
- 'license': ['GPLv3+'],
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl1).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {'spec': {'*-*': {}}},
- },
- {
- 'version': '2',
- 'stability': 'stable',
- 'guid': impl2,
- 'license': ['GPLv3+'],
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl2).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'spec': {'*-*': {
- 'requires': {
- 'dep1': {},
- 'dep2': {'restrictions': [['1', '2']]},
- 'dep3': {'restrictions': [[None, '2']]},
- 'dep4': {'restrictions': [['3', None]]},
- },
- }},
- 'blob_size': 1,
- 'unpack_size': 2,
- 'mime_type': 'foo',
- },
- },
- ],
- },
- ipc.get(['context', context], cmd='feed'))
-
- def test_BLOBs(self):
- self.start_online_client()
- ipc = IPCConnection()
-
- guid = ipc.post(['context'], {
- 'type': 'package',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- blob = 'logo_blob'
- ipc.request('PUT', ['context', guid, 'logo'], blob, headers={'content-type': 'image/png'})
-
- self.assertEqual(
- blob,
- ipc.request('GET', ['context', guid, 'logo']).content)
- self.assertEqual({
- 'logo': {
- 'url': 'http://127.0.0.1:8888/context/%s/logo' % guid,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'image/png',
- },
- },
- ipc.get(['context', guid], reply=['logo']))
- self.assertEqual([{
- 'logo': {
- 'url': 'http://127.0.0.1:8888/context/%s/logo' % guid,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'image/png',
- },
- }],
- ipc.get(['context'], reply=['logo'])['result'])
-
- self.assertEqual(
- file(src_root + '/sugar_network/static/httpdocs/images/package.png').read(),
- ipc.request('GET', ['context', guid, 'icon']).content)
- self.assertEqual({
- 'icon': {
- 'url': 'http://127.0.0.1:8888/static/images/package.png',
- 'mime_type': 'image/png',
- },
- },
- ipc.get(['context', guid], reply=['icon']))
- self.assertEqual([{
- 'icon': {
- 'url': 'http://127.0.0.1:8888/static/images/package.png',
- 'mime_type': 'image/png',
- },
- }],
- ipc.get(['context'], reply=['icon'])['result'])
-
- def test_favorite(self):
- local = self.start_online_client()
- ipc = IPCConnection()
- events = []
-
- def read_events():
- for event in ipc.subscribe(event='!commit'):
- events.append(event)
- coroutine.spawn(read_events)
- coroutine.dispatch()
-
- context1 = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title1',
- 'summary': 'summary',
- 'description': 'description',
- 'layer': ['foo'],
- })
- context2 = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title2',
- 'summary': 'summary',
- 'description': 'description',
- 'layer': ['foo'],
- })
-
- self.assertEqual(
- sorted([]),
- sorted(ipc.get(['context'], layer='favorite')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='foo')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': context1, 'layer': ['foo']}, {'guid': context2, 'layer': ['foo']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['foo']}, ipc.get(['context', context1], reply='layer'))
- self.assertEqual(['foo'], ipc.get(['context', context1, 'layer']))
- self.assertEqual({'layer': ['foo']}, ipc.get(['context', context2], reply='layer'))
- self.assertEqual(['foo'], ipc.get(['context', context2, 'layer']))
- self.assertEqual(
- sorted([]),
- sorted([i['layer'] for i in local['context'].find(reply='layer')[0]]))
-
- del events[:]
- ipc.put(['context', context1], True, cmd='favorite')
- coroutine.sleep(.1)
-
- self.assertEqual([
- {'guid': context1, 'resource': 'context', 'event': 'update'},
- ],
- events)
- self.assertEqual(
- sorted([{'guid': context1}]),
- sorted(ipc.get(['context'], layer='favorite')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='foo')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': context1, 'layer': ['foo', 'favorite']}, {'guid': context2, 'layer': ['foo']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['foo', 'favorite']}, ipc.get(['context', context1], reply='layer'))
- self.assertEqual(['foo', 'favorite'], ipc.get(['context', context1, 'layer']))
- self.assertEqual({'layer': ['foo']}, ipc.get(['context', context2], reply='layer'))
- self.assertEqual(['foo'], ipc.get(['context', context2, 'layer']))
- self.assertEqual(
- sorted([['foo', 'favorite']]),
- sorted([i['layer'] for i in local['context'].find(reply='layer')[0]]))
-
- del events[:]
- ipc.put(['context', context2], True, cmd='favorite')
- coroutine.sleep(.1)
-
- self.assertEqual([
- {'guid': context2, 'resource': 'context', 'event': 'update'},
- ],
- events)
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='favorite')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='foo')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': context1, 'layer': ['foo', 'favorite']}, {'guid': context2, 'layer': ['foo', 'favorite']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['foo', 'favorite']}, ipc.get(['context', context1], reply='layer'))
- self.assertEqual(['foo', 'favorite'], ipc.get(['context', context1, 'layer']))
- self.assertEqual({'layer': ['foo', 'favorite']}, ipc.get(['context', context2], reply='layer'))
- self.assertEqual(['foo', 'favorite'], ipc.get(['context', context2, 'layer']))
- self.assertEqual(
- sorted([(context1, ['foo', 'favorite']), (context2, ['foo', 'favorite'])]),
- sorted([(i.guid, i['layer']) for i in local['context'].find(reply='layer')[0]]))
-
- del events[:]
- ipc.put(['context', context1], False, cmd='favorite')
- coroutine.sleep(.1)
-
- self.assertEqual([
- {'guid': context1, 'resource': 'context', 'event': 'update'},
- ],
- events)
- self.assertEqual(
- sorted([{'guid': context2}]),
- sorted(ipc.get(['context'], layer='favorite')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'], layer='foo')['result']))
- self.assertEqual(
- sorted([{'guid': context1}, {'guid': context2}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': context1, 'layer': ['foo']}, {'guid': context2, 'layer': ['foo', 'favorite']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['foo']}, ipc.get(['context', context1], reply='layer'))
- self.assertEqual(['foo'], ipc.get(['context', context1, 'layer']))
- self.assertEqual({'layer': ['foo', 'favorite']}, ipc.get(['context', context2], reply='layer'))
- self.assertEqual(['foo', 'favorite'], ipc.get(['context', context2, 'layer']))
- self.assertEqual(
- sorted([(context1, ['foo']), (context2, ['foo', 'favorite'])]),
- sorted([(i.guid, i['layer']) for i in local['context'].find(reply='layer')[0]]))
-
- def test_clone_Fails(self):
- self.start_online_client([User, Context, Release])
- conn = IPCConnection()
-
- self.assertEqual([
- {'event': 'failure', 'exception': 'NotFound', 'error': "Resource 'foo' does not exist in 'context'"},
- ],
- [i for i in conn.put(['context', 'foo'], True, cmd='clone')])
-
- context = conn.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
-
- self.assertEqual([
- {'event': 'failure', 'exception': 'NotFound',
- 'stability': ['stable'],
- 'logs': [
- tests.tmpdir + '/.sugar/default/logs/shell.log',
- tests.tmpdir + '/.sugar/default/logs/sugar-network-client.log',
- ],
- 'error': """\
-Can't find all required implementations:
-- %s -> (problem)
- No known implementations at all""" % context},
- ],
- [i for i in conn.put(['context', context], True, cmd='clone')])
-
- assert not exists('solutions/%s/%s' % (context[:2], context))
-
- impl = conn.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- self.node_volume['release'].update(impl, {'data': {
- 'blob_size': 1,
- 'spec': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'echo',
- },
- },
- },
- },
- }})
-
- self.assertEqual([
- {'event': 'failure', 'exception': 'NotFound', 'error': 'BLOB does not exist',
- 'stability': ['stable'],
- 'logs': [
- tests.tmpdir + '/.sugar/default/logs/shell.log',
- tests.tmpdir + '/.sugar/default/logs/sugar-network-client.log',
- ],
- 'solution': [{
- 'guid': impl,
- 'context': context,
- 'license': ['GPLv3+'],
- 'stability': 'stable',
- 'version': '1',
- 'path': tests.tmpdir + '/client/release/%s/%s/data.blob' % (impl[:2], impl),
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'spec': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'echo',
- },
- },
- },
- },
- 'blob_size': 1,
- },
- }],
- },
- ],
- [i for i in conn.put(['context', context], True, cmd='clone')])
- assert not exists('solutions/%s/%s' % (context[:2], context))
-
- def test_clone_Content(self):
- local = self.start_online_client([User, Context, Release])
- ipc = IPCConnection()
- events = []
-
- def read_events():
- for event in ipc.subscribe(event='!commit'):
- events.append(event)
- coroutine.spawn(read_events)
- coroutine.dispatch()
-
- context = ipc.post(['context'], {
- 'type': 'book',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- blob = 'content'
- self.node_volume['release'].update(impl, {'data': {'blob': StringIO(blob), 'foo': 'bar'}})
- clone_path = 'client/context/%s/%s/.clone' % (context[:2], context)
- solution = [{
- 'guid': impl,
- 'context': context,
- 'license': ['GPLv3+'],
- 'version': '1',
- 'stability': 'stable',
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'foo': 'bar',
- 'blob_size': len(blob),
- },
- }]
-
- self.assertEqual([
- {'event': 'ready'},
- ],
- [i for i in ipc.put(['context', context], True, cmd='clone')])
-
- self.assertEqual({
- 'event': 'update',
- 'guid': context,
- 'resource': 'context',
- },
- events[-1])
- self.assertEqual(
- sorted([{'guid': context}]),
- sorted(ipc.get(['context'], layer='clone')['result']))
- self.assertEqual(
- sorted([{'guid': context}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': context, 'layer': ['clone']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['clone']}, ipc.get(['context', context], reply='layer'))
- self.assertEqual(['clone'], ipc.get(['context', context, 'layer']))
- self.assertEqual(
- [(context, ['clone'])],
- [(i.guid, i['layer']) for i in local['context'].find(reply='layer')[0]])
- self.assertEqual({
- 'layer': ['clone'],
- 'type': ['book'],
- 'author': {tests.UID: {'role': 3, 'name': 'test', 'order': 0}},
- 'title': {'en-us': 'title'},
- },
- local['context'].get(context).properties(['layer', 'type', 'author', 'title']))
- self.assertEqual({
- 'context': context,
- 'license': ['GPLv3+'],
- 'version': '1',
- 'stability': 'stable',
- },
- local['release'].get(impl).properties(['context', 'license', 'version', 'stability']))
- blob_path = 'client/release/%s/%s/data.blob' % (impl[:2], impl)
- solution[0]['path'] = tests.tmpdir + '/' + blob_path
- self.assertEqual({
- 'seqno': 5,
- 'blob_size': len(blob),
- 'blob': tests.tmpdir + '/' + blob_path,
- 'mtime': int(os.stat(blob_path[:-5]).st_mtime),
- 'foo': 'bar',
- },
- local['release'].get(impl).meta('data'))
- self.assertEqual('content', file(blob_path).read())
- assert exists(clone_path + '/data.blob')
- self.assertEqual(
- [client.api.value, ['stable'], solution],
- json.load(file('solutions/%s/%s' % (context[:2], context))))
-
- self.assertEqual([
- ],
- [i for i in ipc.put(['context', context], False, cmd='clone')])
-
- self.assertEqual({
- 'event': 'update',
- 'guid': context,
- 'resource': 'context',
- },
- events[-1])
- self.assertEqual(
- sorted([{'guid': context, 'layer': []}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': []}, ipc.get(['context', context], reply='layer'))
- self.assertEqual([], ipc.get(['context', context, 'layer']))
- self.assertEqual({
- 'layer': [],
- 'type': ['book'],
- 'author': {tests.UID: {'role': 3, 'name': 'test', 'order': 0}},
- 'title': {'en-us': 'title'},
- },
- local['context'].get(context).properties(['layer', 'type', 'author', 'title']))
- blob_path = 'client/release/%s/%s/data.blob' % (impl[:2], impl)
- self.assertEqual({
- 'seqno': 5,
- 'blob_size': len(blob),
- 'blob': tests.tmpdir + '/' + blob_path,
- 'mtime': int(os.stat(blob_path[:-5]).st_mtime),
- 'foo': 'bar',
- },
- local['release'].get(impl).meta('data'))
- self.assertEqual('content', file(blob_path).read())
- assert not lexists(clone_path)
- self.assertEqual(
- [client.api.value, ['stable'], solution],
- json.load(file('solutions/%s/%s' % (context[:2], context))))
-
- self.assertEqual([
- {'event': 'ready'},
- ],
- [i for i in ipc.put(['context', context], True, cmd='clone')])
-
- self.assertEqual({
- 'event': 'update',
- 'guid': context,
- 'resource': 'context',
- },
- events[-1])
- self.assertEqual(
- sorted([{'guid': context, 'layer': ['clone']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- assert exists(clone_path + '/data.blob')
- self.assertEqual(
- [client.api.value, ['stable'], solution],
- json.load(file('solutions/%s/%s' % (context[:2], context))))
-
- def test_clone_Activity(self):
- local = self.start_online_client([User, Context, Release])
- ipc = IPCConnection()
- events = []
-
- def read_events():
- for event in ipc.subscribe(event='!commit'):
- events.append(event)
- coroutine.spawn(read_events)
- coroutine.dispatch()
-
- activity_info = '\n'.join([
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = bundle_id',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ])
- blob = self.zips(['TestActivity/activity/activity.info', activity_info])
- impl = ipc.upload(['release'], StringIO(blob), cmd='submit', initial=True)
- clone_path = 'client/context/bu/bundle_id/.clone'
- blob_path = tests.tmpdir + '/client/release/%s/%s/data.blob' % (impl[:2], impl)
- solution = [{
- 'guid': impl,
- 'context': 'bundle_id',
- 'license': ['Public Domain'],
- 'stability': 'stable',
- 'version': '1',
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'unpack_size': len(activity_info),
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'application/vnd.olpc-sugar',
- 'spec': {'*-*': {'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
- },
- }]
- downloaded_solution = copy.deepcopy(solution)
- downloaded_solution[0]['path'] = blob_path
-
- self.assertEqual([
- {'event': 'ready'},
- ],
- [i for i in ipc.put(['context', 'bundle_id'], True, cmd='clone')])
-
- self.assertEqual({
- 'event': 'update',
- 'guid': 'bundle_id',
- 'resource': 'context',
- },
- events[-1])
- self.assertEqual(
- sorted([{'guid': 'bundle_id'}]),
- sorted(ipc.get(['context'], layer='clone')['result']))
- self.assertEqual(
- sorted([{'guid': 'bundle_id'}]),
- sorted(ipc.get(['context'])['result']))
- self.assertEqual(
- sorted([{'guid': 'bundle_id', 'layer': ['clone']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': ['clone']}, ipc.get(['context', 'bundle_id'], reply='layer'))
- self.assertEqual(['clone'], ipc.get(['context', 'bundle_id', 'layer']))
- self.assertEqual({
- 'layer': ['clone'],
- 'type': ['activity'],
- 'author': {tests.UID: {'role': 3, 'name': 'test', 'order': 0}},
- 'title': {'en-us': 'TestActivity'},
- },
- local['context'].get('bundle_id').properties(['layer', 'type', 'author', 'title']))
- self.assertEqual({
- 'context': 'bundle_id',
- 'license': ['Public Domain'],
- 'version': '1',
- 'stability': 'stable',
- },
- local['release'].get(impl).properties(['context', 'license', 'version', 'stability']))
- self.assertEqual({
- 'seqno': 5,
- 'unpack_size': len(activity_info),
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'blob': blob_path,
- 'mtime': int(os.stat(blob_path[:-5]).st_mtime),
- 'mime_type': 'application/vnd.olpc-sugar',
- 'spec': {
- '*-*': {
- 'requires': {},
- 'commands': {'activity': {'exec': 'true'}},
- },
- },
- },
- local['release'].get(impl).meta('data'))
- self.assertEqual(activity_info, file(blob_path + '/activity/activity.info').read())
- assert exists(clone_path + '/data.blob/activity/activity.info')
- self.assertEqual(
- [client.api.value, ['stable'], downloaded_solution],
- json.load(file('solutions/bu/bundle_id')))
-
- self.assertEqual([
- ],
- [i for i in ipc.put(['context', 'bundle_id'], False, cmd='clone')])
-
- self.assertEqual({
- 'event': 'update',
- 'guid': 'bundle_id',
- 'resource': 'context',
- },
- events[-1])
- self.assertEqual(
- sorted([{'guid': 'bundle_id', 'layer': []}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- self.assertEqual({'layer': []}, ipc.get(['context', 'bundle_id'], reply='layer'))
- self.assertEqual([], ipc.get(['context', 'bundle_id', 'layer']))
- self.assertEqual({
- 'layer': [],
- 'type': ['activity'],
- 'author': {tests.UID: {'role': 3, 'name': 'test', 'order': 0}},
- 'title': {'en-us': 'TestActivity'},
- },
- local['context'].get('bundle_id').properties(['layer', 'type', 'author', 'title']))
- self.assertEqual({
- 'seqno': 5,
- 'unpack_size': len(activity_info),
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'blob': blob_path,
- 'mtime': int(os.stat(blob_path[:-5]).st_mtime),
- 'mime_type': 'application/vnd.olpc-sugar',
- 'spec': {
- '*-*': {
- 'requires': {},
- 'commands': {'activity': {'exec': 'true'}},
- },
- },
- },
- local['release'].get(impl).meta('data'))
- self.assertEqual(activity_info, file(blob_path + '/activity/activity.info').read())
- assert not exists(clone_path)
- self.assertEqual(
- [client.api.value, ['stable'], downloaded_solution],
- json.load(file('solutions/bu/bundle_id')))
-
- self.assertEqual([
- {'event': 'ready'},
- ],
- [i for i in ipc.put(['context', 'bundle_id'], True, cmd='clone')])
-
- self.assertEqual({
- 'event': 'update',
- 'guid': 'bundle_id',
- 'resource': 'context',
- },
- events[-1])
- self.assertEqual(
- sorted([{'guid': 'bundle_id', 'layer': ['clone']}]),
- sorted(ipc.get(['context'], reply='layer')['result']))
- assert exists(clone_path + '/data.blob/activity/activity.info')
- self.assertEqual(
- [client.api.value, ['stable'], downloaded_solution],
- json.load(file('solutions/bu/bundle_id')))
-
- def test_clone_ActivityWithStabilityPreferences(self):
- local = self.start_online_client([User, Context, Release])
- ipc = IPCConnection()
-
- activity_info1 = '\n'.join([
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = bundle_id',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license = Public Domain',
- ])
- blob1 = self.zips(['TestActivity/activity/activity.info', activity_info1])
- impl1 = ipc.upload(['release'], StringIO(blob1), cmd='submit', initial=True)
-
- activity_info2 = '\n'.join([
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = bundle_id',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 2',
- 'license = Public Domain',
- 'stability = buggy',
- ])
- blob2 = self.zips(['TestActivity/activity/activity.info', activity_info2])
- impl2 = ipc.upload(['release'], StringIO(blob2), cmd='submit', initial=True)
-
- self.assertEqual(
- 'ready',
- [i for i in ipc.put(['context', 'bundle_id'], True, cmd='clone')][-1]['event'])
-
- coroutine.dispatch()
- self.assertEqual({'layer': ['clone']}, ipc.get(['context', 'bundle_id'], reply='layer'))
- self.assertEqual([impl1], [i.guid for i in local['release'].find()[0]])
- self.assertEqual(impl1, basename(os.readlink('client/context/bu/bundle_id/.clone')))
-
- self.touch(('config', [
- '[stabilities]',
- 'bundle_id = buggy stable',
- ]))
- Option.load(['config'])
-
- self.assertEqual(
- [],
- [i for i in ipc.put(['context', 'bundle_id'], False, cmd='clone')])
- self.assertEqual(
- 'ready',
- [i for i in ipc.put(['context', 'bundle_id'], True, cmd='clone')][-1]['event'])
-
- coroutine.dispatch()
- self.assertEqual({'layer': ['clone']}, ipc.get(['context', 'bundle_id'], reply='layer'))
- self.assertEqual([impl1, impl2], [i.guid for i in local['release'].find()[0]])
- self.assertEqual(impl2, basename(os.readlink('client/context/bu/bundle_id/.clone')))
-
- def test_clone_Head(self):
- local = self.start_online_client([User, Context, Release])
- ipc = IPCConnection()
-
- activity_info = '\n'.join([
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = bundle_id',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license = Public Domain',
- ])
- blob = self.zips(['TestActivity/activity/activity.info', activity_info])
- impl = ipc.upload(['release'], StringIO(blob), cmd='submit', initial=True)
- blob_path = 'master/release/%s/%s/data.blob' % (impl[:2], impl)
-
- self.assertEqual({
- 'guid': impl,
- 'license': ['Public Domain'],
- 'stability': 'stable',
- 'version': '1',
- 'context': 'bundle_id',
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'application/vnd.olpc-sugar',
- 'spec': {'*-*': {'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
- 'unpack_size': len(activity_info),
- },
- },
- ipc.head(['context', 'bundle_id'], cmd='clone'))
-
- self.assertEqual(
- 'ready',
- [i for i in ipc.put(['context', 'bundle_id'], True, cmd='clone')][-1]['event'])
- blob_path = tests.tmpdir + '/client/release/%s/%s/data.blob' % (impl[:2], impl)
-
- self.assertEqual({
- 'guid': impl,
- 'license': ['Public Domain'],
- 'stability': 'stable',
- 'version': '1',
- 'context': 'bundle_id',
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'blob': blob_path,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'application/vnd.olpc-sugar',
- 'mtime': int(os.stat(blob_path[:-5]).st_mtime),
- 'seqno': 5,
- 'spec': {'*-*': {'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
- 'unpack_size': len(activity_info),
- },
- },
- ipc.head(['context', 'bundle_id'], cmd='clone'))
-
- def test_launch_Activity(self):
- local = self.start_online_client([User, Context, Release])
- ipc = IPCConnection()
-
- activity_info = '\n'.join([
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = bundle_id',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ])
- blob = self.zips(['TestActivity/activity/activity.info', activity_info])
- impl = ipc.upload(['release'], StringIO(blob), cmd='submit', initial=True)
- coroutine.sleep(.1)
-
- solution = [{
- 'guid': impl,
- 'context': 'bundle_id',
- 'license': ['Public Domain'],
- 'stability': 'stable',
- 'version': '1',
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'unpack_size': len(activity_info),
- 'mime_type': 'application/vnd.olpc-sugar',
- 'spec': {'*-*': {'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
- },
- }]
- downloaded_solution = copy.deepcopy(solution)
- downloaded_solution[0]['path'] = tests.tmpdir + '/client/release/%s/%s/data.blob' % (impl[:2], impl)
- log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id.log'
- self.assertEqual([
- {'event': 'launch', 'foo': 'bar', 'activity_id': 'activity_id'},
- {'event': 'exec', 'activity_id': 'activity_id'},
- {'event': 'exit', 'activity_id': 'activity_id'},
- ],
- [i for i in ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')])
- assert local['release'].exists(impl)
- self.assertEqual(
- [client.api.value, ['stable'], downloaded_solution],
- json.load(file('solutions/bu/bundle_id')))
-
- blob = self.zips(['TestActivity/activity/activity.info', [
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = bundle_id',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 2',
- 'license=Public Domain',
- ]])
- impl = ipc.upload(['release'], StringIO(blob), cmd='submit')
- coroutine.sleep(.1)
-
- shutil.rmtree('solutions')
- solution = [{
- 'guid': impl,
- 'context': 'bundle_id',
- 'license': ['Public Domain'],
- 'stability': 'stable',
- 'version': '2',
- 'path': tests.tmpdir + '/client/release/%s/%s/data.blob' % (impl[:2], impl),
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'unpack_size': len(activity_info),
- 'mime_type': 'application/vnd.olpc-sugar',
- 'spec': {'*-*': {'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
- },
- }]
- log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id_1.log'
- self.assertEqual([
- {'event': 'launch', 'foo': 'bar', 'activity_id': 'activity_id'},
- {'event': 'exec', 'activity_id': 'activity_id'},
- {'event': 'exit', 'activity_id': 'activity_id'},
- ],
- [i for i in ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')])
- assert local['release'].exists(impl)
- self.assertEqual(
- [client.api.value, ['stable'], solution],
- json.load(file('solutions/bu/bundle_id')))
-
- self.node.stop()
- coroutine.sleep(.1)
-
- log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id_2.log'
- self.assertEqual([
- {'event': 'launch', 'foo': 'bar', 'activity_id': 'activity_id'},
- {'event': 'exec', 'activity_id': 'activity_id'},
- {'event': 'exit', 'activity_id': 'activity_id'},
- ],
- [i for i in ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')])
- assert local['release'].exists(impl)
- self.assertEqual(
- [client.api.value, ['stable'], solution],
- json.load(file('solutions/bu/bundle_id')))
-
- shutil.rmtree('solutions')
- log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id_3.log'
- self.assertEqual([
- {'event': 'launch', 'foo': 'bar', 'activity_id': 'activity_id'},
- {'event': 'exec', 'activity_id': 'activity_id'},
- {'event': 'exit', 'activity_id': 'activity_id'},
- ],
- [i for i in ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')])
- assert local['release'].exists(impl)
- self.assertEqual(
- [client.api.value, ['stable'], solution],
- json.load(file('solutions/bu/bundle_id')))
-
- def test_launch_Fails(self):
- local = self.start_online_client([User, Context, Release])
- ipc = IPCConnection()
-
- self.assertEqual([
- {'event': 'failure', 'activity_id': 'activity_id', 'exception': 'NotFound', 'error': "Resource 'foo' does not exist in 'context'"},
- ],
- [i for i in ipc.get(['context', 'foo'], cmd='launch')])
-
- ipc.post(['context'], {
- 'guid': 'bundle_id',
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.assertEqual([
- {'event': 'launch', 'activity_id': 'activity_id', 'foo': 'bar', 'activity_id': 'activity_id'},
- {'event': 'failure', 'activity_id': 'activity_id', 'exception': 'NotFound',
- 'stability': ['stable'],
- 'logs': [
- tests.tmpdir + '/.sugar/default/logs/shell.log',
- tests.tmpdir + '/.sugar/default/logs/sugar-network-client.log',
- ],
- 'error': """\
-Can't find all required implementations:
-- bundle_id -> (problem)
- No known implementations at all"""},
- ],
- [i for i in ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')])
-
- activity_info = '\n'.join([
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = bundle_id',
- 'exec = false',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ])
- blob = self.zips(['TestActivity/activity/activity.info', activity_info])
- impl = ipc.upload(['release'], StringIO(blob), cmd='submit', initial=True)
-
- solution = [{
- 'guid': impl,
- 'context': 'bundle_id',
- 'license': ['Public Domain'],
- 'stability': 'stable',
- 'version': '1',
- 'path': tests.tmpdir + '/client/release/%s/%s/data.blob' % (impl[:2], impl),
- 'layer': ['origin'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'unpack_size': len(activity_info),
- 'mime_type': 'application/vnd.olpc-sugar',
- 'spec': {'*-*': {'commands': {'activity': {'exec': 'false'}}, 'requires': {}}},
- },
- }]
- self.assertEqual([
- {'event': 'launch', 'foo': 'bar', 'activity_id': 'activity_id'},
- {'event': 'exec', 'activity_id': 'activity_id'},
- {'event': 'failure', 'activity_id': 'activity_id', 'exception': 'RuntimeError', 'error': 'Process exited with 1 status',
- 'stability': ['stable'],
- 'args': ['false', '-b', 'bundle_id', '-a', 'activity_id'],
- 'solution': solution,
- 'logs': [
- tests.tmpdir + '/.sugar/default/logs/shell.log',
- tests.tmpdir + '/.sugar/default/logs/sugar-network-client.log',
- tests.tmpdir + '/.sugar/default/logs/bundle_id.log',
- ]},
- ],
- [i for i in ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')])
- assert local['release'].exists(impl)
- self.assertEqual(
- [client.api.value, ['stable'], solution],
- json.load(file('solutions/bu/bundle_id')))
-
- def test_InvalidateSolutions(self):
- self.start_online_client()
- ipc = IPCConnection()
- self.assertNotEqual(None, self.client_routes._node_mtime)
-
- mtime = self.client_routes._node_mtime
- coroutine.sleep(1.1)
-
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- assert self.client_routes._node_mtime == mtime
-
- coroutine.sleep(1.1)
-
- impl1 = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- self.node_volume['release'].update(impl1, {'data': {
- 'spec': {'*-*': {}},
- }})
- assert self.client_routes._node_mtime > mtime
-
- mtime = self.client_routes._node_mtime
- coroutine.sleep(1.1)
-
- impl2 = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '2',
- 'stability': 'stable',
- 'notes': '',
- })
- self.node_volume['release'].update(impl2, {'data': {
- 'spec': {'*-*': {
- 'requires': {
- 'dep1': {},
- 'dep2': {'restrictions': [['1', '2']]},
- 'dep3': {'restrictions': [[None, '2']]},
- 'dep4': {'restrictions': [['3', None]]},
- },
- }},
- }})
- assert self.client_routes._node_mtime > mtime
-
- def test_NoNeedlessRemoteRequests(self):
- home_volume = self.start_online_client()
- ipc = IPCConnection()
-
- guid = ipc.post(['context'], {
- 'type': 'book',
- 'title': 'remote',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.assertEqual(
- {'title': 'remote'},
- ipc.get(['context', guid], reply=['title']))
-
- home_volume['context'].create({
- 'guid': guid,
- 'type': 'activity',
- 'title': 'local',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.assertEqual(
- {'title': 'local'},
- ipc.get(['context', guid], reply=['title']))
-
- def test_RestrictLayers(self):
- self.start_online_client([User, Context, Release])
- ipc = IPCConnection()
-
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- 'layer': 'public',
- })
- impl = ipc.post(['release'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- 'layer': 'public',
- })
- self.node_volume['release'].update(impl, {'data': {
- 'spec': {'*-*': {}},
- }})
-
- self.assertEqual(
- [{'guid': context, 'layer': ['public']}],
- ipc.get(['context'], reply=['guid', 'layer'])['result'])
- self.assertEqual(
- [],
- ipc.get(['context'], reply=['guid', 'layer'], layer='foo')['result'])
- self.assertEqual(
- [{'guid': context, 'layer': ['public']}],
- ipc.get(['context'], reply=['guid', 'layer'], layer='public')['result'])
-
- self.assertEqual(
- [{'guid': impl, 'layer': ['origin', 'public']}],
- ipc.get(['release'], reply=['guid', 'layer'])['result'])
- self.assertEqual(
- [],
- ipc.get(['release'], reply=['guid', 'layer'], layer='foo')['result'])
- self.assertEqual(
- [{'guid': impl, 'layer': ['origin', 'public']}],
- ipc.get(['release'], reply=['guid', 'layer'], layer='public')['result'])
-
- self.assertEqual({
- 'releases': [{
- 'stability': 'stable',
- 'guid': impl,
- 'version': '1',
- 'license': ['GPLv3+'],
- 'layer': ['origin', 'public'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {'spec': {'*-*': {}}},
- }],
- },
- ipc.get(['context', context], cmd='feed'))
- self.assertEqual({
- 'releases': [],
- },
- ipc.get(['context', context], cmd='feed', layer='foo'))
- self.assertEqual({
- 'releases': [{
- 'stability': 'stable',
- 'guid': impl,
- 'version': '1',
- 'license': ['GPLv3+'],
- 'layer': ['origin', 'public'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {'spec': {'*-*': {}}},
- }],
- },
- ipc.get(['context', context], cmd='feed', layer='public'))
-
- client.layers.value = ['foo', 'bar']
-
- self.assertEqual(
- [],
- ipc.get(['context'], reply=['guid', 'layer'])['result'])
- self.assertEqual(
- [],
- ipc.get(['context'], reply=['guid', 'layer'], layer='foo')['result'])
- self.assertEqual(
- [{'guid': context, 'layer': ['public']}],
- ipc.get(['context'], reply=['guid', 'layer'], layer='public')['result'])
-
- self.assertEqual(
- [],
- ipc.get(['release'], reply=['guid', 'layer'])['result'])
- self.assertEqual(
- [],
- ipc.get(['release'], reply=['guid', 'layer'], layer='foo')['result'])
- self.assertEqual(
- [{'guid': impl, 'layer': ['origin', 'public']}],
- ipc.get(['release'], reply=['guid', 'layer'], layer='public')['result'])
-
- self.assertEqual({
- 'releases': [],
- },
- ipc.get(['context', context], cmd='feed'))
- self.assertEqual({
- 'releases': [],
- },
- ipc.get(['context', context], cmd='feed', layer='foo'))
- self.assertEqual({
- 'releases': [{
- 'stability': 'stable',
- 'guid': impl,
- 'version': '1',
- 'license': ['GPLv3+'],
- 'layer': ['origin', 'public'],
- 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}},
- 'ctime': self.node_volume['release'].get(impl).ctime,
- 'notes': {'en-us': ''},
- 'tags': [],
- 'data': {'spec': {'*-*': {}}},
- }],
- },
- ipc.get(['context', context], cmd='feed', layer='public'))
-
- def test_Redirects(self):
-
- class Document(Resource):
-
- @db.blob_property()
- def blob1(self, value):
- raise http.Redirect(prefix + 'blob2')
-
- @db.blob_property()
- def blob3(self, value):
- raise http.Redirect(client.api.value + prefix + 'blob4')
-
- self.start_online_client([User, Document])
- ipc = IPCConnection()
- guid = ipc.post(['document'], {})
- prefix = '/document/' + guid + '/'
-
- response = requests.request('GET', client.api.value + prefix + 'blob1', allow_redirects=False)
- self.assertEqual(303, response.status_code)
- self.assertEqual(prefix + 'blob2', response.headers['Location'])
-
- response = requests.request('GET', client.api.value + prefix + 'blob3', allow_redirects=False)
- self.assertEqual(303, response.status_code)
- self.assertEqual(client.api.value + prefix + 'blob4', response.headers['Location'])
-
- def test_DoNotSwitchToOfflineOnRedirectFails(self):
-
- class Document(Resource):
-
- @db.blob_property()
- def blob1(self, value):
- raise http.Redirect(prefix + '/blob2')
-
- @db.blob_property()
- def blob2(self, value):
- raise http._ConnectionError()
-
- local_volume = self.start_online_client([User, Document])
- ipc = IPCConnection()
- guid = ipc.post(['document'], {})
- prefix = client.api.value + '/document/' + guid + '/'
- local_volume['document'].create({'guid': guid})
-
- trigger = self.wait_for_events(ipc, event='inline', state='connecting')
- try:
- ipc.get(['document', guid, 'blob1'])
- except Exception:
- pass
- assert trigger.wait(.1) is None
-
- trigger = self.wait_for_events(ipc, event='inline', state='connecting')
- try:
- ipc.get(['document', guid, 'blob2'])
- except Exception:
- pass
- assert trigger.wait(.1) is not None
-
- def test_ContentDisposition(self):
- self.start_online_client([User, Context, Release, Post])
- ipc = IPCConnection()
-
- post = ipc.post(['post'], {
- 'type': 'object',
- 'context': 'context',
- 'title': 'title',
- 'message': '',
- })
- ipc.request('PUT', ['post', post, 'data'], 'blob', headers={'Content-Type': 'image/png'})
-
- response = ipc.request('GET', ['post', post, 'data'])
- self.assertEqual(
- 'attachment; filename="Title.png"',
- response.headers.get('Content-Disposition'))
-
- def test_FallbackToLocalSNOnRemoteTransportFails(self):
-
- class LocalRoutes(routes._LocalRoutes):
-
- @route('GET', cmd='sleep')
- def sleep(self):
- return 'local'
-
- @route('GET', cmd='yield_raw_and_sleep',
- mime_type='application/octet-stream')
- def yield_raw_and_sleep(self):
- yield 'local'
-
- @route('GET', cmd='yield_json_and_sleep',
- mime_type='application/json')
- def yield_json_and_sleep(self):
- yield '"local"'
-
- self.override(routes, '_LocalRoutes', LocalRoutes)
- home_volume = self.start_client()
- ipc = IPCConnection()
-
- 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"
-
- @route('GET', cmd='yield_json_and_sleep',
- mime_type='application/json')
- def yield_json_and_sleep(self):
- yield '"'
- yield 'r'
- coroutine.sleep(1)
- yield 'emote"'
-
- node_pid = self.fork_master([User], NodeRoutes)
- self.client_routes._remote_connect()
- self.wait_for_events(ipc, event='inline', state='online').wait()
-
- ts = time.time()
- 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 >= 2
-
- def kill():
- coroutine.sleep(.5)
- self.waitpid(node_pid)
-
- coroutine.spawn(kill)
- self.assertEqual('local', ipc.get(cmd='sleep'))
- assert not ipc.get(cmd='inline')
-
- node_pid = self.fork_master([User], NodeRoutes)
- self.client_routes._remote_connect()
- self.wait_for_events(ipc, event='inline', state='online').wait()
-
- coroutine.spawn(kill)
- self.assertEqual('local', ipc.get(cmd='yield_raw_and_sleep'))
- assert not ipc.get(cmd='inline')
-
- node_pid = self.fork_master([User], NodeRoutes)
- self.client_routes._remote_connect()
- self.wait_for_events(ipc, event='inline', state='online').wait()
-
- coroutine.spawn(kill)
- self.assertEqual('local', ipc.get(cmd='yield_json_and_sleep'))
- assert not ipc.get(cmd='inline')
-
- def test_ReconnectOnServerFall(self):
- routes._RECONNECT_TIMEOUT = 1
-
- node_pid = self.fork_master()
- self.start_client()
- ipc = IPCConnection()
- self.wait_for_events(ipc, event='inline', state='online').wait()
-
- def shutdown():
- coroutine.sleep(.1)
- self.waitpid(node_pid)
- coroutine.spawn(shutdown)
- self.wait_for_events(ipc, event='inline', state='offline').wait()
-
- self.fork_master()
- self.wait_for_events(ipc, event='inline', state='online').wait()
-
- def test_SilentReconnectOnGatewayErrors(self):
-
- class Routes(object):
-
- subscribe_tries = 0
-
- def __init__(self, *args):
- pass
-
- @route('GET', cmd='status', mime_type='application/json')
- def info(self):
- return {'resources': {}}
-
- @route('GET', cmd='subscribe', mime_type='text/event-stream')
- def subscribe(self, request=None, response=None, ping=False, **condition):
- Routes.subscribe_tries += 1
- coroutine.sleep(.1)
- if Routes.subscribe_tries % 2:
- raise http.BadGateway()
- else:
- raise http.GatewayTimeout()
-
- node_pid = self.start_master(None, Routes)
- self.start_client()
- ipc = IPCConnection()
- self.wait_for_events(ipc, event='inline', state='online').wait()
-
- def read_events():
- for event in ipc.subscribe():
- events.append(event)
- events = []
- coroutine.spawn(read_events)
-
- coroutine.sleep(1)
- self.assertEqual([], events)
- assert Routes.subscribe_tries > 2
-
- def test_inline(self):
- routes._RECONNECT_TIMEOUT = 2
-
- cp = ClientRoutes(Volume('client', model.RESOURCES), client.api.value)
- assert not cp.inline()
-
- trigger = self.wait_for_events(cp, event='inline', state='online')
- coroutine.sleep(.5)
- self.start_master()
- trigger.wait(.5)
- assert trigger.value is None
- assert not cp.inline()
-
- trigger.wait()
- assert cp.inline()
-
- trigger = self.wait_for_events(cp, event='inline', state='offline')
- self.node.stop()
- trigger.wait()
- assert not cp.inline()
-
- def test_SubmitReport(self):
- self.home_volume = self.start_online_client([User, Context, Release, Report])
- ipc = IPCConnection()
-
- self.touch(
- ['file1', 'content1'],
- ['file2', 'content2'],
- ['file3', 'content3'],
- )
- events = [i for i in ipc.post(['report'], {'context': 'context', 'error': 'error', 'logs': [
- tests.tmpdir + '/file1',
- tests.tmpdir + '/file2',
- tests.tmpdir + '/file3',
- ]}, cmd='submit')]
- self.assertEqual('done', events[-1]['event'])
- guid = events[-1]['guid']
-
- self.assertEqual({
- 'context': 'context',
- 'error': 'error',
- },
- ipc.get(['report', guid], reply=['context', 'error']))
- zipfile = ZipFile('master/report/%s/%s/data.blob' % (guid[:2], guid))
- self.assertEqual('content1', zipfile.read('file1'))
- self.assertEqual('content2', zipfile.read('file2'))
- self.assertEqual('content3', zipfile.read('file3'))
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/client/routes.py b/tests/units/client/routes.py
index 7cd03e6..325ac99 100755
--- a/tests/units/client/routes.py
+++ b/tests/units/client/routes.py
@@ -5,18 +5,22 @@
import os
import json
import time
+import hashlib
from cStringIO import StringIO
from os.path import exists
from __init__ import tests
-from sugar_network import db, client, model, toolkit
-from sugar_network.client import journal, IPCConnection, cache_limit, cache_lifetime
+from sugar_network import db, client, toolkit
+from sugar_network.client import journal, IPCConnection, cache_limit, cache_lifetime, api, injector, routes
+from sugar_network.client.model import RESOURCES
+from sugar_network.client.injector import Injector
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, i18n
+from sugar_network.node.model import User
+from sugar_network.node.master import MasterRoutes
+from sugar_network.toolkit.router import Router, Request, Response, route
+from sugar_network.toolkit.coroutine import this
+from sugar_network.toolkit import coroutine, i18n, parcel, http
import requests
@@ -24,7 +28,7 @@ import requests
class RoutesTest(tests.Test):
def test_Hub(self):
- volume = db.Volume('db', model.RESOURCES)
+ volume = db.Volume('db', RESOURCES)
cp = ClientRoutes(volume)
server = coroutine.WSGIServer(
('127.0.0.1', client.ipc_port.value), Router(cp))
@@ -47,8 +51,305 @@ class RoutesTest(tests.Test):
response = requests.request('GET', url + '/hub/', allow_redirects=False)
self.assertEqual(index_html, response.content)
- def test_LocalLayers(self):
- self.home_volume = self.start_online_client()
+ def test_I18nQuery(self):
+ os.environ['LANGUAGE'] = 'foo'
+ self.start_online_client()
+ ipc = IPCConnection()
+
+ ipc.request('POST', [], ''.join(parcel.encode([
+ ('push', None, [
+ {'resource': 'context'},
+ {'guid': '1', 'patch': {
+ 'guid': {'value': '1', 'mtime': 1},
+ 'ctime': {'value': 1, 'mtime': 1},
+ 'mtime': {'value': 1, 'mtime': 1},
+ 'type': {'value': ['activity'], 'mtime': 1},
+ 'summary': {'value': {}, 'mtime': 1},
+ 'description': {'value': {}, 'mtime': 1},
+ 'title': {'value': {'en-US': 'qwe', 'ru-RU': 'йцу'}, 'mtime': 1},
+ }},
+ {'guid': '2', 'patch': {
+ 'guid': {'value': '2', 'mtime': 1},
+ 'ctime': {'value': 1, 'mtime': 1},
+ 'mtime': {'value': 1, 'mtime': 1},
+ 'type': {'value': ['activity'], 'mtime': 1},
+ 'summary': {'value': {}, 'mtime': 1},
+ 'description': {'value': {}, 'mtime': 1},
+ 'title': {'value': {'en-US': 'qwerty', 'ru-RU': 'йцукен'}, 'mtime': 1},
+ }},
+ ]),
+ ], header={'to': '127.0.0.1:7777', 'from': 'slave'})), params={'cmd': 'push'})
+
+ self.assertEqual([
+ {'guid': '1'},
+ {'guid': '2'},
+ ],
+ ipc.get(['context'], query='йцу')['result'])
+ self.assertEqual([
+ {'guid': '1'},
+ {'guid': '2'},
+ ],
+ ipc.get(['context'], query='qwe')['result'])
+
+ self.assertEqual([
+ {'guid': '2'},
+ ],
+ ipc.get(['context'], query='йцукен')['result'])
+ self.assertEqual([
+ {'guid': '2'},
+ ],
+ ipc.get(['context'], query='qwerty')['result'])
+
+ def test_LanguagesFallbackInRequests(self):
+ self.start_online_client()
+ ipc = IPCConnection()
+
+ ipc.request('POST', [], ''.join(parcel.encode([
+ ('push', None, [
+ {'resource': 'context'},
+ {'guid': '1', 'patch': {
+ 'guid': {'value': '1', 'mtime': 1},
+ 'ctime': {'value': 1, 'mtime': 1},
+ 'mtime': {'value': 1, 'mtime': 1},
+ 'type': {'value': ['activity'], 'mtime': 1},
+ 'summary': {'value': {}, 'mtime': 1},
+ 'description': {'value': {}, 'mtime': 1},
+ 'title': {'value': {'en': '1', 'ru': '2', 'es': '3'}, 'mtime': 1},
+ }},
+ {'guid': '2', 'patch': {
+ 'guid': {'value': '2', 'mtime': 1},
+ 'ctime': {'value': 1, 'mtime': 1},
+ 'mtime': {'value': 1, 'mtime': 1},
+ 'type': {'value': ['activity'], 'mtime': 1},
+ 'summary': {'value': {}, 'mtime': 1},
+ 'description': {'value': {}, 'mtime': 1},
+ 'title': {'value': {'en': '1', 'ru': '2'}, 'mtime': 1},
+ }},
+ {'guid': '3', 'patch': {
+ 'guid': {'value': '3', 'mtime': 1},
+ 'ctime': {'value': 1, 'mtime': 1},
+ 'mtime': {'value': 1, 'mtime': 1},
+ 'type': {'value': ['activity'], 'mtime': 1},
+ 'summary': {'value': {}, 'mtime': 1},
+ 'description': {'value': {}, 'mtime': 1},
+ 'title': {'value': {'en': '1'}, 'mtime': 1},
+ }},
+ ]),
+ ], header={'to': '127.0.0.1:7777', 'from': 'slave'})), params={'cmd': 'push'})
+
+ i18n._default_langs = None
+ os.environ['LANGUAGE'] = 'es:ru:en'
+ ipc = IPCConnection()
+ self.assertEqual('3', ipc.get(['context', '1', 'title']))
+ self.assertEqual('2', ipc.get(['context', '2', 'title']))
+ self.assertEqual('1', ipc.get(['context', '3', 'title']))
+
+ i18n._default_langs = None
+ os.environ['LANGUAGE'] = 'ru:en'
+ ipc = IPCConnection()
+ self.assertEqual('2', ipc.get(['context', '1', 'title']))
+ self.assertEqual('2', ipc.get(['context', '2', 'title']))
+ self.assertEqual('1', ipc.get(['context', '3', 'title']))
+
+ i18n._default_langs = None
+ os.environ['LANGUAGE'] = 'en'
+ ipc = IPCConnection()
+ self.assertEqual('1', ipc.get(['context', '1', 'title']))
+ self.assertEqual('1', ipc.get(['context', '2', 'title']))
+ self.assertEqual('1', ipc.get(['context', '3', 'title']))
+
+ i18n._default_langs = None
+ os.environ['LANGUAGE'] = 'foo'
+ ipc = IPCConnection()
+ self.assertEqual('1', ipc.get(['context', '1', 'title']))
+ self.assertEqual('1', ipc.get(['context', '2', 'title']))
+ self.assertEqual('1', ipc.get(['context', '3', 'title']))
+
+ def test_whoami(self):
+ self.start_offline_client()
+ ipc = IPCConnection()
+
+ self.assertEqual(
+ {'guid': tests.UID, 'roles': [], 'route': 'offline'},
+ ipc.get(cmd='whoami'))
+
+ self.fork_master()
+ self.wait_for_events(event='inline', state='online').wait()
+
+ self.assertEqual(
+ {'guid': tests.UID, 'roles': [], 'route': 'proxy'},
+ ipc.get(cmd='whoami'))
+
+ def test_Events(self):
+ self.override(time, 'time', lambda: 0)
+ self.start_offline_client()
+ ipc = IPCConnection()
+ events = []
+
+ def read_events():
+ for event in ipc.subscribe():
+ if event['event'] not in ('commit', 'pong'):
+ events.append(event)
+ coroutine.spawn(read_events)
+ coroutine.dispatch()
+
+ guid = ipc.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ ipc.put(['context', guid], {
+ 'title': 'title_2',
+ })
+ ipc.delete(['context', guid])
+ coroutine.sleep(.1)
+
+ self.assertEqual([
+ {'event': 'create', 'guid': guid, 'resource': 'context'},
+ {'event': 'update', 'guid': guid, 'resource': 'context', 'props': {'mtime': 0, 'title': {'en-us': 'title_2'}}},
+ {'event': 'delete', 'guid': guid, 'resource': 'context'},
+ ],
+ events)
+ del events[:]
+
+ self.fork_master()
+ self.wait_for_events(event='inline', state='online').wait()
+ coroutine.sleep(.1)
+
+ self.assertEqual([
+ {'event': 'inline', 'state': 'connecting'},
+ {'event': 'inline', 'state': 'online'},
+ ],
+ events)
+ del events[:]
+
+ guid = ipc.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ ipc.put(['context', guid], {
+ 'title': 'title_2',
+ })
+ coroutine.sleep(.1)
+ ipc.delete(['context', guid])
+ coroutine.sleep(.1)
+
+ self.assertEqual([
+ {'event': 'create', 'guid': tests.UID, 'resource': 'user'},
+ {'event': 'create', 'guid': guid, 'resource': 'context'},
+ {'event': 'update', 'guid': guid, 'resource': 'context', 'props': {'mtime': 0, 'title': {'en-us': 'title_2'}}},
+ {'event': 'delete', 'guid': guid, 'resource': 'context'},
+ ],
+ events)
+ del events[:]
+
+ def test_HomeVolumeEventsOnlyInOffline(self):
+ home_volume = self.start_offline_client()
+ ipc = IPCConnection()
+ events = []
+
+ def read_events():
+ for event in ipc.subscribe():
+ if event['event'] not in ('commit', 'pong'):
+ events.append(event)
+ coroutine.spawn(read_events)
+ coroutine.sleep(.1)
+
+ guid = home_volume['context'].create({
+ 'type': ['activity'],
+ 'title': {},
+ 'summary': {},
+ 'description': {},
+ })
+ home_volume['context'].update(guid, {
+ 'title': {'en': 'title_2'},
+ })
+ home_volume['context'].delete(guid)
+ coroutine.sleep(.1)
+
+ self.assertEqual([
+ {'guid': guid, 'resource': 'context', 'event': 'create'},
+ {'guid': guid, 'resource': 'context', 'event': 'update', 'props': {'title': {'en': 'title_2'}}},
+ {'guid': guid, 'event': 'delete', 'resource': 'context'},
+ ],
+ events)
+ del events[:]
+
+ self.fork_master()
+ self.wait_for_events(event='inline', state='online').wait()
+ coroutine.sleep(.1)
+ del events[:]
+
+ guid = home_volume['context'].create({
+ 'type': ['activity'],
+ 'title': {},
+ 'summary': {},
+ 'description': {},
+ })
+ home_volume['context'].update(guid, {
+ 'title': {'en': 'title_2'},
+ })
+ coroutine.sleep(.1)
+ home_volume['context'].delete(guid)
+ coroutine.sleep(.1)
+
+ self.assertEqual([], events)
+
+ def test_BLOBs(self):
+ self.start_offline_client()
+ ipc = IPCConnection()
+
+ blob = 'blob_value'
+ digest = hashlib.sha1(blob).hexdigest()
+
+ guid = ipc.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ ipc.request('PUT', ['context', guid, 'logo'], blob, headers={'content-type': 'image/png'})
+
+ self.assertEqual(
+ blob,
+ ipc.request('GET', ['context', guid, 'logo']).content)
+ self.assertEqual({
+ 'logo': 'http://127.0.0.1:5555/blobs/%s' % digest,
+ },
+ ipc.get(['context', guid], reply=['logo']))
+ self.assertEqual([{
+ 'logo': 'http://127.0.0.1:5555/blobs/%s' % digest,
+ }],
+ ipc.get(['context'], reply=['logo'])['result'])
+
+ self.fork_master()
+ self.wait_for_events(event='inline', state='online').wait()
+
+ guid = ipc.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ ipc.request('PUT', ['context', guid, 'logo'], blob, headers={'content-type': 'image/png'})
+
+ self.assertEqual(
+ blob,
+ ipc.request('GET', ['context', guid, 'logo']).content)
+ self.assertEqual({
+ 'logo': 'http://127.0.0.1:7777/blobs/%s' % digest,
+ },
+ ipc.get(['context', guid], reply=['logo']))
+ self.assertEqual([{
+ 'logo': 'http://127.0.0.1:7777/blobs/%s' % digest,
+ }],
+ ipc.get(['context'], reply=['logo'])['result'])
+
+ def test_OnlinePins(self):
+ home_volume = self.start_online_client()
ipc = IPCConnection()
guid1 = ipc.post(['context'], {
@@ -58,7 +359,7 @@ class RoutesTest(tests.Test):
'summary': 'summary',
'description': 'description',
})
- ipc.upload(['release'], StringIO(self.zips(['TestActivity/activity/activity.info', [
+ ipc.upload(['context'], self.zips(['TestActivity/activity/activity.info', [
'[Activity]',
'name = 2',
'bundle_id = context2',
@@ -67,9 +368,9 @@ class RoutesTest(tests.Test):
'activity_version = 1',
'license = Public Domain',
'stability = stable',
- ]])), cmd='submit', initial=True)
+ ]]), cmd='submit', initial=True)
guid2 = 'context2'
- ipc.upload(['release'], StringIO(self.zips(['TestActivity/activity/activity.info', [
+ ipc.upload(['context'], self.zips(['TestActivity/activity/activity.info', [
'[Activity]',
'name = 3',
'bundle_id = context3',
@@ -78,7 +379,7 @@ class RoutesTest(tests.Test):
'activity_version = 1',
'license = Public Domain',
'stability = stable',
- ]])), cmd='submit', initial=True)
+ ]]), cmd='submit', initial=True)
guid3 = 'context3'
guid4 = ipc.post(['context'], {
'guid': 'context4',
@@ -89,70 +390,722 @@ class RoutesTest(tests.Test):
})
self.assertEqual([
- {'guid': guid1, 'title': '1', 'layer': []},
- {'guid': guid2, 'title': '2', 'layer': []},
- {'guid': guid3, 'title': '3', 'layer': []},
- {'guid': guid4, 'title': '4', 'layer': []},
+ {'guid': guid1, 'title': '1', 'pins': []},
+ {'guid': guid2, 'title': '2', 'pins': []},
+ {'guid': guid3, 'title': '3', 'pins': []},
+ {'guid': guid4, 'title': '4', 'pins': []},
],
- ipc.get(['context'], reply=['guid', 'title', 'layer'])['result'])
+ ipc.get(['context'], reply=['guid', 'title', 'pins'])['result'])
self.assertEqual([
],
- ipc.get(['context'], reply=['guid', 'title'], layer='favorite')['result'])
+ ipc.get(['context'], reply=['guid', 'title'], pins='favorite')['result'])
self.assertEqual([
],
- ipc.get(['context'], reply=['guid', 'title'], layer='clone')['result'])
+ ipc.get(['context'], reply=['guid', 'title'], pins='checkin')['result'])
ipc.put(['context', guid1], True, cmd='favorite')
ipc.put(['context', guid2], True, cmd='favorite')
- ipc.put(['context', guid2], True, cmd='clone')
- ipc.put(['context', guid3], True, cmd='clone')
- self.home_volume['context'].update(guid1, {'title': '1_'})
- self.home_volume['context'].update(guid2, {'title': '2_'})
- self.home_volume['context'].update(guid3, {'title': '3_'})
+ self.assertEqual([
+ {'event': 'checkin', 'state': 'solve'},
+ {'event': 'checkin', 'state': 'download'},
+ {'event': 'checkin', 'state': 'ready'},
+ ],
+ [i for i in ipc.put(['context', guid2], True, cmd='checkin')])
+ self.assertEqual([
+ {'event': 'checkin', 'state': 'solve'},
+ {'event': 'checkin', 'state': 'download'},
+ {'event': 'checkin', 'state': 'ready'},
+ ],
+ [i for i in ipc.put(['context', guid3], True, cmd='checkin')])
+ home_volume['context'].update(guid1, {'title': {i18n.default_lang(): '1_'}})
+ home_volume['context'].update(guid2, {'title': {i18n.default_lang(): '2_'}})
+ home_volume['context'].update(guid3, {'title': {i18n.default_lang(): '3_'}})
self.assertEqual([
- {'guid': guid1, 'title': '1', 'layer': ['favorite']},
- {'guid': guid2, 'title': '2', 'layer': ['clone', 'favorite']},
- {'guid': guid3, 'title': '3', 'layer': ['clone']},
- {'guid': guid4, 'title': '4', 'layer': []},
+ {'guid': guid1, 'title': '1', 'pins': ['favorite']},
+ {'guid': guid2, 'title': '2', 'pins': ['checkin', 'favorite']},
+ {'guid': guid3, 'title': '3', 'pins': ['checkin']},
+ {'guid': guid4, 'title': '4', 'pins': []},
],
- ipc.get(['context'], reply=['guid', 'title', 'layer'])['result'])
+ ipc.get(['context'], reply=['guid', 'title', 'pins'])['result'])
self.assertEqual([
{'guid': guid1, 'title': '1_'},
{'guid': guid2, 'title': '2_'},
],
- ipc.get(['context'], reply=['guid', 'title'], layer='favorite')['result'])
+ ipc.get(['context'], reply=['guid', 'title'], pins='favorite')['result'])
self.assertEqual([
{'guid': guid2, 'title': '2_'},
{'guid': guid3, 'title': '3_'},
],
- ipc.get(['context'], reply=['guid', 'title'], layer='clone')['result'])
+ ipc.get(['context'], reply=['guid', 'title'], pins='checkin')['result'])
- def test_SetLocalLayerInOffline(self):
- volume = db.Volume('client', model.RESOURCES)
- cp = ClientRoutes(volume, client.api.value)
- post = Request(method='POST', path=['context'])
- post.content_type = 'application/json'
- post.content = {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- }
+ ipc.delete(['context', guid1], cmd='favorite')
+ ipc.delete(['context', guid2], cmd='checkin')
- guid = call(cp, post)
- self.assertEqual(['local'], call(cp, Request(method='GET', path=['context', guid, 'layer'])))
+ self.assertEqual([
+ {'guid': guid1, 'pins': []},
+ {'guid': guid2, 'pins': ['favorite']},
+ {'guid': guid3, 'pins': ['checkin']},
+ {'guid': guid4, 'pins': []},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'])['result'])
+ self.assertEqual([
+ {'guid': guid2, 'pins': ['favorite']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='favorite')['result'])
+ self.assertEqual([
+ {'guid': guid3, 'pins': ['checkin']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='checkin')['result'])
+
+ def test_OfflinePins(self):
+ self.start_online_client()
+ ipc = IPCConnection()
+
+ ipc.upload(['context'], self.zips(['TestActivity/activity/activity.info', [
+ '[Activity]',
+ 'name = 1',
+ 'bundle_id = 1',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ ]]), cmd='submit', initial=True)
+ ipc.upload(['context'], self.zips(['TestActivity/activity/activity.info', [
+ '[Activity]',
+ 'name = 2',
+ 'bundle_id = 2',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 2',
+ 'license = Public Domain',
+ ]]), cmd='submit', initial=True)
+ ipc.upload(['context'], self.zips(['TestActivity/activity/activity.info', [
+ '[Activity]',
+ 'name = 3',
+ 'bundle_id = 3',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 3',
+ 'license = Public Domain',
+ ]]), cmd='submit', initial=True)
+
+ ipc.put(['context', '1'], None, cmd='favorite')
+ self.assertEqual([
+ {'event': 'checkin', 'state': 'solve'},
+ {'event': 'checkin', 'state': 'download'},
+ {'event': 'checkin', 'state': 'ready'},
+ ],
+ [i for i in ipc.put(['context', '2'], None, cmd='checkin')])
+ self.assertEqual([
+ {'guid': '1', 'pins': ['favorite']},
+ {'guid': '2', 'pins': ['checkin']},
+ {'guid': '3', 'pins': []},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'])['result'])
+
+ self.stop_master()
+ self.wait_for_events(event='inline', state='offline').wait()
+
+ self.assertEqual([
+ {'guid': '1', 'pins': ['favorite']},
+ {'guid': '2', 'pins': ['checkin']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'])['result'])
+ self.assertEqual([
+ {'guid': '1', 'pins': ['favorite']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='favorite')['result'])
+ self.assertEqual([
+ {'guid': '2', 'pins': ['checkin']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='checkin')['result'])
+
+ ipc.delete(['context', '1'], cmd='favorite')
+ ipc.put(['context', '2'], None, cmd='favorite')
+ self.assertRaises(http.ServiceUnavailable, ipc.put, ['context', '3'], None, cmd='favorite')
+
+ self.assertEqual([
+ {'guid': '1', 'pins': []},
+ {'guid': '2', 'pins': ['checkin', 'favorite']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'])['result'])
+ self.assertEqual([
+ {'guid': '2', 'pins': ['checkin', 'favorite']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='favorite')['result'])
+ self.assertEqual([
+ {'guid': '2', 'pins': ['checkin', 'favorite']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='checkin')['result'])
+
+ ipc.delete(['context', '2'], cmd='checkin')
+ ipc.delete(['context', '2'], cmd='favorite')
+
+ self.assertEqual([
+ {'guid': '1', 'pins': []},
+ {'guid': '2', 'pins': []},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'])['result'])
+ self.assertEqual([
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='favorite')['result'])
+ self.assertEqual([
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='checkin')['result'])
+
+ self.assertEqual([
+ {'event': 'checkin', 'state': 'solve'},
+ {'event': 'failure', 'error': 'Not available in offline', 'exception': 'ServiceUnavailable'},
+ ],
+ [i for i in ipc.put(['context', '1'], None, cmd='checkin')])
+ ipc.put(['context', '1'], None, cmd='favorite')
+ self.assertEqual([
+ {'event': 'checkin', 'state': 'solve'},
+ {'event': 'checkin', 'state': 'ready'},
+ ],
+ [i for i in ipc.put(['context', '2'], None, cmd='checkin')])
+ ipc.put(['context', '2'], None, cmd='favorite')
+ self.assertEqual([
+ {'event': 'failure', 'error': 'Not available in offline', 'exception': 'ServiceUnavailable'},
+ ],
+ [i for i in ipc.put(['context', '3'], None, cmd='checkin')])
+ self.assertRaises(http.ServiceUnavailable, ipc.put, ['context', '3'], None, cmd='favorite')
+
+ self.assertEqual([
+ {'guid': '1', 'pins': ['favorite']},
+ {'guid': '2', 'pins': ['checkin', 'favorite']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'])['result'])
+ self.assertEqual([
+ {'guid': '1', 'pins': ['favorite']},
+ {'guid': '2', 'pins': ['checkin', 'favorite']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='favorite')['result'])
+ self.assertEqual([
+ {'guid': '2', 'pins': ['checkin', 'favorite']},
+ ],
+ ipc.get(['context'], reply=['guid', 'pins'], pins='checkin')['result'])
+
+ def test_checkin_Notificaitons(self):
+ self.start_online_client()
+ ipc = IPCConnection()
+
+ activity_info = '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = context',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ ])
+ activity_bundle = self.zips(('topdir/activity/activity.info', activity_info))
+ release = ipc.upload(['context'], activity_bundle, cmd='submit', initial=True)
+
+ def subscribe():
+ for i in ipc.subscribe():
+ if i.get('event') != 'commit':
+ events.append(i)
+ events = []
+ coroutine.spawn(subscribe)
+ coroutine.sleep(.1)
+ del events[:]
+
+ assert {'event': 'checkin', 'state': 'ready'} in [i for i in ipc.put(['context', 'context'], None, cmd='checkin')]
+ self.assertEqual([
+ {'event': 'update', 'guid': 'context', 'props': {'pins': ['inprogress']}, 'resource': 'context'},
+ {'event': 'update', 'guid': 'context', 'props': {'pins': ['checkin']}, 'resource': 'context'},
+ ], events)
+ del events[:]
+
+ ipc.put(['context', 'context'], None, cmd='favorite')
+ ipc.delete(['context', 'context'], cmd='checkin')
+ coroutine.sleep(.1)
+ self.assertEqual([
+ {'event': 'update', 'guid': 'context', 'props': {'pins': ['favorite']}, 'resource': 'context'},
+ ], events)
+
+ self.stop_master()
+ self.wait_for_events(event='inline', state='offline').wait()
+ coroutine.sleep(.1)
+ del events[:]
+
+ assert {'event': 'checkin', 'state': 'ready'} in [i for i in ipc.put(['context', 'context'], None, cmd='checkin')]
+ self.assertEqual([
+ {'event': 'update', 'guid': 'context', 'props': {'pins': ['favorite', 'inprogress']}, 'resource': 'context'},
+ {'event': 'update', 'guid': 'context', 'props': {'pins': ['checkin', 'favorite']}, 'resource': 'context'},
+ ], events)
+ del events[:]
+
+ ipc.delete(['context', 'context'], cmd='checkin')
+ coroutine.sleep(.1)
+ self.assertEqual([
+ {'event': 'update', 'guid': 'context', 'props': {'pins': ['favorite']}, 'resource': 'context'},
+ ], events)
+
+ def test_launch_Notificaitons(self):
+ self.start_online_client()
+ ipc = IPCConnection()
+
+ activity_info = '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = context',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ ])
+ activity_bundle = self.zips(('topdir/activity/activity.info', activity_info))
+ release = ipc.upload(['context'], activity_bundle, cmd='submit', initial=True)
+
+ def subscribe():
+ for i in ipc.subscribe():
+ if i.get('event') != 'commit':
+ events.append(i)
+ events = []
+ coroutine.spawn(subscribe)
+ coroutine.sleep(.1)
+ del events[:]
+
+ assert {'event': 'launch', 'state': 'exit'} in [i for i in ipc.get(['context', 'context'], cmd='launch')]
+ self.assertEqual([
+ {'event': 'update', 'guid': 'context', 'props': {'pins': ['inprogress']}, 'resource': 'context'},
+ {'event': 'update', 'guid': 'context', 'props': {'pins': []}, 'resource': 'context'},
+ ], events)
+
+ ipc.put(['context', 'context'], None, cmd='favorite')
+ self.stop_master()
+ self.wait_for_events(event='inline', state='offline').wait()
+ coroutine.sleep(.1)
+ del events[:]
+
+ assert {'event': 'launch', 'state': 'exit'} in [i for i in ipc.get(['context', 'context'], None, cmd='launch')]
+ self.assertEqual([
+ {'event': 'update', 'guid': 'context', 'props': {'pins': ['favorite', 'inprogress']}, 'resource': 'context'},
+ {'event': 'update', 'guid': 'context', 'props': {'pins': ['favorite']}, 'resource': 'context'},
+ ], events)
+ del events[:]
+
+ def test_checkin_Fails(self):
+ self.start_online_client()
+ ipc = IPCConnection()
+
+ self.assertEqual([
+ {'event': 'checkin', 'state': 'solve'},
+ {'error': 'Context not found', 'event': 'failure', 'exception': 'NotFound'},
+ ],
+ [i for i in ipc.put(['context', 'context'], None, cmd='checkin')])
+
+ guid = ipc.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ self.assertEqual([
+ {'event': 'checkin', 'state': 'solve'},
+ {'error': 'Failed to solve', 'event': 'failure', 'exception': 'RuntimeError'},
+ ],
+ [i for i in ipc.put(['context', guid], None, cmd='checkin')])
+
+ ipc.put(['context', guid], None, cmd='favorite')
+ self.stop_master()
+ self.wait_for_events(event='inline', state='offline').wait()
+ coroutine.sleep(.1)
+
+ self.assertEqual([
+ {'error': 'Not available in offline', 'event': 'failure', 'exception': 'ServiceUnavailable'},
+ ],
+ [i for i in ipc.put(['context', 'context'], None, cmd='checkin')])
+
+ self.assertEqual([
+ {'event': 'checkin', 'state': 'solve'},
+ {'error': 'Not available in offline', 'event': 'failure', 'exception': 'ServiceUnavailable'},
+ ],
+ [i for i in ipc.put(['context', guid], None, cmd='checkin')])
+
+ def test_launch_Fails(self):
+ self.override(injector, '_activity_id_new', lambda: 'activity_id')
+ self.start_online_client()
+ ipc = IPCConnection()
+
+ self.assertEqual([
+ {'activity_id': 'activity_id'},
+ {'event': 'launch', 'state': 'init'},
+ {'event': 'launch', 'state': 'solve'},
+ {'error': 'Context not found', 'event': 'failure', 'exception': 'NotFound'},
+ ],
+ [i for i in ipc.get(['context', 'context'], cmd='launch')])
+
+ guid1 = ipc.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ self.assertEqual([
+ {'activity_id': 'activity_id'},
+ {'event': 'launch', 'state': 'init'},
+ {'event': 'launch', 'state': 'solve'},
+ {'error': 'Failed to solve', 'event': 'failure', 'exception': 'RuntimeError'},
+ ],
+ [i for i in ipc.get(['context', guid1], cmd='launch')])
+
+ activity_info = '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = context2',
+ 'exec = false',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ ])
+ activity_bundle = self.zips(('topdir/activity/activity.info', activity_info))
+ release = ipc.upload(['context'], activity_bundle, cmd='submit', initial=True)
+
+ self.assertEqual([
+ {'activity_id': 'activity_id'},
+ {'event': 'launch', 'state': 'init'},
+ {'event': 'launch', 'state': 'solve'},
+ {'event': 'launch', 'state': 'download'},
+ {'event': 'launch', 'state': 'exec'},
+ {'context': 'context2',
+ 'args': ['false', '-b', 'context2', '-a', 'activity_id'],
+ 'logs': [
+ tests.tmpdir + '/.sugar/default/logs/shell.log',
+ tests.tmpdir + '/.sugar/default/logs/sugar-network-client.log',
+ tests.tmpdir + '/.sugar/default/logs/context2.log',
+ ],
+ 'solution': {
+ 'context2': {
+ 'blob': release,
+ 'command': ['activity', 'false'],
+ 'content-type': 'application/vnd.olpc-sugar',
+ 'size': len(activity_bundle),
+ 'title': 'Activity',
+ 'unpack_size': len(activity_info),
+ 'version': [[1], 0],
+ },
+ },
+ },
+ {'error': 'Process exited with 1 status', 'event': 'failure', 'exception': 'RuntimeError'},
+ ],
+ [i for i in ipc.get(['context', 'context2'], cmd='launch')])
+
+ ipc.put(['context', guid1], None, cmd='favorite')
+ ipc.put(['context', 'context2'], None, cmd='favorite')
+ self.stop_master()
+ self.wait_for_events(event='inline', state='offline').wait()
+ coroutine.sleep(.1)
+
+ self.assertEqual([
+ {'activity_id': 'activity_id'},
+ {'event': 'launch', 'state': 'init'},
+ {'event': 'launch', 'state': 'solve'},
+ {'error': 'Not available in offline', 'event': 'failure', 'exception': 'ServiceUnavailable'},
+ ],
+ [i for i in ipc.get(['context', 'context'], cmd='launch')])
+
+ self.assertEqual([
+ {'activity_id': 'activity_id'},
+ {'event': 'launch', 'state': 'init'},
+ {'event': 'launch', 'state': 'solve'},
+ {'error': 'Not available in offline', 'event': 'failure', 'exception': 'ServiceUnavailable'},
+ ],
+ [i for i in ipc.get(['context', guid1], cmd='launch')])
+
+ self.assertEqual([
+ {'activity_id': 'activity_id'},
+ {'event': 'launch', 'state': 'init'},
+ {'event': 'launch', 'state': 'solve'},
+ {'event': 'launch', 'state': 'exec'},
+ {'context': 'context2',
+ 'args': ['false', '-b', 'context2', '-a', 'activity_id'],
+ 'logs': [
+ tests.tmpdir + '/.sugar/default/logs/shell.log',
+ tests.tmpdir + '/.sugar/default/logs/sugar-network-client.log',
+ tests.tmpdir + '/.sugar/default/logs/context2_1.log',
+ ],
+ 'solution': {
+ 'context2': {
+ 'blob': release,
+ 'command': ['activity', 'false'],
+ 'content-type': 'application/vnd.olpc-sugar',
+ 'size': len(activity_bundle),
+ 'title': 'Activity',
+ 'unpack_size': len(activity_info),
+ 'version': [[1], 0],
+ },
+ },
+ },
+ {'error': 'Process exited with 1 status', 'event': 'failure', 'exception': 'RuntimeError'},
+ ],
+ [i for i in ipc.get(['context', 'context2'], cmd='launch')])
+
+ def test_SubmitReport(self):
+ home_volume = self.start_online_client()
+ ipc = IPCConnection()
+
+ self.touch(
+ ['file1', 'content1'],
+ ['file2', 'content2'],
+ ['file3', 'content3'],
+ )
+ events = [i for i in ipc.post(['report'], {'context': 'context', 'error': 'error', 'logs': [
+ tests.tmpdir + '/file1',
+ tests.tmpdir + '/file2',
+ tests.tmpdir + '/file3',
+ ]}, cmd='submit')]
+ self.assertEqual('done', events[-1]['event'])
+ guid = events[-1]['guid']
+
+ self.assertEqual({
+ 'context': 'context',
+ 'error': 'error',
+ },
+ ipc.get(['report', guid], reply=['context', 'error']))
+ self.assertEqual(sorted([
+ 'content1',
+ 'content2',
+ 'content3',
+ ]),
+ sorted([ipc.get(['report', guid, 'logs', i]) for i in ipc.get(['report', guid, 'logs']).keys()]))
+ assert not home_volume['report'][guid].exists
+
+ self.stop_master()
+ self.wait_for_events(event='inline', state='offline').wait()
+
+ events = [i for i in ipc.post(['report'], {'context': 'context', 'error': 'error', 'logs': [
+ tests.tmpdir + '/file1',
+ tests.tmpdir + '/file2',
+ tests.tmpdir + '/file3',
+ ]}, cmd='submit')]
+ self.assertEqual('done', events[-1]['event'])
+ guid = events[-1]['guid']
+
+ self.assertEqual({
+ 'context': 'context',
+ 'error': 'error',
+ },
+ ipc.get(['report', guid], reply=['context', 'error']))
+ self.assertEqual(sorted([
+ 'content1',
+ 'content2',
+ 'content3',
+ ]),
+ sorted([ipc.get(['report', guid, 'logs', i]) for i in ipc.get(['report', guid, 'logs']).keys()]))
+ assert home_volume['report'][guid].exists
+
+ def test_inline(self):
+ routes._RECONNECT_TIMEOUT = 2
+
+ this.injector = Injector('client')
+ cp = ClientRoutes(db.Volume('client', RESOURCES))
+ cp.connect(client.api.value)
+ assert not cp.inline()
trigger = self.wait_for_events(cp, event='inline', state='online')
- node_volume = self.start_master()
- cp._remote_connect()
+ coroutine.sleep(.5)
+ self.fork_master()
+ trigger.wait(.5)
+ assert trigger.value is None
+ assert not cp.inline()
+
trigger.wait()
+ assert cp.inline()
+
+ trigger = self.wait_for_events(cp, event='inline', state='offline')
+ self.stop_master()
+ trigger.wait()
+ assert not cp.inline()
+
+ def test_DoNotSwitchToOfflineOnRedirectFails(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(db.Blob)
+ def blob1(self, value):
+ raise http.Redirect(prefix + '/blob2')
+
+ @db.stored_property(db.Blob)
+ def blob2(self, value):
+ raise http._ConnectionError()
+
+ local_volume = self.start_online_client([User, Document])
+ ipc = IPCConnection()
+ guid = ipc.post(['document'], {})
+ prefix = client.api.value + '/document/' + guid + '/'
+ local_volume['document'].create({'guid': guid})
+
+ trigger = self.wait_for_events(ipc, event='inline', state='connecting')
+ try:
+ ipc.get(['document', guid, 'blob1'])
+ except Exception:
+ pass
+ assert trigger.wait(.1) is None
+
+ trigger = self.wait_for_events(ipc, event='inline', state='connecting')
+ try:
+ ipc.get(['document', guid, 'blob2'])
+ except Exception:
+ pass
+ assert trigger.wait(.1) is not None
+
+ def test_FallbackToLocalOnRemoteTransportFails(self):
+
+ class LocalRoutes(routes._LocalRoutes):
+
+ @route('GET', cmd='sleep')
+ def sleep(self):
+ return 'local'
+
+ @route('GET', cmd='yield_raw_and_sleep',
+ mime_type='application/octet-stream')
+ def yield_raw_and_sleep(self):
+ yield 'local'
+
+ @route('GET', cmd='yield_json_and_sleep',
+ mime_type='application/json')
+ def yield_json_and_sleep(self):
+ yield '"local"'
+
+ self.override(routes, '_LocalRoutes', LocalRoutes)
+ this.injector = Injector('client')
+ home_volume = self.start_client()
+ ipc = IPCConnection()
+
+ 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"
+
+ @route('GET', cmd='yield_json_and_sleep',
+ mime_type='application/json')
+ def yield_json_and_sleep(self):
+ yield '"'
+ yield 'r'
+ coroutine.sleep(1)
+ yield 'emote"'
+
+ node_pid = self.fork_master([User], NodeRoutes)
+ self.client_routes._remote_connect()
+ self.wait_for_events(ipc, event='inline', state='online').wait()
+
+ ts = time.time()
+ 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 >= 2
+
+ def kill():
+ coroutine.sleep(.5)
+ self.waitpid(node_pid)
+
+ coroutine.spawn(kill)
+ self.assertEqual('local', ipc.get(cmd='sleep'))
+ assert not ipc.get(cmd='inline')
+
+ node_pid = self.fork_master([User], NodeRoutes)
+ self.client_routes._remote_connect()
+ self.wait_for_events(ipc, event='inline', state='online').wait()
+
+ coroutine.spawn(kill)
+ self.assertEqual('local', ipc.get(cmd='yield_raw_and_sleep'))
+ assert not ipc.get(cmd='inline')
+
+ node_pid = self.fork_master([User], NodeRoutes)
+ self.client_routes._remote_connect()
+ self.wait_for_events(ipc, event='inline', state='online').wait()
+
+ coroutine.spawn(kill)
+ self.assertEqual('local', ipc.get(cmd='yield_json_and_sleep'))
+ assert not ipc.get(cmd='inline')
+
+ def test_ReconnectOnServerFall(self):
+ routes._RECONNECT_TIMEOUT = 1
+
+ this.injector = Injector('client')
+ node_pid = self.fork_master()
+ self.start_client()
+ ipc = IPCConnection()
+ self.wait_for_events(ipc, event='inline', state='online').wait()
+
+ def shutdown():
+ coroutine.sleep(.1)
+ self.waitpid(node_pid)
+ coroutine.spawn(shutdown)
+ self.wait_for_events(ipc, event='inline', state='offline').wait()
+
+ self.fork_master()
+ self.wait_for_events(ipc, event='inline', state='online').wait()
+
+ def test_SilentReconnectOnGatewayErrors(self):
+
+ class Routes(object):
+
+ subscribe_tries = 0
+
+ def __init__(self, volume, *args):
+ pass
+
+ @route('GET', cmd='status', mime_type='application/json')
+ def info(self):
+ return {'resources': {}}
+
+ @route('GET', cmd='subscribe', mime_type='text/event-stream')
+ def subscribe(self, request=None, response=None, **condition):
+ Routes.subscribe_tries += 1
+ coroutine.sleep(.1)
+ if Routes.subscribe_tries % 2:
+ raise http.BadGateway()
+ else:
+ raise http.GatewayTimeout()
+
+ this.injector = Injector('client')
+ node_pid = self.start_master(None, Routes)
+ self.start_client()
+ ipc = IPCConnection()
+ self.wait_for_events(ipc, event='inline', state='online').wait()
+
+ def read_events():
+ for event in ipc.subscribe():
+ events.append(event)
+ events = []
+ coroutine.spawn(read_events)
+
+ coroutine.sleep(1)
+ self.assertEqual([{'event': 'pong'}], events)
+ assert Routes.subscribe_tries > 2
+
- guid = call(cp, post)
- self.assertEqual([], call(cp, Request(method='GET', path=['context', guid, 'layer'])))
- def test_CachedClientRoutes(self):
- volume = db.Volume('client', model.RESOURCES, lazy_open=True)
+
+
+
+
+
+
+ def ___test_CachedClientRoutes(self):
+ volume = db.Volume('client', RESOURCES, lazy_open=True)
cp = CachedClientRoutes(volume, client.api.value)
post = Request(method='POST', path=['context'])
@@ -214,8 +1167,8 @@ class RoutesTest(tests.Test):
{tests.UID: {'role': 3, 'name': 'test', 'order': 0}},
self.node_volume['context'].get(guid2)['author'])
- def test_CachedClientRoutes_WipeReports(self):
- volume = db.Volume('client', model.RESOURCES, lazy_open=True)
+ def ___test_CachedClientRoutes_WipeReports(self):
+ volume = db.Volume('client', RESOURCES, lazy_open=True)
cp = CachedClientRoutes(volume, client.api.value)
post = Request(method='POST', path=['report'])
@@ -227,15 +1180,15 @@ class RoutesTest(tests.Test):
guid = call(cp, post)
trigger = self.wait_for_events(cp, event='push')
- self.start_master([User, Report])
+ self.start_master()
cp._remote_connect()
trigger.wait()
assert not volume['report'].exists(guid)
assert self.node_volume['report'].exists(guid)
- def test_CachedClientRoutes_OpenOnlyChangedResources(self):
- volume = db.Volume('client', model.RESOURCES, lazy_open=True)
+ def ___test_CachedClientRoutes_OpenOnlyChangedResources(self):
+ volume = db.Volume('client', RESOURCES, lazy_open=True)
cp = CachedClientRoutes(volume, client.api.value)
guid = call(cp, Request(method='POST', path=['context'], content_type='application/json', content={
'type': 'activity',
@@ -246,7 +1199,7 @@ class RoutesTest(tests.Test):
}))
cp.close()
- volume = db.Volume('client', model.RESOURCES, lazy_open=True)
+ volume = db.Volume('client', RESOURCES, lazy_open=True)
cp = CachedClientRoutes(volume, client.api.value)
trigger = self.wait_for_events(cp, event='push')
@@ -258,8 +1211,8 @@ class RoutesTest(tests.Test):
assert self.node_volume['context'].exists(guid)
self.assertEqual(['context'], volume.keys())
- def test_SwitchToOfflineForAbsentOnlineProps(self):
- volume = db.Volume('client', model.RESOURCES)
+ def ___test_SwitchToOfflineForAbsentOnlineProps(self):
+ volume = db.Volume('client', RESOURCES)
cp = ClientRoutes(volume, client.api.value)
post = Request(method='POST', path=['context'])
@@ -282,177 +1235,6 @@ class RoutesTest(tests.Test):
assert not self.node_volume['context'].exists(guid)
self.assertEqual('title', call(cp, Request(method='GET', path=['context', guid, 'title'])))
- def test_I18nQuery(self):
- os.environ['LANGUAGE'] = 'foo'
- self.start_online_client()
- ipc = IPCConnection()
-
- guid1 = self.node_volume['context'].create({
- 'type': 'activity',
- 'title': {'en-US': 'qwe', 'ru-RU': 'йцу'},
- 'summary': 'summary',
- 'description': 'description',
- })
- guid2 = self.node_volume['context'].create({
- 'type': 'activity',
- 'title': {'en-US': 'qwerty', 'ru-RU': 'йцукен'},
- 'summary': 'summary',
- 'description': 'description',
- })
-
- self.assertEqual([
- {'guid': guid1},
- {'guid': guid2},
- ],
- ipc.get(['context'], query='йцу')['result'])
- self.assertEqual([
- {'guid': guid1},
- {'guid': guid2},
- ],
- ipc.get(['context'], query='qwe')['result'])
-
- self.assertEqual([
- {'guid': guid2},
- ],
- ipc.get(['context'], query='йцукен')['result'])
- self.assertEqual([
- {'guid': guid2},
- ],
- ipc.get(['context'], query='qwerty')['result'])
-
- def test_IgnoreClonesOnOpen(self):
- self.start_online_client()
- ipc = IPCConnection()
-
- guid = ipc.upload(['release'], StringIO(self.zips(['TestActivity/activity/activity.info', [
- '[Activity]',
- 'name = name',
- 'bundle_id = context',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license = Public Domain',
- 'stability = stable',
- ]])), cmd='submit', initial=True)
- ipc.put(['context', 'context'], True, cmd='clone')
- ts = time.time()
- os.utime('client/release/%s/%s' % (guid[:2], guid), (ts - 2 * 86400, ts - 2 * 86400))
- self.client_routes.close()
- self.stop_nodes()
-
- home_volume = self.start_online_client()
- cache_lifetime.value = 1
- self.client_routes.recycle()
- assert home_volume['release'].exists(guid)
- assert exists('client/release/%s/%s' % (guid[:2], guid))
-
- def test_IgnoreClonesWhileCheckingFreeSpace(self):
- home_volume = self.start_online_client()
- ipc = IPCConnection()
-
- guid = ipc.upload(['release'], StringIO(self.zips(['TestActivity/activity/activity.info', [
- '[Activity]',
- 'name = name',
- 'bundle_id = context',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license = Public Domain',
- 'stability = stable',
- ]])), cmd='submit', initial=True)
- ipc.put(['context', 'context'], True, cmd='clone')
-
- class statvfs(object):
- f_blocks = 100
- f_bfree = 10
- f_frsize = 1
-
- self.override(os, 'statvfs', lambda *args: statvfs())
- cache_limit.value = 10
-
- self.assertRaises(RuntimeError, self.client_routes._cache.ensure, 1, 0)
- assert home_volume['release'].exists(guid)
- assert exists('client/release/%s/%s' % (guid[:2], guid))
-
- def test_IgnoreClonesOnRecycle(self):
- home_volume = self.start_online_client()
- ipc = IPCConnection()
-
- guid = ipc.upload(['release'], StringIO(self.zips(['TestActivity/activity/activity.info', [
- '[Activity]',
- 'name = name',
- 'bundle_id = context',
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license = Public Domain',
- 'stability = stable',
- ]])), cmd='submit', initial=True)
- ipc.put(['context', 'context'], True, cmd='clone')
- ts = time.time()
- os.utime('client/release/%s/%s' % (guid[:2], guid), (ts - 2 * 86400, ts - 2 * 86400))
-
- cache_lifetime.value = 1
- self.client_routes.recycle()
- assert home_volume['release'].exists(guid)
- assert exists('client/release/%s/%s' % (guid[:2], guid))
-
- def test_LanguagesFallbackInRequests(self):
- self.start_online_client()
- ipc = IPCConnection()
-
- guid1 = self.node_volume['context'].create({
- 'type': 'activity',
- 'title': {'en': '1', 'ru': '2', 'es': '3'},
- 'summary': '',
- 'description': '',
- })
- guid2 = self.node_volume['context'].create({
- 'type': 'activity',
- 'title': {'en': '1', 'ru': '2'},
- 'summary': '',
- 'description': '',
- })
- guid3 = self.node_volume['context'].create({
- 'type': 'activity',
- 'title': {'en': '1'},
- 'summary': '',
- 'description': '',
- })
-
- i18n._default_langs = None
- os.environ['LANGUAGE'] = 'es:ru:en'
- ipc = IPCConnection()
- self.assertEqual('3', ipc.get(['context', guid1, 'title']))
- self.assertEqual('2', ipc.get(['context', guid2, 'title']))
- self.assertEqual('1', ipc.get(['context', guid3, 'title']))
-
- i18n._default_langs = None
- os.environ['LANGUAGE'] = 'ru:en'
- ipc = IPCConnection()
- self.assertEqual('2', ipc.get(['context', guid1, 'title']))
- self.assertEqual('2', ipc.get(['context', guid2, 'title']))
- self.assertEqual('1', ipc.get(['context', guid3, 'title']))
-
- i18n._default_langs = None
- os.environ['LANGUAGE'] = 'en'
- ipc = IPCConnection()
- self.assertEqual('1', ipc.get(['context', guid1, 'title']))
- self.assertEqual('1', ipc.get(['context', guid2, 'title']))
- self.assertEqual('1', ipc.get(['context', guid3, 'title']))
-
- i18n._default_langs = None
- os.environ['LANGUAGE'] = 'foo'
- ipc = IPCConnection()
- self.assertEqual('1', ipc.get(['context', guid1, 'title']))
- self.assertEqual('1', ipc.get(['context', guid2, 'title']))
- self.assertEqual('1', ipc.get(['context', guid3, 'title']))
-
-
-def call(routes, request):
- router = Router(routes)
- return router.call(request, Response())
-
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/client/server_routes.py b/tests/units/client/server_routes.py
deleted file mode 100755
index 8c72468..0000000
--- a/tests/units/client/server_routes.py
+++ /dev/null
@@ -1,226 +0,0 @@
-#!/usr/bin/env python
-# sugar-lint: disable
-
-import os
-import shutil
-import hashlib
-from os.path import exists
-
-from __init__ import tests, src_root
-
-from sugar_network import db, client, model
-from sugar_network.client import IPCConnection
-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
-
-
-class ServerRoutesTest(tests.Test):
-
- def test_whoami(self):
- self.start_node()
- ipc = IPCConnection()
-
- self.assertEqual(
- {'guid': tests.UID, 'roles': [], 'route': 'proxy'},
- ipc.get(cmd='whoami'))
-
- def test_Events(self):
- self.start_node()
- ipc = IPCConnection()
- events = []
-
- def read_events():
- for event in ipc.subscribe(event='!commit'):
- events.append(event)
- coroutine.spawn(read_events)
- coroutine.dispatch()
-
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- ipc.put(['context', guid], {
- 'title': 'title_2',
- })
- coroutine.sleep(.1)
- ipc.delete(['context', guid])
- coroutine.sleep(.1)
-
- self.assertEqual([
- {'guid': guid, 'resource': 'context', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'resource': 'context'},
- ],
- events)
- del events[:]
-
- guid = self.node_volume['context'].create({
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.node_volume['context'].update(guid, {
- 'title': 'title_2',
- })
- coroutine.sleep(.1)
- self.node_volume['context'].delete(guid)
- coroutine.sleep(.1)
-
- self.assertEqual([
- {'guid': guid, 'resource': 'context', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'resource': 'context'},
- ],
- events)
- del events[:]
-
- guid = self.home_volume['context'].create({
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.home_volume['context'].update(guid, {
- 'title': 'title_2',
- })
- coroutine.sleep(.1)
- self.home_volume['context'].delete(guid)
- coroutine.sleep(.1)
-
- self.assertEqual([], events)
- return
-
- self.node.stop()
- coroutine.sleep(.1)
- del events[:]
-
- guid = self.home_volume['context'].create({
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- self.home_volume['context'].update(guid, {
- 'title': 'title_2',
- })
- coroutine.sleep(.1)
- self.home_volume['context'].delete(guid)
- coroutine.sleep(.1)
-
- self.assertEqual([
- {'guid': guid, 'resource': 'context', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'resource': 'context'},
- ],
- events)
- del events[:]
-
- def test_BLOBs(self):
- self.start_node()
- ipc = IPCConnection()
-
- guid = ipc.post(['context'], {
- 'type': 'package',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- blob = 'logo_blob'
- ipc.request('PUT', ['context', guid, 'logo'], blob)
-
- self.assertEqual(
- blob,
- ipc.request('GET', ['context', guid, 'logo']).content)
- self.assertEqual({
- 'logo': {
- 'url': 'http://127.0.0.1:5555/context/%s/logo' % guid,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'image/png',
- },
- },
- ipc.get(['context', guid], reply=['logo']))
- self.assertEqual([{
- 'logo': {
- 'url': 'http://127.0.0.1:5555/context/%s/logo' % guid,
- 'blob_size': len(blob),
- 'digest': hashlib.sha1(blob).hexdigest(),
- 'mime_type': 'image/png',
- },
- }],
- ipc.get(['context'], reply=['logo'])['result'])
-
- self.assertEqual(
- file(src_root + '/sugar_network/static/httpdocs/images/package.png').read(),
- ipc.request('GET', ['context', guid, 'icon']).content)
- self.assertEqual({
- 'icon': {
- 'url': 'http://127.0.0.1:5555/static/images/package.png',
- 'mime_type': 'image/png',
- },
- },
- ipc.get(['context', guid], reply=['icon']))
- self.assertEqual([{
- 'icon': {
- 'url': 'http://127.0.0.1:5555/static/images/package.png',
- 'mime_type': 'image/png',
- },
- }],
- ipc.get(['context'], reply=['icon'])['result'])
-
- def test_PopulateNode(self):
- os.makedirs('disk/sugar-network')
- volume = Volume('db', model.RESOURCES)
- cp = ClientRoutes(volume)
-
- assert not cp.inline()
- trigger = self.wait_for_events(cp, event='inline', state='online')
- mountpoints.populate('.')
- coroutine.dispatch()
- assert trigger.value is not None
- assert cp.inline()
-
- def test_MountNode(self):
- volume = Volume('db', model.RESOURCES)
- cp = ClientRoutes(volume)
-
- trigger = self.wait_for_events(cp, event='inline', state='online')
- mountpoints.populate('.')
- assert not cp.inline()
- assert trigger.value is None
-
- coroutine.spawn(mountpoints.monitor, '.')
- coroutine.dispatch()
- os.makedirs('disk/sugar-network')
- trigger.wait()
- assert cp.inline()
-
- def test_UnmountNode(self):
- cp = self.start_node()
- assert cp.inline()
- trigger = self.wait_for_events(cp, event='inline', state='offline')
- shutil.rmtree('disk')
- trigger.wait()
- assert not cp.inline()
-
- def start_node(self):
- os.makedirs('disk/sugar-network')
- self.home_volume = Volume('db', model.RESOURCES)
- cp = ClientRoutes(self.home_volume)
- trigger = self.wait_for_events(cp, event='inline', state='online')
- coroutine.spawn(mountpoints.monitor, tests.tmpdir)
- trigger.wait()
- self.node_volume = cp._node.volume
- server = coroutine.WSGIServer(('127.0.0.1', client.ipc_port.value), Router(cp))
- coroutine.spawn(server.serve_forever)
- coroutine.dispatch()
- return cp
-
-
-if __name__ == '__main__':
- tests.main()
diff --git a/tests/units/db/resource.py b/tests/units/db/resource.py
index 64187aa..05aaddf 100755
--- a/tests/units/db/resource.py
+++ b/tests/units/db/resource.py
@@ -31,6 +31,7 @@ class ResourceTest(tests.Test):
def setUp(self, fork_num=0):
tests.Test.setUp(self, fork_num)
+ this.localcast = lambda x: x
this.broadcast = lambda x: x
def test_ActiveProperty_Slotted(self):
@@ -45,7 +46,7 @@ class ResourceTest(tests.Test):
def not_slotted(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
self.assertEqual(1, directory.metadata['slotted'].slot)
directory.create({'slotted': 'slotted', 'not_slotted': 'not_slotted'})
@@ -70,7 +71,7 @@ class ResourceTest(tests.Test):
def prop_2(self, value):
return value
- self.assertRaises(RuntimeError, Directory, tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ self.assertRaises(RuntimeError, Directory, tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
def test_ActiveProperty_Terms(self):
@@ -84,7 +85,7 @@ class ResourceTest(tests.Test):
def not_term(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
self.assertEqual('T', directory.metadata['term'].prefix)
guid = directory.create({'term': 'term', 'not_term': 'not_term'})
@@ -110,7 +111,7 @@ class ResourceTest(tests.Test):
def prop_2(self, value):
return value
- self.assertRaises(RuntimeError, Directory, tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ self.assertRaises(RuntimeError, Directory, tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
def test_ActiveProperty_FullTextSearch(self):
@@ -124,7 +125,7 @@ class ResourceTest(tests.Test):
def yes(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
self.assertEqual(False, directory.metadata['no'].full_text)
self.assertEqual(True, directory.metadata['yes'].full_text)
@@ -145,7 +146,7 @@ class ResourceTest(tests.Test):
def prop_2(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid = directory.create({'prop_1': '1', 'prop_2': '2'})
self.assertEqual(
@@ -165,7 +166,7 @@ class ResourceTest(tests.Test):
def prop(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid_1 = directory.create({'prop': '1'})
guid_2 = directory.create({'prop': '2'})
@@ -212,7 +213,7 @@ class ResourceTest(tests.Test):
('db/document/2/2/seqno', '{"value": 0}'),
)
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
self.assertEqual(0, directory._index.mtime)
for i in directory.populate():
@@ -264,7 +265,7 @@ class ResourceTest(tests.Test):
('db/document/3/3/seqno', ''),
)
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
populated = 0
for i in directory.populate():
@@ -285,7 +286,7 @@ class ResourceTest(tests.Test):
def prop(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid = directory.create({'guid': 'guid', 'prop': 'foo'})
self.assertEqual(
@@ -305,7 +306,7 @@ class ResourceTest(tests.Test):
def prop(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid_1 = directory.create({'prop': 'value'})
seqno = directory.get(guid_1).get('seqno')
@@ -349,7 +350,7 @@ class ResourceTest(tests.Test):
def prop2(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid = directory.create({'guid': '1', 'prop1': '1', 'prop2': '2'})
doc = directory.get(guid)
@@ -366,7 +367,7 @@ class ResourceTest(tests.Test):
def prop(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid = directory.create({'guid': '1', 'prop': {'ru': 'ru'}})
doc = directory.get(guid)
@@ -384,7 +385,7 @@ class ResourceTest(tests.Test):
def prop(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid = directory.create({'prop': '1'})
self.assertEqual([guid], [i.guid for i in directory.find()[0]])
directory.commit()
@@ -417,7 +418,7 @@ class ResourceTest(tests.Test):
def prop3(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid = directory.create({'guid': 'guid', 'prop1': 'set1', 'prop2': 'set2', 'prop3': 'set3'})
doc = directory.get(guid)
@@ -446,7 +447,7 @@ class ResourceTest(tests.Test):
def prop3(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid = directory.create({'guid': 'guid', 'prop2': 'set2'})
doc = directory.get(guid)
@@ -475,7 +476,7 @@ class ResourceTest(tests.Test):
def prop3(self, value):
return value
- directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno(), this.broadcast)
guid = directory.create({'guid': 'guid', 'prop2': 'set2'})
doc = directory.get(guid)
diff --git a/tests/units/db/routes.py b/tests/units/db/routes.py
index 9f9131e..4fa4cef 100755
--- a/tests/units/db/routes.py
+++ b/tests/units/db/routes.py
@@ -24,6 +24,10 @@ from sugar_network.toolkit import coroutine, http, i18n
class RoutesTest(tests.Test):
+ def setUp(self, fork_num=0):
+ tests.Test.setUp(self, fork_num)
+ this.localcast = lambda x: x
+
def test_PostDefaults(self):
class Document(db.Resource):
@@ -646,12 +650,6 @@ class RoutesTest(tests.Test):
def test_on_create_Override(self):
- class Routes(db.Routes):
-
- def on_create(self, request, props):
- props['prop'] = 'overriden'
- db.Routes.on_create(self, request, props)
-
class TestDocument(db.Resource):
@db.indexed_property(slot=1, default='')
@@ -662,13 +660,16 @@ class RoutesTest(tests.Test):
def localized_prop(self, value):
return value
+ def created(self):
+ self.posts['prop'] = 'overriden'
+
volume = db.Volume(tests.tmpdir, [TestDocument])
- router = Router(Routes(volume))
+ router = Router(db.Routes(volume))
- guid = this.call(method='POST', path=['testdocument'], content={'prop': 'foo'}, routes=Routes)
+ guid = this.call(method='POST', path=['testdocument'], content={'prop': 'foo'})
self.assertEqual('overriden', volume['testdocument'].get(guid)['prop'])
- this.call(method='PUT', path=['testdocument', guid], content={'prop': 'bar'}, routes=Routes)
+ this.call(method='PUT', path=['testdocument', guid], content={'prop': 'bar'})
self.assertEqual('bar', volume['testdocument'].get(guid)['prop'])
def test_on_update(self):
@@ -696,12 +697,6 @@ class RoutesTest(tests.Test):
def test_on_update_Override(self):
- class Routes(db.Routes):
-
- def on_update(self, request, props):
- props['prop'] = 'overriden'
- db.Routes.on_update(self, request, props)
-
class TestDocument(db.Resource):
@db.indexed_property(slot=1, default='')
@@ -712,13 +707,16 @@ class RoutesTest(tests.Test):
def localized_prop(self, value):
return value
+ def updated(self):
+ self.posts['prop'] = 'overriden'
+
volume = db.Volume(tests.tmpdir, [TestDocument])
- router = Router(Routes(volume))
+ router = Router(db.Routes(volume))
- guid = this.call(method='POST', path=['testdocument'], content={'prop': 'foo'}, routes=Routes)
+ guid = this.call(method='POST', path=['testdocument'], content={'prop': 'foo'})
self.assertEqual('foo', volume['testdocument'].get(guid)['prop'])
- this.call(method='PUT', path=['testdocument', guid], content={'prop': 'bar'}, routes=Routes)
+ this.call(method='PUT', path=['testdocument', guid], content={'prop': 'bar'})
self.assertEqual('overriden', volume['testdocument'].get(guid)['prop'])
def __test_DoNotPassGuidsForCreate(self):
@@ -796,6 +794,7 @@ class RoutesTest(tests.Test):
)
events = []
+ this.localcast = lambda x: events.append(x)
this.broadcast = lambda x: events.append(x)
volume = db.Volume(tests.tmpdir, [Document1, Document2])
volume['document1']
@@ -821,8 +820,8 @@ class RoutesTest(tests.Test):
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'},
+ {'event': 'update', 'resource': 'document1', 'guid': 'guid1', 'props': {'prop': 'foo'}},
+ {'event': 'update', 'resource': 'document2', 'guid': 'guid2', 'props': {'prop': 'bar'}},
],
events)
del events[:]
@@ -1516,7 +1515,7 @@ class RoutesTest(tests.Test):
events = []
volume = db.Volume(tests.tmpdir, [Document])
router = Router(db.Routes(volume))
- this.broadcast = lambda x: events.append(x)
+ this.localcast = lambda x: events.append(x)
guid = this.call(method='POST', path=['document'], content={})
self.assertRaises(http.NotFound, this.call, method='POST', path=['document', 'foo', 'bar'], content={})
@@ -1532,7 +1531,10 @@ class RoutesTest(tests.Test):
},
volume['document'].get(guid)['prop3'])
self.assertEqual([
- {'event': 'update', 'resource': 'document', 'guid': guid},
+ {'event': 'update', 'resource': 'document', 'guid': guid, 'props': {
+ 'mtime': 0,
+ 'prop3': {'0': {'seqno': 2, 'value': 0}},
+ }},
],
events)
@@ -1556,6 +1558,7 @@ class RoutesTest(tests.Test):
volume['document'].get(guid)['prop3'])
def test_RemoveAggprops(self):
+ self.override(time, 'time', lambda: 0)
class Document(db.Resource):
@@ -1570,7 +1573,7 @@ class RoutesTest(tests.Test):
events = []
volume = db.Volume(tests.tmpdir, [Document])
router = Router(db.Routes(volume))
- this.broadcast = lambda x: events.append(x)
+ this.localcast = lambda x: events.append(x)
guid = this.call(method='POST', path=['document'], content={})
agg_guid = this.call(method='POST', path=['document', guid, 'prop1'], content=2)
@@ -1594,7 +1597,10 @@ class RoutesTest(tests.Test):
{agg_guid: {'seqno': 4}},
volume['document'].get(guid)['prop2'])
self.assertEqual([
- {'event': 'update', 'resource': 'document', 'guid': guid},
+ {'event': 'update', 'resource': 'document', 'guid': guid, 'props': {
+ 'mtime': 0,
+ 'prop2': {agg_guid: {'seqno': 4}},
+ }},
],
events)
@@ -1609,7 +1615,7 @@ class RoutesTest(tests.Test):
events = []
volume = db.Volume(tests.tmpdir, [Document])
router = Router(db.Routes(volume))
- this.broadcast = lambda x: events.append(x)
+ this.localcast = lambda x: events.append(x)
guid = this.call(method='POST', path=['document'], content={})
del events[:]
@@ -1617,6 +1623,7 @@ class RoutesTest(tests.Test):
self.assertEqual([], events)
def test_UpdateAggprops(self):
+ self.override(time, 'time', lambda: 0)
class Document(db.Resource):
@@ -1631,7 +1638,7 @@ class RoutesTest(tests.Test):
events = []
volume = db.Volume(tests.tmpdir, [Document])
router = Router(db.Routes(volume))
- this.broadcast = lambda x: events.append(x)
+ this.localcast = lambda x: events.append(x)
guid = this.call(method='POST', path=['document'], content={})
agg_guid = this.call(method='POST', path=['document', guid, 'prop1'], content=1)
@@ -1655,11 +1662,15 @@ class RoutesTest(tests.Test):
{agg_guid: {'seqno': 4, 'value': 3}},
volume['document'].get(guid)['prop2'])
self.assertEqual([
- {'event': 'update', 'resource': 'document', 'guid': guid},
+ {'event': 'update', 'resource': 'document', 'guid': guid, 'props': {
+ 'mtime': 0,
+ 'prop2': {agg_guid: {'seqno': 4, 'value': 3}},
+ }},
],
events)
def test_PostAbsentAggpropsOnUpdate(self):
+ self.override(time, 'time', lambda: 0)
class Document(db.Resource):
@@ -1670,7 +1681,7 @@ class RoutesTest(tests.Test):
events = []
volume = db.Volume(tests.tmpdir, [Document])
router = Router(db.Routes(volume))
- this.broadcast = lambda x: events.append(x)
+ this.localcast = lambda x: events.append(x)
guid = this.call(method='POST', path=['document'], content={})
del events[:]
@@ -1679,7 +1690,10 @@ class RoutesTest(tests.Test):
{'absent': {'seqno': 2, 'value': 'probe'}},
volume['document'].get(guid)['prop'])
self.assertEqual([
- {'event': 'update', 'resource': 'document', 'guid': guid},
+ {'event': 'update', 'resource': 'document', 'guid': guid, 'props': {
+ 'mtime': 0,
+ 'prop': {'absent': {'seqno': 2, 'value': 'probe'}},
+ }},
],
events)
@@ -1824,6 +1838,27 @@ class RoutesTest(tests.Test):
sorted([guid2, guid3]),
sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='comments:c')['result']]))
+ def test_HandleDeletes(self):
+
+ class Document(db.Resource):
+ pass
+
+ volume = db.Volume(tests.tmpdir, [Document])
+ router = Router(db.Routes(volume))
+
+ guid = this.call(method='POST', path=['document'], content={})
+ self.assertEqual('active', volume['document'][guid]['state'])
+
+ events = []
+ this.localcast = lambda x: events.append(x)
+ this.call(method='DELETE', path=['document', guid], principal=tests.UID)
+
+ self.assertRaises(http.NotFound, this.call, method='GET', path=['document', guid])
+ self.assertEqual('deleted', volume['document'][guid]['state'])
+ self.assertEqual(
+ [{'event': 'delete', 'resource': 'document', 'guid': guid}],
+ events)
+
if __name__ == '__main__':
tests.main()
diff --git a/tests/units/db/volume.py b/tests/units/db/volume.py
index 3b10d7e..b5f01a7 100755
--- a/tests/units/db/volume.py
+++ b/tests/units/db/volume.py
@@ -31,7 +31,7 @@ class VolumeTest(tests.Test):
def setUp(self, fork_num=0):
tests.Test.setUp(self, fork_num)
- this.broadcast = lambda x: x
+ this.localcast = lambda x: x
def test_diff(self):
@@ -323,6 +323,51 @@ class VolumeTest(tests.Test):
self.assertRaises(StopIteration, patch.next)
self.assertEqual([[4, None]], r)
+ def test_clone(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property()
+ def prop1(self, value):
+ return value
+
+ @db.stored_property()
+ def prop2(self, value):
+ return value
+
+ @db.stored_property(db.Blob)
+ def prop3(self, value):
+ return value
+
+ @db.stored_property(db.Blob)
+ def prop4(self, value):
+ return value
+
+ volume = db.Volume('.', [Document])
+
+ volume['document'].create({
+ 'guid': 'guid',
+ 'prop1': '1',
+ 'prop2': 2,
+ 'prop3': volume.blobs.post('333', '3/3').digest,
+ 'prop4': volume.blobs.post('4444', '4/4').digest,
+ })
+ self.utime('db/document/gu/guid', 1)
+
+ self.assertEqual([
+ {'content-type': '3/3', 'content-length': '3', 'x-seqno': '1'},
+ {'content-type': '4/4', 'content-length': '4', 'x-seqno': '2'},
+ {'resource': 'document'},
+ {'guid': 'guid', 'patch': {
+ 'guid': {'value': 'guid', 'mtime': 1},
+ 'prop1': {'value': '1', 'mtime': 1},
+ 'prop2': {'value': 2, 'mtime': 1},
+ 'prop3': {'value': hashlib.sha1('333').hexdigest(), 'mtime': 1},
+ 'prop4': {'value': hashlib.sha1('4444').hexdigest(), 'mtime': 1},
+ }},
+ ],
+ [dict(i) for i in volume.clone('document', 'guid')])
+
def test_patch_New(self):
class Document(db.Resource):
@@ -735,7 +780,7 @@ class VolumeTest(tests.Test):
def prop(self, value):
return value + 1
- directory = Directory('document', Document, IndexWriter, _SessionSeqno())
+ directory = Directory('document', Document, IndexWriter, _SessionSeqno(), this.localcast)
directory.patch('1', {
'guid': {'mtime': 1, 'value': '1'},
@@ -772,7 +817,7 @@ class VolumeTest(tests.Test):
patch = generator()
self.assertEqual((101, [[1, 3]]), volume.patch(patch))
- assert volume['document'].exists('1')
+ assert volume['document']['1'].exists
class _SessionSeqno(object):
diff --git a/tests/units/model/context.py b/tests/units/model/context.py
index bd39c04..45a1ce8 100755
--- a/tests/units/model/context.py
+++ b/tests/units/model/context.py
@@ -96,20 +96,20 @@ class ContextTest(tests.Test):
assert release1 == str(hashlib.sha1(bundle1).hexdigest())
self.assertEqual({
release1: {
- 'seqno': 5,
+ 'seqno': 10,
'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
'value': {
'license': ['Public Domain'],
'announce': next(volume['post'].find(query='title:1')[0]).guid,
'version': [[1], 0],
'requires': {},
- 'command': 'true',
+ 'commands': {'activity': {'exec': 'true'}},
'bundles': {'*-*': {'blob': str(hashlib.sha1(bundle1).hexdigest()), 'unpack_size': len(activity_info1)}},
'stability': 'stable',
},
},
}, conn.get(['context', context, 'releases']))
- assert blobs.get(str(hashlib.sha1(bundle1).hexdigest()))
+ assert volume.blobs.get(str(hashlib.sha1(bundle1).hexdigest())).exists
activity_info2 = '\n'.join([
'[Activity]',
@@ -125,71 +125,71 @@ class ContextTest(tests.Test):
assert release2 == str(hashlib.sha1(bundle2).hexdigest())
self.assertEqual({
release1: {
- 'seqno': 5,
+ 'seqno': 10,
'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
'value': {
'license': ['Public Domain'],
'announce': next(volume['post'].find(query='title:1')[0]).guid,
'version': [[1], 0],
'requires': {},
- 'command': 'true',
+ 'commands': {'activity': {'exec': 'true'}},
'bundles': {'*-*': {'blob': str(hashlib.sha1(bundle1).hexdigest()), 'unpack_size': len(activity_info1)}},
'stability': 'stable',
},
},
release2: {
- 'seqno': 7,
+ 'seqno': 13,
'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
'value': {
'license': ['Public Domain'],
'announce': next(volume['post'].find(query='title:2')[0]).guid,
'version': [[2], 0],
'requires': {},
- 'command': 'true',
+ 'commands': {'activity': {'exec': 'true'}},
'bundles': {'*-*': {'blob': str(hashlib.sha1(bundle2).hexdigest()), 'unpack_size': len(activity_info2)}},
'stability': 'stable',
},
},
}, conn.get(['context', context, 'releases']))
- assert blobs.get(str(hashlib.sha1(bundle1).hexdigest()))
- assert blobs.get(str(hashlib.sha1(bundle2).hexdigest()))
+ assert volume.blobs.get(str(hashlib.sha1(bundle1).hexdigest())).exists
+ assert volume.blobs.get(str(hashlib.sha1(bundle2).hexdigest())).exists
conn.delete(['context', context, 'releases', release1])
self.assertEqual({
release1: {
- 'seqno': 8,
+ 'seqno': 15,
'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
},
release2: {
- 'seqno': 7,
+ 'seqno': 13,
'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
'value': {
'license': ['Public Domain'],
'announce': next(volume['post'].find(query='title:2')[0]).guid,
'version': [[2], 0],
'requires': {},
- 'command': 'true',
+ 'commands': {'activity': {'exec': 'true'}},
'bundles': {'*-*': {'blob': str(hashlib.sha1(bundle2).hexdigest()), 'unpack_size': len(activity_info2)}},
'stability': 'stable',
},
},
}, conn.get(['context', context, 'releases']))
- assert blobs.get(str(hashlib.sha1(bundle1).hexdigest())) is None
- assert blobs.get(str(hashlib.sha1(bundle2).hexdigest()))
+ assert not volume.blobs.get(str(hashlib.sha1(bundle1).hexdigest())).exists
+ assert volume.blobs.get(str(hashlib.sha1(bundle2).hexdigest())).exists
conn.delete(['context', context, 'releases', release2])
self.assertEqual({
release1: {
- 'seqno': 8,
+ 'seqno': 15,
'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
},
release2: {
- 'seqno': 9,
+ 'seqno': 17,
'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
},
}, conn.get(['context', context, 'releases']))
- assert blobs.get(str(hashlib.sha1(bundle1).hexdigest())) is None
- assert blobs.get(str(hashlib.sha1(bundle2).hexdigest())) is None
+ assert not volume.blobs.get(str(hashlib.sha1(bundle1).hexdigest())).exists
+ assert not volume.blobs.get(str(hashlib.sha1(bundle2).hexdigest())).exists
def test_IncrementReleasesSeqnoOnNewReleases(self):
events = []
@@ -287,13 +287,29 @@ class ContextTest(tests.Test):
], [i for i in events if i['event'] == 'release'])
self.assertEqual(0, volume.releases_seqno.value)
+ bundle = self.zips(('topdir/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 2',
+ 'license = Public Domain',
+ ])))
+ release = conn.upload(['context', context, 'releases'], StringIO(bundle))
+ self.assertEqual([
+ {'seqno': 1, 'event': 'release'}
+ ], [i for i in events if i['event'] == 'release'])
+ self.assertEqual(1, volume.releases_seqno.value)
+ del events[:]
+
conn.put(['context', context], {
'dependencies': 'dep',
})
self.assertEqual([
- {'event': 'release', 'seqno': 1},
+ {'event': 'release', 'seqno': 2},
], [i for i in events if i['event'] == 'release'])
- self.assertEqual(1, volume.releases_seqno.value)
+ self.assertEqual(2, volume.releases_seqno.value)
def test_IncrementReleasesSeqnoOnDeletes(self):
events = []
@@ -311,22 +327,28 @@ class ContextTest(tests.Test):
], [i for i in events if i['event'] == 'release'])
self.assertEqual(0, volume.releases_seqno.value)
- conn.put(['context', context], {
- 'layer': ['deleted'],
- })
+ bundle = self.zips(('topdir/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 2',
+ 'license = Public Domain',
+ ])))
+ release = conn.upload(['context', context, 'releases'], StringIO(bundle))
self.assertEqual([
- {'event': 'release', 'seqno': 1},
+ {'seqno': 1, 'event': 'release'}
], [i for i in events if i['event'] == 'release'])
self.assertEqual(1, volume.releases_seqno.value)
+ del events[:]
- conn.put(['context', context], {
- 'layer': [],
- })
+ conn.delete(['context', context])
self.assertEqual([
- {'event': 'release', 'seqno': 1},
{'event': 'release', 'seqno': 2},
], [i for i in events if i['event'] == 'release'])
self.assertEqual(2, volume.releases_seqno.value)
+ del events[:]
def test_RestoreReleasesSeqno(self):
events = []
@@ -341,6 +363,16 @@ class ContextTest(tests.Test):
'description': 'description',
'dependencies': 'dep',
})
+ bundle = self.zips(('topdir/activity/activity.info', '\n'.join([
+ '[Activity]',
+ 'name = Activity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 2',
+ 'license = Public Domain',
+ ])))
+ release = conn.upload(['context', context, 'releases'], StringIO(bundle))
self.assertEqual(1, volume.releases_seqno.value)
volume.close()
diff --git a/tests/units/model/model.py b/tests/units/model/model.py
index 49fd1a3..857a54b 100755
--- a/tests/units/model/model.py
+++ b/tests/units/model/model.py
@@ -10,6 +10,8 @@ from __init__ import tests
from sugar_network import db
from sugar_network.model import load_bundle
from sugar_network.model.post import Post
+from sugar_network.model.context import Context
+from sugar_network.node.model import User
from sugar_network.client import IPCConnection, Connection, keyfile
from sugar_network.toolkit.router import Request
from sugar_network.toolkit.coroutine import this
@@ -19,6 +21,7 @@ from sugar_network.toolkit import i18n, http, coroutine, enforce
class ModelTest(tests.Test):
def test_RatingSort(self):
+ this.localcast = lambda event: None
directory = db.Volume('db', [Post])['post']
directory.create({'guid': '1', 'context': '', 'type': 'post', 'title': {}, 'message': {}, 'rating': [0, 0]})
@@ -518,7 +521,7 @@ class ModelTest(tests.Test):
release['requires'])
def test_load_bundle_IgnoreNotSupportedContextTypes(self):
- volume = self.start_master()
+ volume = self.start_master([User, Context])
conn = Connection(auth=http.SugarAuth(keyfile.value))
context = conn.post(['context'], {
@@ -528,9 +531,9 @@ class ModelTest(tests.Test):
'description': '',
})
this.request = Request(method='POST', path=['context', context])
- aggid = conn.post(['context', context, 'releases'], -1)
+ aggid = conn.post(['context', context, 'releases'], {})
self.assertEqual({
- aggid: {'seqno': 4, 'value': -1, 'author': {tests.UID: {'role': 3, 'name': tests.UID, 'order': 0}}},
+ aggid: {'seqno': 4, 'value': {}, 'author': {tests.UID: {'role': 3, 'name': tests.UID, 'order': 0}}},
}, volume['context'][context]['releases'])
diff --git a/tests/units/model/post.py b/tests/units/model/post.py
index 45b85e1..655c08e 100755
--- a/tests/units/model/post.py
+++ b/tests/units/model/post.py
@@ -5,7 +5,6 @@ from __init__ import tests
from sugar_network import db
from sugar_network.client import Connection, keyfile
-from sugar_network.model.user import User
from sugar_network.model.context import Context
from sugar_network.model.post import Post
from sugar_network.toolkit.coroutine import this
diff --git a/tests/units/model/routes.py b/tests/units/model/routes.py
index be5ecdf..06a3dc3 100755
--- a/tests/units/model/routes.py
+++ b/tests/units/model/routes.py
@@ -10,7 +10,6 @@ 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, Request
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import coroutine
@@ -49,7 +48,7 @@ class RoutesTest(tests.Test):
self.assertEqual([
{'event': 'pong'},
{'guid': 'guid', 'resource': 'document', 'event': 'create'},
- {'guid': 'guid', 'resource': 'document', 'event': 'update'},
+ {'guid': 'guid', 'resource': 'document', 'event': 'update', 'props': {'prop': 'value2'}},
{'guid': 'guid', 'event': 'delete', 'resource': u'document'},
],
events)
diff --git a/tests/units/node/master.py b/tests/units/node/master.py
index 69fc6a7..2577ba9 100755
--- a/tests/units/node/master.py
+++ b/tests/units/node/master.py
@@ -20,8 +20,8 @@ from sugar_network.client import Connection, keyfile, api
from sugar_network.db.directory import Directory
from sugar_network import db, node, toolkit
from sugar_network.node.master import MasterRoutes
+from sugar_network.node.model import User
from sugar_network.db.volume import Volume
-from sugar_network.model.user import User
from sugar_network.toolkit.router import Response, File
from sugar_network.toolkit import coroutine, parcel, http
@@ -64,7 +64,7 @@ class MasterTest(tests.Test):
response = conn.request('POST', [], patch, params={'cmd': 'push'})
reply = parcel.decode(response.raw)
- assert volume['document'].exists('1')
+ assert volume['document']['1'].exists
blob = volume.blobs.get(hashlib.sha1('1').hexdigest())
self.assertEqual('1', ''.join(blob.iter_content()))
blob = volume.blobs.get('foo/bar')
@@ -165,7 +165,7 @@ class MasterTest(tests.Test):
})
reply = parcel.decode(response.raw)
- assert volume['document'].exists('1')
+ assert volume['document']['1'].exists
blob_digest = hashlib.sha1('blob').hexdigest()
blob = volume.blobs.get(blob_digest)
self.assertEqual('blob', ''.join(blob.iter_content()))
@@ -541,7 +541,7 @@ class MasterTest(tests.Test):
],
[(packet.header, [dict(record) for record in packet]) for packet in parcel.decode(response.raw)])
- assert volume['document'].exists('2')
+ assert volume['document']['2'].exists
self.assertEqual('ccc', ''.join(blob2.iter_content()))
diff --git a/tests/units/node/model.py b/tests/units/node/model.py
index 6788105..4187d3c 100755
--- a/tests/units/node/model.py
+++ b/tests/units/node/model.py
@@ -8,10 +8,10 @@ from __init__ import tests
from sugar_network import db, toolkit
from sugar_network.client import Connection, keyfile, api
-from sugar_network.model.user import User
from sugar_network.model.post import Post
from sugar_network.model.context import Context
from sugar_network.node import model, obs
+from sugar_network.node.model import User
from sugar_network.node.routes import NodeRoutes
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit.router import Request, Router
diff --git a/tests/units/node/node.py b/tests/units/node/node.py
index 0f934d4..89373dc 100755
--- a/tests/units/node/node.py
+++ b/tests/units/node/node.py
@@ -20,9 +20,8 @@ from sugar_network.client import Connection, keyfile, api
from sugar_network.toolkit import http, coroutine
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.user import User
+from sugar_network.node.model import User
from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, ACL, route
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit import http
@@ -30,72 +29,6 @@ from sugar_network.toolkit import http
class NodeTest(tests.Test):
- def test_HandleDeletes(self):
- volume = self.start_master()
- conn = Connection(auth=http.SugarAuth(keyfile.value))
- volume['user'].create({'guid': tests.UID, 'name': 'user', 'pubkey': tests.PUBKEY})
-
- guid = this.call(method='POST', path=['context'], principal=tests.UID, content={
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- guid_path = 'master/db/context/%s/%s' % (guid[:2], guid)
-
- assert exists(guid_path)
- self.assertEqual({
- 'guid': guid,
- 'title': 'title',
- 'layer': [],
- },
- this.call(method='GET', path=['context', guid], reply=['guid', 'title', 'layer']))
- self.assertEqual([], volume['context'].get(guid)['layer'])
-
- def subscribe():
- for event in conn.subscribe():
- events.append(event)
- events = []
- coroutine.spawn(subscribe)
- coroutine.dispatch()
-
- this.call(method='DELETE', path=['context', guid], principal=tests.UID)
- coroutine.dispatch()
- self.assertRaises(http.NotFound, this.call, method='GET', path=['context', guid], reply=['guid', 'title'])
- self.assertEqual(['deleted'], volume['context'].get(guid)['layer'])
-
- def test_DeletedRestoredHandlers(self):
- trigger = []
-
- class TestDocument(db.Resource):
-
- def deleted(self):
- trigger.append(False)
-
- def restored(self):
- trigger.append(True)
-
- volume = self.start_master([TestDocument, User])
- conn = Connection(auth=http.SugarAuth(keyfile.value))
-
- guid = conn.post(['testdocument'], {})
- self.assertEqual([], trigger)
-
- conn.put(['testdocument', guid, 'layer'], ['deleted'])
- self.assertEqual([False], trigger)
-
- conn.put(['testdocument', guid, 'layer'], [])
- self.assertEqual([False, True], trigger)
-
- conn.put(['testdocument', guid, 'layer'], ['bar'])
- self.assertEqual([False, True], trigger)
-
- conn.put(['testdocument', guid, 'layer'], ['deleted'])
- self.assertEqual([False, True, False], trigger)
-
- conn.put(['testdocument', guid, 'layer'], ['deleted', 'foo'])
- self.assertEqual([False, True, False], trigger)
-
def test_RegisterUser(self):
volume = self.start_master()
conn = Connection(auth=http.SugarAuth(keyfile.value))
@@ -369,7 +302,7 @@ class NodeTest(tests.Test):
this.call(method='GET', path=['context', guid])
self.assertNotEqual([], this.call(method='GET', path=['context'])['result'])
- volume['context'].update(guid, {'layer': ['deleted']})
+ volume['context'].update(guid, {'state': 'deleted'})
self.assertRaises(http.NotFound, this.call, method='GET', path=['context', guid])
self.assertEqual([], this.call(method='GET', path=['context'])['result'])
@@ -415,7 +348,7 @@ class NodeTest(tests.Test):
'description': 'description',
})
- self.assertRaises(http.BadRequest, this.call, method='POST', path=['context'], principal=tests.UID, content={
+ self.assertRaises(RuntimeError, this.call, method='POST', path=['context'], principal=tests.UID, content={
'guid': guid,
'type': 'activity',
'title': 'title',
@@ -496,7 +429,7 @@ class NodeTest(tests.Test):
self.assertEqual({
release: {
- 'seqno': 6,
+ 'seqno': 9,
'author': {tests.UID: {'name': tests.UID, 'order': 0, 'role': 3}},
'value': {
'license': ['Public Domain'],
@@ -568,6 +501,7 @@ class NodeTest(tests.Test):
'version': [[1], 0],
'size': len(activity_pack),
'unpack_size': len(activity_unpack),
+ 'content-type': 'application/vnd.olpc-sugar',
},
'dep': {
'title': 'dep',
@@ -575,6 +509,7 @@ class NodeTest(tests.Test):
'version': [[2], 0],
'size': len(dep_pack),
'unpack_size': len(dep_unpack),
+ 'content-type': 'application/vnd.olpc-sugar',
},
'package': {
'packages': ['package.bin'],
@@ -646,6 +581,7 @@ class NodeTest(tests.Test):
'version': [[1], 0],
'size': len(activity_pack),
'unpack_size': len(activity_unpack),
+ 'content-type': 'application/vnd.olpc-sugar',
},
'dep': {
'title': 'dep',
@@ -653,6 +589,7 @@ class NodeTest(tests.Test):
'version': [[2], 0],
'size': len(dep_pack),
'unpack_size': len(dep_unpack),
+ 'content-type': 'application/vnd.olpc-sugar',
},
'package': {
'packages': ['package.bin'],
@@ -662,7 +599,7 @@ class NodeTest(tests.Test):
conn.get(['context', 'activity'], cmd='solve',
stability='developer', lsb_id='Ubuntu', lsb_release='10.04', requires=['dep', 'package']))
- def test_Clone(self):
+ def test_Resolve(self):
volume = self.start_master()
conn = http.Connection(api.value, http.SugarAuth(keyfile.value))
@@ -699,7 +636,7 @@ class NodeTest(tests.Test):
conn.put(['context', 'package', 'releases', '*'], {'binary': ['package.bin']})
response = Response()
- reply = conn.call(Request(method='GET', path=['context', 'activity'], cmd='clone'), response)
+ reply = conn.call(Request(method='GET', path=['context', 'activity'], cmd='resolve'), response)
assert activity_blob == reply.read()
def test_AggpropInsertAccess(self):
diff --git a/tests/units/node/slave.py b/tests/units/node/slave.py
index 55da003..3afab04 100755
--- a/tests/units/node/slave.py
+++ b/tests/units/node/slave.py
@@ -14,8 +14,8 @@ from sugar_network.client import Connection, keyfile
from sugar_network.node import master_api
from sugar_network.node.master import MasterRoutes
from sugar_network.node.slave import SlaveRoutes
+from sugar_network.node.model import User
from sugar_network.db.volume import Volume
-from sugar_network.model.user import User
from sugar_network.toolkit.router import Router, File
from sugar_network.toolkit import coroutine, http, parcel
diff --git a/tests/units/toolkit/router.py b/tests/units/toolkit/router.py
index 0c18cee..61d8dff 100755
--- a/tests/units/toolkit/router.py
+++ b/tests/units/toolkit/router.py
@@ -550,6 +550,7 @@ class RouterTest(tests.Test):
@postroute
def _(self, request, response, result, exception):
+ print exception
postroutes.append(('_', result, str(exception)))
class B1(A):
diff --git a/tests/units/toolkit/toolkit.py b/tests/units/toolkit/toolkit.py
index b3e7f6b..87baedc 100755
--- a/tests/units/toolkit/toolkit.py
+++ b/tests/units/toolkit/toolkit.py
@@ -16,16 +16,12 @@ class ToolkitTest(tests.Test):
def test_Seqno_commit(self):
seqno = Seqno(tests.tmpdir + '/seqno')
- self.assertEqual(False, seqno.commit())
-
seqno.next()
- self.assertEqual(True, seqno.commit())
- self.assertEqual(False, seqno.commit())
+ seqno.commit()
seqno.next()
seqno = Seqno(tests.tmpdir + '/seqno')
self.assertEqual(1, seqno.value)
- self.assertEqual(False, seqno.commit())
def test_readline(self):