Add suite version name extraction for BL am: eb0504fcf0 am: bf8419c9ad am: 93d5143bf3

Original change: https://android-review.googlesource.com/c/platform/test/suite_harness/+/2896740

Change-Id: I22372a6aefe9bed88ecb8e6a08c3722ada31d955
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java
index da24425..889ca7d 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java
@@ -67,6 +67,8 @@
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
 import java.util.Set;
 
 /**
@@ -140,6 +142,16 @@
     @Option(name = "version", description = "The module configuration version to retrieve.")
     private String mModuleVersion = null;
 
+    @Option(
+            name = "suite-version-extraction-regex",
+            description =
+                    "A regex string with a named capture group \"version\". Used to compare"
+                            + " versions on the BL server. To exclude a platform version name"
+                            + " prefix for example, use \".+?_sts(?<version>.+)\""
+                            + "('12.1_sts-r1' -> '-r1'). Note that <version> can be represented"
+                            + " in xml with &lt;version&gt;.")
+    private String mSuiteVersionExtractionRegex = "(?<version>.+)";
+
     private String mDeviceFilePushed;
     private String mHostFilePushed;
     private IAbi mAbi = null;
@@ -267,10 +279,9 @@
     /** Helper to populate the business logic service request with info about the device. */
     @VisibleForTesting
     String buildRequestParams(ITestDevice device, IBuildInfo buildInfo)
