Add system property to randomize R8 partial split

Change-Id: I6488ce8ac55ebc9f460b27b270dc628db5c6d8cd
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialCompilationConfiguration.java b/src/main/java/com/android/tools/r8/partial/R8PartialCompilationConfiguration.java
index 1bc3961..4061d34 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialCompilationConfiguration.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialCompilationConfiguration.java
@@ -28,6 +28,10 @@
       "com.android.tools.r8.experimentalPartialShrinkingIncludePatterns";
   public static final String EXCLUDE_PROPERTY_NAME =
       "com.android.tools.r8.experimentalPartialShrinkingExcludePatterns";
+  public static final String RANDOMIZE_PROPERTY_NAME =
+      "com.android.tools.r8.experimentalPartialShrinkingRandomize";
+  public static final String RANDOMIZE_SEED_PROPERTY_NAME =
+      "com.android.tools.r8.experimentalPartialShrinkingRandomizeSeed";
 
   private final boolean enabled;
   private final R8PartialPredicateCollection includePredicates;
@@ -47,7 +51,7 @@
       R8PartialPredicateCollection includePredicates,
       R8PartialPredicateCollection excludePredicates,
       Random randomizeForTesting) {
-    assert !enabled || !includePredicates.isEmpty();
+    assert !enabled || !includePredicates.isEmpty() || randomizeForTesting != null;
     assert !enabled || excludePredicates != null;
     this.enabled = enabled;
     this.includePredicates = includePredicates;
@@ -106,6 +110,18 @@
   }
 
   public static R8PartialCompilationConfiguration fromSystemProperties() {
+    return fromSystemProperties(true);
+  }
+
+  public static R8PartialCompilationConfiguration fromSystemProperties(boolean printSeed) {
+    if (System.getProperty(RANDOMIZE_PROPERTY_NAME) != null) {
+      if (System.getProperty(RANDOMIZE_SEED_PROPERTY_NAME) != null) {
+        long seed = Long.parseLong(System.getProperty(RANDOMIZE_SEED_PROPERTY_NAME));
+        return builder().randomizeForTesting(printSeed, seed).build();
+      } else {
+        return builder().randomizeForTesting(printSeed).build();
+      }
+    }
     return fromIncludeExcludePatterns(
         System.getProperty(INCLUDE_PROPERTY_NAME), System.getProperty(EXCLUDE_PROPERTY_NAME));
   }
@@ -133,7 +149,10 @@
 
     public R8PartialCompilationConfiguration build() {
       return new R8PartialCompilationConfiguration(
-          !includePredicates.isEmpty(), includePredicates, excludePredicates, randomizeForTesting);
+          !includePredicates.isEmpty() || randomizeForTesting != null,
+          includePredicates,
+          excludePredicates,
+          randomizeForTesting);
     }
 
     public Builder includeAll() {
@@ -146,19 +165,21 @@
       return this;
     }
 
