#!/usr/bin/env python # sugar-lint: disable import os import shutil import hashlib from os.path import abspath, lexists, exists from __init__ import tests from sugar_network.resources.user import User from sugar_network.resources.context import Context from sugar_network.client import clones from sugar_network.toolkit import coroutine, util from sugar_network.resources.volume import Volume class CloneTest(tests.Test): def setUp(self): tests.Test.setUp(self) self.volume = Volume('local', [User, Context]) self.job = None def tearDown(self): if self.job is not None: self.job.kill() self.volume.close() tests.Test.tearDown(self) def test_Inotify_NoPermissions(self): assert not exists('/foo/bar') inotify = clones._Inotify(self.volume['context']) inotify.setup(['/foo/bar']) assert not exists('/foo/bar') def test_Inotify_Walkthrough(self): self.touch('file') os.makedirs('activity-1') os.makedirs('activity-2/activity') self.touch('activity-3/activity/activity.info') self.touch('activity-4/activity/activity.info') self.touch('activity-5/activity/activity.info') found = [] lost = [] inotify = clones._Inotify(self.volume['context']) inotify.found = found.append inotify.lost = lost.append inotify.setup(['.']) self.job = coroutine.spawn(inotify.serve_forever) coroutine.sleep(1) self.assertEqual( sorted([ tests.tmpdir + '/activity-3', tests.tmpdir + '/activity-4', tests.tmpdir + '/activity-5', ]), sorted(found)) self.assertEqual([], lost) del found[:] with file('activity-4/activity/activity.info', 'w') as f: f.close() coroutine.sleep(.1) self.assertEqual([], found) self.assertEqual([], lost) with file('activity-2/activity/activity.info', 'w') as f: f.close() coroutine.sleep(.1) self.assertEqual([tests.tmpdir + '/activity-2'], found) self.assertEqual([], lost) del found[:] os.makedirs('activity-6/activity') coroutine.sleep(.1) self.assertEqual([], found) self.assertEqual([], lost) with file('activity-6/activity/activity.info', 'w') as f: f.close() coroutine.sleep(.1) self.assertEqual([tests.tmpdir + '/activity-6'], found) self.assertEqual([], lost) del found[:] os.unlink('activity-5/activity/activity.info') coroutine.sleep(.1) self.assertEqual([], found) self.assertEqual([tests.tmpdir + '/activity-5'], lost) del lost[:] shutil.rmtree('activity-5') coroutine.sleep(.1) self.assertEqual([], found) self.assertEqual([], lost) shutil.rmtree('activity-4') coroutine.sleep(.1) coroutine.sleep(.1) self.assertEqual([], found) self.assertEqual([tests.tmpdir + '/activity-4'], lost) del lost[:] def test_Inotify_Moves(self): self.touch('Activities/activity/activity/activity.info') found = [] lost = [] inotify = clones._Inotify(self.volume['context']) inotify.found = found.append inotify.lost = lost.append inotify.setup(['Activities']) self.job = coroutine.spawn(inotify.serve_forever) coroutine.sleep(.1) shutil.move('Activities/activity', '.') coroutine.sleep(.1) self.assertEqual([tests.tmpdir + '/Activities/activity'], found) self.assertEqual([tests.tmpdir + '/Activities/activity'], lost) del found[:] del lost[:] shutil.move('activity', 'Activities/') coroutine.sleep(.1) self.assertEqual([tests.tmpdir + '/Activities/activity'], found) self.assertEqual([], lost) del found[:] del lost[:] shutil.move('Activities/activity/activity', 'Activities/activity/activity2') coroutine.sleep(.1) self.assertEqual([], found) self.assertEqual([tests.tmpdir + '/Activities/activity'], lost) del found[:] del lost[:] shutil.move('Activities/activity/activity2', 'Activities/activity/activity') coroutine.sleep(.1) self.assertEqual([tests.tmpdir + '/Activities/activity'], found) self.assertEqual([], lost) del found[:] del lost[:] shutil.move('Activities/activity/activity/activity.info', 'Activities/activity/activity/activity.info2') coroutine.sleep(.1) self.assertEqual([], found) self.assertEqual([tests.tmpdir + '/Activities/activity'], lost) del found[:] del lost[:] shutil.move('Activities/activity/activity/activity.info2', 'Activities/activity/activity/activity.info') coroutine.sleep(.1) self.assertEqual([tests.tmpdir + '/Activities/activity'], found) self.assertEqual([], lost) del found[:] del lost[:] def test_Checkin_Create(self): self.job = coroutine.spawn(clones.monitor, self.volume['context'], ['Activities']) coroutine.sleep() self.volume['context'].create({ 'guid': 'org.sugarlabs.HelloWorld', 'type': 'activity', 'title': {'en': 'title'}, 'summary': {'en': 'summary'}, 'description': {'en': 'description'}, 'user': [tests.UID], }) os.makedirs('Activities/activity/activity') coroutine.sleep(1) self.touch('Activities/activity/activity/icon.svg') self.touch(('Activities/activity/activity/mimetypes.xml', [ '', '', '', 'foo-bar', '', '', '', ])) spec = ['[Activity]', 'name = HelloWorld', 'activity_version = 1', 'bundle_id = org.sugarlabs.HelloWorld', 'exec = sugar-activity activity.HelloWorldActivity', 'icon = icon', 'license = GPLv2+', 'mime_types = foo/bar', ] with file('Activities/activity/activity/activity.info', 'w') as f: coroutine.sleep(1) f.write('\n'.join(spec)) coroutine.sleep(1) hashed_path = hashlib.sha1(tests.tmpdir + '/Activities/activity').hexdigest() assert exists('clones/checkin/' + hashed_path) self.assertEqual( abspath('Activities/activity'), os.readlink('clones/context/org.sugarlabs.HelloWorld/' + hashed_path)) self.assertEqual( {'guid': 'org.sugarlabs.HelloWorld', 'title': {'en': 'title'}, 'favorite': False, 'clone': 2}, self.volume['context'].get('org.sugarlabs.HelloWorld').properties(['guid', 'title', 'favorite', 'clone'])) assert exists('share/icons/sugar/scalable/mimetypes/foo-bar.svg') self.assertEqual( tests.tmpdir + '/Activities/activity/activity/icon.svg', os.readlink('share/icons/sugar/scalable/mimetypes/foo-bar.svg')) assert exists('share/mime/packages/%s.xml' % hashed_path) self.assertEqual( tests.tmpdir + '/Activities/activity/activity/mimetypes.xml', os.readlink('share/mime/packages/%s.xml' % hashed_path)) assert exists('share/mime/application/x-foo-bar.xml') def test_Checkin_Copy(self): self.job = coroutine.spawn(clones.monitor, self.volume['context'], ['Activities']) coroutine.sleep() self.volume['context'].create({ 'guid': 'org.sugarlabs.HelloWorld', 'type': 'activity', 'title': {'en': 'title'}, 'summary': {'en': 'summary'}, 'description': {'en': 'description'}, 'user': [tests.UID], }) self.touch(('activity/activity/activity.info', [ '[Activity]', 'name = HelloWorld', 'activity_version = 1', 'bundle_id = org.sugarlabs.HelloWorld', 'exec = sugar-activity activity.HelloWorldActivity', 'icon = activity-helloworld', 'license = GPLv2+', ])) shutil.copytree('activity', 'Activities/activity') coroutine.sleep(1) hashed_path = hashlib.sha1(tests.tmpdir + '/Activities/activity').hexdigest() assert exists('clones/checkin/' + hashed_path) self.assertEqual( abspath('Activities/activity'), os.readlink('clones/context/org.sugarlabs.HelloWorld/' + hashed_path)) self.assertEqual( {'guid': 'org.sugarlabs.HelloWorld', 'title': {'en': 'title'}, 'favorite': False, 'clone': 2}, self.volume['context'].get('org.sugarlabs.HelloWorld').properties(['guid', 'title', 'favorite', 'clone'])) def test_Checkin_Hardlink(self): self.job = coroutine.spawn(clones.monitor, self.volume['context'], ['Activities']) coroutine.sleep() self.volume['context'].create({ 'guid': 'org.sugarlabs.HelloWorld', 'type': 'activity', 'title': {'en': 'title'}, 'summary': {'en': 'summary'}, 'description': {'en': 'description'}, 'user': [tests.UID], }) self.touch(('activity/activity/activity.info', [ '[Activity]', 'name = HelloWorld', 'activity_version = 1', 'bundle_id = org.sugarlabs.HelloWorld', 'exec = sugar-activity activity.HelloWorldActivity', 'icon = activity-helloworld', 'license = GPLv2+', ])) os.makedirs('Activities/activity/activity') coroutine.sleep(1) os.link('activity/activity/activity.info', 'Activities/activity/activity/activity.info') coroutine.sleep(1) hashed_path = hashlib.sha1(tests.tmpdir + '/Activities/activity').hexdigest() assert exists('clones/checkin/' + hashed_path) self.assertEqual( abspath('Activities/activity'), os.readlink('clones/context/org.sugarlabs.HelloWorld/' + hashed_path)) self.assertEqual( {'guid': 'org.sugarlabs.HelloWorld', 'title': {'en': 'title'}, 'favorite': False, 'clone': 2}, self.volume['context'].get('org.sugarlabs.HelloWorld').properties(['guid', 'title', 'favorite', 'clone'])) def test_OfflineCheckin(self): self.job = coroutine.spawn(clones.monitor, self.volume['context'], ['Activities']) coroutine.sleep() self.touch(('Activities/activity/activity/activity.info', [ '[Activity]', 'name = HelloWorld', 'activity_version = 1', 'bundle_id = org.sugarlabs.HelloWorld', 'exec = sugar-activity activity.HelloWorldActivity', 'icon = activity-helloworld', 'license = GPLv2+', ])) coroutine.sleep(1) hashed_path = hashlib.sha1(tests.tmpdir + '/Activities/activity').hexdigest() assert exists('clones/checkin/' + hashed_path) self.assertEqual( abspath('Activities/activity'), os.readlink('clones/context/org.sugarlabs.HelloWorld/' + hashed_path)) self.assertEqual( {'guid': 'org.sugarlabs.HelloWorld', 'title': {'en-us': 'HelloWorld'}, 'favorite': False, 'clone': 2}, self.volume['context'].get('org.sugarlabs.HelloWorld').properties(['guid', 'title', 'favorite', 'clone'])) def test_Checkout(self): self.job = coroutine.spawn(clones.monitor, self.volume['context'], ['Activities']) self.volume['context'].create({ 'guid': 'org.sugarlabs.HelloWorld', 'type': 'activity', 'title': {'en': 'title'}, 'summary': {'en': 'summary'}, 'description': {'en': 'description'}, 'user': [tests.UID], }) self.touch('Activities/activity/activity/icon.svg') self.touch(('Activities/activity/activity/mimetypes.xml', [ '', '', '', 'foo-bar', '', '', '', ])) self.touch(('Activities/activity/activity/activity.info', [ '[Activity]', 'name = HelloWorld', 'activity_version = 1', 'bundle_id = org.sugarlabs.HelloWorld', 'exec = sugar-activity activity.HelloWorldActivity', 'icon = icon', 'license = GPLv2+', 'mime_types = foo/bar', ])) coroutine.sleep(1) hashed_path = hashlib.sha1(tests.tmpdir + '/Activities/activity').hexdigest() assert exists('clones/checkin/' + hashed_path) assert exists('clones/context/org.sugarlabs.HelloWorld/' + hashed_path) self.assertEqual( {'guid': 'org.sugarlabs.HelloWorld', 'title': {'en': 'title'}, 'favorite': False, 'clone': 2}, self.volume['context'].get('org.sugarlabs.HelloWorld').properties(['guid', 'title', 'favorite', 'clone'])) assert exists('share/icons/sugar/scalable/mimetypes/foo-bar.svg') assert exists('share/mime/packages/%s.xml' % hashed_path) assert exists('share/mime/application/x-foo-bar.xml') shutil.rmtree('Activities/activity') coroutine.sleep(1) assert not exists('clones/checkin/' + hashed_path) assert not exists('clones/context/org.sugarlabs.HelloWorld/' + hashed_path) self.assertEqual( {'guid': 'org.sugarlabs.HelloWorld', 'title': {'en': 'title'}, 'favorite': False, 'clone': 0}, self.volume['context'].get('org.sugarlabs.HelloWorld').properties(['guid', 'title', 'favorite', 'clone'])) assert not lexists('share/icons/sugar/scalable/mimetypes/foo-bar.svg') assert not lexists('share/mime/packages/%s.xml' % hashed_path) assert not lexists('share/mime/application/x-foo-bar.xml') def test_Sync(self): volume = Volume('client') volume['context'].create({ 'guid': 'context1', 'type': 'activity', 'title': 'title', 'summary': 'summary', 'description': 'description', 'clone': 0, }) volume['context'].create({ 'guid': 'context2', 'type': 'activity', 'title': 'title', 'summary': 'summary', 'description': 'description', 'clone': 1, }) volume['context'].create({ 'guid': 'context3', 'type': 'activity', 'title': 'title', 'summary': 'summary', 'description': 'description', 'clone': 2, }) os.makedirs('Activities') os.utime('Activities', (volume['context'].mtime + 1, volume['context'].mtime + 1)) self.touch(clones._context_path('context1', 'clone')) self.touch(clones._context_path('context2', 'clone')) clones.populate(volume['context'], ['Activities']) self.assertEqual(0, volume['context'].get('context1')['clone']) self.assertEqual(2, volume['context'].get('context2')['clone']) self.assertEqual(0, volume['context'].get('context3')['clone']) def test_SyncByMtime(self): volume = Volume('client') volume['context'].create({ 'guid': 'context', 'type': 'activity', 'title': 'title', 'summary': 'summary', 'description': 'description', 'clone': 2, }) os.makedirs('Activities') os.utime('Activities', (2, 2)) volume['context'].mtime = 3 clones.populate(volume['context'], ['Activities']) self.assertEqual(2, volume['context'].get('context')['clone']) volume['context'].mtime = 2 clones.populate(volume['context'], ['Activities']) self.assertEqual(2, volume['context'].get('context')['clone']) volume['context'].mtime = 1 clones.populate(volume['context'], ['Activities']) self.assertEqual(0, volume['context'].get('context')['clone']) if __name__ == '__main__': tests.main()