-            throws DeviceNotAvailableException {
-        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
+            throws DeviceNotAvailableException, TargetSetupError {
         MultiMap<String, String> paramMap = new MultiMap<>();
-        String suiteVersion = buildHelper.getSuiteVersion();
+        String suiteVersion = getSuiteVersionExtracted(buildInfo);
         if (suiteVersion == null) {
             suiteVersion = "null";
         }
@@ -296,6 +307,41 @@
     }
 
     /**
+     * Extract the version string we should use to compare versions on the BL server. Control what's
+     * extracted with the suite-version-extraction-regex option. This defaults to no changes to the
+     * original build. Suites that prepend the platform version name may use this to remove it.
+     */
+    @VisibleForTesting
+    String getSuiteVersionExtracted(IBuildInfo buildInfo) throws TargetSetupError {
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
+        String suiteVersion = buildHelper.getSuiteVersion();
+        if (suiteVersion == null) {
+            return null;
+        }
+        Matcher m = Pattern.compile(mSuiteVersionExtractionRegex).matcher(suiteVersion);
+        if (m.matches()) {
+            try {
+                String extracted = m.group("version");
+                CLog.d("original version: %s, extracted version: %s", suiteVersion, extracted);
+                return extracted;
+            } catch (IllegalStateException | IllegalArgumentException e) {
+                throw new TargetSetupError(
+                        String.format(
+                                "Could not match the extraction regex (%s) against the suite"
+                                        + " version (%s)",
+                                mSuiteVersionExtractionRegex, suiteVersion),
+                        e,
+                        InfraErrorIdentifier.OPTION_CONFIGURATION_ERROR);
+            }
+        }
+        throw new TargetSetupError(
+                String.format(
+                        "Could not match the extraction regex (%s) against the suite version (%s)",
+                        mSuiteVersionExtractionRegex, suiteVersion),
+                InfraErrorIdentifier.OPTION_CONFIGURATION_ERROR);
+    }
+
+    /**
      * Return list of test-suite-tag from configuration if it's not empty,
      * otherwise, return the name from test-suite-info.properties.
      */
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparerTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparerTest.java
index 3b0998e..7b272a9 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparerTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparerTest.java
@@ -17,14 +17,17 @@
 package com.android.compatibility.common.tradefed.targetprep;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.when;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.BuildInfo;
 import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionCopier;
 import com.android.tradefed.config.OptionSetter;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.TargetSetupError;
 import com.android.tradefed.util.FileUtil;
 
 import org.junit.After;
@@ -37,6 +40,8 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -46,7 +51,6 @@
 import java.util.Map;
 import java.util.Set;
 
-
 /**
  * Unit test for {@link BusinessLogicPreparer}.
  */
@@ -128,17 +132,37 @@
     private String serviceUrl = "https://androidpartner.googleapis.com/v1/dynamicconfig/" +
             "suites/{suite-name}/modules/{module}/version/{version}?key=123";
 
+    private static final String[] SUITE_VERSIONS_STS = {
+        "9_sts-r1",
+        "10_sts-r1",
+        "R_sts-r1",
+        "11_sts-r1",
+        "S_sts-r1",
+        "12_sts-r1",
+        "Sv2_sts-r1",
+        "12.1_sts-r1",
+        "Tiramisu_sts-r1",
+    };
+    private static final String[] SUITE_VERSIONS_GTS = {
+        "9.0_r1", "9.0_r2", "9.1_r1", "9.1_r2", "10_r1", "10_r2", "10_r3", "10_r4", "11_r1",
+        "11_r2", "11_r3",
+    };
+    private static final List<String> SUITE_VERSIONS_ALL =
+            Stream.concat(Arrays.stream(SUITE_VERSIONS_STS), Arrays.stream(SUITE_VERSIONS_GTS))
+                    .collect(Collectors.toList());
+
     @Before
     public void setUp() throws Exception {
         mTmpDir = FileUtil.createTempDir("business-logic-unit-tests");
         mMockDevice = Mockito.mock(ITestDevice.class);
         mMockBuildInfo = new BuildInfo();
-        mPreparer = new BusinessLogicPreparer() {
-            @Override
-            List<String> getSuiteNames() {
-                return Collections.singletonList("cts");
-            }
-        };
+        mPreparer =
+                new BusinessLogicPreparer() {
+                    @Override
+                    List<String> getSuiteNames() {
+                        return Collections.singletonList("cts");
+                    }
+                };
 
         OptionSetter setter = new OptionSetter(mPreparer);
         setter.setOptionValue("business-logic-url", serviceUrl);
@@ -152,6 +176,51 @@
     }
 
     @Test
+    public void testGetSuiteVersionExtractedDefaultNoChange() throws Exception {
+        // default case doesn't change original
+        for (String version : SUITE_VERSIONS_ALL) {
+            IBuildInfo buildInfo = new BuildInfo();
+            buildInfo.addBuildAttribute(CompatibilityBuildHelper.SUITE_VERSION, version);
+            assertEquals(
+                    version,
+                    buildInfo.getBuildAttributes().get(CompatibilityBuildHelper.SUITE_VERSION));
+            assertEquals(version, mPreparer.getSuiteVersionExtracted(buildInfo));
+        }
+    }
+
+    @Test
+    public void testGetSuiteVersionExtractedRemovePlatformPrefix() throws Exception {
+        final BusinessLogicPreparer modifiedPreparer = new BusinessLogicPreparer();
+        OptionCopier.copyOptions(mPreparer, modifiedPreparer);
+        OptionSetter setter = new OptionSetter(modifiedPreparer);
+        // apbs compares version but also prepends the suite version.
+        // extract '-r1' from '*_sts-r1' so that it becomes 'sts-r1' when comparing in BL.
+        setter.setOptionValue("suite-version-extraction-regex", ".+?_sts(?<version>.+)");
+        for (String version : SUITE_VERSIONS_STS) {
+            IBuildInfo buildInfo = new BuildInfo();
+            buildInfo.addBuildAttribute(CompatibilityBuildHelper.SUITE_VERSION, version);
+            assertEquals("-r1", modifiedPreparer.getSuiteVersionExtracted(buildInfo));
+        }
+    }
+
+    @Test
+    public void testGetSuiteVersionExtractedNonMatchingRegex() throws Exception {
+        final BusinessLogicPreparer modifiedPreparer = new BusinessLogicPreparer();
+        OptionCopier.copyOptions(mPreparer, modifiedPreparer);
+        OptionSetter setter = new OptionSetter(modifiedPreparer);
+        setter.setOptionValue("suite-version-extraction-regex", "not-matching-regex");
+        for (String version : SUITE_VERSIONS_ALL) {
+            IBuildInfo buildInfo = new BuildInfo();
+            buildInfo.addBuildAttribute(CompatibilityBuildHelper.SUITE_VERSION, version);
+            assertThrows(
+                    TargetSetupError.class,
+                    () -> {
+                        modifiedPreparer.getSuiteVersionExtracted(buildInfo);
+                    });
+        }
+    }
+
+    @Test
     public void testBuildRequestString_success() throws Exception {
         Map<String, String> attributes = new HashMap<>();
         // Create a memory device info JSON file for test.
@@ -210,14 +279,28 @@
         when(mMockDevice.getInstalledPackageNames()).thenReturn(mPackages);
         when(mMockDevice.getTotalMemory()).thenReturn(MEMORY_SIZE);
 
-        ArrayList<String> expectFeatures = new ArrayList<String>(
-            Arrays.asList(FEATURE_WATCH, FEATURE_LEANBACK));
-        ArrayList<String> expectProperties = new ArrayList<String>(
-            Arrays.asList("search_client_id", "client_id", RO_BRAND, RO_FIRST_API_LEVEL,
-                RO_MANIFACTURER, RO_MODEL, RO_NAME));
-        ArrayList<String> expectPropertyValues = new ArrayList<String>(
-            Arrays.asList("ms-android-google", "android-google", "BRAND_NAME", "26", "MANUFACTURER_NAME",
-                "fake_model", "fake_name"));
+        ArrayList<String> expectFeatures =
+                new ArrayList<String>(Arrays.asList(FEATURE_WATCH, FEATURE_LEANBACK));
+        ArrayList<String> expectProperties =
+                new ArrayList<String>(
+                        Arrays.asList(
+                                "search_client_id",
+                                "client_id",
+                                RO_BRAND,
+                                RO_FIRST_API_LEVEL,
+                                RO_MANIFACTURER,
+                                RO_MODEL,
+                                RO_NAME));
+        ArrayList<String> expectPropertyValues =
+                new ArrayList<String>(
+                        Arrays.asList(
+                                "ms-android-google",
+                                "android-google",
+                                "BRAND_NAME",
+                                "26",
+                                "MANUFACTURER_NAME",
+                                "fake_model",
+                                "fake_name"));
         ArrayList<String> expectPackages = new ArrayList<String>(pkgNameList);
         ArrayList<String> expectDeviceInfos = new ArrayList<String>(
             Arrays.asList("MemoryDeviceInfo%3Atotal_memory%3A1902936064",