do not combine control files with retries when running a test suite

The previous behavior of run_remote_tests.sh when running a suite
consisting of only client or only server side tests, was to combine all
the control files for the suite's tests into one control file. This
reduces overhead, and makes the suite faster.

However, for tests in a suite that make use of the new test retries
feature using the RETRIES attribute, combining the control files into
one breaks the retries feature.

This CL causes run_remote_tests.sh to only combine a suite's control
files which have files with 0 or unspecified retries, and run all tests
that use retries separately.

CQ-DEPEND=I3baec71737eb5fed66f2d1a225b334eaa8e3d91b

BUG=chromium-os:39799
TEST=Run run_remote_tests.sh --remove=<dut> suite:dummyclientretries
See info output that two files are being combined for efficiency, and
two files with retires are being run separately. See that this is indeed
the case when the tests run.

Change-Id: I80010c713451e6224cb8e74f1812a2c0fdccb361
Reviewed-on: https://gerrit.chromium.org/gerrit/45790
Tested-by: Aviv Keshet <akeshet@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
Commit-Queue: Aviv Keshet <akeshet@chromium.org>
diff --git a/run_remote_tests.sh b/run_remote_tests.sh
index 7c29b03..bb25fd7 100755
--- a/run_remote_tests.sh
+++ b/run_remote_tests.sh
@@ -249,6 +249,43 @@
   echo "${tmp}"
 }
 
+_equals_zero () {
+  [ "$1" == "0" ]
+}
+
+_notequals_zero () {
+  [ "$1" != "0" ]
+}
+
+get_matching_retry_control_files() {
+  local predicate_function="$1"
+  shift 1
+  local control_files="$@"
+  local test_retries
+
+  for control_file in ${control_files}; do
+    local normalized_file=$(normalize_control_path "${control_file}")
+    test_retries=$(read_retry_value ${normalized_file})
+    if $predicate_function ${test_retries}; then
+      echo "${control_file}"
+    fi
+  done
+}
+
+# Given a list of control files (with paths either relative or absolute),
+# returns the sublist of these control files (absolute paths)
+# for which the RETRIES field is either 0 or unspecified.
+get_zero_retry_control_files() {
+  get_matching_retry_control_files _equals_zero "$@"
+}
+
+# Given a list of control files (with paths either relative or absolute),
+# returns the sublist of these control files (absolute paths)
+# for which the RETRIES field is not 0
+get_nonzero_retry_control_files() {
+  get_matching_retry_control_files _notequals_zero "$@"
+}
+
 # Given a control_type (client or server) and a list of control files, assembles
 # them all into a single control file. Useful for reducing repeated packaging
 # between tests sharing the same resources.
@@ -470,14 +507,31 @@
         die "Cannot enumerate ${suite}"
     # Combine into a single control file if possible.
     control_type="$(check_control_file_types ${suite_map[${suite}]})"
+
+    local nonretry_files retry_files
+    nonretry_files="$(get_zero_retry_control_files \
+                      ${suite_map[${suite}]})"
+    retry_files="$(get_nonzero_retry_control_files \
+                      ${suite_map[${suite}]})"
+
     info "Control type: ${control_type}"
     if [[ -n "${control_type}" ]]; then
       new_control_file="$(generate_combined_control_file ${control_type} \
-                          ${suite_map[${suite}]})"
+                          ${nonretry_files})"
       suite_map[${suite}]="${new_control_file}"
     fi
+
+    if [[ -n "${retry_files}" ]]; then
+      info "Running the following control files that use RETRIES separately:"
+      for control_file in $retry_files; do
+        info "$control_file"
+      done
+      suite_map[${suite}]+=" ${retry_files}"
+    fi
   done
 
+
+
   echo ""
 
   if [[ -z "${control_files_to_run}" ]] && [[ -z "${suite_map[@]}" ]]; then