Skip to content

Commit

Permalink
change_hook integration with unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: Pierre Tardy <pierre.tardy@intel.com>
  • Loading branch information
Pierre Tardy committed May 10, 2015
1 parent bc46cbe commit b62c766
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 3 deletions.
42 changes: 42 additions & 0 deletions master/buildbot/test/unit/test_www_service.py
Expand Up @@ -19,11 +19,14 @@
from buildbot.test.fake import fakemaster
from buildbot.test.util import www
from buildbot.www import auth
from buildbot.www import change_hook
from buildbot.www import resource
from buildbot.www import rest
from buildbot.www import service
from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse
from twisted.internet import defer
from twisted.trial import unittest
from twisted.web._auth.wrapper import HTTPAuthSessionWrapper


class NeedsReconfigResource(resource.Resource):
Expand Down Expand Up @@ -127,3 +130,42 @@ def test_setupSite(self):
req = mock.Mock()
self.assertIsInstance(root.getChildWithDefault('api', req),
rest.RestRootResource)

def test_setupSiteWithProtectedHook(self):
checker = InMemoryUsernamePasswordDatabaseDontUse()
checker.addUser("guest", "password")

self.svc.setupSite(self.makeConfig(
change_hook_dialects={'base': True},
change_hook_auth=[checker]))
site = self.svc.site

# check that it has the right kind of resources attached to its
# root
root = site.resource
req = mock.Mock()
self.assertIsInstance(root.getChildWithDefault('change_hook', req),
HTTPAuthSessionWrapper)

@defer.inlineCallbacks
def test_setupSiteWithHook(self):
new_config = self.makeConfig(
change_hook_dialects={'base': True})
self.svc.setupSite(new_config)
site = self.svc.site

# check that it has the right kind of resources attached to its
# root
root = site.resource
req = mock.Mock()
ep = root.getChildWithDefault('change_hook', req)
self.assertIsInstance(ep,
change_hook.ChangeHookResource)

# not yet configured
self.assertEqual(ep.dialects, {})

yield self.svc.reconfigServiceWithBuildbotConfig(new_config)

# now configured
self.assertEqual(ep.dialects, {'base': True})
10 changes: 7 additions & 3 deletions master/buildbot/www/change_hook.py
Expand Up @@ -20,32 +20,36 @@

import re

from buildbot.www import resource
from twisted.internet import defer
from twisted.python import log
from twisted.python.reflect import namedModule
from twisted.web import resource
from twisted.web import server


class ChangeHookResource(resource.Resource):
# this is a cheap sort of template thingy
contentType = "text/html; charset=utf-8"
children = {}
needsReconfig = True

def __init__(self, dialects=None):
def __init__(self, dialects=None, master=None):
"""
The keys of 'dialects' select a modules to load under
master/buildbot/www/hooks/
The value is passed to the module's getChanges function, providing
configuration options to the dialect.
"""
resource.Resource.__init__(self)
resource.Resource.__init__(self, master)

if dialects is None:
dialects = {}
self.dialects = dialects
self.request_dialect = None

def reconfigResource(self, new_config):
self.dialects = new_config.www.get('change_hook_dialects', {})

def getChild(self, name, request):
return self

Expand Down
35 changes: 35 additions & 0 deletions master/buildbot/www/service.py
Expand Up @@ -19,14 +19,20 @@
from buildbot.util import service
from buildbot.www import auth
from buildbot.www import avatar
from buildbot.www import change_hook
from buildbot.www import config as wwwconfig
from buildbot.www import rest
from buildbot.www import sse
from buildbot.www import ws
from twisted.application import strports
from twisted.cred.portal import IRealm
from twisted.cred.portal import Portal
from twisted.internet import defer
from twisted.python import log
from twisted.web import guard
from twisted.web import resource
from twisted.web import server
from zope.interface import implements


class WWWService(service.ReconfigurableServiceMixin, service.AsyncMultiService):
Expand Down Expand Up @@ -150,6 +156,16 @@ def setupSite(self, new_config):
# /sse
root.putChild('sse', sse.EventResource(self.master))

# /change_hook
resource_obj = change_hook.ChangeHookResource(master=self.master)

# FIXME: this does not work with reconfig
change_hook_auth = new_config.www.get('change_hook_auth')
if change_hook_auth is not None:
resource_obj = self.setupProtectedResource(
resource_obj, change_hook_auth)
root.putChild("change_hook", resource_obj)

self.root = root

def either(a, b): # a if a else b for py2.4
Expand Down Expand Up @@ -201,3 +217,22 @@ def reconfigSite(self, new_config):
new_config.www['auth'].reconfigAuth(self.master, new_config)
for rsrc in self.reconfigurableResources:
rsrc.reconfigResource(new_config)

def setupProtectedResource(self, resource_obj, checkers):
class SimpleRealm(object):

"""
A realm which gives out L{ChangeHookResource} instances for authenticated
users.
"""
implements(IRealm)

def requestAvatar(self, avatarId, mind, *interfaces):
if resource.IResource in interfaces:
return (resource.IResource, resource_obj, lambda: None)
raise NotImplementedError()

portal = Portal(SimpleRealm(), checkers)
credentialFactory = guard.BasicCredentialFactory('Protected area')
wrapper = guard.HTTPAuthSessionWrapper(portal, [credentialFactory])
return wrapper

0 comments on commit b62c766

Please sign in to comment.