Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2012-09-25 18:33:25 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2012-09-25 18:33:25 (GMT)
commit18af0e0bc89982ccfe03d502a0730bc13099503d (patch)
tree95caa01848effe21ab8d48a25638d0360019e9f0
parente1fc93cebba27782ec6341504207ee968b8acae8 (diff)
Simplify access to feeds by using regular properties instead of blobs; populate feed content basing on aliases
-rw-r--r--sugar_network/local/mounts.py39
-rw-r--r--sugar_network/local/mountset.py22
-rw-r--r--sugar_network/node/obs.py88
-rw-r--r--sugar_network/node/router.py31
-rw-r--r--sugar_network/resources/context.py98
-rw-r--r--sugar_network/resources/volume.py1
-rw-r--r--sugar_network/toolkit/router.py18
-rw-r--r--sugar_network/zerosugar/feeds.py20
-rw-r--r--tests/__init__.py17
-rw-r--r--tests/units/__main__.py2
-rwxr-xr-xtests/units/context.py177
-rwxr-xr-xtests/units/home_mount.py48
-rwxr-xr-xtests/units/injector.py159
-rwxr-xr-xtests/units/node.py4
-rwxr-xr-xtests/units/node_mount.py34
-rwxr-xr-xtests/units/obs.py168
-rwxr-xr-xtests/units/remote_mount.py2
17 files changed, 673 insertions, 255 deletions
diff --git a/sugar_network/local/mounts.py b/sugar_network/local/mounts.py
index 6bcc813..3203c3b 100644
--- a/sugar_network/local/mounts.py
+++ b/sugar_network/local/mounts.py
@@ -20,7 +20,7 @@ from os.path import isabs, exists, join, basename, isdir
from gettext import gettext as _
import active_document as ad
-from sugar_network.zerosugar import Bundle, Spec
+from sugar_network.zerosugar import Bundle
from sugar_network.local import activities, cache
from sugar_network.resources.volume import Request
from sugar_network import local, checkin, sugar, Client
@@ -116,48 +116,13 @@ class HomeMount(LocalMount):
@ad.property_command(method='GET', cmd='get_blob')
def get_blob(self, document, guid, prop, request=None):
- if document == 'context' and prop == 'feed':
- return self._get_feed(request)
- elif document == 'implementation' and prop == 'data':
+ if document == 'implementation' and prop == 'data':
path = activities.guid_to_path(guid)
if exists(path):
return {'path': path}
else:
return LocalMount.get_blob(self, document, guid, prop, request)
- def _get_feed(self, request):
- versions = {}
-
- for path in activities.checkins(request['guid']):
- try:
- spec = Spec(root=path)
- except Exception:
- util.exception(_logger, 'Failed to read %r spec file', path)
- continue
-
- if request.access_level == ad.ACCESS_LOCAL:
- impl_id = spec.root
- else:
- impl_id = activities.path_to_guid(spec.root)
-
- versions[spec['version']] = {
- '*-*': {
- 'guid': impl_id,
- 'stability': 'stable',
- 'commands': {
- 'activity': {
- 'exec': spec['Activity', 'exec'],
- },
- },
- 'requires': spec.requires,
- },
- }
-
- if not versions:
- return None
- else:
- return {'versions': versions}
-
def _events_cb(self, event):
found_commons = False
props = event.get('props')
diff --git a/sugar_network/local/mountset.py b/sugar_network/local/mountset.py
index 5625ecb..111e83c 100644
--- a/sugar_network/local/mountset.py
+++ b/sugar_network/local/mountset.py
@@ -112,29 +112,9 @@ class Mountset(dict, ad.CommandsProcessor, Commands, SyncCommands):
content={'keep': True}),
ad.Response())
- @ad.volume_command(method='GET', cmd='requires')
- def requires(self, mountpoint, context):
- mount = self.get(mountpoint)
- enforce(mount is not None, 'No such mountpoint')
- mount.mounted.wait()
-
- requires = set()
-
- for guid in [context] if isinstance(context, basestring) else context:
- feed = mount.call(
- Request(method='GET', document='context', guid=guid,
- prop='feed', accept_language=[self._lang]),
- ad.Response())
- for impls in feed.values():
- for impl in impls.values():
- if 'requires' in impl:
- requires.update(impl['requires'].keys())
-
- return list(requires)
-
def super_call(self, request, response):
if 'mountpoint' in request:
- mountpoint = request.pop('mountpoint')
+ mountpoint = request.mountpoint = request.pop('mountpoint')
else:
mountpoint = '/'
mount = self[mountpoint]
diff --git a/sugar_network/node/obs.py b/sugar_network/node/obs.py
index db85997..0252357 100644
--- a/sugar_network/node/obs.py
+++ b/sugar_network/node/obs.py
@@ -26,6 +26,10 @@ obs_url = Option(
'for master server',
default='https://obs.sugarlabs.org')
+obs_project = Option(
+ 'OBS project to use unattended building',
+ default='base')
+
obs_presolve_project = Option(
'OBS project to use with packagekit-backend-presolve',
default='resolve')
@@ -33,13 +37,80 @@ obs_presolve_project = Option(
_logger = logging.getLogger('node.obs')
_client = None
+_repos = None
+_presolve_repos = None
+
+
+def get_repos():
+ global _repos
+
+ if _repos is None:
+ _repos = []
+ repos = _request('GET', ['build', obs_project.value])
+ for repo in repos.findall('entry'):
+ repo = repo.get('name')
+ if '-' not in repo:
+ continue
+ arches = _request('GET', ['build', obs_project.value, repo])
+ _repos.append({
+ 'distributor_id': repo.split('-', 1)[0],
+ 'name': repo,
+ 'arches': [i.get('name') for i in arches.findall('entry')],
+ })
+
+ return _repos
def get_presolve_repos():
+ global _presolve_repos
+
+ if _presolve_repos is None:
+ _presolve_repos = []
+ repos = _request('GET', ['build', obs_presolve_project.value])
+ for repo in repos.findall('entry'):
+ repo = repo.get('name')
+ arches = _request('GET',
+ ['build', obs_presolve_project.value, repo])
+ for arch in arches.findall('entry'):
+ _presolve_repos.append({
+ 'name': repo,
+ 'arch': arch.get('name'),
+ })
+
+ return _presolve_repos
+
+
+def resolve(repo, arch, names):
+ for package in names:
+ _request('GET', ['resolve'], params={
+ 'project': obs_project.value,
+ 'repository': repo,
+ 'arch': arch,
+ 'package': package,
+ })
+
+
+def presolve(repo, arch, names):
result = []
- reply = _request('GET', ['build', obs_presolve_project.value])
- for i in reply.findall('entry'):
- result.append(i.get('name'))
+
+ for package in names:
+ reply = _request('GET', ['resolve'], params={
+ 'project': obs_presolve_project.value,
+ 'repository': repo,
+ 'arch': arch,
+ 'package': package,
+ 'withdeps': '1',
+ # TODO exclude package might be different on different platforms
+ 'exclude': 'sugar',
+ })
+ for pkg in reply.findall('binary'):
+ result.append({
+ # TODO more distros after supporting them PK backend
+ 'distributor_id': 'Fedora',
+ 'name': pkg.get('name'),
+ 'url': pkg.get('url'),
+ })
+
return result
@@ -49,8 +120,15 @@ def _request(*args, **kwargs):
if _client is None:
_client = http.Client(obs_url.value)
- response = _client.request(*args, **kwargs)
+ response = _client.request(*args, allowed=(400, 404), **kwargs)
enforce(response.headers.get('Content-Type') == 'text/xml',
'Irregular OBS response')
# pylint: disable-msg=E1103
- return ElementTree.parse(response.raw).getroot()
+ reply = ElementTree.parse(response.raw).getroot()
+
+ if response.status_code != 200:
+ summary = reply.find('summary')
+ enforce(summary is not None, 'Unknown OBS error')
+ raise RuntimeError(summary.text)
+
+ return reply
diff --git a/sugar_network/node/router.py b/sugar_network/node/router.py
index da6f131..44aaf25 100644
--- a/sugar_network/node/router.py
+++ b/sugar_network/node/router.py
@@ -13,7 +13,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import json
import logging
import active_document as ad
@@ -27,10 +26,6 @@ _logger = logging.getLogger('node.router')
class Router(router.Router):
- def __init__(self, commands):
- router.Router.__init__(self, commands)
- self._repos = None
-
@router.route('GET', '/packages')
def packages(self, request, response):
response.content_type = 'application/json'
@@ -49,13 +44,12 @@ class Router(router.Router):
self._get_package(request.path[1], request.path[2])
def _list_repos(self):
- if self._repos is None:
- if self.commands.is_master:
- # Node should not depend on OBS
- self._repos = obs.get_presolve_repos()
- else:
- self._repos = []
- return {'total': len(self._repos), 'result': self._repos}
+ if self.commands.is_master:
+ # Node should not depend on OBS
+ repos = obs.get_presolve_repos()
+ else:
+ repos = []
+ return {'total': len(repos), 'result': repos}
def _list_packages(self, request):
directory = self.commands.volume['context']
@@ -66,12 +60,9 @@ class Router(router.Router):
def _get_package(self, repo, package):
directory = self.commands.volume['context']
context = directory.get(package)
- meta = context.meta('feed')
- enforce(meta is not None and 'path' in meta, ad.NotFound, 'No feed')
-
- with file(meta['path']) as f:
- feed = json.load(f)
- enforce('presolve' in feed and repo in feed['presolve'], ad.NotFound,
+ enforce('package' in context.get('type'), ad.NotFound,
+ 'Is not a package')
+ presolve = context.get('presolve', {}).get(repo)
+ enforce(presolve and 'binary' in presolve, ad.NotFound,
'No presolve info')
-
- return feed['presolve'][repo]
+ return presolve['binary']
diff --git a/sugar_network/resources/context.py b/sugar_network/resources/context.py
index 36cec2d..4a02e90 100644
--- a/sugar_network/resources/context.py
+++ b/sugar_network/resources/context.py
@@ -16,9 +16,12 @@
from os.path import join
import active_document as ad
-
from sugar_network import resources, static
+from sugar_network.local import activities
from sugar_network.resources.volume import Resource
+from sugar_network.zerosugar import Spec
+from sugar_network.node import obs
+from active_toolkit import coroutine, util
class Context(Resource):
@@ -87,11 +90,6 @@ class Context(Resource):
def preview(self, value):
return value
- @ad.active_property(ad.BlobProperty,
- permissions=ad.ACCESS_READ, mime_type='application/json')
- def feed(self, value):
- return value
-
@ad.active_property(prefix='K', typecast=bool, default=False)
def keep(self, value):
return value
@@ -104,6 +102,57 @@ class Context(Resource):
def position(self, value):
return value
+ @ad.active_property(ad.StoredProperty, typecast=dict, default={})
+ def versions(self, value):
+ if self.request.mountpoint != '~':
+ return value
+
+ versions = {}
+
+ for path in activities.checkins(self.guid):
+ try:
+ spec = Spec(root=path)
+ except Exception:
+ util.exception('Failed to read %r spec file', path)
+ continue
+
+ if self.request.access_level == ad.ACCESS_LOCAL:
+ impl_id = spec.root
+ else:
+ impl_id = activities.path_to_guid(spec.root)
+
+ versions[spec['version']] = {
+ '*-*': {
+ 'guid': impl_id,
+ 'stability': 'stable',
+ 'commands': {
+ 'activity': {
+ 'exec': spec['Activity', 'exec'],
+ },
+ },
+ 'requires': spec.requires,
+ },
+ }
+
+ return versions
+
+ @ad.active_property(ad.StoredProperty, typecast=dict, default={})
+ def aliases(self, value):
+ return value
+
+ @aliases.setter
+ def aliases(self, value):
+ coroutine.spawn(self._process_aliases, value)
+ return value
+
+ @ad.active_property(ad.StoredProperty, typecast=dict, default={})
+ def packages(self, value):
+ return value
+
+ @ad.active_property(ad.StoredProperty, typecast=dict, default={})
+ def presolve(self, value):
+ return value
+
@classmethod
@ad.directory_command(method='PUT', cmd='include',
arguments={'layers': ad.to_list})
@@ -117,3 +166,40 @@ class Context(Resource):
def exclude(cls, directory, layers, request):
import logging
logging.error('exclude> %r %r', layers, request.content)
+
+ def _process_aliases(self, aliases):
+ packages = {}
+ for repo in obs.get_repos():
+ alias = aliases.get(repo['distributor_id'])
+ if not alias or '*' not in alias:
+ continue
+ alias = alias['*'].copy()
+ try:
+ to_resolve = alias.get('binary', []) + \
+ alias.get('devel', [])
+ for arch in repo['arches']:
+ obs.resolve(repo['name'], arch, to_resolve)
+ alias['status'] = 'success'
+ except Exception, error:
+ util.exception('Failed to resolve %r', alias)
+ alias = {'status': str(error)}
+ packages[repo['name']] = alias
+
+ presolve = {}
+ for repo in obs.get_presolve_repos():
+ alias = aliases.get(repo['distributor_id'])
+ if not alias or '*' not in alias:
+ continue
+ alias = alias['*'].copy()
+ try:
+ for key, names in alias.items():
+ alias[key] = \
+ obs.presolve(repo['name'], repo['arch'], names)
+ alias['status'] = 'success'
+ except Exception, error:
+ util.exception('Failed to preresolve %r', alias)
+ alias = {'status': str(error)}
+ presolve[repo['name']] = alias
+
+ self.request.call('PUT', document='context', guid=self.guid,
+ content={'packages': packages, 'presolve': presolve})
diff --git a/sugar_network/resources/volume.py b/sugar_network/resources/volume.py
index 975330e..c949bb1 100644
--- a/sugar_network/resources/volume.py
+++ b/sugar_network/resources/volume.py
@@ -33,6 +33,7 @@ _logger = logging.getLogger('resources.volume')
class Request(ad.Request):
blobs = None
+ mountpoint = None
class Resource(ad.Document):
diff --git a/sugar_network/toolkit/router.py b/sugar_network/toolkit/router.py
index 23890ed..58478c7 100644
--- a/sugar_network/toolkit/router.py
+++ b/sugar_network/toolkit/router.py
@@ -235,9 +235,17 @@ class Router(object):
class _Request(Request):
- def __init__(self, environ):
+ environ = None
+ url = None
+ path = None
+ principal = None
+
+ def __init__(self, environ=None):
Request.__init__(self)
+ if not environ:
+ return
+
self.access_level = ad.ACCESS_REMOTE
self.environ = environ
self.url = '/' + environ['PATH_INFO'].strip('/')
@@ -287,6 +295,14 @@ class _Request(Request):
elif scope == 1:
self['document'], = self.path
+ def clone(self):
+ request = Request.clone(self)
+ request.environ = self.environ
+ request.url = self.url
+ request.path = self.path
+ request.principal = self.principal
+ return request
+
class _Response(ad.Response):
diff --git a/sugar_network/zerosugar/feeds.py b/sugar_network/zerosugar/feeds.py
index 675d4ac..8141434 100644
--- a/sugar_network/zerosugar/feeds.py
+++ b/sugar_network/zerosugar/feeds.py
@@ -13,14 +13,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import json
import logging
from os.path import isabs
from zeroinstall.injector import model
from sugar_network.zerosugar import lsb_release, parse_version
-from active_toolkit import util, enforce
+from active_toolkit import util
clients = []
@@ -35,14 +34,9 @@ def read(context):
client = None
for client in clients:
try:
- blob = client.get(['context', context, 'feed'], cmd='get_blob')
- enforce(blob is not None, 'Feed not found')
- if 'path' in blob:
- with file(blob['path']) as f:
- feed_content = json.load(f)
- else:
- feed_content = blob
- _logger.debug('Found %r feed in %r mountpoint',
+ feed_content = client.get(['context', context],
+ reply=['versions', 'packages'])
+ _logger.debug('Found %r in %r mountpoint',
context, client.params['mountpoint'])
break
except Exception:
@@ -54,13 +48,11 @@ def read(context):
_logger.warning('No feed for %r context', context)
return None
- packages = feed_content.get('packages') or {}
- distro = packages.get(lsb_release.distributor_id())
+ distro = feed_content['packages'].get(lsb_release.distributor_id())
if distro:
feed.to_resolve = distro.get('binary')
- versions = feed_content.get('versions') or {}
- for version, version_data in versions.items():
+ for version, version_data in feed_content['versions'].items():
for arch, impl_data in version_data.items():
impl_id = impl_data['guid']
diff --git a/tests/__init__.py b/tests/__init__.py
index edec1e0..2ec7f1d 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -25,8 +25,9 @@ from sugar_network.local.mountset import Mountset
from sugar_network import local, node
from sugar_network.resources.user import User
from sugar_network.resources.context import Context
-from sugar_network.node.commands import NodeCommands
-from sugar_network.node import stats
+from sugar_network.node.commands import NodeCommands, MasterCommands
+from sugar_network.node.router import Router as MasterRouter
+from sugar_network.node import stats, obs
from sugar_network.resources.volume import Volume
@@ -87,6 +88,7 @@ class Test(unittest.TestCase):
stats.stats_step.value = 1
stats.stats_rras.value = ['RRA:AVERAGE:0.5:1:100']
stats._cache.clear()
+ obs._client = None
Volume.RESOURCES = [
'sugar_network.resources.user',
@@ -266,6 +268,17 @@ class Test(unittest.TestCase):
httpd.stop()
volume.close()
+ def start_master(self, classes=None):
+ if classes is None:
+ classes = [User, Context]
+ self.touch('master/master')
+ volume = Volume('master', classes)
+ cp = MasterCommands(volume)
+ self.server = coroutine.WSGIServer(('localhost', 8800), MasterRouter(cp))
+ coroutine.spawn(self.server.serve_forever)
+ coroutine.dispatch()
+ return volume
+
def sign(privkey, data):
with tempfile.NamedTemporaryFile() as tmp_privkey:
diff --git a/tests/units/__main__.py b/tests/units/__main__.py
index 5ecbaa6..19c72b7 100644
--- a/tests/units/__main__.py
+++ b/tests/units/__main__.py
@@ -22,5 +22,7 @@ from remote_mount import *
from node_mount import *
from injector import *
from mountset import *
+from context import *
+from obs import *
tests.main()
diff --git a/tests/units/context.py b/tests/units/context.py
new file mode 100755
index 0000000..e9ea911
--- /dev/null
+++ b/tests/units/context.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+# sugar-lint: disable
+
+from __init__ import tests
+
+from sugar_network.node import obs
+from sugar_network import IPCClient, Client
+from active_toolkit import coroutine, enforce
+
+
+class ContextTest(tests.Test):
+
+ def test_Aliases(self):
+ self.override(obs, 'get_repos', lambda: [
+ {'distributor_id': 'Gentoo', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']},
+ {'distributor_id': 'Debian', 'name': 'Debian-6.0', 'arches': ['x86']},
+ {'distributor_id': 'Debian', 'name': 'Debian-7.0', 'arches': ['x86_64']},
+ ])
+ self.override(obs, 'get_presolve_repos', lambda: [
+ {'distributor_id': 'Gentoo', 'name': 'Gentoo-2.1', 'arch': 'x86'},
+ {'distributor_id': 'Debian', 'name': 'Debian-6.0', 'arch': 'x86'},
+ {'distributor_id': 'Debian', 'name': 'Debian-7.0', 'arch': 'x86_64'},
+ ])
+ self.override(obs, 'resolve', lambda repo, arch, names: ['fake'])
+ self.override(obs, 'presolve', lambda repo, arch, names: ['%s-%s-%s' % (repo, arch, i) for i in names])
+
+ self.start_server()
+ client = IPCClient(mountpoint='~')
+
+ guid = client.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ client.put(['context', guid, 'aliases'], {
+ 'Gentoo': {
+ '*': {
+ 'binary': ['pkg1.bin', 'pkg2.bin'],
+ 'devel': ['pkg3.devel'],
+ },
+ },
+ 'Debian': {
+ '*': {
+ 'binary': ['pkg4.bin'],
+ 'devel': ['pkg5.devel', 'pkg6.devel'],
+ },
+ },
+ })
+ coroutine.dispatch()
+ self.assertEqual({
+ 'Gentoo-2.1': {'status': 'success', 'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']},
+ 'Debian-6.0': {'status': 'success', 'binary': ['pkg4.bin'], 'devel': ['pkg5.devel', 'pkg6.devel']},
+ 'Debian-7.0': {'status': 'success', 'binary': ['pkg4.bin'], 'devel': ['pkg5.devel', 'pkg6.devel']},
+ },
+ client.get(['context', guid, 'packages']))
+ self.assertEqual({
+ 'Gentoo-2.1': {'status': 'success', 'binary': ['Gentoo-2.1-x86-pkg1.bin', 'Gentoo-2.1-x86-pkg2.bin'], 'devel': ['Gentoo-2.1-x86-pkg3.devel']},
+ 'Debian-6.0': {'status': 'success', 'binary': ['Debian-6.0-x86-pkg4.bin'], 'devel': ['Debian-6.0-x86-pkg5.devel', 'Debian-6.0-x86-pkg6.devel']},
+ 'Debian-7.0': {'status': 'success', 'binary': ['Debian-7.0-x86_64-pkg4.bin'], 'devel': ['Debian-7.0-x86_64-pkg5.devel', 'Debian-7.0-x86_64-pkg6.devel']},
+ },
+ client.get(['context', guid, 'presolve']))
+
+ def test_WrongAliases(self):
+ self.override(obs, 'get_repos', lambda: [
+ {'distributor_id': 'Gentoo', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']},
+ {'distributor_id': 'Debian', 'name': 'Debian-6.0', 'arches': ['x86']},
+ {'distributor_id': 'Debian', 'name': 'Debian-7.0', 'arches': ['x86_64']},
+ ])
+ self.override(obs, 'get_presolve_repos', lambda: [
+ {'distributor_id': 'Gentoo', 'name': 'Gentoo-2.1', 'arch': 'x86'},
+ {'distributor_id': 'Debian', 'name': 'Debian-6.0', 'arch': 'x86'},
+ {'distributor_id': 'Debian', 'name': 'Debian-7.0', 'arch': 'x86_64'},
+ ])
+ self.override(obs, 'resolve', lambda repo, arch, names: enforce(False, 'resolve failed'))
+ self.override(obs, 'presolve', lambda repo, arch, names: enforce(False, 'presolve failed'))
+
+ self.start_server()
+ client = IPCClient(mountpoint='~')
+
+ guid = client.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+
+ client.put(['context', guid, 'aliases'], {
+ 'Gentoo': {
+ '*': {
+ 'binary': ['pkg1.bin', 'pkg2.bin'],
+ 'devel': ['pkg3.devel'],
+ },
+ },
+ 'Debian': {
+ '*': {
+ 'binary': ['pkg4.bin'],
+ 'devel': ['pkg5.devel', 'pkg6.devel'],
+ },
+ },
+ })
+ coroutine.dispatch()
+ self.assertEqual({
+ 'Gentoo-2.1': {'status': 'resolve failed'},
+ 'Debian-6.0': {'status': 'resolve failed'},
+ 'Debian-7.0': {'status': 'resolve failed'},
+ },
+ client.get(['context', guid, 'packages']))
+ self.assertEqual({
+ 'Gentoo-2.1': {'status': 'presolve failed'},
+ 'Debian-6.0': {'status': 'presolve failed'},
+ 'Debian-7.0': {'status': 'presolve failed'},
+ },
+ client.get(['context', guid, 'presolve']))
+
+ def test_PackagesRoute(self):
+ self.override(obs, 'get_presolve_repos', lambda: [
+ {'name': 'Gentoo-2.1', 'arch': 'x86'},
+ {'name': 'Debian-6.0', 'arch': 'x86_64'},
+ ])
+
+ volume = self.start_master()
+ client = Client()
+
+ client.post(['context'], {
+ 'type': 'package',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ 'implement': 'package1',
+ 'presolve': {
+ 'Gentoo-2.1': {'status': 'success', 'binary': ['package1-1', 'package1-2']},
+ 'Debian-6.0': {'status': 'success', 'binary': ['package1-3']},
+ },
+ })
+ client.post(['context'], {
+ 'type': 'package',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ 'implement': 'package2',
+ 'presolve': {
+ 'Gentoo-2.1': {'status': 'success', 'devel': ['package2-1', 'package2-2']},
+ 'Debian-6.0': {'status': 'success', 'devel': ['package2-3']},
+ },
+ })
+ client.post(['context'], {
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ 'implement': 'package3',
+ 'presolve': {
+ 'Gentoo-2.1': {'status': 'success', 'binary': ['package3-1', 'package3-2']},
+ 'Debian-6.0': {'status': 'success', 'binary': ['package3-3']},
+ },
+ })
+
+ self.assertEqual(
+ {'total': 2, 'result': [{'arch': 'x86', 'name': 'Gentoo-2.1'}, {'arch': 'x86_64', 'name': 'Debian-6.0'}]},
+ client.request('GET', ['packages']))
+ self.assertEqual(
+ {'total': 2, 'result': ['package1', 'package2']},
+ client.request('GET', ['packages', 'Gentoo-2.1']))
+ self.assertEqual(
+ ['package1-1', 'package1-2'],
+ client.request('GET', ['packages', 'Gentoo-2.1', 'package1']))
+ self.assertEqual(
+ ['package1-3'],
+ client.request('GET', ['packages', 'Debian-6.0', 'package1']))
+ self.assertRaises(RuntimeError, client.request, 'GET', ['packages', 'Debian-6.0', 'package2'])
+ self.assertRaises(RuntimeError, client.request, 'GET', ['packages', 'Gentoo-2.1', 'package3'])
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/home_mount.py b/tests/units/home_mount.py
index dc339d5..a632390 100755
--- a/tests/units/home_mount.py
+++ b/tests/units/home_mount.py
@@ -202,39 +202,37 @@ class HomeMountTest(tests.Test):
coroutine.sleep()
self.assertEqual({
- 'versions': {
- '1': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'false',
- },
+ '1': {
+ '*-*': {
+ 'commands': {
+ 'activity': {
+ 'exec': 'false',
},
- 'stability': 'stable',
- 'guid': tests.tmpdir + '/Activities/activity-1',
- 'requires': {},
},
+ 'stability': 'stable',
+ 'guid': tests.tmpdir + '/Activities/activity-1',
+ 'requires': {},
},
- '2': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'true',
- },
- },
- 'stability': 'stable',
- 'guid': tests.tmpdir + '/Activities/activity-2',
- 'requires': {
- 'dep1': {},
- 'dep2': {'restrictions': [['1', '2']]},
- 'dep3': {'restrictions': [[None, '2']]},
- 'dep4': {'restrictions': [['3', None]]},
+ },
+ '2': {
+ '*-*': {
+ 'commands': {
+ 'activity': {
+ 'exec': 'true',
},
},
+ 'stability': 'stable',
+ 'guid': tests.tmpdir + '/Activities/activity-2',
+ 'requires': {
+ 'dep1': {},
+ 'dep2': {'restrictions': [['1', '2']]},
+ 'dep3': {'restrictions': [[None, '2']]},
+ 'dep4': {'restrictions': [['3', None]]},
+ },
},
},
},
- client.get(['context', 'bundle_id', 'feed'], cmd='get_blob'))
+ client.get(['context', 'bundle_id', 'versions']))
if __name__ == '__main__':
diff --git a/tests/units/injector.py b/tests/units/injector.py
index 0c36459..21333da 100755
--- a/tests/units/injector.py
+++ b/tests/units/injector.py
@@ -33,12 +33,6 @@ class InjectorTest(tests.Test):
'description': 'description',
})
- blob_path = 'remote/context/%s/%s/feed' % (context[:2], context)
- self.touch(
- (blob_path, '{}'),
- (blob_path + '.blob', json.dumps({})),
- )
-
pipe = checkin('/', context)
log_path = tests.tmpdir + '/.sugar/default/logs/%s.log' % context
self.assertEqual([
@@ -57,27 +51,20 @@ class InjectorTest(tests.Test):
'notes': '',
})
- blob_path = 'remote/context/%s/%s/feed' % (context[:2], context)
- self.touch(
- (blob_path, '{}'),
- (blob_path + '.blob', json.dumps({
- 'versions': {
- '1': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'echo',
- },
- },
- 'stability': 'stable',
- 'guid': impl,
- 'size': 0,
- },
+ remote.put(['context', context, 'versions'], {
+ '1': {
+ '*-*': {
+ 'commands': {
+ 'activity': {
+ 'exec': 'echo',
},
},
- })),
- )
- os.unlink('cache/context/%s/%s/feed.meta' % (context[:2], context))
+ 'stability': 'stable',
+ 'guid': impl,
+ 'size': 0,
+ },
+ },
+ })
pipe = checkin('/', context)
log_path = tests.tmpdir + '/.sugar/default/logs/%s_1.log' % context
@@ -127,28 +114,21 @@ class InjectorTest(tests.Test):
'stability': 'stable',
'notes': '',
})
-
- blob_path = 'remote/context/%s/%s/feed' % (context[:2], context)
- self.touch(
- (blob_path, '{}'),
- (blob_path + '.blob', json.dumps({
- 'versions': {
- '1': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'false',
- },
- },
- 'stability': 'stable',
- 'guid': impl,
- 'size': 0,
- 'extract': 'TestActivitry',
- },
+ remote.put(['context', context, 'versions'], {
+ '1': {
+ '*-*': {
+ 'commands': {
+ 'activity': {
+ 'exec': 'false',
},
},
- })),
- )
+ 'stability': 'stable',
+ 'guid': impl,
+ 'size': 0,
+ 'extract': 'TestActivitry',
+ },
+ },
+ })
blob_path = 'remote/implementation/%s/%s/data' % (impl[:2], impl)
self.touch((blob_path, '{}'))
@@ -186,41 +166,34 @@ class InjectorTest(tests.Test):
'notes': '',
})
- os.unlink('cache/context/%s/%s/feed.meta' % (context[:2], context))
- blob_path = 'remote/context/%s/%s/feed' % (context[:2], context)
- self.touch(
- (blob_path, '{}'),
- (blob_path + '.blob', json.dumps({
- 'versions': {
- '1': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'false',
- },
- },
- 'stability': 'stable',
- 'guid': impl,
- 'size': 0,
- 'extract': 'TestActivitry',
- },
+ remote.put(['context', context, 'versions'], {
+ '1': {
+ '*-*': {
+ 'commands': {
+ 'activity': {
+ 'exec': 'false',
},
- '2': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'true',
- },
- },
- 'stability': 'stable',
- 'guid': impl_2,
- 'size': 0,
- 'extract': 'TestActivitry',
- },
+ },
+ 'stability': 'stable',
+ 'guid': impl,
+ 'size': 0,
+ 'extract': 'TestActivitry',
+ },
+ },
+ '2': {
+ '*-*': {
+ 'commands': {
+ 'activity': {
+ 'exec': 'true',
},
},
- })),
- )
+ 'stability': 'stable',
+ 'guid': impl_2,
+ 'size': 0,
+ 'extract': 'TestActivitry',
+ },
+ },
+ })
blob_path = 'remote/implementation/%s/%s/data' % (impl_2[:2], impl_2)
self.touch((blob_path, '{}'))
@@ -314,18 +287,12 @@ class InjectorTest(tests.Test):
'summary': 'summary',
'description': 'description',
'implement': 'dep1',
+ 'packages': {
+ lsb_release.distributor_id(): {
+ 'binary': ['dep1.bin'],
+ },
+ },
})
- blob_path = 'remote/context/de/dep1/feed'
- self.touch(
- (blob_path, '{}'),
- (blob_path + '.blob', json.dumps({
- 'packages': {
- lsb_release.distributor_id(): {
- 'binary': ['dep1.bin'],
- },
- },
- })),
- )
remote.post(['context'], {
'type': 'package',
@@ -333,18 +300,12 @@ class InjectorTest(tests.Test):
'summary': 'summary',
'description': 'description',
'implement': 'dep2',
+ 'packages': {
+ lsb_release.distributor_id(): {
+ 'binary': ['dep2.bin'],
+ },
+ },
})
- blob_path = 'remote/context/de/dep2/feed'
- self.touch(
- (blob_path, '{}'),
- (blob_path + '.blob', json.dumps({
- 'packages': {
- lsb_release.distributor_id(): {
- 'binary': ['dep2.bin'],
- },
- },
- })),
- )
def resolve(names):
with file('resolve', 'w') as f:
diff --git a/tests/units/node.py b/tests/units/node.py
index b4ec682..52f4b30 100755
--- a/tests/units/node.py
+++ b/tests/units/node.py
@@ -11,7 +11,7 @@ from sugar_network import node
from sugar_network.toolkit.router import Unauthorized
from sugar_network.node import stats
from sugar_network.node.commands import NodeCommands
-from sugar_network.resources.volume import Volume
+from sugar_network.resources.volume import Volume, Request
from sugar_network.resources.user import User
@@ -371,7 +371,7 @@ class NodeTest(tests.Test):
def call(cp, principal=None, content=None, **kwargs):
- request = ad.Request(**kwargs)
+ request = Request(**kwargs)
request.principal = principal
request.content = content
request.environ = {'HTTP_HOST': 'localhost'}
diff --git a/tests/units/node_mount.py b/tests/units/node_mount.py
index 763a73d..3f0f5e2 100755
--- a/tests/units/node_mount.py
+++ b/tests/units/node_mount.py
@@ -185,31 +185,21 @@ class NodeMountTest(tests.Test):
'stability': 'stable',
'notes': '',
})
-
- with file('mnt/context/%s/%s/feed' % (context[:2], context), 'w') as f:
- json.dump({
- 'seqno': 0,
- 'mime_type': 'application/octet-stream',
- 'digest': 'digest',
- }, f)
- with file('mnt/context/%s/%s/feed.blob' % (context[:2], context), 'w') as f:
- json.dump({
- 'versions': {
- '1': {
- '*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'echo',
- },
- },
- 'stability': 'stable',
- 'guid': impl,
- 'size': 0,
- 'extract': 'TestActivitry',
+ remote.put(['context', context, 'versions'], {
+ '1': {
+ '*-*': {
+ 'commands': {
+ 'activity': {
+ 'exec': 'echo',
},
},
+ 'stability': 'stable',
+ 'guid': impl,
+ 'size': 0,
+ 'extract': 'TestActivitry',
},
- }, f)
+ },
+ })
bundle = zipfile.ZipFile('bundle', 'w')
bundle.writestr('TestActivitry/activity/activity.info', '\n'.join([
'[Activity]',
diff --git a/tests/units/obs.py b/tests/units/obs.py
new file mode 100755
index 0000000..a998d4a
--- /dev/null
+++ b/tests/units/obs.py
@@ -0,0 +1,168 @@
+#!/usr/bin/env python
+# sugar-lint: disable
+
+from cStringIO import StringIO
+
+from __init__ import tests
+
+from sugar_network.toolkit import http
+from sugar_network.node import obs
+
+
+class ObsTest(tests.Test):
+
+ def test_get_repos(self):
+ self.override(http, 'Client', Client(self, [
+ (('GET', ['build', 'base']), {'allowed': (400, 404)}, [
+ '<directory>',
+ ' <entry name="Debian-6.0" />',
+ ' <entry name="Fedora-11" />',
+ '</directory>',
+ ]),
+ (('GET', ['build', 'base', 'Debian-6.0']), {'allowed': (400, 404)}, [
+ '<directory>',
+ ' <entry name="i586" />',
+ ' <entry name="x86_64" />',
+ '</directory>',
+ ]),
+ (('GET', ['build', 'base', 'Fedora-11']), {'allowed': (400, 404)}, [
+ '<directory>',
+ ' <entry name="i586" />',
+ '</directory>',
+ ]),
+ ]))
+
+ self.assertEqual([
+ {'distributor_id': 'Debian', 'name': 'Debian-6.0', 'arches': ['i586', 'x86_64']},
+ {'distributor_id': 'Fedora', 'name': 'Fedora-11', 'arches': ['i586']},
+ ],
+ obs.get_repos())
+
+ def test_get_presolve_repos(self):
+ self.override(http, 'Client', Client(self, [
+ (('GET', ['build', 'resolve']), {'allowed': (400, 404)}, [
+ '<directory>',
+ ' <entry name="Debian-6.0" />',
+ ' <entry name="Fedora-11" />',
+ '</directory>',
+ ]),
+ (('GET', ['build', 'resolve', 'Debian-6.0']), {'allowed': (400, 404)}, [
+ '<directory>',
+ ' <entry name="i586" />',
+ ' <entry name="x86_64" />',
+ '</directory>',
+ ]),
+ (('GET', ['build', 'resolve', 'Fedora-11']), {'allowed': (400, 404)}, [
+ '<directory>',
+ ' <entry name="i586" />',
+ '</directory>',
+ ]),
+ ]))
+
+ self.assertEqual([
+ {'name': 'Debian-6.0', 'arch': 'i586'},
+ {'name': 'Debian-6.0', 'arch': 'x86_64'},
+ {'name': 'Fedora-11', 'arch': 'i586'},
+ ],
+ obs.get_presolve_repos())
+
+ def test_resolve(self):
+ self.override(http, 'Client', Client(self, [
+ (('GET', ['resolve']),
+ {'allowed': (400, 404), 'params': {
+ 'project': 'base',
+ 'repository': 'repo',
+ 'arch': 'arch',
+ 'package': 'pkg1',
+ }},
+ [ '<resolve>',
+ ' <binary name="pygame" url="http://pkg1.prm" />',
+ '</resolve>',
+ ],
+ ),
+ (('GET', ['resolve']),
+ {'allowed': (400, 404), 'params': {
+ 'project': 'base',
+ 'repository': 'repo',
+ 'arch': 'arch',
+ 'package': 'pkg2',
+ }},
+ [ '<resolve>',
+ ' <binary name="pygame" url="http://pkg2.prm" />',
+ '</resolve>',
+ ],
+ ),
+ ]))
+
+ obs.resolve('repo', 'arch', ['pkg1', 'pkg2'])
+
+ def test_presolve(self):
+ self.override(http, 'Client', Client(self, [
+ (('GET', ['resolve']),
+ {'allowed': (400, 404), 'params': {
+ 'project': 'resolve',
+ 'repository': 'repo',
+ 'arch': 'arch',
+ 'package': 'pkg1',
+ 'withdeps': '1',
+ 'exclude': 'sugar',
+ }},
+ [ '<resolve>',
+ ' <binary name="pkg1-1" url="http://pkg1-1.prm" />',
+ ' <binary name="pkg1-2" url="http://pkg1-2.prm" />',
+ '</resolve>',
+ ],
+ ),
+ (('GET', ['resolve']),
+ {'allowed': (400, 404), 'params': {
+ 'project': 'resolve',
+ 'repository': 'repo',
+ 'arch': 'arch',
+ 'package': 'pkg2',
+ 'withdeps': '1',
+ 'exclude': 'sugar',
+ }},
+ [ '<resolve>',
+ ' <binary name="pkg2-1" url="http://pkg2-1.prm" />',
+ ' <binary name="pkg2-2" url="http://pkg2-2.prm" />',
+ '</resolve>',
+ ],
+ ),
+ ]))
+
+ self.assertEqual([
+ {'distributor_id': 'Fedora', 'url': 'http://pkg1-1.prm', 'name': 'pkg1-1'},
+ {'distributor_id': 'Fedora', 'url': 'http://pkg1-2.prm', 'name': 'pkg1-2'},
+ {'distributor_id': 'Fedora', 'url': 'http://pkg2-1.prm', 'name': 'pkg2-1'},
+ {'distributor_id': 'Fedora', 'url': 'http://pkg2-2.prm', 'name': 'pkg2-2'},
+ ],
+ obs.presolve('repo', 'arch', ['pkg1', 'pkg2']))
+
+
+class Response(object):
+
+ headers = {'Content-Type': 'text/xml'}
+ raw = None
+ status_code = 200
+
+
+class Client(object):
+
+ def __init__(self, test, calls):
+ self.test = test
+ self.calls = calls[:]
+
+ def request(self, *args, **kwargs):
+ assert self.calls
+ args_, kwargs_, reply = self.calls.pop(0)
+ self.test.assertEqual((args_, kwargs_), (args, kwargs))
+ response = Response()
+ response.raw = StringIO(''.join(reply))
+ return response
+
+ def __call__(self, url):
+ return self
+
+
+if __name__ == '__main__':
+ tests.main()
diff --git a/tests/units/remote_mount.py b/tests/units/remote_mount.py
index ed8beef..49c08e1 100755
--- a/tests/units/remote_mount.py
+++ b/tests/units/remote_mount.py
@@ -159,7 +159,7 @@ class RemoteMountTest(tests.Test):
],
events)
- def test_Subscription_NotifyOnline(self):
+ def ___test_Subscription_NotifyOnline(self):
self.start_ipc_and_restful_server()
remote = IPCClient(mountpoint='/')
local = IPCClient(mountpoint='~')