*~
*.pyc
*.user
+*.class
.*
!.gitignore
!.editorconfig
--- /dev/null
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.drawelements.deqp.runner;
+
+/**
+ * Test configuration of dEPQ test instance execution.
+ */
+public class BatchRunConfiguration {
+ public static final String ROTATION_UNSPECIFIED = "unspecified";
+ public static final String ROTATION_PORTRAIT = "0";
+ public static final String ROTATION_LANDSCAPE = "90";
+ public static final String ROTATION_REVERSE_PORTRAIT = "180";
+ public static final String ROTATION_REVERSE_LANDSCAPE = "270";
+
+ private final String mGlConfig;
+ private final String mRotation;
+ private final String mSurfaceType;
+ private final boolean mRequired;
+
+ public BatchRunConfiguration(String glConfig, String rotation, String surfaceType,
+ boolean required) {
+ mGlConfig = glConfig;
+ mRotation = rotation;
+ mSurfaceType = surfaceType;
+ mRequired = required;
+ }
+
+ /**
+ * Get string that uniquely identifies this config
+ */
+ public String getId() {
+ return String.format("{glformat=%s,rotation=%s,surfacetype=%s,required=%b}",
+ mGlConfig, mRotation, mSurfaceType, mRequired);
+ }
+
+ /**
+ * Get the GL config used in this configuration.
+ */
+ public String getGlConfig() {
+ return mGlConfig;
+ }
+
+ /**
+ * Get the screen rotation used in this configuration.
+ */
+ public String getRotation() {
+ return mRotation;
+ }
+
+ /**
+ * Get the surface type used in this configuration.
+ */
+ public String getSurfaceType() {
+ return mSurfaceType;
+ }
+
+ /**
+ * Is this configuration mandatory to support, if target API is supported?
+ */
+ public boolean isRequired() {
+ return mRequired;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ } else if (!(other instanceof BatchRunConfiguration)) {
+ return false;
+ } else {
+ return getId().equals(((BatchRunConfiguration)other).getId());
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+}
import com.android.ddmlib.TimeoutException;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IDeviceTest;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IRuntimeHintProvider;
import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.testtype.IStrictShardableTest;
import com.android.tradefed.testtype.ITestCollector;
import com.android.tradefed.testtype.ITestFilterReceiver;
+import com.android.tradefed.testtype.StubTest;
import com.android.tradefed.util.AbiUtils;
import com.android.tradefed.util.IRunUtil;
import com.android.tradefed.util.RunInterruptedException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
-import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.regex.Pattern;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
/**
* Test runner for dEQP tests
@OptionClass(alias="deqp-test-runner")
public class DeqpTestRunner implements IBuildReceiver, IDeviceTest,
ITestFilterReceiver, IAbiReceiver, IShardableTest, ITestCollector,
- IRuntimeHintProvider {
+ IRuntimeHintProvider, IStrictShardableTest {
private static final String DEQP_ONDEVICE_APK = "com.drawelements.deqp.apk";
private static final String DEQP_ONDEVICE_PKG = "com.drawelements.deqp";
private static final String INCOMPLETE_LOG_MESSAGE = "Crash: Incomplete test log";
}
/**
- * Test configuration of dEPQ test instance execution.
- * Exposed for unit testing
- */
- public static final class BatchRunConfiguration {
- public static final String ROTATION_UNSPECIFIED = "unspecified";
- public static final String ROTATION_PORTRAIT = "0";
- public static final String ROTATION_LANDSCAPE = "90";
- public static final String ROTATION_REVERSE_PORTRAIT = "180";
- public static final String ROTATION_REVERSE_LANDSCAPE = "270";
-
- private final String mGlConfig;
- private final String mRotation;
- private final String mSurfaceType;
- private final boolean mRequired;
-
- public BatchRunConfiguration(String glConfig, String rotation, String surfaceType, boolean required) {
- mGlConfig = glConfig;
- mRotation = rotation;
- mSurfaceType = surfaceType;
- mRequired = required;
- }
-
- /**
- * Get string that uniquely identifies this config
- */
- public String getId() {
- return String.format("{glformat=%s,rotation=%s,surfacetype=%s,required=%b}",
- mGlConfig, mRotation, mSurfaceType, mRequired);
- }
-
- /**
- * Get the GL config used in this configuration.
- */
- public String getGlConfig() {
- return mGlConfig;
- }
-
- /**
- * Get the screen rotation used in this configuration.
- */
- public String getRotation() {
- return mRotation;
- }
-
- /**
- * Get the surface type used in this configuration.
- */
- public String getSurfaceType() {
- return mSurfaceType;
- }
-
- /**
- * Is this configuration mandatory to support, if target API is supported?
- */
- public boolean isRequired() {
- return mRequired;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == null) {
- return false;
- } else if (!(other instanceof BatchRunConfiguration)) {
- return false;
- } else {
- return getId().equals(((BatchRunConfiguration)other).getId());
- }
- }
-
- @Override
- public int hashCode() {
- return getId().hashCode();
- }
- }
-
- /**
* dEQP test instance listerer and invocation result forwarded
*/
private class TestInstanceResultListener {
}
private static class SleepProvider implements ISleepProvider {
+ @Override
public void sleep(int milliseconds) {
- try {
- Thread.sleep(milliseconds);
- } catch (InterruptedException ex) {
- }
+ RunUtil.getDefault().sleep(milliseconds);
}
}
/**
* Tries to recover device after abnormal execution termination or link failure.
*
- * @param progressedSinceLastCall true if test execution has progressed since last call
* @throws DeviceNotAvailableException if recovery did not succeed
*/
public void recoverComLinkKilled() throws DeviceNotAvailableException;
- };
+ }
/**
* State machine for execution failure recovery.
RECOVER, // recover by calling recover()
REBOOT, // recover by rebooting
FAIL, // cannot recover
- };
+ }
private MachineState mState = MachineState.WAIT;
private ITestDevice mDevice;
/**
* {@inheritDoc}
*/
+ @Override
public void setSleepProvider(ISleepProvider sleepProvider) {
mSleepProvider = sleepProvider;
}
case FAIL:
// Third failure in a row, just fail
CLog.w("Cannot recover ADB connection");
- throw new DeviceNotAvailableException("failed to connect after reboot");
+ throw new DeviceNotAvailableException("failed to connect after reboot",
+ mDevice.getSerialNumber());
}
}
case FAIL:
// Fourth failure in a row, just fail
CLog.w("Cannot recover ADB connection");
- throw new DeviceNotAvailableException("link killed after reboot");
+ throw new DeviceNotAvailableException("link killed after reboot",
+ mDevice.getSerialNumber());
}
}
}
private static Map<TestIdentifier, Set<BatchRunConfiguration>> generateTestInstances(
- Reader testlist, String configName, String screenRotation, String surfaceType, boolean required) throws FileNotFoundException {
+ Reader testlist, String configName, String screenRotation, String surfaceType,
+ boolean required) {
// Note: This is specifically a LinkedHashMap to guarantee that tests are iterated
// in the insertion order.
final Map<TestIdentifier, Set<BatchRunConfiguration>> instances = new LinkedHashMap<>();
return instances;
}
- private Set<BatchRunConfiguration> getTestRunConfigs (TestIdentifier testId) {
+ private Set<BatchRunConfiguration> getTestRunConfigs(TestIdentifier testId) {
return mTestInstances.get(testId);
}
/**
+ * Get the test instance of the runner. Exposed for testing.
+ */
+ Map<TestIdentifier, Set<BatchRunConfiguration>> getTestInstance() {
+ return mTestInstances;
+ }
+
+ /**
* Converts dEQP testcase path to TestIdentifier.
*/
private static TestIdentifier pathToIdentifier(String testPath) {
/**
* Get GL major version (based on package name)
*/
- private int getGlesMajorVersion() throws DeviceNotAvailableException {
+ private int getGlesMajorVersion() {
if ("dEQP-GLES2".equals(mDeqpPackage)) {
return 2;
} else if ("dEQP-GLES3".equals(mDeqpPackage)) {
/**
* Get GL minor version (based on package name)
*/
- private int getGlesMinorVersion() throws DeviceNotAvailableException {
+ private int getGlesMinorVersion() {
if ("dEQP-GLES2".equals(mDeqpPackage)) {
return 0;
} else if ("dEQP-GLES3".equals(mDeqpPackage)) {
List<Pattern> includePatterns = getPatternFilters(includeFilters);
List<Pattern> excludePatterns = getPatternFilters(excludeFilters);
- List<TestIdentifier> testList = new ArrayList(tests.keySet());
+ List<TestIdentifier> testList = new ArrayList<>(tests.keySet());
for (TestIdentifier test : testList) {
if (excludeStrings.contains(test.toString())) {
tests.remove(test); // remove test if explicitly excluded
}
/**
+ * Helper to update the RuntimeHint of the tests after being sharded.
+ */
+ private void updateRuntimeHint(long originalSize, Collection<IRemoteTest> runners) {
+ if (originalSize > 0) {
+ long fullRuntimeMs = getRuntimeHint();
+ for (IRemoteTest remote: runners) {
+ DeqpTestRunner runner = (DeqpTestRunner)remote;
+ long shardRuntime = (fullRuntimeMs * runner.mTestInstances.size()) / originalSize;
+ runner.mRuntimeHint = shardRuntime;
+ }
+ }
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
Map<TestIdentifier, Set<BatchRunConfiguration>> currentSet = new LinkedHashMap<>();
Map<TestIdentifier, Set<BatchRunConfiguration>> iterationSet = this.mTestInstances;
+ if (iterationSet.keySet().isEmpty()) {
+ CLog.i("Cannot split deqp tests, no tests to run");
+ return null;
+ }
+
// Go through tests, split
for (TestIdentifier test: iterationSet.keySet()) {
currentSet.put(test, iterationSet.get(test));
runners.add(new DeqpTestRunner(this, currentSet));
// NOTE: Use linked hash map to keep the insertion order in iteration
currentSet = new LinkedHashMap<>();
- }
+ }
}
runners.add(new DeqpTestRunner(this, currentSet));
// Compute new runtime hints
- long originalSize = iterationSet.size();
- if (originalSize > 0) {
- long fullRuntimeMs = getRuntimeHint();
- for (IRemoteTest remote: runners) {
- DeqpTestRunner runner = (DeqpTestRunner)remote;
- long shardRuntime = (fullRuntimeMs * runner.mTestInstances.size()) / originalSize;
- runner.mRuntimeHint = shardRuntime;
+ updateRuntimeHint(iterationSet.size(), runners);
+ CLog.i("Split deqp tests into %d shards", runners.size());
+ return runners;
+ }
+
+ /**
+ * This sharding should be deterministic for the same input and independent.
+ * Through this API, each shard could be executed on different machine.
+ */
+ @Override
+ public IRemoteTest getTestShard(int shardCount, int shardIndex) {
+ // TODO: refactor getTestshard and split to share some logic.
+ if (mTestInstances == null) {
+ loadTests();
+ }
+
+ List<IRemoteTest> runners = new ArrayList<>();
+ // NOTE: Use linked hash map to keep the insertion order in iteration
+ Map<TestIdentifier, Set<BatchRunConfiguration>> currentSet = new LinkedHashMap<>();
+ Map<TestIdentifier, Set<BatchRunConfiguration>> iterationSet = this.mTestInstances;
+
+ int batchLimit = iterationSet.keySet().size() / shardCount;
+ int i = 1;
+ // Go through tests, split
+ for (TestIdentifier test: iterationSet.keySet()) {
+ currentSet.put(test, iterationSet.get(test));
+ if (currentSet.size() >= batchLimit && i < shardCount) {
+ runners.add(new DeqpTestRunner(this, currentSet));
+ i++;
+ // NOTE: Use linked hash map to keep the insertion order in iteration
+ currentSet = new LinkedHashMap<>();
}
}
+ runners.add(new DeqpTestRunner(this, currentSet));
- CLog.i("Split deqp tests into %d shards", runners.size());
- return runners;
+ // Compute new runtime hints
+ updateRuntimeHint(iterationSet.size(), runners);
+
+ // If too many shards were requested, we complete with placeholder.
+ if (runners.size() < shardCount) {
+ for (int j = runners.size(); j < shardCount; j++) {
+ runners.add(new StubTest());
+ }
+ }
+
+ CLog.i("Split deqp tests into %d shards, return shard: %s", runners.size(), shardIndex);
+ return runners.get(shardIndex);
}
/**
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.IShellOutputReceiver;
-import com.android.ddmlib.ShellCommandUnresponsiveException;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.ConfigurationException;
import junit.framework.TestCase;
-import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.easymock.IMocksControl;
-
import java.io.File;
import java.io.FileNotFoundException;
import java.io.StringReader;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.easymock.IMocksControl;
+
/**
* Unit tests for {@link DeqpTestRunner}.
*/
DEFAULT_INSTANCE_ARGS.iterator().next().put("surfacetype", "window");
}
- private static class StubRecovery implements DeqpTestRunner.IRecovery {
- /**
- * {@inheritDoc}
- */
- @Override
- public void setSleepProvider(DeqpTestRunner.ISleepProvider sleepProvider) {
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setDevice(ITestDevice device) {
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onExecutionProgressed() {
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void recoverConnectionRefused() throws DeviceNotAvailableException {
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void recoverComLinkKilled() throws DeviceNotAvailableException {
- }
- };
-
public static class BuildHelperMock extends CompatibilityBuildHelper {
public BuildHelperMock(IFolderBuildInfo buildInfo) {
super(buildInfo);
String expectedTrie = "{dEQP-GLES3{pick_me{yes,ok,accepted}}}";
- Set<String> includes = new HashSet();
+ Set<String> includes = new HashSet<>();
includes.add("dEQP-GLES3.pick_me#*");
testFiltering(includes, null, allTests, expectedTrie, activeTests);
}
String expectedTrie = "{dEQP-GLES3{pick_me{yes,ok,accepted}}}";
- Set<String> excludes = new HashSet();
+ Set<String> excludes = new HashSet<>();
excludes.add("dEQP-GLES3.missing#*");
testFiltering(null, excludes, allTests, expectedTrie, activeTests);
}
String expectedTrie = "{dEQP-GLES3{group2{yes}}}";
- Set<String> includes = new HashSet();
+ Set<String> includes = new HashSet<>();
includes.add("dEQP-GLES3.group2#*");
- Set<String> excludes = new HashSet();
+ Set<String> excludes = new HashSet<>();
excludes.add("*foo");
excludes.add("*thoushallnotpass");
testFiltering(includes, excludes, allTests, expectedTrie, activeTests);
String expectedTrie = "{dEQP-GLES3{group1{mememe,yeah,takeitall},group2{jeba,yes,granted}}}";
- Set<String> includes = new HashSet();
+ Set<String> includes = new HashSet<>();
includes.add("*");
testFiltering(includes, null, allTests, expectedTrie, allTests);
String expectedTrie = "";
- Set<String> excludes = new HashSet();
+ Set<String> excludes = new HashSet<>();
excludes.add("*");
testFiltering(null, excludes, allTests, expectedTrie, new ArrayList<TestIdentifier>());
EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
.andReturn(Integer.toString(version)).atLeastOnce();
- if (!rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_UNSPECIFIED)) {
+ if (!rotation.equals(BatchRunConfiguration.ROTATION_UNSPECIFIED)) {
EasyMock.expect(mockDevice.executeShellCommand("pm list features"))
.andReturn(featureString);
}
final boolean isPortraitOrientation =
- rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_PORTRAIT) ||
- rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_REVERSE_PORTRAIT);
+ rotation.equals(BatchRunConfiguration.ROTATION_PORTRAIT) ||
+ rotation.equals(BatchRunConfiguration.ROTATION_REVERSE_PORTRAIT);
final boolean isLandscapeOrientation =
- rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_LANDSCAPE) ||
- rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_REVERSE_LANDSCAPE);
+ rotation.equals(BatchRunConfiguration.ROTATION_LANDSCAPE) ||
+ rotation.equals(BatchRunConfiguration.ROTATION_REVERSE_LANDSCAPE);
final boolean executable =
- rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_UNSPECIFIED) ||
+ rotation.equals(BatchRunConfiguration.ROTATION_UNSPECIFIED) ||
(isPortraitOrientation &&
featureString.contains(DeqpTestRunner.FEATURE_PORTRAIT)) ||
(isLandscapeOrientation &&
public void testRun_unsupportedPixelFormat() throws Exception {
final String pixelFormat = "rgba5658d16m4";
final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.pixelformat", "test");
- final String testPath = "dEQP-GLES3.pixelformat.test";
- final String testTrie = "{dEQP-GLES3{pixelformat{test}}}";
- final String output = "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=" + testPath + "\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_CODE: 0\r\n";
ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
ITestInvocationListener mockListener
PROGRESS,
FAIL_CONNECTION_REFUSED,
FAIL_LINK_KILLED,
- };
+ }
private void runRecoveryWithPattern(DeqpTestRunner.Recovery recovery, RecoveryEvent[] events)
throws DeviceNotAvailableException {
DeqpTestRunner.Recovery recovery = new DeqpTestRunner.Recovery();
IMocksControl orderedControl = EasyMock.createStrictControl();
RecoverableTestDevice mockDevice = orderedControl.createMock(RecoverableTestDevice.class);
+ EasyMock.expect(mockDevice.getSerialNumber()).andStubReturn("SERIAL");
DeqpTestRunner.ISleepProvider mockSleepProvider =
orderedControl.createMock(DeqpTestRunner.ISleepProvider.class);
public void testSharding_empty() throws Exception {
DeqpTestRunner runner = buildGlesTestRunner(3, 0, new ArrayList<TestIdentifier>());
ArrayList<IRemoteTest> shards = (ArrayList<IRemoteTest>)runner.split();
- // \todo [2015-11-23 kalle] What should the result be? The runner or nothing?
+ // Returns null when cannot be sharded.
+ assertNull(shards);
}
/**
((IRuntimeHintProvider)shards.get(1)).getRuntimeHint());
}
+ /**
+ * Test that strict shardable is able to split deterministically the set of tests.
+ */
+ public void testGetTestShard() throws Exception {
+ final int TEST_COUNT = 2237;
+ final int SHARD_COUNT = 4;
+
+ ArrayList<TestIdentifier> testIds = new ArrayList<>(TEST_COUNT);
+ for (int i = 0; i < TEST_COUNT; i++) {
+ testIds.add(new TestIdentifier("dEQP-GLES3.funny.group", String.valueOf(i)));
+ }
+
+ DeqpTestRunner deqpTest = buildGlesTestRunner(3, 0, testIds);
+ OptionSetter setter = new OptionSetter(deqpTest);
+ final long fullRuntimeMs = testIds.size()*100;
+ setter.setOptionValue("runtime-hint", String.valueOf(fullRuntimeMs));
+
+ DeqpTestRunner shard1 = (DeqpTestRunner)deqpTest.getTestShard(SHARD_COUNT, 0);
+ assertEquals(559, shard1.getTestInstance().size());
+ int j = 0;
+ // Ensure numbers, and that order is stable
+ for (TestIdentifier t : shard1.getTestInstance().keySet()) {
+ assertEquals(String.format("dEQP-GLES3.funny.group#%s", j),
+ String.format("%s#%s", t.getClassName(), t.getTestName()));
+ j++;
+ }
+ DeqpTestRunner shard2 = (DeqpTestRunner)deqpTest.getTestShard(SHARD_COUNT, 1);
+ assertEquals(559, shard2.getTestInstance().size());
+ for (TestIdentifier t : shard2.getTestInstance().keySet()) {
+ assertEquals(String.format("dEQP-GLES3.funny.group#%s", j),
+ String.format("%s#%s", t.getClassName(), t.getTestName()));
+ j++;
+ }
+ DeqpTestRunner shard3 = (DeqpTestRunner)deqpTest.getTestShard(SHARD_COUNT, 2);
+ assertEquals(559, shard3.getTestInstance().size());
+ for (TestIdentifier t : shard3.getTestInstance().keySet()) {
+ assertEquals(String.format("dEQP-GLES3.funny.group#%s", j),
+ String.format("%s#%s", t.getClassName(), t.getTestName()));
+ j++;
+ }
+ DeqpTestRunner shard4 = (DeqpTestRunner)deqpTest.getTestShard(SHARD_COUNT, 3);
+ assertEquals(560, shard4.getTestInstance().size());
+ for (TestIdentifier t : shard4.getTestInstance().keySet()) {
+ assertEquals(String.format("dEQP-GLES3.funny.group#%s", j),
+ String.format("%s#%s", t.getClassName(), t.getTestName()));
+ j++;
+ }
+ assertEquals(TEST_COUNT, j);
+ }
+
public void testRuntimeHint_optionNotSet() throws Exception {
final TestIdentifier[] testIds = {
new TestIdentifier("dEQP-GLES3.info", "vendor"),