From patchwork Tue Jul 12 03:08:14 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zygmunt Krynicki X-Patchwork-Id: 2656 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 0930124356 for ; Tue, 12 Jul 2011 03:08:17 +0000 (UTC) Received: from mail-qw0-f52.google.com (mail-qw0-f52.google.com [209.85.216.52]) by fiordland.canonical.com (Postfix) with ESMTP id 83AFFA184F3 for ; Tue, 12 Jul 2011 03:08:16 +0000 (UTC) Received: by qwb8 with SMTP id 8so3111447qwb.11 for ; Mon, 11 Jul 2011 20:08:16 -0700 (PDT) Received: by 10.229.68.200 with SMTP id w8mr4566569qci.114.1310440095955; Mon, 11 Jul 2011 20:08:15 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.229.217.78 with SMTP id hl14cs227220qcb; Mon, 11 Jul 2011 20:08:15 -0700 (PDT) Received: by 10.217.6.195 with SMTP id y45mr3728441wes.56.1310440095088; Mon, 11 Jul 2011 20:08:15 -0700 (PDT) Received: from adelie.canonical.com (adelie.canonical.com [91.189.90.139]) by mx.google.com with ESMTP id o53si27222316weq.28.2011.07.11.20.08.14; Mon, 11 Jul 2011 20:08:15 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.139 as permitted sender) client-ip=91.189.90.139; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.139 as permitted sender) smtp.mail=bounces@canonical.com Received: from loganberry.canonical.com ([91.189.90.37]) by adelie.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1QgTKY-0003RC-Fi for ; Tue, 12 Jul 2011 03:08:14 +0000 Received: from loganberry.canonical.com (localhost [127.0.0.1]) by loganberry.canonical.com (Postfix) with ESMTP id 681732E84F6 for ; Tue, 12 Jul 2011 03:08:14 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: lava-dashboard X-Launchpad-Branch: ~linaro-validation/lava-dashboard/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 242 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~linaro-validation/lava-dashboard/trunk] Rev 242: Use linaro-django-xmlrpc in dashboard Message-Id: <20110712030814.22044.83783.launchpad@loganberry.canonical.com> Date: Tue, 12 Jul 2011 03:08:14 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="13388"; Instance="initZopeless config overlay" X-Launchpad-Hash: 460cc496ef6d83dd99624d37fbdb33b28860cbde Merge authors: Zygmunt Krynicki (zkrynicki) Related merge proposals: https://code.launchpad.net/~linaro-validation/lava-dashboard/use_linaro_django_xmlrpc/+merge/67173 proposed by: Zygmunt Krynicki (zkrynicki) review: Approve - Michael Hudson-Doyle (mwhudson) ------------------------------------------------------------ revno: 242 [merge] committer: Zygmunt Krynicki branch nick: test_browser timestamp: Tue 2011-07-12 05:06:00 +0200 message: Use linaro-django-xmlrpc in dashboard modified: dashboard_app/extension.py dashboard_app/tests/other/dashboard_api.py dashboard_app/tests/other/dataview.py dashboard_app/views.py dashboard_app/xmlrpc.py setup.py --- lp:lava-dashboard https://code.launchpad.net/~linaro-validation/lava-dashboard/trunk You are subscribed to branch lp:lava-dashboard. To unsubscribe from this branch go to https://code.launchpad.net/~linaro-validation/lava-dashboard/trunk/+edit-subscription === modified file 'dashboard_app/extension.py' --- dashboard_app/extension.py 2011-07-12 02:32:26 +0000 +++ dashboard_app/extension.py 2011-07-12 03:06:00 +0000 @@ -1,4 +1,23 @@ +# Copyright (C) 2010 Linaro Limited +# +# Author: Zygmunt Krynicki +# +# This file is part of Launch Control. +# +# Launch Control is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License version 3 +# as published by the Free Software Foundation +# +# Launch Control is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Launch Control. If not, see . + import os + from lava_server.extension import LavaServerExtension @@ -22,9 +41,14 @@ @property def version(self): + from dashboard_app import __version__ import versiontools - import dashboard_app - return versiontools.format_version(dashboard_app.__version__) + return versiontools.format_version(__version__) + + @property + def api_class(self): + from dashboard_app.xmlrpc import DashboardAPI + return DashboardAPI def contribute_to_settings(self, settings_module): super(DashboardExtension, self).contribute_to_settings(settings_module) @@ -55,4 +79,3 @@ # properly, having permissions to login, permissions to view proper data) settings_module['DATABASES']['dataview'] = dict(settings_module['DATABASES']['default']) settings_module['DATABASES']['dataview']['USER'] += "_dataview" - === modified file 'dashboard_app/tests/other/dashboard_api.py' --- dashboard_app/tests/other/dashboard_api.py 2011-05-30 16:52:46 +0000 +++ dashboard_app/tests/other/dashboard_api.py 2011-07-07 11:38:01 +0000 @@ -31,38 +31,6 @@ from dashboard_app.xmlrpc import errors -class DashboardAPITests(DashboardXMLRPCViewsTestCase): - - def test_xml_rpc_help_returns_200(self): - response = self.client.get(self.endpoint_path) - self.assertEqual(response.status_code, 200) - - def test_help_page_lists_all_methods(self): - from dashboard_app.views import DashboardDispatcher as dispatcher - expected_methods = [] - for name in dispatcher.system_listMethods(): - expected_methods.append({ - 'name': name, - 'signature': dispatcher.system_methodSignature(name), - 'help': dispatcher.system_methodHelp(name) - }) - response = self.client.get(self.endpoint_path) - self.assertEqual(response.context['methods'], expected_methods) - - def test_get_request_shows_help(self): - response = self.client.get(self.endpoint_path) - self.assertTemplateUsed(response, "dashboard_app/api.html") - - def test_empty_post_request_shows_help(self): - response = self.client.post(self.endpoint_path) - self.assertTemplateUsed(response, "dashboard_app/api.html") - - def test_version(self): - from dashboard_app import __version__ - self.assertEqual(self.xml_rpc_call('version'), - ".".join(map(str, __version__))) - - class DashboardAPIStreamsTests(DashboardXMLRPCViewsTestCase): scenarios = [ === modified file 'dashboard_app/tests/other/dataview.py' --- dashboard_app/tests/other/dataview.py 2011-06-23 10:09:42 +0000 +++ dashboard_app/tests/other/dataview.py 2011-07-07 11:38:53 +0000 @@ -19,11 +19,12 @@ import unittest from mocker import Mocker, expect +from testtools import TestCase from dashboard_app.dataview import DataView -class DataViewHandlerTests(unittest.TestCase): +class DataViewHandlerTests(TestCase): text = """ @@ -43,6 +44,7 @@ """ def setUp(self): + super(DataViewHandlerTests, self).setUp() self.dataview = DataView.load_from_xml(self.text) def test_name_parsed_ok(self): @@ -74,7 +76,7 @@ self.assertEqual(arg.help, "sorting order") -class DataViewConnectionTests(unittest.TestCase): +class DataViewConnectionTests(TestCase): def test_get_connection_without_sandbox(self): # Mock connections['dataview'] to raise ConnectionDoesNotExist === modified file 'dashboard_app/views.py' --- dashboard_app/views.py 2011-07-12 03:00:26 +0000 +++ dashboard_app/views.py 2011-07-12 03:06:00 +0000 @@ -42,23 +42,9 @@ TestResult, TestRun, ) -from dashboard_app.xmlrpc import DashboardAPI from dashboard_app.bread_crumbs import BreadCrumb, BreadCrumbTrail -def _get_dashboard_dispatcher(): - """ - Build dashboard XML-RPC dispatcher. - """ - dispatcher = DjangoXMLRPCDispatcher() - dispatcher.register_instance(DashboardAPI()) - dispatcher.register_introspection_functions() - return dispatcher - - -DashboardDispatcher = _get_dashboard_dispatcher() - - def _get_queryset(klass): """ Returns a QuerySet from a Model, Manager, or QuerySet. Created to make @@ -97,41 +83,11 @@ raise Http404('No %s matches the given query.' % queryset.model._meta.object_name) -# Original inspiration from: -# Brendan W. McAdams -def xml_rpc_handler(request, dispatcher): - """ - XML-RPC handler. - - If post data is defined, it assumes it's XML-RPC and tries to - process as such. Empty POST request and GET requests assumes you're - viewing from a browser and tells you about the service. - """ - if len(request.POST): - raw_data = request.raw_post_data - response = HttpResponse(mimetype="application/xml") - result = dispatcher._marshaled_dispatch(raw_data) - response.write(result) - response['Content-length'] = str(len(response.content)) - return response - else: - methods = [{ - 'name': method, - 'signature': dispatcher.system_methodSignature(method), - 'help': dispatcher.system_methodHelp(method)} - for method in dispatcher.system_listMethods()] - return render_to_response( - 'dashboard_app/api.html', { - 'methods': methods, - 'dashboard_url': "http://{domain}".format( - domain = Site.objects.get_current().domain) - }, RequestContext(request) - ) - - @csrf_exempt def dashboard_xml_rpc_handler(request): - return xml_rpc_handler(request, DashboardDispatcher) + from dashboard_app.xmlrpc import legacy_mapper + from linaro_django_xmlrpc.views import handler + return handler(request, legacy_mapper) @BreadCrumb("Dashboard") === modified file 'dashboard_app/xmlrpc.py' --- dashboard_app/xmlrpc.py 2011-07-04 02:35:35 +0000 +++ dashboard_app/xmlrpc.py 2011-07-07 11:39:05 +0000 @@ -26,6 +26,8 @@ from django.contrib.auth.models import User from django.db import IntegrityError, DatabaseError +from linaro_django_xmlrpc.models import ExposedAPI +from linaro_django_xmlrpc.models import Mapper from dashboard_app import __version__ from dashboard_app.dataview import DataView, DataViewRepository @@ -48,7 +50,7 @@ NOT_IMPLEMENTED = 501 -class DashboardAPI(object): +class DashboardAPI(ExposedAPI): """ Dashboard API object. @@ -139,17 +141,16 @@ - team streams are accessible by team members """ - user = None try: logging.debug("Getting bundle stream") - bundle_stream = BundleStream.objects.accessible_by_principal(user).get(pathname=pathname) + bundle_stream = BundleStream.objects.accessible_by_principal(self.user).get(pathname=pathname) except BundleStream.DoesNotExist: logging.debug("Bundle stream does not exists, aborting") raise xmlrpclib.Fault(errors.NOT_FOUND, "Bundle stream not found") try: logging.debug("Creating bundle object") - bundle = Bundle.objects.create_with_content(bundle_stream, user, content_filename, content) + bundle = Bundle.objects.create_with_content(bundle_stream, self.user, content_filename, content) except (IntegrityError, ValueError) as exc: logging.debug("Raising xmlrpclib.Fault(errors.CONFLICT)") raise xmlrpclib.Fault(errors.CONFLICT, str(exc)) @@ -203,10 +204,9 @@ - personal streams are accessible by owners - team streams are accessible by team members """ - user = None try: bundle = Bundle.objects.get(content_sha1=content_sha1) - if not bundle.bundle_stream.is_accessible_by(user): + if not bundle.bundle_stream.is_accessible_by(self.user): raise Bundle.DoesNotExist() except Bundle.DoesNotExist: raise xmlrpclib.Fault(errors.NOT_FOUND, @@ -259,8 +259,7 @@ - personal streams are accessible by owners - team streams are accessible by team members """ - user = None - bundle_streams = BundleStream.objects.accessible_by_principal(user) + bundle_streams = BundleStream.objects.accessible_by_principal(self.user) return [{ 'pathname': bundle_stream.pathname, 'name': bundle_stream.name, @@ -323,9 +322,8 @@ - personal streams are accessible by owners - team streams are accessible by team members """ - user = None try: - bundle_stream = BundleStream.objects.accessible_by_principal(user).get(pathname=pathname) + bundle_stream = BundleStream.objects.accessible_by_principal(self.user).get(pathname=pathname) except BundleStream.DoesNotExist: raise xmlrpclib.Fault(errors.NOT_FOUND, "Bundle stream not found") return [{ @@ -431,6 +429,7 @@ except IntegrityError: raise xmlrpclib.Fault(errors.CONFLICT, "Stream with the specified pathname already exists") else: + # TODO: Make this constraint unnecessary raise xmlrpclib.Fault(errors.FORBIDDEN, "Only anonymous streams can be constructed") return bundle_stream.pathname @@ -583,3 +582,10 @@ "type": item[1] } for item in columns] } + + + +# Mapper used by the legacy URL +legacy_mapper = Mapper() +legacy_mapper.register_introspection_methods() +legacy_mapper.register(DashboardAPI, '') === modified file 'setup.py' --- setup.py 2011-07-01 11:43:06 +0000 +++ setup.py 2011-07-07 11:38:01 +0000 @@ -54,6 +54,7 @@ 'lava-server >= 0.2.1', 'linaro-dashboard-bundle >= 1.5.2', 'linaro-django-pagination >= 2.0.2', + 'linaro-django-xmlrpc >= 0.3.2', 'linaro-json >= 2.0.1', # TODO: use json-schema-validator 'pygments >= 1.2', 'south >= 0.7.3',