[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/server/cros/dynamic_suite_unittest.py b/server/cros/dynamic_suite_unittest.py
index 9a94763..7b6a9e9 100755
--- a/server/cros/dynamic_suite_unittest.py
+++ b/server/cros/dynamic_suite_unittest.py
@@ -15,6 +15,7 @@
 import unittest
 
 from autotest_lib.client.common_lib import base_job, control_data, global_config
+from autotest_lib.frontend.afe.json_rpc import proxy
 from autotest_lib.server.cros import control_file_getter, dynamic_suite
 from autotest_lib.server import frontend
 
@@ -155,9 +156,14 @@
 
 
     def testEnsureVersionLabelAlreadyExists(self):
-        """Should not create a label if it already exists."""
+        """Should tolerate a label that already exists."""
         name = 'label'
-        self.afe.get_labels(name=name).AndReturn([name])
+        error = proxy.ValidationError(
+            {'name': 'ValidationError',
+             'message': '{"name": "This value must be unique"}',
+             'traceback': ''},
+            'BAD')
+        self.afe.create_label(name=name).AndRaise(error)
         self.mox.ReplayAll()
         self.reimager._ensure_version_label(name)
 
@@ -165,7 +171,6 @@
     def testEnsureVersionLabel(self):
         """Should create a label if it doesn't already exist."""
         name = 'label'
-        self.afe.get_labels(name=name).AndReturn([])
         self.afe.create_label(name=name)
         self.mox.ReplayAll()
         self.reimager._ensure_version_label(name)
@@ -301,17 +306,6 @@
         self.reimager._schedule_reimage_job(self._BUILD, self._NUM, self._BOARD)
 
 
-    def expect_label_cleanup(self, build):
-        """Sets up |self.afe| to expect deletion of the version label.
-
-        @param build: the build the label is named after.
-        """
-        label = FakeLabel(id=random.randrange(0, 5))
-        self.afe.get_labels(
-            name__startswith=mox.StrContains(build)).AndReturn([label])
-        self.afe.run('delete_label', id=label.id)
-
-
     def expect_attempt(self, success, ex=None, check_hosts=True):
         """Sets up |self.reimager| to expect an attempt() that returns |success|
 
@@ -349,7 +343,6 @@
             self.afe.poll_job_results(mox.IgnoreArg(),
                                       canary, 0).AndReturn(success)
 
-        self.expect_label_cleanup(self._BUILD)
         self.mox.StubOutWithMock(self.reimager, '_clear_build_state')
 
         return canary
@@ -434,7 +427,6 @@
         rjob.record('START', mox.IgnoreArg(), mox.IgnoreArg())
         rjob.record('END WARN', mox.IgnoreArg(), mox.IgnoreArg(),
                     mox.StrContains('Too few hosts'))
-        self.expect_label_cleanup(self._BUILD)
         self.mox.ReplayAll()
         self.reimager.attempt(self._BUILD, self._BOARD, rjob.record, True)
         self.reimager.clear_reimaged_host_state(self._BUILD)
@@ -452,7 +444,6 @@
         rjob.record('START', mox.IgnoreArg(), mox.IgnoreArg())
         rjob.record('END ERROR', mox.IgnoreArg(), mox.IgnoreArg(),
                     mox.StrContains('All hosts'))
-        self.expect_label_cleanup(self._BUILD)
         self.mox.ReplayAll()
         self.reimager.attempt(self._BUILD, self._BOARD, rjob.record, True)
         self.reimager.clear_reimaged_host_state(self._BUILD)