-    public Builder randomizeForTesting() {
-      return randomizeForTesting(System.currentTimeMillis());
+    public Builder randomizeForTesting(boolean printSeed) {
+      return randomizeForTesting(printSeed, System.currentTimeMillis());
     }
 
-    public Builder randomizeForTesting(long seed) {
+    public Builder randomizeForTesting(boolean printSeed, long seed) {
       randomizeForTesting = new Random();
       randomizeForTesting.setSeed(seed);
-      System.out.println(
-          "Partial compilation seed: "
-              + seed
-              + ". Use .setPartialCompilationSeed(parameters, "
-              + seed
-              + "L) to reproduce.");
+      if (printSeed) {
+        System.out.println(
+            "Partial compilation seed: "
+                + seed
+                + ". Use .setPartialCompilationSeed(parameters, "
+                + seed
+                + "L) to reproduce.");
+      }
       return this;
     }
 
diff --git a/src/test/java/com/android/tools/r8/partial/PartialCompilationSystemPropertyTest.java b/src/test/java/com/android/tools/r8/partial/PartialCompilationSystemPropertyTest.java
index 1e5c8cc..5b3c87c 100644
--- a/src/test/java/com/android/tools/r8/partial/PartialCompilationSystemPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/partial/PartialCompilationSystemPropertyTest.java
@@ -3,14 +3,22 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.partial;
 
+import static com.android.tools.r8.MarkerMatcher.assertMarkersMatch;
+import static com.android.tools.r8.MarkerMatcher.markerTool;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 
+import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.utils.ExtractMarkerUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import java.util.Collection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -30,23 +38,73 @@
 
   @Test
   public void test() throws Exception {
-    System.setProperty(
-        R8PartialCompilationConfiguration.INCLUDE_PROPERTY_NAME, IncludedMain.class.getTypeName());
-    testForR8(Backend.DEX)
-        .addInnerClasses(getClass())
-        .addKeepMainRule(IncludedMain.class)
-        .setMinApi(apiLevelWithNativeMultiDexSupport())
-        .compile()
-        .inspect(
-            inspector -> {
-              ClassSubject includedClass = inspector.clazz(IncludedMain.class);
-              assertThat(includedClass, isPresent());
-              assertThat(includedClass.uniqueMethodWithOriginalName("test"), isAbsent());
+    try {
+      System.setProperty(
+          R8PartialCompilationConfiguration.INCLUDE_PROPERTY_NAME,
+          IncludedMain.class.getTypeName());
+      testForR8(Backend.DEX)
+          .addInnerClasses(getClass())
+          .addKeepMainRule(IncludedMain.class)
+          .setMinApi(apiLevelWithNativeMultiDexSupport())
+          .compile()
+          .inspect(
+              inspector -> {
+                ClassSubject includedClass = inspector.clazz(IncludedMain.class);
+                assertThat(includedClass, isPresent());
+                assertThat(includedClass.uniqueMethodWithOriginalName("test"), isAbsent());
 
-              ClassSubject excludedClass = inspector.clazz(ExcludedMain.class);
-              assertThat(excludedClass, isPresent());
-              assertThat(excludedClass.uniqueMethodWithOriginalName("test"), isPresent());
-            });
+                ClassSubject excludedClass = inspector.clazz(ExcludedMain.class);
+                assertThat(excludedClass, isPresent());
+                assertThat(excludedClass.uniqueMethodWithOriginalName("test"), isPresent());
+              });
+    } finally {
+      System.clearProperty(R8PartialCompilationConfiguration.INCLUDE_PROPERTY_NAME);
+    }
+  }
+
+  @Test
+  public void testRandomize() throws Exception {
+    try {
+      System.setProperty(R8PartialCompilationConfiguration.RANDOMIZE_PROPERTY_NAME, "1");
+      R8TestCompileResult compileResult =
+          testForR8(Backend.DEX)
+              .addInnerClasses(getClass())
+              .addKeepMainRule(IncludedMain.class)
+              .allowUnusedProguardConfigurationRules()
+              .collectStdout()
+              .setMinApi(apiLevelWithNativeMultiDexSupport())
+              .compile()
+              .assertStdoutThatMatches(containsString("Partial compilation seed:"));
+
+      Collection<Marker> markers =
+          ExtractMarkerUtils.extractMarkersFromFile(compileResult.writeToZip());
+      assertMarkersMatch(markers, markerTool(Tool.R8Partial));
+    } finally {
+      System.clearProperty(R8PartialCompilationConfiguration.RANDOMIZE_PROPERTY_NAME);
+    }
+  }
+
+  @Test
+  public void randomizeWithSeed() throws Exception {
+    try {
+      System.setProperty(R8PartialCompilationConfiguration.RANDOMIZE_PROPERTY_NAME, "1");
+      System.setProperty(R8PartialCompilationConfiguration.RANDOMIZE_SEED_PROPERTY_NAME, "42");
+      R8TestCompileResult compileResult =
+          testForR8(Backend.DEX)
+              .addInnerClasses(getClass())
+              .addKeepMainRule(IncludedMain.class)
+              .allowUnusedProguardConfigurationRules()
+              .collectStdout()
+              .setMinApi(apiLevelWithNativeMultiDexSupport())
+              .compile()
+              .assertStdoutThatMatches(containsString("Partial compilation seed: 42."));
+
+      Collection<Marker> markers =
+          ExtractMarkerUtils.extractMarkersFromFile(compileResult.writeToZip());
+      assertMarkersMatch(markers, markerTool(Tool.R8Partial));
+    } finally {
+      System.clearProperty(R8PartialCompilationConfiguration.RANDOMIZE_PROPERTY_NAME);
+    }
   }
 
   static class IncludedMain {
diff --git a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
index 3393d2c..8e21496 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
@@ -265,7 +265,7 @@
   public R8PartialTestBuilder setPartialCompilationSeed(TestParameters parameters, long seed) {
     if (parameters.getPartialCompilationTestParameters().isRandom()) {
       r8PartialConfiguration =
-          R8PartialCompilationConfiguration.builder().randomizeForTesting(seed).build();
+          R8PartialCompilationConfiguration.builder().randomizeForTesting(true, seed).build();
     }
     return this;
   }
diff --git a/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java b/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java
index 67c4a92..cd0be24 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java
@@ -234,6 +234,10 @@
       if (configuration != null && configuration.isRandomizeForTestingEnabled()) {
         return false;
       }
+    } else if (isR8TestBuilder()
+        && R8PartialCompilationConfiguration.fromSystemProperties(false)
+            .isRandomizeForTestingEnabled()) {
+      return false;
     }
     return true;
   }
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBase.java b/src/test/testbase/java/com/android/tools/r8/TestBase.java
index 6af16c9..e0bdbb1 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBase.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBase.java
@@ -258,7 +258,7 @@
                 builder.includeAll();
               } else {
                 assert parameters.isRandom();
-                builder.randomizeForTesting();
+                builder.randomizeForTesting(true);
               }
             })
         .applyIf(parameters.isRandom(), R8PartialTestBuilder::allowUnusedDontWarnPatterns);