Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tests/units/client/online_routes.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/units/client/online_routes.py')
-rwxr-xr-xtests/units/client/online_routes.py1778
1 files changed, 900 insertions, 878 deletions
diff --git a/tests/units/client/online_routes.py b/tests/units/client/online_routes.py
index 891b239..79b01cb 100755
--- a/tests/units/client/online_routes.py
+++ b/tests/units/client/online_routes.py
@@ -7,12 +7,12 @@ import time
import shutil
import zipfile
from cStringIO import StringIO
-from os.path import exists
+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, clones, injector, routes
+from sugar_network.client import IPCConnection, journal, routes, implementations
from sugar_network.toolkit import coroutine, http
from sugar_network.toolkit.spec import Spec
from sugar_network.client.routes import ClientRoutes, Request, Response
@@ -30,26 +30,9 @@ import requests
class OnlineRoutes(tests.Test):
- def test_inline(self):
- cp = ClientRoutes(Volume('client', model.RESOURCES), client.api_url.value)
- assert not cp.inline()
-
- trigger = self.wait_for_events(cp, event='inline', state='online')
- coroutine.sleep(1)
- self.start_master()
- trigger.wait(1)
- assert trigger.value is None
- assert not cp.inline()
-
- request = Request(method='GET', cmd='whoami')
- cp.whoami(request, Response())
- 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 setUp(self, fork_num=0):
+ tests.Test.setUp(self, fork_num)
+ self.override(implementations, '_activity_id_new', lambda: 'activity_id')
def test_whoami(self):
self.start_online_client()
@@ -59,109 +42,102 @@ class OnlineRoutes(tests.Test):
{'guid': tests.UID, 'roles': []},
ipc.get(cmd='whoami'))
- def test_clone_Activities(self):
- self.home_volume = self.start_online_client()
+ def test_Events(self):
+ local_volume = self.start_online_client()
ipc = IPCConnection()
- coroutine.spawn(clones.monitor, self.home_volume['context'], ['Activities'])
+ events = []
- context = ipc.post(['context'], {
+ 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',
})
- impl = ipc.post(['implementation'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
+ ipc.put(['context', guid], {
+ 'title': 'title_2',
})
- self.node_volume['implementation'].update(impl, {'data': {
- 'spec': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'true',
- },
- },
- 'extract': 'TestActivitry',
- },
- },
- 'blob': StringIO(self.zips(['TestActivitry/activity/activity.info', [
- '[Activity]',
- 'name = TestActivitry',
- 'bundle_id = %s' % context,
- 'exec = false',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ]])),
- }})
-
- assert not exists('Activities/TestActivitry/activity/activity.info')
- assert not exists('Activities/TestActivitry_1/activity/activity.info')
- self.assertEqual(
- {'clone': 0, 'type': ['activity']},
- ipc.get(['context', context], reply=['clone']))
-
- ipc.put(['context', context], 2, cmd='clone')
- coroutine.sleep(.5)
-
- assert exists('Activities/TestActivitry/activity/activity.info')
- assert not exists('Activities/TestActivitry_1/activity/activity.info')
- self.assertEqual(
- {'clone': 2},
- ipc.get(['context', context], reply=['clone']))
-
- ipc.put(['context', context], 2, cmd='clone')
- coroutine.sleep(.5)
-
- assert exists('Activities/TestActivitry/activity/activity.info')
- assert not exists('Activities/TestActivitry_1/activity/activity.info')
- self.assertEqual(
- {'clone': 2},
- ipc.get(['context', context], reply=['clone']))
-
- ipc.put(['context', context], 1, cmd='clone', force=1)
- coroutine.sleep(.5)
+ coroutine.sleep(.1)
+ ipc.delete(['context', guid])
+ coroutine.sleep(.1)
- assert exists('Activities/TestActivitry/activity/activity.info')
- assert exists('Activities/TestActivitry_1/activity/activity.info')
- self.assertEqual(
- {'clone': 2},
- ipc.get(['context', context], reply=['clone']))
+ self.assertEqual([
+ {'guid': guid, 'resource': 'context', 'event': 'create'},
+ {'guid': guid, 'resource': 'context', 'event': 'update'},
+ {'guid': guid, 'event': 'delete', 'resource': 'context'},
+ ],
+ events)
+ del events[:]
- ipc.put(['context', context], 0, cmd='clone')
- coroutine.sleep(.5)
+ 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)
- assert not exists('Activities/TestActivitry/activity/activity.info')
- assert not exists('Activities/TestActivitry_1/activity/activity.info')
- self.assertEqual(
- {'clone': 0},
- ipc.get(['context', context], reply=['clone']))
+ self.assertEqual([
+ {'guid': guid, 'resource': 'context', 'event': 'create'},
+ {'guid': guid, 'resource': 'context', 'event': 'update'},
+ {'guid': guid, 'event': 'delete', 'resource': 'context'},
+ ],
+ events)
+ del events[:]
- ipc.put(['context', context], 1, cmd='clone')
- coroutine.sleep(.5)
+ 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)
- assert exists('Activities/TestActivitry/activity/activity.info')
- self.assertEqual(
- {'clone': 2},
- ipc.get(['context', context], reply=['clone']))
+ self.assertEqual([], events)
- trigger = self.wait_for_events(ipc, event='inline', state='offline')
self.node.stop()
- trigger.wait()
- assert ipc.get(cmd='status')['route'] == 'offline'
+ coroutine.sleep(.1)
+ del events[:]
- self.assertEqual(
- {'clone': 2},
- ipc.get(['context', context], reply=['clone']))
+ 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)
- def test_clone_ActivitiesWithStabilityPreferences(self):
- self.home_volume = self.start_online_client()
+ 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()
- coroutine.spawn(clones.monitor, self.home_volume['context'], ['Activities'])
context = ipc.post(['context'], {
'type': 'activity',
@@ -169,7 +145,6 @@ class OnlineRoutes(tests.Test):
'summary': 'summary',
'description': 'description',
})
-
impl1 = ipc.post(['implementation'], {
'context': context,
'license': 'GPLv3+',
@@ -177,216 +152,306 @@ class OnlineRoutes(tests.Test):
'stability': 'stable',
'notes': '',
})
- info1 = '\n'.join([
- '[Activity]',
- 'name = TestActivitry',
- 'bundle_id = %s' % context,
- 'exec = false',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ])
self.node_volume['implementation'].update(impl1, {'data': {
- 'spec': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'true',
- },
- },
- 'extract': 'TestActivitry',
- },
- },
- 'blob': StringIO(self.zips(['TestActivitry/activity/activity.info', info1])),
+ 'spec': {'*-*': {}},
}})
-
impl2 = ipc.post(['implementation'], {
'context': context,
'license': 'GPLv3+',
'version': '2',
- 'stability': 'testing',
+ 'stability': 'stable',
'notes': '',
})
- info2 = '\n'.join([
- '[Activity]',
- 'name = TestActivitry',
- 'bundle_id = %s' % context,
- 'exec = false',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ])
self.node_volume['implementation'].update(impl2, {'data': {
- 'spec': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'true',
- },
- },
- 'extract': 'TestActivitry2',
+ 'spec': {'*-*': {
+ 'requires': {
+ 'dep1': {},
+ 'dep2': {'restrictions': [['1', '2']]},
+ 'dep3': {'restrictions': [[None, '2']]},
+ 'dep4': {'restrictions': [['3', None]]},
},
- },
- 'blob': StringIO(self.zips(['TestActivitry2/activity/activity.info', info2])),
+ }},
}})
- ipc.put(['context', context], 2, cmd='clone')
- coroutine.sleep(.5)
- not exists('Activities/TestActivitry2/activity/activity.info')
- self.assertEqual(info1, file('Activities/TestActivitry/activity/activity.info').read())
-
- self.touch(('config', [
- '[stabilities]',
- '%s = testing stable' % context,
- ]))
- Option.load(['config'])
-
- shutil.rmtree('cache/solutions')
- ipc.put(['context', context], 2, cmd='clone', force=1)
- coroutine.sleep(.5)
- self.assertEqual(info2, file('Activities/TestActivitry2/activity/activity.info').read())
+ self.assertEqual({
+ 'implementations': [
+ {
+ 'version': '1',
+ 'arch': '*-*',
+ 'stability': 'stable',
+ 'guid': impl1,
+ 'license': ['GPLv3+'],
+ },
+ {
+ 'version': '2',
+ 'arch': '*-*',
+ 'stability': 'stable',
+ 'guid': impl2,
+ 'requires': {
+ 'dep1': {},
+ 'dep2': {'restrictions': [['1', '2']]},
+ 'dep3': {'restrictions': [[None, '2']]},
+ 'dep4': {'restrictions': [['3', None]]},
+ },
+ 'license': ['GPLv3+'],
+ },
+ ],
+ },
+ ipc.get(['context', context], cmd='feed'))
- def test_clone_ActivityImpl(self):
- self.home_volume = self.start_online_client()
+ def test_BLOBs(self):
+ self.start_online_client()
ipc = IPCConnection()
- coroutine.spawn(clones.monitor, self.home_volume['context'], ['Activities'])
- context = ipc.post(['context'], {
+ guid = ipc.post(['context'], {
'type': 'activity',
'title': 'title',
'summary': 'summary',
'description': 'description',
})
+ ipc.request('PUT', ['context', guid, 'preview'], 'image')
- impl1 = ipc.post(['implementation'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
+ self.assertEqual(
+ 'image',
+ ipc.request('GET', ['context', guid, 'preview']).content)
+ self.assertEqual(
+ {'preview': 'http://127.0.0.1:8888/context/%s/preview' % guid},
+ ipc.get(['context', guid], reply=['preview']))
+ self.assertEqual(
+ [{'preview': 'http://127.0.0.1:8888/context/%s/preview' % guid}],
+ ipc.get(['context'], reply=['preview'])['result'])
+
+ self.assertEqual(
+ file(src_root + '/sugar_network/static/httpdocs/images/missing.png').read(),
+ ipc.request('GET', ['context', guid, 'icon']).content)
+ self.assertEqual(
+ {'icon': 'http://127.0.0.1:8888/static/images/missing.png'},
+ ipc.get(['context', guid], reply=['icon']))
+ self.assertEqual(
+ [{'icon': 'http://127.0.0.1:8888/static/images/missing.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.node_volume['implementation'].update(impl1, {'data': {
- 'blob': StringIO(self.zips(('TestActivity/activity/activity.info', [
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = %s' % context,
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license=GPLv3+',
- ]))),
- 'spec': {
- '*-*': {
- 'extract': 'TestActivity',
- 'commands': {'activity': {'exec': 'true'}},
- 'requires': {
- 'dep1': {},
- },
- },
- },
- }})
- impl2 = ipc.post(['implementation'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '2',
- 'stability': 'stable',
- 'notes': '',
+ 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, Implementation])
+ conn = IPCConnection()
+ events = []
+
+ def read_events():
+ for event in conn.subscribe(event='!commit'):
+ events.append(event)
+ coroutine.spawn(read_events)
+ coroutine.dispatch()
+
+ context = conn.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
})
- self.node_volume['implementation'].update(impl2, {'data': {
- 'blob': StringIO(self.zips(('TestActivity/activity/activity.info', [
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = %s' % context,
- 'exec = true',
- 'icon = icon',
- 'activity_version = 2',
- 'license=GPLv3+',
- ]))),
- 'spec': {
- '*-*': {
- 'extract': 'TestActivity',
- 'commands': {'activity': {'exec': 'true'}},
- 'requires': {
- 'dep2': {},
- },
- },
- },
- }})
- impl3 = ipc.post(['implementation'], {
+ self.assertRaises(http.NotFound, conn.put, ['context', context], True, cmd='clone')
+ coroutine.dispatch()
+ self.assertEqual({
+ 'event': 'failure',
+ 'method': 'PUT',
+ 'cmd': 'clone',
+ 'resource': 'context',
+ 'guid': context,
+ 'prop': None,
+ 'exception': 'NotFound',
+ 'error': """\
+Can't find all required implementations:
+- %s -> (problem)
+ No known implementations at all""" % context,
+ },
+ events[-1])
+ assert not exists('cache/solutions/%s/%s' % (context[:2], context))
+
+ impl = conn.post(['implementation'], {
'context': context,
'license': 'GPLv3+',
- 'version': '3',
- 'stability': 'developer',
+ 'version': '1',
+ 'stability': 'stable',
'notes': '',
})
- self.node_volume['implementation'].update(impl3, {'data': {
- 'blob': StringIO(self.zips(('TestActivity/activity/activity.info', [
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = %s' % context,
- 'exec = true',
- 'icon = icon',
- 'activity_version = 3',
- 'license=GPLv3+',
- ]))),
+ self.node_volume['implementation'].update(impl, {'data': {
+ 'extract': 'topdir',
'spec': {
'*-*': {
- 'extract': 'TestActivity',
- 'commands': {'activity': {'exec': 'true'}},
- 'requires': {
- 'dep3': {},
+ 'commands': {
+ 'activity': {
+ 'exec': 'echo',
+ },
},
},
},
}})
- self.assertRaises(RuntimeError, ipc.put, ['context', context], 2, cmd='clone', nodeps=1, requires='foo')
- coroutine.sleep(.1)
- self.assertEqual({'clone': 0}, ipc.get(['context', context], reply=['clone']))
- assert not exists('Activities/TestActivity/activity/activity.info')
-
- ipc.put(['context', context], 2, cmd='clone', nodeps=1)
- # XXX seems to be an ugly low level bug, removing the following sleep means not reasing HTTP response for the next request
- coroutine.sleep(.1)
- self.assertEqual({'clone': 2}, ipc.get(['context', context], reply=['clone']))
- self.assertEqual('2', Spec('Activities/TestActivity/activity/activity.info')['version'])
-
- ipc.put(['context', context], 0, cmd='clone')
- coroutine.sleep(.1)
- self.assertEqual({'clone': 0}, ipc.get(['context', context], reply=['clone']))
- assert not exists('Activities/TestActivity/activity/activity.info')
-
- ipc.put(['context', context], 2, cmd='clone', nodeps=1, stability='developer')
- coroutine.sleep(.1)
- self.assertEqual({'clone': 2}, ipc.get(['context', context], reply=['clone']))
- self.assertEqual('3', Spec('Activities/TestActivity/activity/activity.info')['version'])
-
- ipc.put(['context', context], 0, cmd='clone')
- coroutine.sleep(.1)
- self.assertEqual({'clone': 0}, ipc.get(['context', context], reply=['clone']))
- assert not exists('Activities/TestActivity/activity/activity.info')
-
- ipc.put(['context', context], 2, cmd='clone', nodeps=1, requires='dep1')
- coroutine.sleep(.1)
- self.assertEqual({'clone': 2}, ipc.get(['context', context], reply=['clone']))
- self.assertEqual('1', Spec('Activities/TestActivity/activity/activity.info')['version'])
+ self.assertRaises(http.NotFound, conn.put, ['context', context], True, cmd='clone')
+ coroutine.dispatch()
+ self.assertEqual({
+ 'event': 'failure',
+ 'method': 'PUT',
+ 'cmd': 'clone',
+ 'resource': 'context',
+ 'guid': context,
+ 'prop': None,
+ 'exception': 'NotFound',
+ 'error': 'BLOB does not exist',
+ 'solution': [{
+ 'command': ['echo'],
+ 'context': context,
+ 'guid': impl,
+ 'license': ['GPLv3+'],
+ 'extract': 'topdir',
+ 'stability': 'stable',
+ 'version': '1',
+ 'path': tests.tmpdir + '/client/implementation/%s/%s/data.blob' % (impl[:2], impl),
+ }],
+ },
+ events[-1])
+ assert not exists('cache/solutions/%s/%s' % (context[:2], context))
def test_clone_Content(self):
- self.start_online_client()
- updates = []
-
- def journal_update(self, guid, data=None, preview=None, **kwargs):
- if data is not None:
- kwargs['data'] = data.read()
- updates.append((guid, kwargs))
-
- self.override(journal.Routes, '__init__', lambda *args: None)
- self.override(journal.Routes, 'journal_update', journal_update)
- self.override(journal.Routes, 'journal_delete', lambda self, guid: updates.append((guid,)))
-
+ local = self.start_online_client([User, Context, Implementation])
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': 'content',
@@ -401,260 +466,540 @@ class OnlineRoutes(tests.Test):
'stability': 'stable',
'notes': '',
})
- ipc.request('PUT', ['implementation', impl, 'data'], 'version_1')
+ blob = 'content'
+ self.node_volume['implementation'].update(impl, {'data': {'blob': StringIO(blob), 'foo': 'bar'}})
+ clone_path = 'client/context/%s/%s/.clone' % (context[:2], context)
- self.assertEqual({'clone': 0, 'type': ['content']}, ipc.get(['context', context], reply=['clone']))
-
- ipc.put(['context', context], 2, cmd='clone')
- self.touch('datastore/%s/%s/metadata/uid' % (context[:2], context))
+ ipc.put(['context', context], True, cmd='clone')
+ coroutine.dispatch()
- self.assertEqual([
- (context, {'activity_id': impl, 'data': 'version_1', 'description': 'description', 'title': 'title', 'mime_type': 'application/octet-stream'}),
- ],
- updates)
+ self.assertEqual({
+ 'event': 'update',
+ 'guid': context,
+ 'resource': 'context',
+ },
+ events[-1])
self.assertEqual(
- {'clone': 2, 'type': ['content']},
- ipc.get(['context', context], reply=['clone']))
- del updates[:]
-
- ipc.request('PUT', ['implementation', impl, 'data'], 'version_2',
- headers={'Content-Type': 'foo/bar'})
- ipc.put(['context', context], 2, cmd='clone')
-
+ sorted([{'guid': context}]),
+ sorted(ipc.get(['context'], layer='clone')['result']))
self.assertEqual(
- [],
- updates)
+ sorted([{'guid': context}]),
+ sorted(ipc.get(['context'])['result']))
self.assertEqual(
- {'clone': 2, 'type': ['content']},
- ipc.get(['context', context], reply=['clone']))
-
- ipc.put(['context', context], 1, cmd='clone', force=1)
-
- self.assertEqual([
- (context, {'activity_id': impl, 'data': 'version_2', 'description': 'description', 'title': 'title', 'mime_type': 'foo/bar'}),
- ],
- updates)
+ 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(
- {'clone': 2, 'type': ['content']},
- ipc.get(['context', context], reply=['clone']))
- del updates[:]
+ [(context, ['clone'])],
+ [(i.guid, i['layer']) for i in local['context'].find(reply='layer')[0]])
+ self.assertEqual({
+ 'layer': ['clone'],
+ 'type': ['content'],
+ '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['implementation'].get(impl).properties(['context', 'license', 'version', 'stability']))
+ blob_path = 'client/implementation/%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['implementation'].get(impl).meta('data'))
+ self.assertEqual('content', file(blob_path).read())
+ assert exists(clone_path + '/data.blob')
+ assert not exists('cache/solutions/%s/%s' % (context[:2], context))
- ipc.put(['context', context], 0, cmd='clone')
- shutil.rmtree('datastore/%s/%s' % (context[:2], context))
+ ipc.put(['context', context], False, cmd='clone')
+ coroutine.dispatch()
- self.assertEqual([
- (context,),
- ],
- updates)
+ self.assertEqual({
+ 'event': 'update',
+ 'guid': context,
+ 'resource': 'context',
+ },
+ events[-1])
self.assertEqual(
- {'clone': 0, 'type': ['content']},
- ipc.get(['context', context], reply=['clone']))
- del updates[:]
-
- def test_clone_Artifacts(self):
- self.start_online_client([User, Context, Implementation, Artifact])
- updates = []
+ 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': ['content'],
+ '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/implementation/%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['implementation'].get(impl).meta('data'))
+ self.assertEqual('content', file(blob_path).read())
+ assert not lexists(clone_path)
+ assert not exists('cache/solutions/%s/%s' % (context[:2], context))
- def journal_update(self, guid, data=None, preview=None, **kwargs):
- if data is not None:
- kwargs['data'] = data.read()
- updates.append((guid, kwargs))
+ ipc.put(['context', context], True, cmd='clone')
+ coroutine.dispatch()
- self.override(journal.Routes, '__init__', lambda *args: None)
- self.override(journal.Routes, 'journal_update', journal_update)
- self.override(journal.Routes, 'journal_delete', lambda self, guid: updates.append((guid,)))
+ 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')
+ assert not exists('cache/solutions/%s/%s' % (context[:2], context))
+ def test_clone_Activity(self):
+ local = self.start_online_client([User, Context, Implementation])
ipc = IPCConnection()
+ events = []
- artifact = ipc.post(['artifact'], {
- 'context': 'context',
- 'type': 'instance',
- 'title': 'title',
- 'description': 'description',
- })
- ipc.request('PUT', ['artifact', artifact, 'data'], 'data')
+ def read_events():
+ for event in ipc.subscribe(event='!commit'):
+ events.append(event)
+ coroutine.spawn(read_events)
+ coroutine.dispatch()
- self.assertEqual({'clone': 0}, ipc.get(['artifact', artifact], reply=['clone']))
+ 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(['implementation'], StringIO(blob), cmd='release', initial=True)
+ clone_path = 'client/context/bu/bundle_id/.clone'
+ blob_path = tests.tmpdir + '/client/implementation/%s/%s/data.blob' % (impl[:2], impl)
+ solution = [{
+ 'guid': impl,
+ 'context': 'bundle_id',
+ 'extract': 'TestActivity',
+ 'license': ['Public Domain'],
+ 'stability': 'stable',
+ 'version': '1',
+ 'command': ['true'],
+ 'path': blob_path,
+ }]
- ipc.put(['artifact', artifact], 2, cmd='clone')
- self.touch('datastore/%s/%s/metadata/uid' % (artifact[:2], artifact))
+ ipc.put(['context', 'bundle_id'], True, cmd='clone')
+ coroutine.dispatch()
- self.assertEqual([
- (artifact, {'data': 'data', 'description': 'description', 'title': 'title', 'activity': 'context'}),
- ],
- updates)
+ self.assertEqual({
+ 'event': 'update',
+ 'guid': 'bundle_id',
+ 'resource': 'context',
+ },
+ events[-1])
self.assertEqual(
- {'clone': 2},
- ipc.get(['artifact', artifact], reply=['clone']))
- del updates[:]
-
- ipc.put(['artifact', artifact], 2, cmd='clone')
-
+ sorted([{'guid': 'bundle_id'}]),
+ sorted(ipc.get(['context'], layer='clone')['result']))
self.assertEqual(
- [],
- updates)
+ sorted([{'guid': 'bundle_id'}]),
+ sorted(ipc.get(['context'])['result']))
self.assertEqual(
- {'clone': 2},
- ipc.get(['artifact', artifact], reply=['clone']))
+ 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['implementation'].get(impl).properties(['context', 'license', 'version', 'stability']))
+ self.assertEqual({
+ 'seqno': 5,
+ 'unpack_size': len(activity_info),
+ 'blob_size': len(blob),
+ 'blob': blob_path,
+ 'mtime': int(os.stat(blob_path[:-5]).st_mtime),
+ 'extract': 'TestActivity',
+ 'mime_type': 'application/vnd.olpc-sugar',
+ 'spec': {
+ '*-*': {
+ 'requires': {},
+ 'commands': {'activity': {'exec': 'true'}},
+ },
+ },
+ },
+ local['implementation'].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_url.value, ['stable'], solution],
+ json.load(file('cache/solutions/bu/bundle_id')))
- ipc.request('PUT', ['artifact', artifact, 'data'], 'data_2')
- ipc.put(['artifact', artifact], 1, cmd='clone', force=1)
+ ipc.put(['context', 'bundle_id'], False, cmd='clone')
+ coroutine.dispatch()
- self.assertEqual([
- (artifact, {'data': 'data_2', 'description': 'description', 'title': 'title', 'activity': 'context'}),
- ],
- updates)
+ 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),
+ 'blob': blob_path,
+ 'mtime': int(os.stat(blob_path[:-5]).st_mtime),
+ 'extract': 'TestActivity',
+ 'mime_type': 'application/vnd.olpc-sugar',
+ 'spec': {
+ '*-*': {
+ 'requires': {},
+ 'commands': {'activity': {'exec': 'true'}},
+ },
+ },
+ },
+ local['implementation'].get(impl).meta('data'))
+ self.assertEqual(activity_info, file(blob_path + '/activity/activity.info').read())
+ assert not exists(clone_path)
self.assertEqual(
- {'clone': 2},
- ipc.get(['artifact', artifact], reply=['clone']))
- del updates[:]
+ [client.api_url.value, ['stable'], solution],
+ json.load(file('cache/solutions/bu/bundle_id')))
- ipc.put(['artifact', artifact], 0, cmd='clone')
- shutil.rmtree('datastore/%s/%s' % (artifact[:2], artifact))
+ ipc.put(['context', 'bundle_id'], True, cmd='clone')
+ coroutine.dispatch()
- self.assertEqual([
- (artifact,),
- ],
- updates)
+ self.assertEqual({
+ 'event': 'update',
+ 'guid': 'bundle_id',
+ 'resource': 'context',
+ },
+ events[-1])
self.assertEqual(
- {'clone': 0},
- ipc.get(['artifact', artifact], reply=['clone']))
- del updates[:]
+ 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_url.value, ['stable'], solution],
+ json.load(file('cache/solutions/bu/bundle_id')))
- def test_favorite(self):
- self.start_online_client()
+ def test_clone_ActivityWithStabilityPreferences(self):
+ local = self.start_online_client([User, Context, Implementation])
ipc = IPCConnection()
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
+ 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(['implementation'], StringIO(blob1), cmd='release', initial=True)
- self.assertEqual(
- {'favorite': 0, 'type': ['activity']},
- ipc.get(['context', context], reply=['favorite']))
+ 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(['implementation'], StringIO(blob2), cmd='release', initial=True)
- ipc.put(['context', context], True, cmd='favorite')
- coroutine.sleep(.5)
- self.assertEqual(
- {'favorite': True},
- ipc.get(['context', context], reply=['favorite']))
+ ipc.put(['context', 'bundle_id'], True, cmd='clone')
+ coroutine.dispatch()
+ self.assertEqual({'layer': ['clone']}, ipc.get(['context', 'bundle_id'], reply='layer'))
+ self.assertEqual([impl1], [i.guid for i in local['implementation'].find()[0]])
+ self.assertEqual(impl1, basename(os.readlink('client/context/bu/bundle_id/.clone')))
- ipc.put(['context', context], False, cmd='favorite')
- self.assertEqual(
- {'favorite': False},
- ipc.get(['context', context], reply=['favorite']))
+ self.touch(('config', [
+ '[stabilities]',
+ 'bundle_id = buggy stable',
+ ]))
+ Option.load(['config'])
- ipc.put(['context', context], True, cmd='favorite')
- coroutine.sleep(.5)
- self.assertEqual(
- {'favorite': True},
- ipc.get(['context', context], reply=['favorite']))
+ ipc.put(['context', 'bundle_id'], False, cmd='clone')
+ ipc.put(['context', 'bundle_id'], True, cmd='clone')
+ coroutine.dispatch()
+ self.assertEqual({'layer': ['clone']}, ipc.get(['context', 'bundle_id'], reply='layer'))
+ self.assertEqual([impl1, impl2], [i.guid for i in local['implementation'].find()[0]])
+ self.assertEqual(impl2, basename(os.readlink('client/context/bu/bundle_id/.clone')))
- trigger = self.wait_for_events(ipc, event='inline', state='offline')
- self.node.stop()
- trigger.wait()
- assert ipc.get(cmd='status')['route'] == 'offline'
+ def test_clone_Head(self):
+ local = self.start_online_client([User, Context, Implementation])
+ ipc = IPCConnection()
- self.assertEqual(
- {'favorite': True},
- ipc.get(['context', context], reply=['favorite']))
+ 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(['implementation'], StringIO(blob), cmd='release', initial=True)
+ blob_path = 'master/implementation/%s/%s/data.blob' % (impl[:2], impl)
- def test_subscribe(self):
- self.start_online_client()
+ self.assertEqual({
+ 'guid': impl,
+ 'license': ['Public Domain'],
+ 'stability': 'stable',
+ 'version': '1',
+ 'context': 'bundle_id',
+ 'data': {
+ 'blob_size': len(blob),
+ 'extract': 'TestActivity',
+ 'mime_type': 'application/vnd.olpc-sugar',
+ 'mtime': int(os.stat(blob_path[:-5]).st_mtime),
+ 'seqno': 3,
+ 'spec': {'*-*': {'commands': {'activity': {'exec': 'true'}}, 'requires': {}}},
+ 'unpack_size': len(activity_info),
+ },
+ },
+ ipc.head(['context', 'bundle_id'], cmd='clone'))
+
+ ipc.put(['context', 'bundle_id'], True, cmd='clone')
+ coroutine.dispatch()
+ blob_path = tests.tmpdir + '/client/implementation/%s/%s/data.blob' % (impl[:2], impl)
+
+ self.assertEqual({
+ 'guid': impl,
+ 'license': ['Public Domain'],
+ 'stability': 'stable',
+ 'version': '1',
+ 'context': 'bundle_id',
+ 'data': {
+ 'blob': blob_path,
+ 'blob_size': len(blob),
+ 'extract': 'TestActivity',
+ '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, Implementation])
ipc = IPCConnection()
- events = []
+
+ blob = self.zips(['TestActivity/activity/activity.info', [
+ '[Activity]',
+ 'name = TestActivity',
+ 'bundle_id = bundle_id',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license=Public Domain',
+ ]])
+ impl = ipc.upload(['implementation'], StringIO(blob), cmd='release', initial=True)
+ coroutine.sleep(.1)
def read_events():
for event in ipc.subscribe(event='!commit'):
events.append(event)
- job = coroutine.spawn(read_events)
- coroutine.dispatch(.1)
+ events = []
+ coroutine.spawn(read_events)
+ coroutine.dispatch()
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- coroutine.dispatch(.1)
- ipc.put(['context', guid], {
- 'title': 'title_2',
- })
- coroutine.dispatch(.1)
- ipc.delete(['context', guid])
- coroutine.sleep(.5)
- job.kill()
+ ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')
+ coroutine.sleep(.1)
+ solution = [{
+ 'guid': impl,
+ 'context': 'bundle_id',
+ 'extract': 'TestActivity',
+ 'license': ['Public Domain'],
+ 'stability': 'stable',
+ 'version': '1',
+ 'command': ['true'],
+ 'path': tests.tmpdir + '/client/implementation/%s/%s/data.blob' % (impl[:2], impl),
+ }]
+ log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id.log'
self.assertEqual([
- {'guid': guid, 'resource': 'context', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'resource': 'context'},
+ {'event': 'exec', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['true', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
+ {'event': 'exit', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['true', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
],
events)
- del events[:]
+ assert local['implementation'].exists(impl)
+ self.assertEqual(
+ [client.api_url.value, ['stable'], solution],
+ json.load(file('cache/solutions/bu/bundle_id')))
- job = coroutine.spawn(read_events)
- coroutine.dispatch(.1)
- guid = self.node_volume['context'].create({
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- coroutine.dispatch(.1)
- self.node_volume['context'].update(guid, {
- 'title': 'title_2',
- })
- coroutine.dispatch(.1)
- self.node_volume['context'].delete(guid)
- coroutine.dispatch(.1)
- job.kill()
+ 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(['implementation'], StringIO(blob), cmd='release')
+ coroutine.sleep(.1)
+
+ shutil.rmtree('cache/solutions')
+ del events[:]
+ ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')
+ coroutine.sleep(.1)
+ solution = [{
+ 'guid': impl,
+ 'context': 'bundle_id',
+ 'extract': 'TestActivity',
+ 'license': ['Public Domain'],
+ 'stability': 'stable',
+ 'version': '2',
+ 'command': ['true'],
+ 'path': tests.tmpdir + '/client/implementation/%s/%s/data.blob' % (impl[:2], impl),
+ }]
+ log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id_1.log'
self.assertEqual([
- {'guid': guid, 'resource': 'context', 'event': 'create'},
- {'guid': guid, 'resource': 'context', 'event': 'update'},
- {'guid': guid, 'event': 'delete', 'resource': 'context'},
+ {'event': 'exec', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['true', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
+ {'event': 'exit', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['true', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
],
events)
+ assert local['implementation'].exists(impl)
+ self.assertEqual(
+ [client.api_url.value, ['stable'], solution],
+ json.load(file('cache/solutions/bu/bundle_id')))
- def test_BLOBs(self):
- self.start_online_client()
- ipc = IPCConnection()
+ self.node.stop()
+ coroutine.sleep(.1)
- guid = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- ipc.request('PUT', ['context', guid, 'preview'], 'image')
+ del events[:]
+ ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')
+ coroutine.sleep(.1)
+ log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id_2.log'
+ self.assertEqual([
+ {'event': 'exec', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['true', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
+ {'event': 'exit', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['true', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
+ ],
+ events)
+ assert local['implementation'].exists(impl)
self.assertEqual(
- 'image',
- ipc.request('GET', ['context', guid, 'preview']).content)
- self.assertEqual(
- {'preview': 'http://127.0.0.1:8888/context/%s/preview' % guid},
- ipc.get(['context', guid], reply=['preview']))
- self.assertEqual(
- [{'preview': 'http://127.0.0.1:8888/context/%s/preview' % guid}],
- ipc.get(['context'], reply=['preview'])['result'])
+ [client.api_url.value, ['stable'], solution],
+ json.load(file('cache/solutions/bu/bundle_id')))
+ shutil.rmtree('cache/solutions')
+ del events[:]
+ ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')
+ coroutine.sleep(.1)
+
+ log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id_3.log'
+ self.assertEqual([
+ {'event': 'exec', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['true', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
+ {'event': 'exit', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['true', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
+ ],
+ events)
+ assert local['implementation'].exists(impl)
self.assertEqual(
- file(src_root + '/sugar_network/static/httpdocs/images/missing.png').read(),
- ipc.request('GET', ['context', guid, 'icon']).content)
- self.assertEqual(
- {'icon': 'http://127.0.0.1:8888/static/images/missing.png'},
- ipc.get(['context', guid], reply=['icon']))
+ [client.api_url.value, ['stable'], solution],
+ json.load(file('cache/solutions/bu/bundle_id')))
+
+ def test_launch_ActivityFailed(self):
+ local = self.start_online_client([User, Context, Implementation])
+ ipc = IPCConnection()
+
+ 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(['implementation'], StringIO(blob), cmd='release', initial=True)
+ coroutine.sleep(.1)
+
+ def read_events():
+ for event in ipc.subscribe(event='!commit'):
+ events.append(event)
+ events = []
+ coroutine.spawn(read_events)
+ coroutine.dispatch()
+
+ ipc.get(['context', 'bundle_id'], cmd='launch', foo='bar')
+ coroutine.sleep(.1)
+
+ solution = [{
+ 'guid': impl,
+ 'context': 'bundle_id',
+ 'extract': 'TestActivity',
+ 'license': ['Public Domain'],
+ 'stability': 'stable',
+ 'version': '1',
+ 'command': ['false'],
+ 'path': tests.tmpdir + '/client/implementation/%s/%s/data.blob' % (impl[:2], impl),
+ }]
+ log_path = tests.tmpdir + '/.sugar/default/logs/bundle_id.log'
+ self.assertEqual([
+ {'event': 'exec', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['false', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
+ {'event': 'failure', 'error': 'Process exited with 1 status', 'cmd': 'launch', 'guid': 'bundle_id', 'args': ['false', '-b', 'bundle_id', '-a', 'activity_id'], 'foo': 'bar', 'activity_id': 'activity_id', 'log_path': log_path, 'solution': solution},
+ ],
+ events)
+ assert local['implementation'].exists(impl)
self.assertEqual(
- [{'icon': 'http://127.0.0.1:8888/static/images/missing.png'}],
- ipc.get(['context'], reply=['icon'])['result'])
+ [client.api_url.value, ['stable'], solution],
+ json.load(file('cache/solutions/bu/bundle_id')))
- def test_Feeds(self):
+ 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',
@@ -662,6 +1007,10 @@ class OnlineRoutes(tests.Test):
'summary': 'summary',
'description': 'description',
})
+ assert self.client_routes._node_mtime == mtime
+
+ coroutine.sleep(1.1)
+
impl1 = ipc.post(['implementation'], {
'context': context,
'license': 'GPLv3+',
@@ -672,6 +1021,11 @@ class OnlineRoutes(tests.Test):
self.node_volume['implementation'].update(impl1, {'data': {
'spec': {'*-*': {}},
}})
+ assert self.client_routes._node_mtime > mtime
+
+ mtime = self.client_routes._node_mtime
+ coroutine.sleep(1.1)
+
impl2 = ipc.post(['implementation'], {
'context': context,
'license': 'GPLv3+',
@@ -689,37 +1043,34 @@ class OnlineRoutes(tests.Test):
},
}},
}})
+ assert self.client_routes._node_mtime > mtime
- self.assertEqual({
- 'name': 'title',
- 'implementations': [
- {
- 'version': '1',
- 'arch': '*-*',
- 'stability': 'stable',
- 'guid': impl1,
- 'unpack_size': None,
- 'blob_size': None,
- },
- {
- 'version': '2',
- 'arch': '*-*',
- 'stability': 'stable',
- 'guid': impl2,
- 'requires': {
- 'dep1': {},
- 'dep2': {'restrictions': [['1', '2']]},
- 'dep3': {'restrictions': [[None, '2']]},
- 'dep4': {'restrictions': [['3', None]]},
- },
- 'unpack_size': None,
- 'blob_size': None,
- },
- ],
- },
- ipc.get(['context', context], cmd='feed'))
+ def test_NoNeedlessRemoteRequests(self):
+ home_volume = self.start_online_client()
+ ipc = IPCConnection()
+
+ guid = ipc.post(['context'], {
+ 'type': 'content',
+ '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_Feeds_RestrictLayers(self):
+ def test_RestrictLayers(self):
self.start_online_client([User, Context, Implementation, Artifact])
ipc = IPCConnection()
@@ -741,70 +1092,48 @@ class OnlineRoutes(tests.Test):
self.node_volume['implementation'].update(impl, {'data': {
'spec': {'*-*': {}},
}})
- artifact = ipc.post(['artifact'], {
- 'type': 'instance',
- 'context': 'context',
- 'title': 'title',
- 'description': 'description',
- 'layer': 'public',
- })
-
- self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['context'], reply='layer')['result'])
- self.assertEqual(
- [],
- ipc.get(['context'], reply='layer', layer='foo')['result'])
- self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['context'], reply='layer', layer='public')['result'])
self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['implementation'], reply='layer')['result'])
+ [{'guid': context, 'layer': ['public']}],
+ ipc.get(['context'], reply=['guid', 'layer'])['result'])
self.assertEqual(
[],
- ipc.get(['implementation'], reply='layer', layer='foo')['result'])
+ ipc.get(['context'], reply=['guid', 'layer'], layer='foo')['result'])
self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['implementation'], reply='layer', layer='public')['result'])
+ [{'guid': context, 'layer': ['public']}],
+ ipc.get(['context'], reply=['guid', 'layer'], layer='public')['result'])
self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['artifact'], reply='layer')['result'])
+ [{'guid': impl, 'layer': ['public']}],
+ ipc.get(['implementation'], reply=['guid', 'layer'])['result'])
self.assertEqual(
[],
- ipc.get(['artifact'], reply='layer', layer='foo')['result'])
+ ipc.get(['implementation'], reply=['guid', 'layer'], layer='foo')['result'])
self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['artifact'], reply='layer', layer='public')['result'])
+ [{'guid': impl, 'layer': ['public']}],
+ ipc.get(['implementation'], reply=['guid', 'layer'], layer='public')['result'])
self.assertEqual({
- 'name': 'title',
'implementations': [{
'stability': 'stable',
'guid': impl,
'arch': '*-*',
'version': '1',
- 'unpack_size': None,
- 'blob_size': None,
+ 'license': ['GPLv3+'],
}],
},
ipc.get(['context', context], cmd='feed'))
self.assertEqual({
- 'name': 'title',
'implementations': [],
},
ipc.get(['context', context], cmd='feed', layer='foo'))
self.assertEqual({
- 'name': 'title',
'implementations': [{
'stability': 'stable',
'guid': impl,
'arch': '*-*',
'version': '1',
- 'unpack_size': None,
- 'blob_size': None,
+ 'license': ['GPLv3+'],
}],
},
ipc.get(['context', context], cmd='feed', layer='public'))
@@ -813,192 +1142,43 @@ class OnlineRoutes(tests.Test):
self.assertEqual(
[],
- ipc.get(['context'], reply='layer')['result'])
+ ipc.get(['context'], reply=['guid', 'layer'])['result'])
self.assertEqual(
[],
- ipc.get(['context'], reply='layer', layer='foo')['result'])
+ ipc.get(['context'], reply=['guid', 'layer'], layer='foo')['result'])
self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['context'], reply='layer', layer='public')['result'])
+ [{'guid': context, 'layer': ['public']}],
+ ipc.get(['context'], reply=['guid', 'layer'], layer='public')['result'])
self.assertEqual(
[],
- ipc.get(['implementation'], reply='layer')['result'])
+ ipc.get(['implementation'], reply=['guid', 'layer'])['result'])
self.assertEqual(
[],
- ipc.get(['implementation'], reply='layer', layer='foo')['result'])
+ ipc.get(['implementation'], reply=['guid', 'layer'], layer='foo')['result'])
self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['implementation'], reply='layer', layer='public')['result'])
-
- self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['artifact'], reply='layer')['result'])
- self.assertEqual(
- [],
- ipc.get(['artifact'], reply='layer', layer='foo')['result'])
- self.assertEqual(
- [{'layer': ['public']}],
- ipc.get(['artifact'], reply='layer', layer='public')['result'])
+ [{'guid': impl, 'layer': ['public']}],
+ ipc.get(['implementation'], reply=['guid', 'layer'], layer='public')['result'])
self.assertEqual({
- 'name': 'title',
'implementations': [],
},
ipc.get(['context', context], cmd='feed'))
self.assertEqual({
- 'name': 'title',
'implementations': [],
},
ipc.get(['context', context], cmd='feed', layer='foo'))
self.assertEqual({
- 'name': 'title',
'implementations': [{
'stability': 'stable',
'guid': impl,
'arch': '*-*',
'version': '1',
- 'unpack_size': None,
- 'blob_size': None,
+ 'license': ['GPLv3+'],
}],
},
ipc.get(['context', context], cmd='feed', layer='public'))
- def test_Feeds_PreferLocalFeeds(self):
- home_volume = self.start_online_client()
- ipc = IPCConnection()
-
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl = ipc.post(['implementation'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '2',
- 'stability': 'stable',
- 'notes': '',
- })
- self.node_volume['implementation'].update(impl, {'data': {
- 'spec': {'*-*': {}},
- }})
-
- self.assertEqual({
- 'name': 'title',
- 'implementations': [
- {
- 'version': '2',
- 'arch': '*-*',
- 'stability': 'stable',
- 'guid': impl,
- 'unpack_size': None,
- 'blob_size': None,
- },
- ],
- },
- ipc.get(['context', context], cmd='feed'))
-
- self.touch(('Activities/activity-1/activity/activity.info', [
- '[Activity]',
- 'name = TestActivity',
- 'bundle_id = ' + context,
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license = Public Domain',
- ]))
- monitor = coroutine.spawn(clones.monitor, home_volume['context'], ['Activities'])
- coroutine.dispatch()
-
- self.assertEqual({
- 'name': 'TestActivity',
- 'implementations': [
- {
- 'version': '1',
- 'arch': '*-*',
- 'commands': {
- 'activity': {
- 'exec': 'true',
- },
- },
- 'stability': 'stable',
- 'guid': tests.tmpdir + '/Activities/activity-1',
- 'requires': {},
- },
- ],
- },
- ipc.get(['context', context], cmd='feed'))
-
- def test_InvalidateSolutions(self):
- self.start_online_client()
- ipc = IPCConnection()
- self.assertNotEqual(None, injector._mtime)
-
- mtime = injector._mtime
- coroutine.sleep(1.5)
-
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- assert injector._mtime == mtime
-
- impl1 = ipc.post(['implementation'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- self.node_volume['implementation'].update(impl1, {'data': {
- 'spec': {'*-*': {}},
- }})
- coroutine.sleep(.5)
- assert injector._mtime > mtime
-
- mtime = injector._mtime
- coroutine.sleep(1)
-
- impl2 = ipc.post(['implementation'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '2',
- 'stability': 'stable',
- 'notes': '',
- })
- self.node_volume['implementation'].update(impl2, {'data': {
- 'spec': {'*-*': {
- 'requires': {
- 'dep1': {},
- 'dep2': {'restrictions': [['1', '2']]},
- 'dep3': {'restrictions': [[None, '2']]},
- 'dep4': {'restrictions': [['3', None]]},
- },
- }},
- }})
- assert injector._mtime > mtime
-
- def test_ContentDisposition(self):
- self.start_online_client([User, Context, Implementation, Artifact])
- ipc = IPCConnection()
-
- artifact = ipc.post(['artifact'], {
- 'type': 'instance',
- 'context': 'context',
- 'title': 'title',
- 'description': 'description',
- })
- ipc.request('PUT', ['artifact', artifact, 'data'], 'blob', headers={'Content-Type': 'image/png'})
-
- response = ipc.request('GET', ['artifact', artifact, 'data'])
- self.assertEqual(
- 'attachment; filename="Title.png"',
- response.headers.get('Content-Disposition'))
-
def test_Redirects(self):
URL = 'http://sugarlabs.org'
@@ -1016,201 +1196,22 @@ class OnlineRoutes(tests.Test):
self.assertEqual(303, response.status_code)
self.assertEqual(URL, response.headers['Location'])
- def test_Proxy_Activities(self):
- home_volume = self.start_online_client()
- ipc = IPCConnection()
-
- context = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
-
- self.assertEqual(
- [{'guid': context, 'favorite': False, 'clone': 0, 'type': ['activity']}],
- ipc.get(['context'], reply=['favorite', 'clone'])['result'])
- self.assertEqual(
- {'favorite': False, 'clone': 0, 'type': ['activity']},
- ipc.get(['context', context], reply=['favorite', 'clone']))
-
- home_volume['context'].create({
- 'guid': context,
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- 'favorite': True,
- 'clone': 2,
- })
-
- self.assertEqual(
- [{'guid': context, 'favorite': True, 'clone': 2, 'type': ['activity']}],
- ipc.get(['context'], reply=['favorite', 'clone'])['result'])
- self.assertEqual(
- {'favorite': True, 'clone': 2},
- ipc.get(['context', context], reply=['favorite', 'clone']))
-
- def test_Proxy_Content(self):
- self.start_online_client([User, Context, Implementation, Artifact])
- ipc = IPCConnection()
-
- guid = ipc.post(['context'], {
- 'type': 'content',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
-
- self.assertEqual(
- [{'guid': guid, 'favorite': False, 'clone': 0, 'type': ['content']}],
- ipc.get(['context'], reply=['favorite', 'clone'])['result'])
- self.assertEqual(
- {'favorite': False, 'clone': 0, 'type': ['content']},
- ipc.get(['context', guid], reply=['favorite', 'clone']))
-
- self.touch(('datastore/%s/%s/metadata/keep' % (guid[:2], guid), '0'))
-
- self.assertEqual(
- [{'guid': guid, 'favorite': False, 'clone': 2, 'type': ['content']}],
- ipc.get(['context'], reply=['favorite', 'clone'])['result'])
- self.assertEqual(
- {'favorite': False, 'clone': 2, 'type': ['content']},
- ipc.get(['context', guid], reply=['favorite', 'clone']))
-
- self.touch(('datastore/%s/%s/metadata/keep' % (guid[:2], guid), '1'))
-
- self.assertEqual(
- [{'guid': guid, 'favorite': True, 'clone': 2, 'type': ['content']}],
- ipc.get(['context'], reply=['favorite', 'clone'])['result'])
- self.assertEqual(
- {'favorite': True, 'clone': 2, 'type': ['content']},
- ipc.get(['context', guid], reply=['favorite', 'clone']))
-
- def test_Proxy_Artifacts(self):
+ def test_ContentDisposition(self):
self.start_online_client([User, Context, Implementation, Artifact])
ipc = IPCConnection()
- guid = ipc.post(['artifact'], {
+ artifact = ipc.post(['artifact'], {
'type': 'instance',
'context': 'context',
'title': 'title',
'description': 'description',
})
+ ipc.request('PUT', ['artifact', artifact, 'data'], 'blob', headers={'Content-Type': 'image/png'})
+ response = ipc.request('GET', ['artifact', artifact, 'data'])
self.assertEqual(
- [{'guid': guid, 'favorite': False, 'clone': 0}],
- ipc.get(['artifact'], reply=['favorite', 'clone'])['result'])
- self.assertEqual(
- {'favorite': False, 'clone': 0},
- ipc.get(['artifact', guid], reply=['favorite', 'clone']))
-
- self.touch(('datastore/%s/%s/metadata/keep' % (guid[:2], guid), '0'))
-
- self.assertEqual(
- [{'guid': guid, 'favorite': False, 'clone': 2}],
- ipc.get(['artifact'], reply=['favorite', 'clone'])['result'])
- self.assertEqual(
- {'favorite': False, 'clone': 2},
- ipc.get(['artifact', guid], reply=['favorite', 'clone']))
-
- self.touch(('datastore/%s/%s/metadata/keep' % (guid[:2], guid), '1'))
-
- self.assertEqual(
- [{'guid': guid, 'favorite': True, 'clone': 2}],
- ipc.get(['artifact'], reply=['favorite', 'clone'])['result'])
- self.assertEqual(
- {'favorite': True, 'clone': 2},
- ipc.get(['artifact', guid], reply=['favorite', 'clone']))
-
- def test_Proxy_NoNeedlessRemoteRequests(self):
- home_volume = self.start_online_client()
- ipc = IPCConnection()
-
- guid = ipc.post(['context'], {
- 'type': 'content',
- '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',
- 'favorite': True,
- })
- self.assertEqual(
- {'title': 'local'},
- ipc.get(['context', guid], reply=['title']))
-
- def test_HomeVolumeEvents(self):
- self.home_volume = self.start_online_client()
- ipc = IPCConnection()
- coroutine.spawn(clones.monitor, self.home_volume['context'], ['Activities'])
-
- context1 = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl = ipc.post(['implementation'], {
- 'context': context1,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- self.node_volume['implementation'].update(impl, {'data': {
- 'spec': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'true',
- },
- },
- 'stability': 'stable',
- 'size': 0,
- 'extract': 'TestActivitry',
- },
- },
- 'blob': StringIO(self.zips(['TestActivitry/activity/activity.info', [
- '[Activity]',
- 'name = TestActivitry',
- 'bundle_id = %s' % context1,
- 'exec = false',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ]])),
-
- }})
-
- trigger = self.wait_for_events(ipc, event='update', resource='context', guid=context1)
- ipc.put(['context', context1], 2, cmd='clone')
- trigger.wait()
- self.assertEqual(
- {'clone': 2},
- ipc.get(['context', context1], reply=['clone']))
-
- context2 = ipc.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- trigger = self.wait_for_events(ipc, event='create', resource='context', guid=context2)
- ipc.put(['context', context2], True, cmd='favorite')
- trigger.wait()
- self.assertEqual(
- {'favorite': True},
- ipc.get(['context', context2], reply=['favorite']))
+ 'attachment; filename="Title.png"',
+ response.headers.get('Content-Disposition'))
def test_FallbackToLocalSNOnRemoteTransportFails(self):
@@ -1313,6 +1314,27 @@ class OnlineRoutes(tests.Test):
self.fork_master([User])
self.wait_for_events(ipc, event='inline', state='online').wait()
+ def test_inline(self):
+ cp = ClientRoutes(Volume('client', model.RESOURCES), client.api_url.value)
+ assert not cp.inline()
+
+ trigger = self.wait_for_events(cp, event='inline', state='online')
+ coroutine.sleep(1)
+ self.start_master()
+ trigger.wait(1)
+ assert trigger.value is None
+ assert not cp.inline()
+
+ request = Request(method='GET', cmd='whoami')
+ cp.whoami(request, Response())
+ trigger.wait()
+ assert cp.inline()
+
+ trigger = self.wait_for_events(cp, event='inline', state='offline')
+ self.node.stop()
+ trigger.wait()
+ assert not cp.inline()
+
if __name__ == '__main__':
tests.main()