[autotest] Add num control to provision suite

BUG=chromium:672348
TEST=None

Change-Id: Id8e782cd3c087d79c819649ab7e5c6d63a67519e
Reviewed-on: https://chromium-review.googlesource.com/565333
Commit-Ready: Allen Li <ayatane@chromium.org>
Tested-by: Allen Li <ayatane@chromium.org>
Reviewed-by: Prathmesh Prabhu <pprabhu@chromium.org>
diff --git a/frontend/afe/rpc_interface.py b/frontend/afe/rpc_interface.py
index 9c22806..53f1aad 100644
--- a/frontend/afe/rpc_interface.py
+++ b/frontend/afe/rpc_interface.py
@@ -1883,7 +1883,6 @@
         'timeout_mins': timeout_mins,
         'devserver_url': ds.url(),
         'priority': priority,
-        'suite_args' : suite_args,
         'wait_for_results': wait_for_results,
         'job_retry': job_retry,
         'max_retries': max_retries,
diff --git a/server/cros/dynamic_suite/dynamic_suite.py b/server/cros/dynamic_suite/dynamic_suite.py
index 9dd6e27..1aa380b 100644
--- a/server/cros/dynamic_suite/dynamic_suite.py
+++ b/server/cros/dynamic_suite/dynamic_suite.py
@@ -417,6 +417,14 @@
         )
 
 
+class _ProvisionSuiteSpec(_SuiteSpec):
+
+    def __init__(self, num_required, **kwargs):
+        self.num_required = num_required
+        super(_ProvisionSuiteSpec, self).__init__(**kwargs)
+
+
+
 def run_provision_suite(**dargs):
     """
     Run a provision suite.
@@ -432,7 +440,7 @@
     @raises MalformedDependenciesException: if the dependency_info file for
                                             the required build fails to parse.
     """
-    spec = _SuiteSpec(**dargs)
+    spec = _ProvisionSuiteSpec(**dargs)
 
     afe = frontend_wrappers.RetryingAFE(timeout_min=30, delay_sec=10,
                                         user=spec.job.user, debug=False)
@@ -451,6 +459,8 @@
             builds=spec.builds,
             board=spec.board,
             devserver=spec.devserver,
+            num=spec.num,
+            num_required=spec.num_required,
             count=1,
             afe=afe,
             tko=tko,
diff --git a/server/cros/dynamic_suite/suite.py b/server/cros/dynamic_suite/suite.py
index 7837661..4268c95 100644
--- a/server/cros/dynamic_suite/suite.py
+++ b/server/cros/dynamic_suite/suite.py
@@ -1253,6 +1253,8 @@
                     record=record,
                     waiter=waiter,
                     reporter=reporter)
+                if self._finished_waiting():
+                    break
         except Exception:  # pylint: disable=W0703
             logging.exception('Exception waiting for results')
             Status('FAIL', self._tag,
@@ -1283,6 +1285,11 @@
             return _EmailResultReporter(self)
 
 
+    def _finished_waiting(self):
+        """Return whether the suite is finished waiting for child jobs."""
+        return False
+
+
     def _handle_result(self, result, record, waiter, reporter):
         """
         Handle a test job result.
@@ -1619,8 +1626,9 @@
             tag,
             builds,
             board,
-            count,
             devserver,
+            num,
+            num_required,
             cf_getter=None,
             run_prod_code=False,
             test_args=None,
@@ -1632,8 +1640,9 @@
         @param tag: a string with which to tag jobs run in this suite.
         @param builds: the builds on which we're running this suite.
         @param board: the board on which we're running this suite.
-        @param count: number of dummy tests to make
         @param devserver: the devserver which contains the build.
+        @param num: number of dummy tests to make.
+        @param num_required: number of tests that must pass.
         @param cf_getter: a control_file_getter.ControlFileGetter.
         @param test_args: A dict of args passed all the way to each individual
                           test that will be actually ran.
@@ -1644,13 +1653,23 @@
         dummy_test = _load_dummy_test(
                 builds, devserver, cf_getter,
                 run_prod_code, test_args, test_source_build)
-
         super(ProvisionSuite, self).__init__(
-                tests=[dummy_test] * count,
+                tests=[dummy_test] * num,
                 tag=tag,
                 builds=builds,
                 board=board,
                 **kwargs)
+        self._num_required = num_required
+        self._num_successful = 0
+
+    def _handle_result(self, result, record, waiter, reporter):
+        super(ProvisionSuite, self)._handle_result(
+                result, record, waiter, reporter)
+        if result.is_good():
+            self._num_successful += 1
+
+    def _finished_waiting(self):
+        return self._num_successful >= self._num_required
 
 
 def _load_dummy_test(
diff --git a/test_suites/control.suite_attr_wrapper b/test_suites/control.suite_attr_wrapper
index fcdd0ce..c33c4dc 100644
--- a/test_suites/control.suite_attr_wrapper
+++ b/test_suites/control.suite_attr_wrapper
@@ -31,7 +31,7 @@
 
 # Get the predicate object from attr_filter argument
 try:
-    attr = suite_args['attr_filter']
+    attr = args_dict['attr_filter']
     attr_predicate = suite.Suite.matches_attribute_expression_predicate(attr)
 except KeyError:
     logging.error('Unable to find the attribute boolean expression used to '