Allow lab status to block based on a build regex.
Previously, the lab status could contain a string to block testing
based on the board. With this change, the status can block any
build that matches a regex in the status. This allows closing the
lab to either a build or a milestone. It also allows closing the
lab for other more specific conditions, for anyone desperate enough
to want to.
BUG=chromium:220934
TEST=unit tests
Change-Id: I8a44f5e9be504415a7c5bd73c714c778bf684d2c
Reviewed-on: https://chromium-review.googlesource.com/179544
Tested-by: Richard Barnette <jrbarnette@chromium.org>
Reviewed-by: Alex Miller <milleral@chromium.org>
Commit-Queue: Richard Barnette <jrbarnette@chromium.org>
diff --git a/server/lab_status_unittest.py b/server/lab_status_unittest.py
index fad4285..1299a66 100644
--- a/server/lab_status_unittest.py
+++ b/server/lab_status_unittest.py
@@ -13,6 +13,8 @@
from autotest_lib.client.common_lib import global_config
from autotest_lib.server import site_utils
+_DEADBUILD = 'deadboard-release/R33-4966.0.0'
+_LIVEBUILD = 'liveboard-release/R32-4920.14.0'
_OPEN_STATUS_VALUES = [
'''
@@ -44,6 +46,16 @@
"general_state": "open"
}
''',
+
+ '''
+ {
+ "username": "fizzbin@google.com",
+ "date": "2013-11-16 00:25:23.511208",
+ "message": "Lab is up despite R33-4966.0.0",
+ "can_commit_freely": true,
+ "general_state": "open"
+ }
+ ''',
]
_CLOSED_STATUS_VALUES = [
@@ -61,19 +73,19 @@
{
"username": "fizzbin@google.com",
"date": "2013-11-16 00:25:23.511208",
- "message": "Lab is down even for [deadboard]",
+ "message": "Lab is down even for [liveboard-release/R32-4920.14.0]",
"can_commit_freely": false,
"general_state": "closed"
}
''',
]
-_DEADBOARD_STATUS_VALUES = [
+_DEADBUILD_STATUS_VALUES = [
'''
{
"username": "fizzbin@google.com",
"date": "2013-11-16 00:25:23.511208",
- "message": "Lab is up except for [deadboard]",
+ "message": "Lab is up except for [deadboard-]",
"can_commit_freely": false,
"general_state": "open"
}
@@ -83,7 +95,7 @@
{
"username": "fizzbin@google.com",
"date": "2013-11-16 00:25:23.511208",
- "message": "liveboard is good, but [deadboard] is bad",
+ "message": "Lab is up except for [R33-]",
"can_commit_freely": false,
"general_state": "open"
}
@@ -93,7 +105,7 @@
{
"username": "fizzbin@google.com",
"date": "2013-11-16 00:25:23.511208",
- "message": "Lab is up [deadboard otherboard]",
+ "message": "Lab is up except for [deadboard-.*/R33-]",
"can_commit_freely": false,
"general_state": "open"
}
@@ -103,7 +115,7 @@
{
"username": "fizzbin@google.com",
"date": "2013-11-16 00:25:23.511208",
- "message": "Lab is up [otherboard deadboard]",
+ "message": "Lab is up except for [ deadboard-]",
"can_commit_freely": false,
"general_state": "open"
}
@@ -113,7 +125,47 @@
{
"username": "fizzbin@google.com",
"date": "2013-11-16 00:25:23.511208",
- "message": "Lab is up [first deadboard last]",
+ "message": "Lab is up except for [deadboard- ]",
+ "can_commit_freely": false,
+ "general_state": "open"
+ }
+ ''',
+
+ '''
+ {
+ "username": "fizzbin@google.com",
+ "date": "2013-11-16 00:25:23.511208",
+ "message": "Lab is up [first R33- last]",
+ "can_commit_freely": false,
+ "general_state": "open"
+ }
+ ''',
+
+ '''
+ {
+ "username": "fizzbin@google.com",
+ "date": "2013-11-16 00:25:23.511208",
+ "message": "liveboard is good, but [deadboard-] is bad",
+ "can_commit_freely": false,
+ "general_state": "open"
+ }
+ ''',
+
+ '''
+ {
+ "username": "fizzbin@google.com",
+ "date": "2013-11-16 00:25:23.511208",
+ "message": "Lab is up [deadboard- otherboard-]",
+ "can_commit_freely": false,
+ "general_state": "open"
+ }
+ ''',
+
+ '''
+ {
+ "username": "fizzbin@google.com",
+ "date": "2013-11-16 00:25:23.511208",
+ "message": "Lab is up [otherboard- deadboard-]",
"can_commit_freely": false,
"general_state": "open"
}
@@ -249,10 +301,10 @@
1. Lab is up. All calls to _decode_lab_status() will
succeed without raising an exception.
2. Lab is down. All calls to _decode_lab_status() will
- fail with LabIsDownException.
- 3. Board disabled. Calls to _decode_lab_status() will
- succeed, except that board 'deadboard' will raise
- BoardIsDisabledException.
+ fail with TestLabException.
+ 3. Build disabled. Calls to _decode_lab_status() will
+ succeed, except that board `_DEADBUILD` will raise
+ TestLabException.
"""
@@ -265,42 +317,37 @@
@param lab_status JSON value describing lab status.
"""
- site_utils._decode_lab_status(lab_status, None)
- site_utils._decode_lab_status(lab_status, 'liveboard')
- site_utils._decode_lab_status(lab_status, 'deadboard')
+ site_utils._decode_lab_status(lab_status, _LIVEBUILD)
+ site_utils._decode_lab_status(lab_status, _DEADBUILD)
def _assert_lab_closed(self, lab_status):
"""Test that closed status values are handled properly.
- Test that _decode_lab_status() raises LabIsDownException
+ Test that _decode_lab_status() raises TestLabException
when the lab status is down.
@param lab_status JSON value describing lab status.
"""
- with self.assertRaises(site_utils.LabIsDownException):
- site_utils._decode_lab_status(lab_status, None)
- with self.assertRaises(site_utils.LabIsDownException):
- site_utils._decode_lab_status(lab_status, 'liveboard')
- with self.assertRaises(site_utils.LabIsDownException):
- site_utils._decode_lab_status(lab_status, 'deadboard')
+ with self.assertRaises(site_utils.TestLabException):
+ site_utils._decode_lab_status(lab_status, _LIVEBUILD)
+ with self.assertRaises(site_utils.TestLabException):
+ site_utils._decode_lab_status(lab_status, _DEADBUILD)
- def _assert_lab_deadboard(self, lab_status):
- """Test that disabled boards are handled properly.
+ def _assert_lab_deadbuild(self, lab_status):
+ """Test that disabled builds are handled properly.
- Test that _decode_lab_status() raises
- BoardIsDisabledException for board 'deadboard' and
- succeeds otherwise.
+ Test that _decode_lab_status() raises TestLabException
+ for build `_DEADBUILD` and succeeds otherwise.
@param lab_status JSON value describing lab status.
"""
- site_utils._decode_lab_status(lab_status, None)
- site_utils._decode_lab_status(lab_status, 'liveboard')
- with self.assertRaises(site_utils.BoardIsDisabledException):
- site_utils._decode_lab_status(lab_status, 'deadboard')
+ site_utils._decode_lab_status(lab_status, _LIVEBUILD)
+ with self.assertRaises(site_utils.TestLabException):
+ site_utils._decode_lab_status(lab_status, _DEADBUILD)
def _assert_lab_status(self, test_values, checker):
@@ -333,10 +380,10 @@
self._assert_lab_closed)
- def test_dead_board(self):
- """Test that disabled boards are handled correctly."""
- self._assert_lab_status(_DEADBOARD_STATUS_VALUES,
- self._assert_lab_deadboard)
+ def test_dead_build(self):
+ """Test that disabled builds are handled correctly."""
+ self._assert_lab_status(_DEADBUILD_STATUS_VALUES,
+ self._assert_lab_deadbuild)
class CheckStatusTest(mox.MoxTestBase):
@@ -389,100 +436,51 @@
site_utils._get_lab_status(_FAKE_URL).AndReturn(json_value)
- def _try_check_no_board(self):
- """Test calling check_lab_status() with no board."""
+ def _try_check_status(self, build):
+ """Test calling check_lab_status() with `build`."""
try:
self.mox.ReplayAll()
- site_utils.check_lab_status()
+ site_utils.check_lab_status(build)
finally:
self.mox.VerifyAll()
- def _try_check_dead_board(self):
- """Test calling check_lab_status() with 'deadboard'."""
- try:
- self.mox.ReplayAll()
- site_utils.check_lab_status('deadboard')
- finally:
- self.mox.VerifyAll()
-
-
- def _try_check_live_board(self):
- """Test calling check_lab_status() with 'liveboard'."""
- try:
- self.mox.ReplayAll()
- site_utils.check_lab_status('liveboard')
- finally:
- self.mox.VerifyAll()
-
-
- def test_non_cautotest_no_board(self):
- """Test a call with no board when the host isn't cautotest."""
+ def test_non_cautotest(self):
+ """Test a call with a build when the host isn't cautotest."""
self._setup_not_cautotest()
- self._try_check_no_board()
+ self._try_check_status(_LIVEBUILD)
- def test_non_cautotest_with_board(self):
- """Test a call with a board when the host isn't cautotest."""
- self._setup_not_cautotest()
- self._try_check_live_board()
-
-
- def test_no_status_no_board(self):
- """Test without a board when `_get_lab_status()` returns `None`."""
+ def test_no_lab_status(self):
+ """Test with a build when `_get_lab_status()` returns `None`."""
self._setup_no_status()
- self._try_check_no_board()
+ self._try_check_status(_LIVEBUILD)
- def test_no_lab_status_with_board(self):
- """Test with a board when `_get_lab_status()` returns `None`."""
- self._setup_no_status()
- self._try_check_live_board()
-
-
- def test_lab_up_no_board(self):
- """Test lab open with no board specified."""
+ def test_lab_up_live_build(self):
+ """Test lab open with a build specified."""
self._setup_lab_status(_OPEN_STATUS_VALUES[0])
- self._try_check_no_board()
+ self._try_check_status(_LIVEBUILD)
- def test_lab_up_live_board(self):
- """Test lab open with a board specified."""
- self._setup_lab_status(_OPEN_STATUS_VALUES[0])
- self._try_check_live_board()
-
-
- def test_lab_down_no_board(self):
- """Test lab closed with no board specified."""
+ def test_lab_down_live_build(self):
+ """Test lab closed with a build specified."""
self._setup_lab_status(_CLOSED_STATUS_VALUES[0])
- with self.assertRaises(site_utils.LabIsDownException):
- self._try_check_no_board()
+ with self.assertRaises(site_utils.TestLabException):
+ self._try_check_status(_LIVEBUILD)
- def test_lab_down_live_board(self):
- """Test lab closed with a board specified."""
- self._setup_lab_status(_CLOSED_STATUS_VALUES[0])
- with self.assertRaises(site_utils.LabIsDownException):
- self._try_check_live_board()
+ def test_build_disabled_live_build(self):
+ """Test build disabled with a live build specified."""
+ self._setup_lab_status(_DEADBUILD_STATUS_VALUES[0])
+ self._try_check_status(_LIVEBUILD)
- def test_board_disabled_no_board(self):
- """Test board disabled with no board specified."""
- self._setup_lab_status(_DEADBOARD_STATUS_VALUES[0])
- self._try_check_no_board()
-
-
- def test_board_disabled_live_board(self):
- """Test board disabled with a live board specified."""
- self._setup_lab_status(_DEADBOARD_STATUS_VALUES[0])
- self._try_check_live_board()
-
-
- def test_board_disabled_dead_board(self):
- """Test board disabled with the disabled board specified."""
- self._setup_lab_status(_DEADBOARD_STATUS_VALUES[0])
- with self.assertRaises(site_utils.BoardIsDisabledException):
- self._try_check_dead_board()
+ def test_build_disabled_dead_build(self):
+ """Test build disabled with the disabled build specified."""
+ self._setup_lab_status(_DEADBUILD_STATUS_VALUES[0])
+ with self.assertRaises(site_utils.TestLabException):
+ self._try_check_status(_DEADBUILD)
if __name__ == '__main__':
diff --git a/server/site_utils.py b/server/site_utils.py
index daa0a6b..d27aff3 100644
--- a/server/site_utils.py
+++ b/server/site_utils.py
@@ -25,13 +25,8 @@
LAB_GOOD_STATES = ('open', 'throttled')
-class LabIsDownException(Exception):
- """Raised when the Lab is Down"""
- pass
-
-
-class BoardIsDisabledException(Exception):
- """Raised when a certain board is disabled in the Lab"""
+class TestLabException(Exception):
+ """Exception raised when the Test Lab blocks a test or suite."""
pass
@@ -178,50 +173,48 @@
return None
-def _decode_lab_status(lab_status, board):
+def _decode_lab_status(lab_status, build):
"""Decode lab status, and report exceptions as needed.
- Takes a deserialized JSON object from the lab status page, and
- interprets it to determine the actual lab status. Raises
+ Take a deserialized JSON object from the lab status page, and
+ interpret it to determine the actual lab status. Raise
exceptions as required to report when the lab is down.
- @param board: board name that we want to check the status of.
+ @param build: build name that we want to check the status of.
- @raises LabIsDownException if the lab is not up.
- @raises BoardIsDisabledException if the desired board is currently
- disabled.
+ @raises TestLabException Raised if a request to test for the given
+ status and build should be blocked.
"""
# First check if the lab is up.
if not lab_status['general_state'] in LAB_GOOD_STATES:
- raise LabIsDownException('Chromium OS Lab is currently not up: '
- '%s.' % lab_status['message'])
+ raise TestLabException('Chromium OS Test Lab is closed: '
+ '%s.' % lab_status['message'])
- # Check if the board we wish to use is disabled.
+ # Check if the build we wish to use is disabled.
# Lab messages should be in the format of:
- # Lab is 'status' [boards not to be ran] (comment). Example:
- # Lab is Open [stumpy, kiev, x86-alex] (power_resume rtc causing duts to go
- # down)
- boards_are_disabled = re.search('\[(.*)\]', lab_status['message'])
- if board and boards_are_disabled:
- if board in boards_are_disabled.group(1):
- raise BoardIsDisabledException('Chromium OS Lab is '
- 'currently not allowing suites to be scheduled on board '
- '%s: %s' % (board, lab_status['message']))
+ # Lab is 'status' [regex ...] (comment)
+ # If the build name matches any regex, it will be blocked.
+ build_exceptions = re.search('\[(.*)\]', lab_status['message'])
+ if not build_exceptions:
+ return
+ for build_pattern in build_exceptions.group(1).split():
+ if re.search(build_pattern, build):
+ raise TestLabException('Chromium OS Test Lab is closed: '
+ '%s matches %s.' % (
+ build, build_pattern))
return
-def check_lab_status(board=None):
- """Check if the lab status allows us to schedule suites.
+def check_lab_status(build):
+ """Check if the lab status allows us to schedule for a build.
- Also checks if the lab is disabled for that particular board, and if so
- will raise an error to prevent new suites from being scheduled for that
- board.
+ Checks if the lab is down, or if testing for the requested build
+ should be blocked.
- @param board: board name that we want to check the status of.
+ @param build: Name of the build to be scheduled for testing.
- @raises LabIsDownException if the lab is not up.
- @raises BoardIsDisabledException if the desired board is currently
- disabled.
+ @raises TestLabException Raised if a request to test for the given
+ status and build should be blocked.
"""
# Ensure we are trying to schedule on the actual lab.
@@ -238,4 +231,4 @@
# We go ahead and say the lab is open if we can't get the status.
logging.warn('Could not get a status from %s', status_url)
return
- _decode_lab_status(json_status, board)
+ _decode_lab_status(json_status, build)