Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2013-06-02 07:07:33 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2013-06-02 07:07:33 (GMT)
commitd1fdc48085e63202c0c4a6a4005bd41b9e0ac90f (patch)
tree7ca85707a492240f7d223322d89283cb2c9bfd10
parenta2181bd9f4cade2b4e1d401e9fd1b643a0b6e030 (diff)
Keep author property all time empty for local db
-rw-r--r--sugar_network/client/__init__.py14
-rw-r--r--sugar_network/client/commands.py72
-rw-r--r--sugar_network/node/commands.py9
-rw-r--r--sugar_network/node/slave.py54
-rw-r--r--tests/__init__.py9
-rwxr-xr-xtests/integration/master_personal.py9
-rwxr-xr-xtests/units/client/commands.py13
-rwxr-xr-xtests/units/client/offline_commands.py7
-rwxr-xr-xtests/units/resources/implementation.py16
-rwxr-xr-xtests/units/resources/volume.py9
10 files changed, 122 insertions, 90 deletions
diff --git a/sugar_network/client/__init__.py b/sugar_network/client/__init__.py
index 109c6a8..62d9128 100644
--- a/sugar_network/client/__init__.py
+++ b/sugar_network/client/__init__.py
@@ -30,6 +30,7 @@ _XO_SERIAL_PATH = ['/ofw/mfg-data/SN', '/proc/device-tree/mfg-data/SN']
_XO_UUID_PATH = ['/ofw/mfg-data/U#', '/proc/device-tree/mfg-data/U#']
_logger = logging.getLogger('client')
+_sugar_uid = None
def profile_path(*args):
@@ -154,7 +155,7 @@ def Client(url=None):
creds = None
if not anonymous.value:
if exists(key_path()):
- creds = (sugar_uid(), key_path(), _profile)
+ creds = (sugar_uid(), key_path(), sugar_profile)
else:
_logger.warning('Sugar session was never started (no DSA key),'
'fallback to anonymous mode')
@@ -211,12 +212,15 @@ def key_path():
def sugar_uid():
- import hashlib
- pubkey = util.pubkey(key_path()).split()[1]
- return str(hashlib.sha1(pubkey).hexdigest())
+ global _sugar_uid
+ if _sugar_uid is None:
+ import hashlib
+ pubkey = util.pubkey(key_path()).split()[1]
+ _sugar_uid = str(hashlib.sha1(pubkey).hexdigest())
+ return _sugar_uid
-def _profile():
+def sugar_profile():
import gconf
conf = gconf.client_get_default()
return {'name': conf.get_string(_NICKNAME_GCONF) or '',
diff --git a/sugar_network/client/commands.py b/sugar_network/client/commands.py
index 9b3093f..92cf488 100644
--- a/sugar_network/client/commands.py
+++ b/sugar_network/client/commands.py
@@ -23,7 +23,7 @@ from sugar_network.toolkit import netlink, mountpoints
from sugar_network.client import journal, clones, injector
from sugar_network.client.spec import Spec
from sugar_network.resources.volume import Volume, Commands
-from sugar_network.node.slave import PersonalCommands
+from sugar_network.node.slave import SlaveCommands
from sugar_network.toolkit import zeroconf, coroutine, util, http
from sugar_network.toolkit import exception, enforce
@@ -32,6 +32,9 @@ from sugar_network.toolkit import exception, enforce
_SN_DIRNAME = 'sugar-network'
_LOCAL_PROPS = frozenset(['favorite', 'clone'])
+# Flag file to recognize a directory as a synchronization directory
+_SYNC_DIRNAME = 'sugar-network-sync'
+
_RECONNECT_TIMEOUT = 3
_RECONNECT_TIMEOUT_MAX = 60 * 15
@@ -138,7 +141,7 @@ class ClientCommands(db.CommandsProcessor, Commands, journal.Commands):
try:
result = self._node_call(request, response)
except db.CommandNotFound:
- result = {'roles': [], 'guid': request.principal}
+ result = {'roles': [], 'guid': client.sugar_uid()}
return result
@db.directory_command(method='GET',
@@ -425,7 +428,7 @@ class ClientCommands(db.CommandsProcessor, Commands, journal.Commands):
node.stats_root.value = join(root, _SN_DIRNAME, 'stats')
node.files_root.value = join(root, _SN_DIRNAME, 'files')
- volume = Volume(db_path, lazy_open=client.lazy_open.value)
+ volume = Volume(db_path)
self._node = _PersonalCommands(join(db_path, 'node'), volume,
self.broadcast)
self._jobs.spawn(volume.populate)
@@ -678,13 +681,36 @@ class _VolumeCommands(db.VolumeCommands):
db.VolumeCommands.before_create(self, request, props)
-class _PersonalCommands(PersonalCommands):
+class _PersonalCommands(SlaveCommands):
def __init__(self, key_path, volume, localcast):
- PersonalCommands.__init__(self, key_path, volume, localcast)
+ SlaveCommands.__init__(self, key_path, volume)
+
self.api_url = 'http://127.0.0.1:%s' % node.port.value
+ self._localcast = localcast
+ self._mounts = util.Pool()
+ self._jobs = coroutine.Pool()
+
+ users = volume['user']
+ if not users.exists(client.sugar_uid()):
+ users.create(guid=client.sugar_uid(), **client.sugar_profile())
+
+ mountpoints.connect(_SYNC_DIRNAME,
+ self.__found_mountcb, self.__lost_mount_cb)
volume.connect(localcast)
+ @db.volume_command(method='GET', cmd='whoami',
+ mime_type='application/json')
+ def whoami(self, request):
+ return {'roles': [], 'guid': client.sugar_uid()}
+
+ def validate(self, *args):
+ return True
+
+ def call(self, request, response=None):
+ request.principal = client.sugar_uid()
+ return SlaveCommands.call(self, request, response)
+
def close(self):
self.volume.disconnect(self._localcast)
self.volume.close()
@@ -693,6 +719,42 @@ class _PersonalCommands(PersonalCommands):
return '<LocalNode path=%s api_url=%s>' % \
(self.volume.root, self.api_url)
+ def _sync_mounts(self):
+ self._localcast({'event': 'sync_start'})
+
+ for mountpoint in self._mounts:
+ self._localcast({'event': 'sync_next', 'path': mountpoint})
+ try:
+ self._offline_session = self._offline_sync(
+ join(mountpoint, _SYNC_DIRNAME),
+ **(self._offline_session or {}))
+ except Exception, error:
+ exception(_logger, 'Failed to complete synchronization')
+ self._localcast({'event': 'sync_abort', 'error': str(error)})
+ self._offline_session = None
+ raise
+
+ if self._offline_session is None:
+ _logger.debug('Synchronization completed')
+ self._localcast({'event': 'sync_complete'})
+ else:
+ _logger.debug('Postpone synchronization with %r session',
+ self._offline_session)
+ self._localcast({'event': 'sync_paused'})
+
+ def __found_mountcb(self, path):
+ self._mounts.add(path)
+ if self._jobs:
+ _logger.debug('Found %r sync mount, pool it', path)
+ else:
+ _logger.debug('Found %r sync mount, start synchronization', path)
+ self._jobs.spawn(self._sync_mounts)
+
+ def __lost_mount_cb(self, path):
+ if self._mounts.remove(path) == util.Pool.ACTIVE:
+ _logger.warning('%r was unmounted, break synchronization', path)
+ self._jobs.kill()
+
class _ResponseStream(object):
diff --git a/sugar_network/node/commands.py b/sugar_network/node/commands.py
index 9a9fc6d..0ef07a7 100644
--- a/sugar_network/node/commands.py
+++ b/sugar_network/node/commands.py
@@ -165,7 +165,7 @@ class NodeCommands(db.VolumeCommands, Commands):
mime_type='application/json')
def whoami(self, request):
roles = []
- if auth.try_validate(request, 'root'):
+ if self.validate(request, 'root'):
roles.append('root')
return {'roles': roles, 'guid': request.principal}
@@ -252,6 +252,9 @@ class NodeCommands(db.VolumeCommands, Commands):
return result
+ def validate(self, *args):
+ return auth.try_validate(*args)
+
def call(self, request, response=None):
if node.static_url.value:
request.static_prefix = node.static_url.value
@@ -272,7 +275,7 @@ class NodeCommands(db.VolumeCommands, Commands):
return
if cmd.permissions & db.ACCESS_AUTH:
- enforce(auth.try_validate(request, 'user'), http.Unauthorized,
+ enforce(self.validate(request, 'user'), http.Unauthorized,
'User is not authenticated')
if cmd.permissions & db.ACCESS_AUTHOR and 'guid' in request:
@@ -281,7 +284,7 @@ class NodeCommands(db.VolumeCommands, Commands):
else:
doc = self.volume[request['document']].get(request['guid'])
allowed = (request.principal in doc['author'])
- enforce(allowed or auth.try_validate(request, 'root'),
+ enforce(allowed or self.validate(request, 'root'),
http.Forbidden, 'Operation is permitted only for authors')
return cmd
diff --git a/sugar_network/node/slave.py b/sugar_network/node/slave.py
index 762f468..2accd9e 100644
--- a/sugar_network/node/slave.py
+++ b/sugar_network/node/slave.py
@@ -25,13 +25,10 @@ from sugar_network import db, node, toolkit
from sugar_network.client import api_url
from sugar_network.node import sync, stats_user, files, volume
from sugar_network.node.commands import NodeCommands
-from sugar_network.toolkit import mountpoints, coroutine, util, http
+from sugar_network.toolkit import util, http
from sugar_network.toolkit import exception, enforce
-# Flag file to recognize a directory as a synchronization directory
-_SYNC_DIRNAME = 'sugar-network-sync'
-
_logger = logging.getLogger('node.slave')
@@ -189,52 +186,3 @@ class SlaveCommands(NodeCommands):
if seq:
self._files_seq.exclude(seq)
self._files_seq.commit()
-
-
-class PersonalCommands(SlaveCommands):
-
- def __init__(self, key_path, volume_, localcast):
- SlaveCommands.__init__(self, key_path, volume_)
-
- self._localcast = localcast
- self._mounts = util.Pool()
- self._jobs = coroutine.Pool()
-
- mountpoints.connect(_SYNC_DIRNAME,
- self.__found_mountcb, self.__lost_mount_cb)
-
- def _sync_mounts(self):
- self._localcast({'event': 'sync_start'})
-
- for mountpoint in self._mounts:
- self._localcast({'event': 'sync_next', 'path': mountpoint})
- try:
- self._offline_session = self._offline_sync(
- join(mountpoint, _SYNC_DIRNAME),
- **(self._offline_session or {}))
- except Exception, error:
- exception(_logger, 'Failed to complete synchronization')
- self._localcast({'event': 'sync_abort', 'error': str(error)})
- self._offline_session = None
- raise
-
- if self._offline_session is None:
- _logger.debug('Synchronization completed')
- self._localcast({'event': 'sync_complete'})
- else:
- _logger.debug('Postpone synchronization with %r session',
- self._offline_session)
- self._localcast({'event': 'sync_paused'})
-
- def __found_mountcb(self, path):
- self._mounts.add(path)
- if self._jobs:
- _logger.debug('Found %r sync mount, pool it', path)
- else:
- _logger.debug('Found %r sync mount, start synchronization', path)
- self._jobs.spawn(self._sync_mounts)
-
- def __lost_mount_cb(self, path):
- if self._mounts.remove(path) == util.Pool.ACTIVE:
- _logger.warning('%r was unmounted, break synchronization', path)
- self._jobs.kill()
diff --git a/tests/__init__.py b/tests/__init__.py
index b99433f..2bef872 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -116,6 +116,15 @@ class Test(unittest.TestCase):
'sugar_network.resources.report',
]
+ if tmp_root is None:
+ self.override(client, 'sugar_profile', lambda: {
+ 'name': 'test',
+ 'color': '#000000,#000000',
+ 'machine_sn': '',
+ 'machine_uuid': '',
+ 'pubkey': PUBKEY,
+ })
+
os.makedirs('tmp')
self.node = None
diff --git a/tests/integration/master_personal.py b/tests/integration/master_personal.py
index 03739b0..718659b 100755
--- a/tests/integration/master_personal.py
+++ b/tests/integration/master_personal.py
@@ -13,7 +13,7 @@ import rrdtool
from __init__ import tests, src_root
-from sugar_network.client import Client
+from sugar_network.client import Client, sugar_uid
from sugar_network.toolkit.rrd import Rrd
from sugar_network.toolkit import util, coroutine
@@ -63,6 +63,7 @@ class MasterPersonalTest(tests.Test):
def test_SyncMounts(self):
master = Client('http://127.0.0.1:8100')
client = Client('http://127.0.0.1:8102')
+ uid = sugar_uid()
# Create shared files on master
self.touch(('master/files/1/1', '1'))
@@ -104,7 +105,7 @@ class MasterPersonalTest(tests.Test):
'layer': 'pilot',
})
stats_timestamp = int(time.time())
- client.post(['user', tests.UID], {
+ client.post(['user', uid], {
'name': 'db',
'values': [(stats_timestamp, {'f': 1}), (stats_timestamp + 1, {'f': 2})],
}, cmd='stats-upload')
@@ -195,12 +196,12 @@ class MasterPersonalTest(tests.Test):
self.assertEqual('1', file('client/mnt/disk/sugar-network/files/1/1').read())
self.assertEqual('2', file('client/mnt/disk/sugar-network/files/2/2').read())
- rrd = Rrd('master/stats/user/%s/%s' % (tests.UID[:2], tests.UID), 1)
+ rrd = Rrd('master/stats/user/%s/%s' % (uid[:2], uid), 1)
self.assertEqual([
[('db', stats_timestamp, {'f': 1.0}), ('db', stats_timestamp + 1, {'f': 2.0})],
],
[[(db.name,) + i for i in db.get(db.first, db.last)] for db in rrd])
- rrd = Rrd('client/mnt/disk/sugar-network/stats/user/%s/%s' % (tests.UID[:2], tests.UID), 1)
+ rrd = Rrd('client/mnt/disk/sugar-network/stats/user/%s/%s' % (uid[:2], uid), 1)
self.assertEqual([
[('db', stats_timestamp, {'f': 1.0}), ('db', stats_timestamp + 1, {'f': 2.0})],
],
diff --git a/tests/units/client/commands.py b/tests/units/client/commands.py
index 0713e04..691eeea 100755
--- a/tests/units/client/commands.py
+++ b/tests/units/client/commands.py
@@ -210,8 +210,14 @@ class CommandsTest(tests.Test):
self.assertEqual([[3, None]], json.load(file('client/push.sequence')))
self.assertEqual({'en-us': 'title'}, volume['context'].get(guid1)['title'])
self.assertEqual({'en-us': 'title'}, self.node_volume['context'].get(guid1)['title'])
+ self.assertEqual(
+ {tests.UID: {'role': 3, 'name': 'test', 'order': 0}},
+ self.node_volume['context'].get(guid1)['author'])
self.assertEqual({'en-us': 'title'}, volume['context'].get(guid2)['title'])
self.assertEqual({'en-us': 'title'}, self.node_volume['context'].get(guid2)['title'])
+ self.assertEqual(
+ {tests.UID: {'role': 3, 'name': 'test', 'order': 0}},
+ self.node_volume['context'].get(guid2)['author'])
trigger = self.wait_for_events(cp, event='inline', state='offline')
self.node.stop()
@@ -229,8 +235,14 @@ class CommandsTest(tests.Test):
self.assertEqual([[4, None]], json.load(file('client/push.sequence')))
self.assertEqual({'en-us': 'title_'}, volume['context'].get(guid1)['title'])
self.assertEqual({'en-us': 'title_'}, self.node_volume['context'].get(guid1)['title'])
+ self.assertEqual(
+ {tests.UID: {'role': 3, 'name': 'test', 'order': 0}},
+ self.node_volume['context'].get(guid1)['author'])
assert not volume['context'].exists(guid2)
self.assertEqual({'en-us': 'title'}, self.node_volume['context'].get(guid2)['title'])
+ self.assertEqual(
+ {tests.UID: {'role': 3, 'name': 'test', 'order': 0}},
+ self.node_volume['context'].get(guid2)['author'])
def test_CachedClientCommands_WipeReports(self):
volume = Volume('client')
@@ -240,7 +252,6 @@ class CommandsTest(tests.Test):
post.content_type = 'application/json'
post.content = {
'context': 'context',
- 'description': 'description',
'error': 'error',
}
guid = cp.call(post)
diff --git a/tests/units/client/offline_commands.py b/tests/units/client/offline_commands.py
index c81dd66..8879c81 100755
--- a/tests/units/client/offline_commands.py
+++ b/tests/units/client/offline_commands.py
@@ -23,7 +23,7 @@ class OfflineCommandsTest(tests.Test):
coroutine.spawn(server.serve_forever)
coroutine.dispatch()
- def test_SetUser(self):
+ def test_NoAuthors(self):
ipc = IPCClient()
guid = ipc.post(['context'], {
@@ -33,7 +33,10 @@ class OfflineCommandsTest(tests.Test):
'description': 'description',
})
self.assertEqual(
- [{'name': tests.UID, 'role': 2}],
+ {},
+ self.home_volume['context'].get(guid)['author'])
+ self.assertEqual(
+ [],
ipc.get(['context', guid, 'author']))
def test_HandleDeletes(self):
diff --git a/tests/units/resources/implementation.py b/tests/units/resources/implementation.py
index 834e0d2..46c9768 100755
--- a/tests/units/resources/implementation.py
+++ b/tests/units/resources/implementation.py
@@ -63,7 +63,7 @@ class ImplementationTest(tests.Test):
_encode_version('1-post1.2-3'))
def test_SetMimeTypeForActivities(self):
- home_volume = self.start_offline_client()
+ self.start_online_client()
client = IPCClient()
context = client.post(['context'], {
@@ -80,17 +80,17 @@ class ImplementationTest(tests.Test):
'notes': '',
})
client.request('PUT', ['implementation', impl, 'data'], 'blob', {'Content-Type': 'image/png'})
- self.assertEqual('image/png', home_volume['implementation'].get(impl).meta('data')['mime_type'])
+ self.assertEqual('image/png', self.node_volume['implementation'].get(impl).meta('data')['mime_type'])
client.put(['context', context, 'type'], 'activity')
client.request('PUT', ['implementation', impl, 'data'], 'blob', {'Content-Type': 'image/png'})
- self.assertEqual('application/vnd.olpc-sugar', home_volume['implementation'].get(impl).meta('data')['mime_type'])
+ self.assertEqual('application/vnd.olpc-sugar', self.node_volume['implementation'].get(impl).meta('data')['mime_type'])
def test_WrongAuthor(self):
- home_volume = self.start_offline_client()
+ self.start_online_client()
client = IPCClient()
- home_volume['context'].create(
+ self.node_volume['context'].create(
guid='context',
type='content',
title='title',
@@ -106,11 +106,11 @@ class ImplementationTest(tests.Test):
'notes': '',
}
self.assertRaises(http.Forbidden, client.post, ['implementation'], impl)
- self.assertEqual(0, home_volume['implementation'].find()[1])
+ self.assertEqual(0, self.node_volume['implementation'].find()[1])
- home_volume['context'].update('context', author={tests.UID: None})
+ self.node_volume['context'].update('context', author={tests.UID: None})
guid = client.post(['implementation'], impl)
- assert home_volume['implementation'].exists(guid)
+ assert self.node_volume['implementation'].exists(guid)
if __name__ == '__main__':
diff --git a/tests/units/resources/volume.py b/tests/units/resources/volume.py
index 1e5b6ca..e07858f 100755
--- a/tests/units/resources/volume.py
+++ b/tests/units/resources/volume.py
@@ -140,15 +140,6 @@ class VolumeTest(tests.Test):
volume = Volume('db')
cp = TestCommands(volume)
- assert not exists('db/context/index')
-
- self.assertEqual(
- [],
- call(cp, method='GET', document='context')['result'])
- coroutine.dispatch()
- self.assertEqual(
- [{'guid': '1'}],
- call(cp, method='GET', document='context')['result'])
assert exists('db/context/index')
def test_DefaultAuthor(self):