Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'clean_shutdown' of git://github.com/catlee/buildbot
* 'clean_shutdown' of git://github.com/catlee/buildbot: Adding some tests for clean shutdown Implemented clean master shutdown.
- Loading branch information
Showing
9 changed files
with
277 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,33 @@ | ||
from buildbot.status.web.base import HtmlResource | ||
from twisted.web.util import redirectTo | ||
from twisted.python import log | ||
from twisted.internet import reactor | ||
|
||
from buildbot.status.web.base import HtmlResource, path_to_root, path_to_authfail | ||
from buildbot.util.eventual import eventually | ||
|
||
class RootPage(HtmlResource): | ||
title = "Buildbot" | ||
|
||
def content(self, request, cxt): | ||
status = self.getStatus(request) | ||
|
||
if request.path == '/shutdown': | ||
if self.getAuthz(request).actionAllowed("cleanShutdown", request): | ||
eventually(status.cleanShutdown) | ||
return redirectTo("/", request) | ||
else: | ||
return redirectTo(path_to_authfail(request), request) | ||
elif request.path == '/cancel_shutdown': | ||
if self.getAuthz(request).actionAllowed("cleanShutdown", request): | ||
eventually(status.cancelCleanShutdown) | ||
return redirectTo("/", request) | ||
else: | ||
return redirectTo(path_to_authfail(request), request) | ||
|
||
cxt.update( | ||
shutting_down = status.shuttingDown, | ||
shutdown_url = request.childLink("shutdown"), | ||
cancel_shutdown_url = request.childLink("cancel_shutdown"), | ||
) | ||
template = request.site.buildbot_service.templates.get_template("root.html") | ||
return template.render(**cxt) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
# Test clean shutdown functionality of the master | ||
from mock import Mock, patch, patch_object | ||
from twisted.trial import unittest | ||
from twisted.internet import defer | ||
from buildbot.master import BotMaster | ||
|
||
class TestCleanShutdown(unittest.TestCase): | ||
def setUp(self): | ||
self.master = BotMaster() | ||
self.master.reactor = Mock() | ||
self.master.startService() | ||
|
||
def test_shutdown_idle(self): | ||
"""Test that the master shuts down when it's idle""" | ||
d = self.master.cleanShutdown() | ||
def _check(ign): | ||
self.assertEquals(self.master.reactor.stop.called, True) | ||
|
||
d.addCallback(_check) | ||
return d | ||
|
||
def test_shutdown_busy(self): | ||
"""Test that the master shuts down after builds finish""" | ||
# Fake some builds | ||
builder = Mock() | ||
build = Mock() | ||
builder.builder_status.getCurrentBuilds.return_value = [build] | ||
|
||
d_finished = defer.Deferred() | ||
build.waitUntilFinished.return_value = d_finished | ||
|
||
self.master.builders = Mock() | ||
self.master.builders.values.return_value = [builder] | ||
|
||
d_shutdown = self.master.cleanShutdown() | ||
|
||
# Trigger the loop to get things going | ||
self.master.loop.trigger() | ||
|
||
# First we wait for it to quiet down again | ||
d = self.master.loop.when_quiet() | ||
|
||
# Next we check that we haven't stopped yet, since there's a running | ||
# build | ||
def _check1(ign): | ||
self.assertEquals(self.master.reactor.stop.called, False) | ||
d.addCallback(_check1) | ||
|
||
# Now we cause the build to finish, then kick the loop again, | ||
# empty out the list of running builds, and wait for the shutdown | ||
# process to finish | ||
def _finish_build(ign): | ||
d_finished.callback(None) | ||
self.master.loop.trigger() | ||
self.master.builders.values.return_value = [] | ||
return d_shutdown | ||
d.addCallback(_finish_build) | ||
|
||
# And now we should be done | ||
def _check2(ign): | ||
self.assertEquals(self.master.reactor.stop.called, True) | ||
d.addCallback(_check2) | ||
|
||
return d | ||
|
||
def test_shutdown_cancel(self): | ||
"""Test that we can cancel a shutdown""" | ||
# Fake some builds | ||
builder = Mock() | ||
build = Mock() | ||
builder.builder_status.getCurrentBuilds.return_value = [build] | ||
|
||
d_finished = defer.Deferred() | ||
build.waitUntilFinished.return_value = d_finished | ||
|
||
self.master.builders = Mock() | ||
self.master.builders.values.return_value = [builder] | ||
|
||
d_shutdown = self.master.cleanShutdown() | ||
|
||
# Trigger the loop to get things going | ||
self.master.loop.trigger() | ||
|
||
# First we wait for it to quiet down again | ||
d = self.master.loop.when_quiet() | ||
|
||
# Next we check that we haven't stopped yet, since there's a running | ||
# build. | ||
# We cancel the shutdown here too | ||
def _check1(ign): | ||
self.assertEquals(self.master.reactor.stop.called, False) | ||
self.master.cancelCleanShutdown() | ||
d.addCallback(_check1) | ||
|
||
# Now we cause the build to finish, then kick the loop again, | ||
# empty out the list of running builds, and wait for the shutdown | ||
# process to finish | ||
def _finish_build(ign): | ||
d_finished.callback(None) | ||
self.master.loop.trigger() | ||
self.master.builders.values.return_value = [] | ||
return d_shutdown | ||
d.addCallback(_finish_build) | ||
|
||
# We should still be running! | ||
def _check2(ign): | ||
self.assertEquals(self.master.reactor.stop.called, False) | ||
d.addCallback(_check2) | ||
|
||
return d | ||
|
||
def test_shutdown_no_new_builds(self): | ||
"""Test that no new builds get handed out when we're shutting down""" | ||
# Fake some builds | ||
builder = Mock() | ||
build = Mock() | ||
builder.builder_status.getCurrentBuilds.return_value = [build] | ||
|
||
d_finished = defer.Deferred() | ||
build.waitUntilFinished.return_value = d_finished | ||
|
||
self.master.builders = Mock() | ||
self.master.builders.values.return_value = [builder] | ||
|
||
self.assertEquals(self.master._get_processors(), [builder.run]) | ||
|
||
d_shutdown = self.master.cleanShutdown() | ||
|
||
# Trigger the loop to get things going | ||
self.master.loop.trigger() | ||
|
||
# First we wait for it to quiet down again | ||
d = self.master.loop.when_quiet() | ||
|
||
# Next we check that we haven't stopped yet, since there's a running | ||
# build. | ||
# Also check that we're not trying to hand out new builds! | ||
def _check1(ign): | ||
self.assertEquals(self.master.reactor.stop.called, False) | ||
self.assertEquals(self.master._get_processors(), []) | ||
d.addCallback(_check1) | ||
|
||
return d |