[autotest] Avoid races due to 'version' labels on devices in the lab.
At a high level, this change makes dynamic suites stop deleting the version
labels we use at the end of a run, and also makes the code charged with
creating that label tolerant of discovering that one already exists.
To do the latter, we needed to make the underlying RPC code return
appropriate RPC errors immediately, so that we can detect (and ignore)
them when we try to create a label and it already exists. Since autotest's
json_rpc just had one type of exception it could throw, we had to add a new
exception type to proxy.py and handle it appropriately.
BUG=chromium-os:29971
TEST=unit
TEST=pre-create a version label and run a suite. It should run, not error out.
TEST=Run a suite without the label existing. Should also run.
Change-Id: I71de5670439c6933d1523ae65f7bfb6bc66c4f88
Reviewed-on: https://gerrit.chromium.org/gerrit/21124
Reviewed-by: Chris Masone <cmasone@chromium.org>
Tested-by: Chris Masone <cmasone@chromium.org>
Commit-Ready: Chris Masone <cmasone@chromium.org>
diff --git a/frontend/afe/json_rpc/proxy.py b/frontend/afe/json_rpc/proxy.py
index 6fb85fe..b01cc36 100644
--- a/frontend/afe/json_rpc/proxy.py
+++ b/frontend/afe/json_rpc/proxy.py
@@ -24,6 +24,39 @@
class JSONRPCException(Exception):
pass
+class ValidationError(JSONRPCException):
+ """Raised when the RPC is malformed."""
+ def __init__(self, error, formatted_message):
+ """Constructor.
+
+ @param error: a dict of error info like so:
+ {error['name']: 'ErrorKind',
+ error['message']: 'Pithy error description.',
+ error['traceback']: 'Multi-line stack trace'}
+ @formatted_message: string representation of this exception.
+ """
+ self.problem_keys = eval(error['message'])
+ self.traceback = error['traceback']
+ super(ValidationError, self).__init__(formatted_message)
+
+def BuildException(error):
+ """Exception factory.
+
+ Given a dict of error info, determine which subclass of
+ JSONRPCException to build and return. If can't determine the right one,
+ just return a JSONRPCException with a pretty-printed error string.
+
+ @param error: a dict of error info like so:
+ {error['name']: 'ErrorKind',
+ error['message']: 'Pithy error description.',
+ error['traceback']: 'Multi-line stack trace'}
+ """
+ error_message = '%(name)s: %(message)s\n%(traceback)s' % error
+ for cls in JSONRPCException.__subclasses__():
+ if error['name'] == cls.__name__:
+ return cls(error, error_message)
+ return JSONRPCException(error_message)
+
class ServiceProxy(object):
def __init__(self, serviceURL, serviceName=None, headers=None):
self.__serviceURL = serviceURL
@@ -51,9 +84,6 @@
except ValueError:
raise JSONRPCException('Error decoding JSON reponse:\n' + respdata)
if resp['error'] is not None:
- error_message = (resp['error']['name'] + ': ' +
- resp['error']['message'] + '\n' +
- resp['error']['traceback'])
- raise JSONRPCException(error_message)
+ raise BuildException(resp['error'])
else:
return resp['result']