From 5f483fe396e0bbd049520bc363bb9a5ec1640b89 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 14 Nov 2017 18:06:54 +0800 Subject: [PATCH 01/51] upgrade gradle and android plugin --- build.gradle | 4 ++-- fork-common-test-dex/build.gradle | 2 +- fork-runner/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 56b0aa62..33395674 100644 --- a/build.gradle +++ b/build.gradle @@ -9,13 +9,13 @@ */ task wrapper(type: Wrapper) { - gradleVersion = '4.1' + gradleVersion = '4.3' } ext.sourceCompatibility = JavaVersion.VERSION_1_8 ext.targetCompatibility = JavaVersion.VERSION_1_8 -ext.androidPlugin = '3.0.0-beta5' +ext.androidPlugin = '3.0.0' def repos = { mavenLocal() diff --git a/fork-common-test-dex/build.gradle b/fork-common-test-dex/build.gradle index 139c1c66..b852d7ab 100644 --- a/fork-common-test-dex/build.gradle +++ b/fork-common-test-dex/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath "com.android.tools.build:gradle:3.0.0-beta5" + classpath "com.android.tools.build:gradle:3.0.0" // NOTE: Do not place your application dependencies here; they belong diff --git a/fork-runner/build.gradle b/fork-runner/build.gradle index d05dc636..e41ebcde 100644 --- a/fork-runner/build.gradle +++ b/fork-runner/build.gradle @@ -19,7 +19,7 @@ targetCompatibility = rootProject.sourceCompatibility dependencies { compile project(':fork-common') - compile 'org.codehaus.groovy:groovy-all:2.4.11' + compile 'org.codehaus.groovy:groovy-all:2.4.12' compile( "com.beust:jcommander:$JCOMMANDER_VERSION", "org.slf4j:slf4j-log4j12:$SLF4J_VERSION", diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6e980fb9..5dafe5a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip From 2062c5288c7034b9277d6fac18eec9506049f09c Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 14 Nov 2017 18:25:20 +0800 Subject: [PATCH 02/51] use implementation and api instead of compile --- chimprunner/build.gradle | 2 +- fork-common/build.gradle | 22 +++++++++---------- .../build.gradle | 4 ++-- fork-reporter/build.gradle | 2 +- fork-runner/build.gradle | 20 ++++++++--------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/chimprunner/build.gradle b/chimprunner/build.gradle index dc039206..3c0ac71f 100644 --- a/chimprunner/build.gradle +++ b/chimprunner/build.gradle @@ -8,7 +8,7 @@ * 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. */ -apply plugin: 'java' +apply plugin: 'java-library' apply plugin: 'application' apply from: '../build-scripts/gradle-mvn-push.gradle' diff --git a/fork-common/build.gradle b/fork-common/build.gradle index a4899fd7..1e2a18af 100644 --- a/fork-common/build.gradle +++ b/fork-common/build.gradle @@ -8,7 +8,7 @@ * 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. */ -apply plugin: 'java' +apply plugin: 'java-library' apply from: '../build-scripts/gradle-mvn-push.gradle' //noinspection GroovyUnusedAssignment @@ -17,26 +17,26 @@ sourceCompatibility = rootProject.sourceCompatibility targetCompatibility = rootProject.sourceCompatibility dependencies { - compile project(':fork-client') - compile( - "com.google.code.findbugs:jsr305:3.0.1", + api project(':fork-client') + api "com.google.code.findbugs:jsr305:3.0.1" + api "com.android.tools.ddms:ddmlib:25.1.0" + api "commons-io:commons-io:2.5" + api "org.apache.commons:commons-lang3:3.4" + api "com.github.spullara.mustache.java:compiler:0.8.0" + api "com.google.code.gson:gson:$GSON_VERSION" + implementation( "com.google.guava:guava:19.0", - "com.android.tools.ddms:ddmlib:25.1.0", - "commons-io:commons-io:2.5", - "org.apache.commons:commons-lang3:3.4", - "com.github.spullara.mustache.java:compiler:0.8.0", - "com.google.code.gson:gson:$GSON_VERSION", "org.slf4j:slf4j-log4j12:$SLF4J_VERSION", "org.smali:dexlib:1.4.2", "com.shazam:axmlparser:1.0" ) - testCompile( + testImplementation( "org.hamcrest:hamcrest-all:$HAMCREST_VERSION", "org.jmock:jmock:$JMOCK_VERSION", "org.jmock:jmock-junit4:$JMOCK_VERSION", "com.shazam:shazamcrest:0.11") - testCompile("junit:junit:$JUNIT_VERSION") { + testImplementation("junit:junit:$JUNIT_VERSION") { exclude module:'hamcrest-core' } } diff --git a/fork-reporter-jenkins-gradle-plugin/build.gradle b/fork-reporter-jenkins-gradle-plugin/build.gradle index 88cccecd..8511692d 100644 --- a/fork-reporter-jenkins-gradle-plugin/build.gradle +++ b/fork-reporter-jenkins-gradle-plugin/build.gradle @@ -19,8 +19,8 @@ repositories { } dependencies { - compile project(':fork-reporter') - compile "com.offbytwo.jenkins:jenkins-client:0.3.4" + implementation project(':fork-reporter') + implementation "com.offbytwo.jenkins:jenkins-client:0.3.4" } jar { diff --git a/fork-reporter/build.gradle b/fork-reporter/build.gradle index 3cc7c8b4..0fc4ae2e 100644 --- a/fork-reporter/build.gradle +++ b/fork-reporter/build.gradle @@ -8,7 +8,7 @@ * 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. */ -apply plugin: 'java' +apply plugin: 'java-library' apply plugin: 'application' apply from: '../build-scripts/gradle-mvn-push.gradle' diff --git a/fork-runner/build.gradle b/fork-runner/build.gradle index e41ebcde..13c692d9 100644 --- a/fork-runner/build.gradle +++ b/fork-runner/build.gradle @@ -8,7 +8,7 @@ * 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. */ -apply plugin: 'java' +apply plugin: 'java-library' apply plugin: 'application' apply from: '../build-scripts/gradle-mvn-push.gradle' @@ -18,9 +18,9 @@ sourceCompatibility = rootProject.sourceCompatibility targetCompatibility = rootProject.sourceCompatibility dependencies { - compile project(':fork-common') - compile 'org.codehaus.groovy:groovy-all:2.4.12' - compile( + api project(':fork-common') + implementation 'org.codehaus.groovy:groovy-all:2.4.12' + implementation( "com.beust:jcommander:$JCOMMANDER_VERSION", "org.slf4j:slf4j-log4j12:$SLF4J_VERSION", "com.google.code.gson:gson:$GSON_VERSION", @@ -28,15 +28,15 @@ dependencies { 'com.madgag:animated-gif-lib:1.2', ) - compile('org.lesscss:lesscss:1.7.0.1.1') { + implementation('org.lesscss:lesscss:1.7.0.1.1') { exclude module: 'slf4j-simple' } - testCompile("org.hamcrest:hamcrest-all:$HAMCREST_VERSION") - testCompile("junit:junit:$JUNIT_VERSION") { - exclude module:'hamcrest-core' + testImplementation("org.hamcrest:hamcrest-all:$HAMCREST_VERSION") + testImplementation("junit:junit:$JUNIT_VERSION") { + exclude module: 'hamcrest-core' } - testCompile( + testImplementation( "org.jmock:jmock:$JMOCK_VERSION", "org.jmock:jmock-junit4:$JMOCK_VERSION") } @@ -56,7 +56,7 @@ jar { run { systemProperties System.getProperties() - if(project.hasProperty('args')) { + if (project.hasProperty('args')) { args project.args.split('\\s+') } } From 99d0f56c99eb69f08d815f82881340b66059a36e Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 14 Nov 2017 18:27:40 +0800 Subject: [PATCH 03/51] migrate chimprunner and fork-reporter --- chimprunner/build.gradle | 10 +++++----- fork-reporter/build.gradle | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/chimprunner/build.gradle b/chimprunner/build.gradle index 3c0ac71f..52644269 100644 --- a/chimprunner/build.gradle +++ b/chimprunner/build.gradle @@ -18,18 +18,18 @@ sourceCompatibility = rootProject.sourceCompatibility targetCompatibility = rootProject.sourceCompatibility dependencies { - compile project(':fork-common') - compile( + api project(':fork-common') + implementation( "org.slf4j:slf4j-log4j12:$SLF4J_VERSION", "com.beust:jcommander:$JCOMMANDER_VERSION", "au.com.bytecode:opencsv:2.4" ) - testCompile("org.hamcrest:hamcrest-all:$HAMCREST_VERSION") - testCompile("junit:junit:$JUNIT_VERSION") { + testImplementation("org.hamcrest:hamcrest-all:$HAMCREST_VERSION") + testImplementation("junit:junit:$JUNIT_VERSION") { exclude module:'hamcrest-core' } - testCompile( + testImplementation( "org.jmock:jmock:$JMOCK_VERSION", "org.jmock:jmock-junit4:$JMOCK_VERSION") } diff --git a/fork-reporter/build.gradle b/fork-reporter/build.gradle index 0fc4ae2e..2763dd36 100644 --- a/fork-reporter/build.gradle +++ b/fork-reporter/build.gradle @@ -18,8 +18,8 @@ sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 dependencies { - compile project(':fork-common') - compile( + api project(':fork-common') + implementation( "com.beust:jcommander:$JCOMMANDER_VERSION", "org.slf4j:slf4j-log4j12:$SLF4J_VERSION", "com.google.code.gson:gson:$GSON_VERSION", From d1fbe6b594a73cb6eee33ff4e6e99d9cd8fcc45c Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 16 Nov 2017 17:17:13 +0800 Subject: [PATCH 04/51] remove old implementation --- .../main/java/com/shazam/fork/runner/TestRun.java | 7 ------- .../java/com/shazam/fork/runner/TestRunFactory.java | 1 - .../com/shazam/fork/runner/TestRunParameters.java | 12 ------------ 3 files changed, 20 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.java b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.java index 850cfd08..abdbf4e7 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.java @@ -71,13 +71,6 @@ public void execute() { runner.setCoverage(true); runner.addInstrumentationArg("coverageFile", RemoteFileManager.getCoverageFileName(new TestIdentifier(testClassName, testMethodName))); } - String excludedAnnotation = testRunParameters.getExcludedAnnotation(); - if (!Strings.isNullOrEmpty(excludedAnnotation)) { - logger.info("Tests annotated with {} will be excluded", excludedAnnotation); - runner.addInstrumentationArg("notAnnotation", excludedAnnotation); - } else { - logger.info("No excluding any test based on annotations"); - } List permissionsToRevoke = testRunParameters.getTest().getPermissionsToRevoke(); diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java index a10fd1d6..ae6fba46 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java @@ -45,7 +45,6 @@ public TestRun createTestRun(TestCaseEvent testCase, .withTestSize(configuration.getTestSize()) .withTestOutputTimeout((int) configuration.getTestOutputTimeout()) .withCoverageEnabled(configuration.isCoverageEnabled()) - .withExcludedAnnotation(configuration.getExcludedAnnotation()) .build(); List testRunListeners = testRunListenersFactory.createTestListeners( diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunParameters.java b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunParameters.java index a3b6a70b..dbdcdfb2 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunParameters.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunParameters.java @@ -26,7 +26,6 @@ public class TestRunParameters { private final IRemoteAndroidTestRunner.TestSize testSize; private final int testOutputTimeout; private final IDevice deviceInterface; - private final String excludedAnnotation; private final String applicationPackage; public TestCaseEvent getTest() { @@ -58,10 +57,6 @@ public boolean isCoverageEnabled(){ return isCoverageEnabled; } - public String getExcludedAnnotation() { - return excludedAnnotation; - } - public String getApplicationPackage() { return applicationPackage; } @@ -74,7 +69,6 @@ public static class Builder { private IRemoteAndroidTestRunner.TestSize testSize; private IDevice deviceInterface; private int testOutputTimeout; - private String excludedAnnotation; private String applicationPackage; public static Builder testRunParameters() { @@ -116,11 +110,6 @@ public Builder withCoverageEnabled(boolean isCoverageEnabled){ return this; } - public Builder withExcludedAnnotation(String excludedAnnotation) { - this.excludedAnnotation = excludedAnnotation; - return this; - } - public Builder withApplicationPackage(String applicationPackage) { this.applicationPackage = applicationPackage; return this; @@ -139,7 +128,6 @@ private TestRunParameters(Builder builder) { testOutputTimeout = builder.testOutputTimeout; deviceInterface = builder.deviceInterface; isCoverageEnabled = builder.isCoverageEnabled; - this.excludedAnnotation = builder.excludedAnnotation; this.applicationPackage = builder.applicationPackage; } } From 233e1d2f7b9969d4c822c64d6502c003b453e405 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 16 Nov 2017 17:20:56 +0800 Subject: [PATCH 05/51] add includedAnnotation to config and gradle plugin task --- .../groovy/com/shazam/fork/gradle/ForkRunTask.groovy | 3 +++ .../src/main/java/com/shazam/fork/Configuration.java | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy index 2857b2b4..e526b1ec 100644 --- a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy +++ b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy @@ -77,6 +77,8 @@ class ForkRunTask extends DefaultTask implements VerificationTask { String excludedAnnotation + String includedAnnotation + @TaskAction void runFork() { LOG.info("Run instrumentation tests $instrumentationApk for app $applicationApk") @@ -102,6 +104,7 @@ class ForkRunTask extends DefaultTask implements VerificationTask { .withPoolingStrategy(poolingStrategy) .withAutoGrantPermissions(autoGrantPermissions) .withExcludedAnnotation(excludedAnnotation) + .withIncludedAnnotation(includedAnnotation) .build(); boolean success = new Fork(configuration).run() diff --git a/fork-runner/src/main/java/com/shazam/fork/Configuration.java b/fork-runner/src/main/java/com/shazam/fork/Configuration.java index 175730e5..56d57c93 100644 --- a/fork-runner/src/main/java/com/shazam/fork/Configuration.java +++ b/fork-runner/src/main/java/com/shazam/fork/Configuration.java @@ -57,6 +57,7 @@ public class Configuration { private final PoolingStrategy poolingStrategy; private final boolean autoGrantPermissions; private final String excludedAnnotation; + private final String includedAnnotation; private ApplicationInfo applicationInfo; @@ -82,6 +83,7 @@ private Configuration(Builder builder) { poolingStrategy = builder.poolingStrategy; autoGrantPermissions = builder.autoGrantPermissions; this.excludedAnnotation = builder.excludedAnnotation; + this.includedAnnotation = builder.includedAnnotation; this.applicationInfo = builder.applicationInfo; } @@ -182,6 +184,10 @@ public String getExcludedAnnotation() { return excludedAnnotation; } + public String getIncludedAnnotation() { + return includedAnnotation; + } + public ApplicationInfo getApplicationInfo() { return applicationInfo; } @@ -208,6 +214,7 @@ public static class Builder { private PoolingStrategy poolingStrategy; private boolean autoGrantPermissions; private String excludedAnnotation; + private String includedAnnotation; private ApplicationInfo applicationInfo; public static Builder configuration() { @@ -304,6 +311,11 @@ public Builder withExcludedAnnotation(String excludedAnnotation) { return this; } + public Builder withIncludedAnnotation(String includedAnnotation) { + this.includedAnnotation = includedAnnotation; + return this; + } + public Configuration build() { checkNotNull(androidSdk, "SDK is required."); checkArgument(androidSdk.exists(), "SDK directory does not exist."); From 9ca635a2d119b9957cc8cb2528a63e41b60c0523 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 16 Nov 2017 17:23:30 +0800 Subject: [PATCH 06/51] add includedAnnotation and excludedAnnotation to TestSuiteLoader --- .../chimprunner/injector/suite/TestSuiteLoaderInjector.java | 2 +- .../main/java/com/shazam/fork/suite/TestSuiteLoader.java | 6 +++++- .../java/com/shazam/fork/suite/TestSuiteLoaderTest.java | 2 +- .../shazam/fork/injector/suite/TestSuiteLoaderInjector.java | 6 +++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java b/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java index 6a6e6a84..2c331f41 100644 --- a/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java +++ b/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java @@ -22,6 +22,6 @@ private TestSuiteLoaderInjector() { } public static TestSuiteLoader testSuiteLoader() { - return new TestSuiteLoader(configuration().getInstrumentationApk(), dexFileExtractor(), testClassMatcher()); + return new TestSuiteLoader(configuration().getInstrumentationApk(), dexFileExtractor(), testClassMatcher(), configuration().getIncludedAnnotation(), configuration().getExcludedAnnotation()); } } diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index 34a01db0..072fade4 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -38,7 +38,11 @@ public class TestSuiteLoader { private final DexFileExtractor dexFileExtractor; private final TestClassMatcher testClassMatcher; - public TestSuiteLoader(File instrumentationApkFile, DexFileExtractor dexFileExtractor, TestClassMatcher testClassMatcher) { + public TestSuiteLoader(File instrumentationApkFile, + DexFileExtractor dexFileExtractor, + TestClassMatcher testClassMatcher, + String includedAnnotation, + String excludedAnnotation) { this.instrumentationApkFile = instrumentationApkFile; this.dexFileExtractor = dexFileExtractor; this.testClassMatcher = testClassMatcher; diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java index 5f039f2c..cae6748b 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java @@ -82,7 +82,7 @@ private DexFile testDexFile() { @Before public void setUp() throws Exception { - testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher); + testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, configuration().getIncludedAnnotation(), configuration().getExcludedAnnotation()); } @SuppressWarnings("unchecked") diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java index 595da188..e13ec893 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java @@ -21,6 +21,10 @@ public class TestSuiteLoaderInjector { private TestSuiteLoaderInjector() {} public static TestSuiteLoader testSuiteLoader() { - return new TestSuiteLoader(configuration().getInstrumentationApk(), dexFileExtractor(), testClassMatcher()); + return new TestSuiteLoader(configuration().getInstrumentationApk(), + dexFileExtractor(), + testClassMatcher(), + configuration().getIncludedAnnotation(), + configuration().getExcludedAnnotation()); } } From f19bc06dbb1e2929916e37306b50b2dd483ad8f6 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 16 Nov 2017 17:32:24 +0800 Subject: [PATCH 07/51] implement convert from com.example.Test to Lcom/example/Test; --- .../java/com/shazam/fork/suite/TestSuiteLoader.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index 072fade4..1fe32809 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -10,6 +10,7 @@ package com.shazam.fork.suite; +import com.google.common.base.Strings; import com.shazam.fork.io.DexFileExtractor; import com.shazam.fork.model.TestCaseEvent; import org.jf.dexlib.*; @@ -37,6 +38,8 @@ public class TestSuiteLoader { private final File instrumentationApkFile; private final DexFileExtractor dexFileExtractor; private final TestClassMatcher testClassMatcher; + private final List includedAnnotations; + private final List excludedAnnotations; public TestSuiteLoader(File instrumentationApkFile, DexFileExtractor dexFileExtractor, @@ -46,6 +49,15 @@ public TestSuiteLoader(File instrumentationApkFile, this.instrumentationApkFile = instrumentationApkFile; this.dexFileExtractor = dexFileExtractor; this.testClassMatcher = testClassMatcher; + this.includedAnnotations = parseAnnotations(includedAnnotation); + this.excludedAnnotations = parseAnnotations(excludedAnnotation); + } + + private List parseAnnotations(String annotations) { + if (Strings.isNullOrEmpty(annotations)) return emptyList(); + return Arrays.stream(annotations.split(",")) + .map(s -> "L" + s.replace('.', '/').trim() + ';') + .collect(toList()); } public Collection loadTestSuite() throws NoTestCasesFoundException { From 7b1847e5bfe601c4580a9099f954c51ee0e3f295 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 16 Nov 2017 18:09:00 +0800 Subject: [PATCH 08/51] implement exclude/include on TestSuiteLoader level --- .../shazam/fork/suite/TestSuiteLoader.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index 1fe32809..2e3fc6a3 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -82,16 +82,30 @@ private List convertClassToTestCaseEvents(ClassDefItem classDefIt return emptyList(); } + if (isClassExcluded(classDefItem)) { + return emptyList(); + } + List testCaseEvents = new ArrayList<>(); for (AnnotationDirectoryItem.MethodAnnotation method : annotationDirectoryItem.getMethodAnnotations()) { stream(method.annotationSet.getAnnotations()) .filter(annotation -> TEST_ANNOTATION.equals(stringType(annotation))) + .filter(this::isMethodIncluded) .map(annotation -> convertToTestCaseEvent(classDefItem, annotationDirectoryItem, method)) .forEach(testCaseEvents::add); } return testCaseEvents; } + private boolean isClassExcluded(ClassDefItem classDefItem) { + AnnotationItem[] annotations = classDefItem.getAnnotations().getClassAnnotations().getAnnotations(); + return !included(annotations) || excluded(annotations); + } + + private boolean isMethodIncluded(AnnotationItem annotation) { + return included(annotation) && !excluded(annotation); + } + @Nonnull private TestCaseEvent convertToTestCaseEvent(ClassDefItem classDefItem, AnnotationDirectoryItem annotationDirectoryItem, @@ -169,6 +183,22 @@ private boolean isClassIgnored(AnnotationDirectoryItem annotationDirectoryItem) return containsAnnotation(IGNORE_ANNOTATION, classAnnotations.getAnnotations()); } + private boolean included(AnnotationItem... annotations) { + if (includedAnnotations.isEmpty()) { + return true; + } + return includedAnnotations.stream() + .anyMatch(included -> containsAnnotation(included, annotations)); + } + + private boolean excluded(AnnotationItem... annotations) { + if (excludedAnnotations.isEmpty()) { + return false; + } + return excludedAnnotations.stream() + .anyMatch(included -> containsAnnotation(included, annotations)); + } + private boolean containsAnnotation(String comparisonAnnotation, AnnotationItem... annotations) { return stream(annotations).anyMatch(annotation -> comparisonAnnotation.equals(stringType(annotation))); } From 65fa81b8bd9328d9fb3f9c062776feb66ad7ba1f Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 16 Nov 2017 18:16:46 +0800 Subject: [PATCH 09/51] fix compilation error --- .../chimprunner/injector/suite/TestSuiteLoaderInjector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java b/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java index 2c331f41..58b20ffb 100644 --- a/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java +++ b/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java @@ -22,6 +22,6 @@ private TestSuiteLoaderInjector() { } public static TestSuiteLoader testSuiteLoader() { - return new TestSuiteLoader(configuration().getInstrumentationApk(), dexFileExtractor(), testClassMatcher(), configuration().getIncludedAnnotation(), configuration().getExcludedAnnotation()); + return new TestSuiteLoader(configuration().getInstrumentationApk(), dexFileExtractor(), testClassMatcher(), "", ""); } } From 79b278bbba5ba744eff57833ac878972aa411d5d Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Fri, 17 Nov 2017 10:56:09 +0800 Subject: [PATCH 10/51] add common pool strategy --- .../java/com/shazam/fork/Configuration.java | 10 +++++---- .../java/com/shazam/fork/PoolingStrategy.java | 1 + .../fork/pooling/CommonDevicePoolLoader.java | 21 +++++++++++++++++++ .../com/shazam/fork/pooling/PoolLoader.java | 4 ++++ 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 fork-runner/src/main/java/com/shazam/fork/pooling/CommonDevicePoolLoader.java diff --git a/fork-runner/src/main/java/com/shazam/fork/Configuration.java b/fork-runner/src/main/java/com/shazam/fork/Configuration.java index 175730e5..d3afafdf 100644 --- a/fork-runner/src/main/java/com/shazam/fork/Configuration.java +++ b/fork-runner/src/main/java/com/shazam/fork/Configuration.java @@ -23,7 +23,9 @@ import java.io.File; import java.util.Collection; import java.util.Collections; +import java.util.Objects; import java.util.regex.Pattern; +import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -361,13 +363,13 @@ private PoolingStrategy validatePoolingStrategy(PoolingStrategy poolingStrategy) poolingStrategy = new PoolingStrategy(); poolingStrategy.eachDevice = true; } else { - long selectedStrategies = asList( + long selectedStrategies = Stream.of( poolingStrategy.eachDevice, poolingStrategy.splitTablets, poolingStrategy.computed, - poolingStrategy.manual) - .stream() - .filter(p -> p != null) + poolingStrategy.manual, + poolingStrategy.common) + .filter(Objects::nonNull) .count(); if (selectedStrategies > Defaults.STRATEGY_LIMIT) { throw new IllegalArgumentException("You have selected more than one strategies in configuration. " + diff --git a/fork-runner/src/main/java/com/shazam/fork/PoolingStrategy.java b/fork-runner/src/main/java/com/shazam/fork/PoolingStrategy.java index 39af923b..b5f9624b 100644 --- a/fork-runner/src/main/java/com/shazam/fork/PoolingStrategy.java +++ b/fork-runner/src/main/java/com/shazam/fork/PoolingStrategy.java @@ -14,6 +14,7 @@ public class PoolingStrategy { public Boolean splitTablets; public Boolean eachDevice; + public Boolean common; public ComputedPooling computed; public ManualPooling manual; diff --git a/fork-runner/src/main/java/com/shazam/fork/pooling/CommonDevicePoolLoader.java b/fork-runner/src/main/java/com/shazam/fork/pooling/CommonDevicePoolLoader.java new file mode 100644 index 00000000..46f4654f --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/pooling/CommonDevicePoolLoader.java @@ -0,0 +1,21 @@ +package com.shazam.fork.pooling; + +import com.shazam.fork.model.Device; +import com.shazam.fork.model.Devices; +import com.shazam.fork.model.Pool; + +import java.util.Collection; +import java.util.Collections; + +import static com.shazam.fork.model.Pool.Builder.aDevicePool; + +public class CommonDevicePoolLoader implements DevicePoolLoader { + @Override + public Collection loadPools(Devices devices) { + Pool.Builder pool = aDevicePool().withName("common"); + for (Device device : devices.getDevices()) { + pool.addDevice(device); + } + return Collections.singleton(pool.build()); + } +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java b/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java index f13be430..58aaeedf 100644 --- a/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java +++ b/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java @@ -81,6 +81,10 @@ private DevicePoolLoader pickPoolLoader(Configuration configuration) throws NoPo return new EveryoneGetsAPoolLoader(); } + if(poolingStrategy.common != null && poolingStrategy.common){ + return new CommonDevicePoolLoader(); + } + throw new NoPoolLoaderConfiguredException("Could not determine which how to load pools to use based on your configuration"); } } From 737b8f67f72d84574eadcb879284de1105f38aea Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Fri, 17 Nov 2017 18:23:08 +0800 Subject: [PATCH 11/51] implement exclude/include annotations at TestSuiteLoader --- .../shazam/fork/suite/TestSuiteLoader.java | 54 ++++++++++++------- .../fork/suite/TestSuiteLoaderTest.java | 2 +- .../com/shazam/fork/gradle/ForkPlugin.groovy | 1 + .../main/java/com/shazam/fork/ForkCli.java | 1 + .../com/shazam/fork/ForkConfiguration.java | 5 ++ 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index 2e3fc6a3..b98c8bc6 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -18,10 +18,14 @@ import org.jf.dexlib.EncodedValue.ArrayEncodedValue; import org.jf.dexlib.EncodedValue.EncodedValue; import org.jf.dexlib.EncodedValue.StringEncodedValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import java.io.File; import java.util.*; +import java.util.function.Function; +import java.util.stream.Stream; import static com.shazam.fork.model.TestCaseEvent.newTestCase; import static java.lang.Math.min; @@ -41,6 +45,8 @@ public class TestSuiteLoader { private final List includedAnnotations; private final List excludedAnnotations; + Logger logger = LoggerFactory.getLogger(TestSuiteLoader.class); + public TestSuiteLoader(File instrumentationApkFile, DexFileExtractor dexFileExtractor, TestClassMatcher testClassMatcher, @@ -71,39 +77,50 @@ public Collection loadTestSuite() throws NoTestCasesFoundExceptio if (testCaseEvents.isEmpty()) { throw new NoTestCasesFoundException("No tests cases were found in the test APK: " + instrumentationApkFile.getAbsolutePath()); + } else { + logger.info("testCaseEvents.size = " + testCaseEvents.size()); } return testCaseEvents; } @Nonnull private List convertClassToTestCaseEvents(ClassDefItem classDefItem) { - AnnotationDirectoryItem annotationDirectoryItem = classDefItem.getAnnotations(); - if (annotationDirectoryItem == null) { + AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations(); + if (annotationDirectory == null) { return emptyList(); } - - if (isClassExcluded(classDefItem)) { + AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations(); + if (annotationSet == null) { return emptyList(); } - - List testCaseEvents = new ArrayList<>(); - for (AnnotationDirectoryItem.MethodAnnotation method : annotationDirectoryItem.getMethodAnnotations()) { - stream(method.annotationSet.getAnnotations()) - .filter(annotation -> TEST_ANNOTATION.equals(stringType(annotation))) - .filter(this::isMethodIncluded) - .map(annotation -> convertToTestCaseEvent(classDefItem, annotationDirectoryItem, method)) - .forEach(testCaseEvents::add); + AnnotationItem[] annotations = annotationSet.getAnnotations(); + if (isClassExcluded(annotations)) { + return emptyList(); } - return testCaseEvents; + + return parseMethods(classDefItem, annotationDirectory); } - private boolean isClassExcluded(ClassDefItem classDefItem) { - AnnotationItem[] annotations = classDefItem.getAnnotations().getClassAnnotations().getAnnotations(); + private List parseMethods(ClassDefItem classDefItem, AnnotationDirectoryItem annotationDirectory) { + return annotationDirectory.getMethodAnnotations() + .stream() + .flatMap(method -> parseTestCaseEvents(classDefItem, annotationDirectory, method)) + .collect(toList()); + } + + private Stream parseTestCaseEvents(ClassDefItem classDefItem, AnnotationDirectoryItem annotationDirectoryItem, AnnotationDirectoryItem.MethodAnnotation methodAnnotation) { + return stream(methodAnnotation.annotationSet.getAnnotations()) + .filter(annotation -> TEST_ANNOTATION.equals(stringType(annotation))) + .filter(this::isMethodIncluded) + .map(annotation -> convertToTestCaseEvent(classDefItem, annotationDirectoryItem, methodAnnotation)); + } + + private boolean isClassExcluded(AnnotationItem... annotations) { return !included(annotations) || excluded(annotations); } - private boolean isMethodIncluded(AnnotationItem annotation) { - return included(annotation) && !excluded(annotation); + private boolean isMethodIncluded(AnnotationItem... annotations) { + return !excluded(annotations); } @Nonnull @@ -183,6 +200,7 @@ private boolean isClassIgnored(AnnotationDirectoryItem annotationDirectoryItem) return containsAnnotation(IGNORE_ANNOTATION, classAnnotations.getAnnotations()); } + private boolean included(AnnotationItem... annotations) { if (includedAnnotations.isEmpty()) { return true; @@ -196,7 +214,7 @@ private boolean excluded(AnnotationItem... annotations) { return false; } return excludedAnnotations.stream() - .anyMatch(included -> containsAnnotation(included, annotations)); + .anyMatch(excluded -> containsAnnotation(excluded, annotations)); } private boolean containsAnnotation(String comparisonAnnotation, AnnotationItem... annotations) { diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java index cae6748b..f1063694 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java @@ -82,7 +82,7 @@ private DexFile testDexFile() { @Before public void setUp() throws Exception { - testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, configuration().getIncludedAnnotation(), configuration().getExcludedAnnotation()); + testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, "", ""); } @SuppressWarnings("unchecked") diff --git a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy index 4e33f620..56cd5b78 100644 --- a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy +++ b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy @@ -83,6 +83,7 @@ class ForkPlugin implements Plugin { autoGrantPermissions = config.autoGrantPermissions ignoreFailures = config.ignoreFailures excludedAnnotation = config.excludedAnnotation + includedAnnotation = config.includedAnnotation applicationApk = new File(baseVariantOutput.packageApplication.outputDirectory.path + "/" + baseVariantOutput.outputFileName) diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkCli.java b/fork-runner/src/main/java/com/shazam/fork/ForkCli.java index 7322434f..8e8e9ef3 100644 --- a/fork-runner/src/main/java/com/shazam/fork/ForkCli.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkCli.java @@ -100,6 +100,7 @@ public static void main(String... args) { .withPoolingStrategy(forkConfiguration.poolingStrategy) .withAutoGrantPermissions(forkConfiguration.autoGrantPermissions) .withExcludedAnnotation(forkConfiguration.excludedAnnotation) + .withIncludedAnnotation(forkConfiguration.includedAnnotation) .build(); Fork fork = new Fork(configuration); diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java b/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java index 5673227d..b93eb2e2 100644 --- a/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java @@ -99,6 +99,11 @@ public class ForkConfiguration { */ public String excludedAnnotation; + /** + * Filter test run to tests without given annotation + */ + public String includedAnnotation; + public void poolingStrategy(Closure poolingStrategyClosure) { poolingStrategy = new PoolingStrategy(); poolingStrategyClosure.setDelegate(poolingStrategy); From 3179a55161f0fc57ad2e9877fe7210a34254c527 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Fri, 17 Nov 2017 18:27:42 +0800 Subject: [PATCH 12/51] remove logger --- .../main/java/com/shazam/fork/suite/TestSuiteLoader.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index b98c8bc6..eecbf59a 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -18,13 +18,10 @@ import org.jf.dexlib.EncodedValue.ArrayEncodedValue; import org.jf.dexlib.EncodedValue.EncodedValue; import org.jf.dexlib.EncodedValue.StringEncodedValue; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import java.io.File; import java.util.*; -import java.util.function.Function; import java.util.stream.Stream; import static com.shazam.fork.model.TestCaseEvent.newTestCase; @@ -45,8 +42,6 @@ public class TestSuiteLoader { private final List includedAnnotations; private final List excludedAnnotations; - Logger logger = LoggerFactory.getLogger(TestSuiteLoader.class); - public TestSuiteLoader(File instrumentationApkFile, DexFileExtractor dexFileExtractor, TestClassMatcher testClassMatcher, @@ -77,8 +72,6 @@ public Collection loadTestSuite() throws NoTestCasesFoundExceptio if (testCaseEvents.isEmpty()) { throw new NoTestCasesFoundException("No tests cases were found in the test APK: " + instrumentationApkFile.getAbsolutePath()); - } else { - logger.info("testCaseEvents.size = " + testCaseEvents.size()); } return testCaseEvents; } From cac59d995acda384c7344212fa9921901433bd7d Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Fri, 17 Nov 2017 21:37:47 +0800 Subject: [PATCH 13/51] refactoring of TestSuiteLoader. add tests for parseAnnotation function --- .../shazam/fork/suite/AnnotationParser.java | 23 +++++++++++ .../shazam/fork/suite/TestSuiteLoader.java | 12 ++---- .../fork/suite/AnnotationParserTest.java | 39 +++++++++++++++++++ 3 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 fork-common/src/main/java/com/shazam/fork/suite/AnnotationParser.java create mode 100644 fork-common/src/test/java/com/shazam/fork/suite/AnnotationParserTest.java diff --git a/fork-common/src/main/java/com/shazam/fork/suite/AnnotationParser.java b/fork-common/src/main/java/com/shazam/fork/suite/AnnotationParser.java new file mode 100644 index 00000000..b8cd6927 --- /dev/null +++ b/fork-common/src/main/java/com/shazam/fork/suite/AnnotationParser.java @@ -0,0 +1,23 @@ +package com.shazam.fork.suite; + +import com.google.common.base.Strings; + +import javax.annotation.Nonnull; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.toList; + +public class AnnotationParser { + @Nonnull + public static Function> parseAnnotation() { + return annotations -> { + if (Strings.isNullOrEmpty(annotations)) return emptyList(); + return Arrays.stream(annotations.split(",")) + .map(c -> "L" + c.replace('.', '/').trim() + ';') + .collect(toList()); + }; + } +} diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index eecbf59a..b45bc875 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -25,6 +25,7 @@ import java.util.stream.Stream; import static com.shazam.fork.model.TestCaseEvent.newTestCase; +import static com.shazam.fork.suite.AnnotationParser.parseAnnotation; import static java.lang.Math.min; import static java.util.Arrays.stream; import static java.util.Collections.emptyList; @@ -50,15 +51,8 @@ public TestSuiteLoader(File instrumentationApkFile, this.instrumentationApkFile = instrumentationApkFile; this.dexFileExtractor = dexFileExtractor; this.testClassMatcher = testClassMatcher; - this.includedAnnotations = parseAnnotations(includedAnnotation); - this.excludedAnnotations = parseAnnotations(excludedAnnotation); - } - - private List parseAnnotations(String annotations) { - if (Strings.isNullOrEmpty(annotations)) return emptyList(); - return Arrays.stream(annotations.split(",")) - .map(s -> "L" + s.replace('.', '/').trim() + ';') - .collect(toList()); + this.includedAnnotations = parseAnnotation().apply(includedAnnotation); + this.excludedAnnotations = parseAnnotation().apply(excludedAnnotation); } public Collection loadTestSuite() throws NoTestCasesFoundException { diff --git a/fork-common/src/test/java/com/shazam/fork/suite/AnnotationParserTest.java b/fork-common/src/test/java/com/shazam/fork/suite/AnnotationParserTest.java new file mode 100644 index 00000000..31ce73f7 --- /dev/null +++ b/fork-common/src/test/java/com/shazam/fork/suite/AnnotationParserTest.java @@ -0,0 +1,39 @@ +package com.shazam.fork.suite; + +import org.junit.Test; + +import java.util.List; + +import static com.shazam.fork.suite.AnnotationParser.parseAnnotation; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; + +public class AnnotationParserTest { + + private static final String first = "com.test.Ignore"; + private static final String firstResult = "Lcom/test/Ignore;"; + private static final String second = "com.test.Test"; + private static final String secondResult = "Lcom/test/Test;"; + + @Test + public void testEmptyString() throws Exception { + assertThat(parseAnnotation().apply("").size(), is(0)); + } + + @Test + public void testOneAnnotation() throws Exception { + List annotations = parseAnnotation().apply(first); + assertThat(annotations.size(), is(1)); + assertThat(annotations.get(0), equalTo(firstResult)); + } + + @Test + public void testTwoAnnotations() throws Exception { + String combined = first + "," + second; + List annotations = parseAnnotation().apply(combined); + assertThat(annotations.size(), is(2)); + assertThat(annotations.get(0), equalTo(firstResult)); + assertThat(annotations.get(1), equalTo(secondResult)); + } +} From 8712a4c853630ed02a225cf6b78046291e3cc63a Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Sat, 18 Nov 2017 11:30:14 +0800 Subject: [PATCH 14/51] fix TestSuiteLoader bug --- .../java/com/shazam/fork/suite/TestSuiteLoader.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index b45bc875..b130e19e 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -76,13 +76,13 @@ private List convertClassToTestCaseEvents(ClassDefItem classDefIt if (annotationDirectory == null) { return emptyList(); } + AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations(); - if (annotationSet == null) { - return emptyList(); - } - AnnotationItem[] annotations = annotationSet.getAnnotations(); - if (isClassExcluded(annotations)) { - return emptyList(); + if (annotationSet != null) { + AnnotationItem[] annotations = annotationSet.getAnnotations(); + if (isClassExcluded(annotations)) { + return emptyList(); + } } return parseMethods(classDefItem, annotationDirectory); From a44944609f977e2c148e94d9aaa4552c9781d0d8 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Sat, 18 Nov 2017 16:28:36 +0800 Subject: [PATCH 15/51] fix TestSuiteLoader --- .../annotations/CustomTestAnnotation1.java | 13 ++++ .../annotations/CustomTestAnnotation2.java | 13 ++++ .../CustomTestAnnotation1ClassTest.java | 17 ++++++ .../CustomTestAnnotation2ClassTest.java | 17 ++++++ .../shazam/fork/suite/TestSuiteLoader.java | 34 ++++++----- .../suite/TestSuiteLoaderExcludeTest.java | 57 ++++++++++++++++++ .../suite/TestSuiteLoaderIncludedTest.java | 49 +++++++++++++++ .../fork/suite/TestSuiteLoaderTest.java | 17 +----- .../fork/suite/TestSuiteLoaderTestUtils.java | 30 +++++++++ .../test/java/com/shazam/fork/suite/tests.dex | Bin 653388 -> 668280 bytes fork-common/src/test/resources/app-debug.apk | Bin 37691 -> 35612 bytes fork-common/src/test/resources/tests.dex | Bin 655640 -> 668896 bytes 12 files changed, 219 insertions(+), 28 deletions(-) create mode 100644 fork-common-test-dex/app/src/androidTest/java/com/shazam/annotations/CustomTestAnnotation1.java create mode 100644 fork-common-test-dex/app/src/androidTest/java/com/shazam/annotations/CustomTestAnnotation2.java create mode 100644 fork-common-test-dex/app/src/androidTest/java/com/shazam/forktest/CustomTestAnnotation1ClassTest.java create mode 100644 fork-common-test-dex/app/src/androidTest/java/com/shazam/forktest/CustomTestAnnotation2ClassTest.java create mode 100644 fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java create mode 100644 fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java create mode 100644 fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java mode change 100644 => 100755 fork-common/src/test/java/com/shazam/fork/suite/tests.dex mode change 100644 => 100755 fork-common/src/test/resources/tests.dex diff --git a/fork-common-test-dex/app/src/androidTest/java/com/shazam/annotations/CustomTestAnnotation1.java b/fork-common-test-dex/app/src/androidTest/java/com/shazam/annotations/CustomTestAnnotation1.java new file mode 100644 index 00000000..862b4549 --- /dev/null +++ b/fork-common-test-dex/app/src/androidTest/java/com/shazam/annotations/CustomTestAnnotation1.java @@ -0,0 +1,13 @@ +package com.shazam.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Retention(RUNTIME) +@Target({TYPE, METHOD}) +public @interface CustomTestAnnotation1 { +} diff --git a/fork-common-test-dex/app/src/androidTest/java/com/shazam/annotations/CustomTestAnnotation2.java b/fork-common-test-dex/app/src/androidTest/java/com/shazam/annotations/CustomTestAnnotation2.java new file mode 100644 index 00000000..26f69a8b --- /dev/null +++ b/fork-common-test-dex/app/src/androidTest/java/com/shazam/annotations/CustomTestAnnotation2.java @@ -0,0 +1,13 @@ +package com.shazam.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Retention(RUNTIME) +@Target({TYPE, METHOD}) +public @interface CustomTestAnnotation2 { +} diff --git a/fork-common-test-dex/app/src/androidTest/java/com/shazam/forktest/CustomTestAnnotation1ClassTest.java b/fork-common-test-dex/app/src/androidTest/java/com/shazam/forktest/CustomTestAnnotation1ClassTest.java new file mode 100644 index 00000000..1724e8c8 --- /dev/null +++ b/fork-common-test-dex/app/src/androidTest/java/com/shazam/forktest/CustomTestAnnotation1ClassTest.java @@ -0,0 +1,17 @@ +package com.shazam.forktest; + +import org.junit.Ignore; +import org.junit.Test; +import com.shazam.annotations.CustomTestAnnotation1; + +import static org.junit.Assert.assertEquals; + +@CustomTestAnnotation1 +public class CustomTestAnnotation1ClassTest { + + @Test + public void methodOfAnCustomTestAnnotation1TestClass() { + assertEquals(4, 2 + 2); + } +} + diff --git a/fork-common-test-dex/app/src/androidTest/java/com/shazam/forktest/CustomTestAnnotation2ClassTest.java b/fork-common-test-dex/app/src/androidTest/java/com/shazam/forktest/CustomTestAnnotation2ClassTest.java new file mode 100644 index 00000000..2ee86b83 --- /dev/null +++ b/fork-common-test-dex/app/src/androidTest/java/com/shazam/forktest/CustomTestAnnotation2ClassTest.java @@ -0,0 +1,17 @@ +package com.shazam.forktest; + +import org.junit.Ignore; +import org.junit.Test; +import com.shazam.annotations.CustomTestAnnotation2; + +import static org.junit.Assert.assertEquals; + +@CustomTestAnnotation2 +public class CustomTestAnnotation2ClassTest { + + @Test + public void methodOfAnCustomTestAnnotation2TestClass() { + assertEquals(4, 2 + 2); + } +} + diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index b130e19e..46ccb988 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -72,42 +72,48 @@ public Collection loadTestSuite() throws NoTestCasesFoundExceptio @Nonnull private List convertClassToTestCaseEvents(ClassDefItem classDefItem) { - AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations(); - if (annotationDirectory == null) { + boolean classIncluded = false; + AnnotationDirectoryItem annotationDirectoryItem = classDefItem.getAnnotations(); + if (annotationDirectoryItem == null) { return emptyList(); } - AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations(); - if (annotationSet != null) { - AnnotationItem[] annotations = annotationSet.getAnnotations(); + AnnotationSetItem classSet = annotationDirectoryItem.getClassAnnotations(); + if (classSet != null) { + AnnotationItem[] annotations = classSet.getAnnotations(); if (isClassExcluded(annotations)) { return emptyList(); + } else { + classIncluded = true; } } - return parseMethods(classDefItem, annotationDirectory); + return parseMethods(classDefItem, annotationDirectoryItem, classIncluded); } - private List parseMethods(ClassDefItem classDefItem, AnnotationDirectoryItem annotationDirectory) { + private List parseMethods(ClassDefItem classDefItem, AnnotationDirectoryItem annotationDirectory, boolean classIncluded) { return annotationDirectory.getMethodAnnotations() .stream() - .flatMap(method -> parseTestCaseEvents(classDefItem, annotationDirectory, method)) + .flatMap(method -> parseTestCaseEvents(classDefItem, annotationDirectory, method, classIncluded)) .collect(toList()); } - private Stream parseTestCaseEvents(ClassDefItem classDefItem, AnnotationDirectoryItem annotationDirectoryItem, AnnotationDirectoryItem.MethodAnnotation methodAnnotation) { + private Stream parseTestCaseEvents(ClassDefItem classDefItem, + AnnotationDirectoryItem annotationDirectoryItem, + AnnotationDirectoryItem.MethodAnnotation methodAnnotation, + boolean classIncluded) { return stream(methodAnnotation.annotationSet.getAnnotations()) .filter(annotation -> TEST_ANNOTATION.equals(stringType(annotation))) - .filter(this::isMethodIncluded) + .filter(item -> isMethodIncluded(item, classIncluded)) .map(annotation -> convertToTestCaseEvent(classDefItem, annotationDirectoryItem, methodAnnotation)); } - private boolean isClassExcluded(AnnotationItem... annotations) { - return !included(annotations) || excluded(annotations); + private boolean isMethodIncluded(AnnotationItem a, boolean classIncluded) { + return classIncluded || included(a) && !excluded(a); } - private boolean isMethodIncluded(AnnotationItem... annotations) { - return !excluded(annotations); + private boolean isClassExcluded(AnnotationItem... annotations) { + return !included(annotations) || excluded(annotations); } @Nonnull diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java new file mode 100644 index 00000000..feebfbee --- /dev/null +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java @@ -0,0 +1,57 @@ + +package com.shazam.fork.suite; + +import com.shazam.fork.io.DexFileExtractor; +import com.shazam.fork.model.TestCaseEvent; +import org.hamcrest.Matcher; +import org.jf.dexlib.DexFile; +import org.junit.Before; +import org.junit.Test; + +import javax.annotation.Nonnull; +import java.io.File; +import java.net.URL; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.shazam.fork.io.FakeDexFileExtractor.fakeDexFileExtractor; +import static com.shazam.fork.io.Files.convertFileToDexFile; +import static com.shazam.fork.model.TestCaseEvent.newTestCase; +import static com.shazam.fork.suite.FakeTestClassMatcher.fakeTestClassMatcher; +import static com.shazam.fork.suite.TestSuiteLoaderTestUtils.sameTestEventAs; +import static com.shazam.shazamcrest.MatcherAssert.assertThat; +import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; +import static java.util.Arrays.asList; +import static java.util.Collections.*; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.not; + +public class TestSuiteLoaderExcludeTest { + private static final File ANY_INSTRUMENTATION_APK_FILE = null; + + private final DexFileExtractor fakeDexFileExtractor = fakeDexFileExtractor().thatReturns(testDexFile()); + private final TestClassMatcher fakeTestClassMatcher = fakeTestClassMatcher().thatAlwaysMatches(); + private TestSuiteLoader testSuiteLoader; + + private DexFile testDexFile() { + URL testDexResourceUrl = this.getClass().getResource("/tests.dex"); + String testDexFile = testDexResourceUrl.getFile(); + File file = new File(testDexFile); + return convertFileToDexFile().apply(file); + } + + @Before + public void setUp() throws Exception { + testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, "", "com.shazam.annotations.CustomTestAnnotation1"); + } + + @Test + public void testExcludeAnnotation() throws Exception { + Collection events = testSuiteLoader.loadTestSuite(); + assertThat(events, not(hasItem(sameTestEventAs("methodOfAnCustomTestAnnotation1TestClass", "com.shazam.forktest.CustomTestAnnotation1ClassTest", false)))); + assertThat(events, hasItem(sameTestEventAs("methodOfAnCustomTestAnnotation2TestClass", "com.shazam.forktest.CustomTestAnnotation2ClassTest", false))); + } +} diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java new file mode 100644 index 00000000..ca63a3e1 --- /dev/null +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java @@ -0,0 +1,49 @@ + +package com.shazam.fork.suite; + +import com.shazam.fork.io.DexFileExtractor; +import com.shazam.fork.model.TestCaseEvent; +import org.jf.dexlib.DexFile; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.net.URL; +import java.util.Collection; + +import static com.shazam.fork.io.FakeDexFileExtractor.fakeDexFileExtractor; +import static com.shazam.fork.io.Files.convertFileToDexFile; +import static com.shazam.fork.suite.FakeTestClassMatcher.fakeTestClassMatcher; +import static com.shazam.fork.suite.TestSuiteLoaderTestUtils.sameTestEventAs; +import static com.shazam.shazamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.core.Is.is; + +public class TestSuiteLoaderIncludedTest { + private static final File ANY_INSTRUMENTATION_APK_FILE = null; + + private final DexFileExtractor fakeDexFileExtractor = fakeDexFileExtractor().thatReturns(testDexFile()); + private final TestClassMatcher fakeTestClassMatcher = fakeTestClassMatcher().thatAlwaysMatches(); + private TestSuiteLoader testSuiteLoader; + + private DexFile testDexFile() { + URL testDexResourceUrl = this.getClass().getResource("/tests.dex"); + String testDexFile = testDexResourceUrl.getFile(); + File file = new File(testDexFile); + return convertFileToDexFile().apply(file); + } + + @Before + public void setUp() throws Exception { + testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, "com.shazam.annotations.CustomTestAnnotation2", ""); + } + + @Test + public void testIncludeAnnotation() throws Exception { + Collection events = testSuiteLoader.loadTestSuite(); + assertThat(events.size(),is(1)); + assertThat(events, not(hasItem(sameTestEventAs("methodOfAnCustomTestAnnotation1TestClass", "com.shazam.forktest.CustomTestAnnotation1ClassTest", false)))); + assertThat(events, hasItem(sameTestEventAs("methodOfAnCustomTestAnnotation2TestClass", "com.shazam.forktest.CustomTestAnnotation2ClassTest", false))); + } +} diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java index f1063694..4c8e1a55 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java @@ -28,6 +28,7 @@ import static com.shazam.fork.io.Files.convertFileToDexFile; import static com.shazam.fork.model.TestCaseEvent.newTestCase; import static com.shazam.fork.suite.FakeTestClassMatcher.fakeTestClassMatcher; +import static com.shazam.fork.suite.TestSuiteLoaderTestUtils.sameTestEventAs; import static com.shazam.shazamcrest.MatcherAssert.assertThat; import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; import static java.util.Arrays.asList; @@ -93,7 +94,8 @@ public void setsIgnoredFlag() throws Exception { sameTestEventAs("firstTestMethod", "com.shazam.forktest.ClassWithNoIgnoredMethodsTest", false), sameTestEventAs("secondTestMethod", "com.shazam.forktest.ClassWithNoIgnoredMethodsTest", false), sameTestEventAs("nonIgnoredTestMethod", "com.shazam.forktest.ClassWithSomeIgnoredMethodsTest", false), - sameTestEventAs("ignoredTestMethod", "com.shazam.forktest.ClassWithSomeIgnoredMethodsTest", true))); + sameTestEventAs("ignoredTestMethod", "com.shazam.forktest.ClassWithSomeIgnoredMethodsTest", true), + sameTestEventAs("methodOfAnCustomTestAnnotation1TestClass","com.shazam.forktest.CustomTestAnnotation1ClassTest",false))); } @SuppressWarnings("unchecked") @@ -123,18 +125,5 @@ public void populatesTestProperties() throws Exception { sameTestEventAs("methodWithUnmatchedKey", testClass, singlePropertyMap))); } - @Nonnull - private Matcher sameTestEventAs(String testMethod, String testClass, Map properties) { - return sameBeanAs(newTestCase(testMethod, testClass, false, emptyList(), properties)); - } - - @Nonnull - private Matcher sameTestEventAs(String testMethod, String testClass, boolean isIgnored) { - return sameBeanAs(newTestCase(testMethod, testClass, isIgnored, emptyList(), emptyMap())); - } - @Nonnull - private Matcher sameTestEventAs(String testMethod, String testClass, boolean isIgnored, List permissions) { - return sameBeanAs(newTestCase(testMethod, testClass, isIgnored, permissions, emptyMap())); - } } diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java new file mode 100644 index 00000000..61b1a43d --- /dev/null +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java @@ -0,0 +1,30 @@ +package com.shazam.fork.suite; + +import com.shazam.fork.model.TestCaseEvent; +import org.hamcrest.Matcher; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.Map; + +import static com.shazam.fork.model.TestCaseEvent.newTestCase; +import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; + +public class TestSuiteLoaderTestUtils { + @Nonnull + static Matcher sameTestEventAs(String testMethod, String testClass, Map properties) { + return sameBeanAs(newTestCase(testMethod, testClass, false, emptyList(), properties)); + } + + @Nonnull + static Matcher sameTestEventAs(String testMethod, String testClass, boolean isIgnored) { + return sameBeanAs(newTestCase(testMethod, testClass, isIgnored, emptyList(), emptyMap())); + } + + @Nonnull + static Matcher sameTestEventAs(String testMethod, String testClass, boolean isIgnored, List permissions) { + return sameBeanAs(newTestCase(testMethod, testClass, isIgnored, permissions, emptyMap())); + } +} diff --git a/fork-common/src/test/java/com/shazam/fork/suite/tests.dex b/fork-common/src/test/java/com/shazam/fork/suite/tests.dex old mode 100644 new mode 100755 index 1109363eba2046284bb214e0b3d0efb8fba0d59e..c64c6d2ccd0e05a3b4648db60bb2cd8620d89679 GIT binary patch literal 668280 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 UE&Sw>Jj$~YLkqH1;12Nr0PZZxqW}N^ literal 653388 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 z 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 diff --git a/fork-common/src/test/resources/app-debug.apk b/fork-common/src/test/resources/app-debug.apk index dc91a18a1cd5b336a91e503c32fa40b7faaad82c..7e514dac3c45713a5f2759ab5909798fb2cdf864 100644 GIT binary patch delta 26273 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 DV5`aj diff --git a/fork-common/src/test/resources/tests.dex b/fork-common/src/test/resources/tests.dex old mode 100644 new mode 100755 index a48209d62fa3d72492fa02e6c56fa6245acb26fe..e854c20c2539d411b1014007cf25b8b64e4e25b0 GIT binary patch literal 668896 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

o6QJnr3D**4$V8dBZ! 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%0D)jrv=Bh%UjdsfuUpc)-s=E!7wVLr>yowevTb%C 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 z0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%C zA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA z90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G? zz#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M z1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUN zL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;K zI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL( zfJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j z2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpj zhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-re za0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem z0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>6 z5O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI5 z4grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49` z;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B z0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%C zA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA z90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G? 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 z1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUN zL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;K zI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL( zfJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j z2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpj zhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-re za0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem z0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>6 z5O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI5 z4grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49` z;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B z0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%C zA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA z90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M1RMem0f&G? zz#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M z1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUN zL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;K zI0PI54grUNL%<>65O4@M1RMem0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL( 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 Date: Fri, 15 Dec 2017 10:42:58 +0800 Subject: [PATCH 16/51] [WIP] Execution chart + Sorting (#13) * add teamcity client * add fork sorting common module. add basic entities * add fork-sorting-teamcity module. this module incapsulate teamcity client and mapping * add Teamcity based sorting strategy * add dependencies between modules * add chart page * move history manager and testexecution reporter to stat package * return optional from test history manager * fix summary printer injector * cleanup properties * use long timestamp instead of string format * use timestamp instead of string * change format of report * rework loader * rename package * rework teamcity loader * remove test.yaml * temp solution * fix compile time errors * add testMetrics getter * remove dependency to fork-stat-teamcity from fork-runner * move teamcity client to fork-stat-teamcity * add queue provider * use TestCaseEventFactory instead of static factory methods * remove testHistoryManager * remove unused AuthConfig * removed unused function * fix chart * add info about idling * remove logs * fix comments * change tick format * experiment with PriorityBlockingQueue * fix codeformat --- .../model/TestCaseEventFactoryInjector.java | 11 + .../stat/StatServiceLoaderInjector.java | 15 + .../injector/stat/TestStatLoaderInjector.java | 13 + .../suite/TestSuiteLoaderInjector.java | 7 +- fork-common/build.gradle | 1 + .../com/shazam/fork/model/TestCaseEvent.java | 22 +- .../fork/model/TestCaseEventFactory.java | 31 ++ .../shazam/fork/stat/StatServiceLoader.java | 39 +++ .../com/shazam/fork/stat/TestStatsLoader.java | 56 +++ .../shazam/fork/suite/TestSuiteLoader.java | 13 +- .../suite/TestSuiteLoaderExcludeTest.java | 16 +- .../suite/TestSuiteLoaderIncludedTest.java | 7 +- .../fork/suite/TestSuiteLoaderTest.java | 34 +- .../fork/suite/TestSuiteLoaderTestUtils.java | 14 +- .../com/shazam/fork/gradle/ForkPlugin.groovy | 1 + .../com/shazam/fork/gradle/ForkRunTask.groovy | 4 + fork-runner/build.gradle | 1 + .../java/com/shazam/fork/Configuration.java | 21 ++ .../main/java/com/shazam/fork/ForkCli.java | 1 + .../com/shazam/fork/ForkConfiguration.java | 13 +- .../main/java/com/shazam/fork/ForkRunner.java | 24 +- .../java/com/shazam/fork/SortingStrategy.java | 16 + .../fork/injector/ForkRunnerInjector.java | 6 +- .../TestRunListenersFactoryInjector.java | 6 +- .../model/TestCaseEventFactoryInjector.java | 11 + .../runner/TestRunFactoryInjector.java | 3 +- .../sorting/QueueProviderInjector.java | 11 + ...ecutionTimeLineSummaryPrinterInjector.java | 27 ++ .../stat/StatServiceLoaderInjector.java | 17 + .../stat/TestExecutionReporterInjector.java | 11 + .../injector/stat/TestStatLoaderInjector.java | 13 + .../suite/TestSuiteLoaderInjector.java | 7 +- .../summary/SummaryPrinterInjector.java | 8 +- .../com/shazam/fork/pooling/PoolLoader.java | 1 - .../fork/runner/PoolTestRunnerFactory.java | 5 +- .../shazam/fork/runner/TestRunFactory.java | 9 +- .../listeners/ForkXmlTestRunListener.java | 9 +- .../fork/runner/listeners/RetryListener.java | 11 +- .../listeners/TestExecutionListener.java | 72 ++++ .../listeners/TestRunListenersFactory.java | 28 +- .../shazam/fork/sorting/QueueProvider.java | 24 ++ .../shazam/fork/sorting/SortedTestQueue.java | 19 + .../java/com/shazam/fork/sorting/Stats.java | 5 + .../shazam/fork/sorting/TestComparator.java | 24 ++ .../com/shazam/fork/stat/TestExecution.java | 39 +++ .../fork/stat/TestExecutionReporter.java | 25 ++ .../shazam/fork/stat/TestHistoryManager.java | 27 ++ .../fork/summary/executiontimeline/Data.java | 43 +++ .../executiontimeline/DateSerializer.java | 24 ++ .../executiontimeline/ExecutionResult.java | 33 ++ .../executiontimeline/ExecutionStats.java | 19 + .../HtmlStatsSummaryPrinter.java | 56 +++ .../JsonStatsSummarySerializer.java | 44 +++ .../summary/executiontimeline/Measure.java | 35 ++ .../executiontimeline/StatHtmlSummary.java | 5 + .../StatSummarySerializer.java | 137 ++++++++ .../src/main/resources/stat/index.html | 38 ++ .../src/main/resources/static/chart.css | 85 +++++ .../src/main/resources/static/chart.js | 328 ++++++++++++++++++ .../PoolTestCaseAccumulatorTestFailure.java | 10 +- .../runner/OverallProgressReporterTest.java | 13 +- fork-stat-common/build.gradle | 23 ++ fork-stat-common/gradle.properties | 4 + .../java/com/agoda/fork/stat/MathUtils.java | 39 +++ .../java/com/agoda/fork/stat/StatLoader.java | 7 + .../agoda/fork/stat/StatLoaderProvider.java | 7 + .../com/agoda/fork/stat/TestExecution.java | 13 + .../java/com/agoda/fork/stat/TestHistory.java | 34 ++ .../java/com/agoda/fork/stat/TestMetric.java | 36 ++ fork-stat-teamcity/build.gradle | 30 ++ fork-stat-teamcity/gradle.properties | 4 + .../agoda/fork/teamcity/TeamCityClient.java | 56 +++ .../agoda/fork/teamcity/TeamCityConfig.java | 49 +++ .../agoda/fork/teamcity/TeamCityService.java | 18 + .../fork/teamcity/TeamCityStatLoader.java | 96 +++++ .../teamcity/TeamCityStatLoaderProvider.java | 21 ++ .../agoda/fork/teamcity/entities/Build.java | 13 + .../agoda/fork/teamcity/entities/Builds.java | 15 + .../agoda/fork/teamcity/entities/Test.java | 37 ++ .../fork/teamcity/entities/TestResult.java | 27 ++ .../com.agoda.fork.stat.StatLoaderProvider | 1 + settings.gradle | 3 + 82 files changed, 2088 insertions(+), 93 deletions(-) create mode 100644 chimprunner/src/main/java/com/shazam/chimprunner/injector/model/TestCaseEventFactoryInjector.java create mode 100644 chimprunner/src/main/java/com/shazam/chimprunner/injector/stat/StatServiceLoaderInjector.java create mode 100644 chimprunner/src/main/java/com/shazam/chimprunner/injector/stat/TestStatLoaderInjector.java create mode 100644 fork-common/src/main/java/com/shazam/fork/model/TestCaseEventFactory.java create mode 100644 fork-common/src/main/java/com/shazam/fork/stat/StatServiceLoader.java create mode 100644 fork-common/src/main/java/com/shazam/fork/stat/TestStatsLoader.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/SortingStrategy.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/injector/model/TestCaseEventFactoryInjector.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/injector/sorting/QueueProviderInjector.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/injector/stat/ExecutionTimeLineSummaryPrinterInjector.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/injector/stat/StatServiceLoaderInjector.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/injector/stat/TestExecutionReporterInjector.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/injector/stat/TestStatLoaderInjector.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/sorting/QueueProvider.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/sorting/SortedTestQueue.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/sorting/Stats.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/stat/TestExecutionReporter.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/stat/TestHistoryManager.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Data.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/DateSerializer.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/ExecutionResult.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/ExecutionStats.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/HtmlStatsSummaryPrinter.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/JsonStatsSummarySerializer.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Measure.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatHtmlSummary.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java create mode 100755 fork-runner/src/main/resources/stat/index.html create mode 100755 fork-runner/src/main/resources/static/chart.css create mode 100755 fork-runner/src/main/resources/static/chart.js create mode 100644 fork-stat-common/build.gradle create mode 100644 fork-stat-common/gradle.properties create mode 100644 fork-stat-common/src/main/java/com/agoda/fork/stat/MathUtils.java create mode 100644 fork-stat-common/src/main/java/com/agoda/fork/stat/StatLoader.java create mode 100644 fork-stat-common/src/main/java/com/agoda/fork/stat/StatLoaderProvider.java create mode 100644 fork-stat-common/src/main/java/com/agoda/fork/stat/TestExecution.java create mode 100644 fork-stat-common/src/main/java/com/agoda/fork/stat/TestHistory.java create mode 100644 fork-stat-common/src/main/java/com/agoda/fork/stat/TestMetric.java create mode 100644 fork-stat-teamcity/build.gradle create mode 100644 fork-stat-teamcity/gradle.properties create mode 100644 fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityClient.java create mode 100644 fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityConfig.java create mode 100644 fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityService.java create mode 100644 fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoader.java create mode 100644 fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoaderProvider.java create mode 100644 fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Build.java create mode 100644 fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Builds.java create mode 100644 fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Test.java create mode 100644 fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/TestResult.java create mode 100644 fork-stat-teamcity/src/main/resources/META-INF/services/com.agoda.fork.stat.StatLoaderProvider diff --git a/chimprunner/src/main/java/com/shazam/chimprunner/injector/model/TestCaseEventFactoryInjector.java b/chimprunner/src/main/java/com/shazam/chimprunner/injector/model/TestCaseEventFactoryInjector.java new file mode 100644 index 00000000..4e21f2e0 --- /dev/null +++ b/chimprunner/src/main/java/com/shazam/chimprunner/injector/model/TestCaseEventFactoryInjector.java @@ -0,0 +1,11 @@ +package com.shazam.chimprunner.injector.model; + +import com.shazam.fork.model.TestCaseEventFactory; + +import static com.shazam.chimprunner.injector.stat.TestStatLoaderInjector.testStatsLoader; + +public class TestCaseEventFactoryInjector { + public static TestCaseEventFactory testCaseEventFactory(){ + return new TestCaseEventFactory(testStatsLoader()); + } +} diff --git a/chimprunner/src/main/java/com/shazam/chimprunner/injector/stat/StatServiceLoaderInjector.java b/chimprunner/src/main/java/com/shazam/chimprunner/injector/stat/StatServiceLoaderInjector.java new file mode 100644 index 00000000..32642991 --- /dev/null +++ b/chimprunner/src/main/java/com/shazam/chimprunner/injector/stat/StatServiceLoaderInjector.java @@ -0,0 +1,15 @@ +package com.shazam.chimprunner.injector.stat; + +import com.shazam.fork.stat.StatServiceLoader; + +public class StatServiceLoaderInjector { + + private static StatServiceLoader INSTANCE = null; + + public static synchronized StatServiceLoader statServiceLoader() { + if (INSTANCE == null) { + INSTANCE = new StatServiceLoader(""); + } + return INSTANCE; + } +} diff --git a/chimprunner/src/main/java/com/shazam/chimprunner/injector/stat/TestStatLoaderInjector.java b/chimprunner/src/main/java/com/shazam/chimprunner/injector/stat/TestStatLoaderInjector.java new file mode 100644 index 00000000..1f562dbe --- /dev/null +++ b/chimprunner/src/main/java/com/shazam/chimprunner/injector/stat/TestStatLoaderInjector.java @@ -0,0 +1,13 @@ +package com.shazam.chimprunner.injector.stat; + +import com.shazam.fork.stat.TestStatsLoader; + +import static com.shazam.chimprunner.injector.stat.StatServiceLoaderInjector.statServiceLoader; + +public class TestStatLoaderInjector { + private static final TestStatsLoader INSTANCE = new TestStatsLoader(statServiceLoader()); + + public static TestStatsLoader testStatsLoader() { + return INSTANCE; + } +} diff --git a/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java b/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java index 58b20ffb..97ad9ec9 100644 --- a/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java +++ b/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java @@ -14,6 +14,8 @@ import static com.shazam.chimprunner.injector.ConfigurationInjector.configuration; import static com.shazam.chimprunner.injector.io.DexFileExtractorInjector.dexFileExtractor; +import static com.shazam.chimprunner.injector.model.TestCaseEventFactoryInjector.testCaseEventFactory; +import static com.shazam.chimprunner.injector.stat.TestStatLoaderInjector.testStatsLoader; import static com.shazam.chimprunner.injector.suite.TestClassMatcherInjector.testClassMatcher; public class TestSuiteLoaderInjector { @@ -22,6 +24,9 @@ private TestSuiteLoaderInjector() { } public static TestSuiteLoader testSuiteLoader() { - return new TestSuiteLoader(configuration().getInstrumentationApk(), dexFileExtractor(), testClassMatcher(), "", ""); + return new TestSuiteLoader(configuration().getInstrumentationApk(), + dexFileExtractor(), testClassMatcher(), + "", "", + testCaseEventFactory()); } } diff --git a/fork-common/build.gradle b/fork-common/build.gradle index 1e2a18af..8d408e8a 100644 --- a/fork-common/build.gradle +++ b/fork-common/build.gradle @@ -18,6 +18,7 @@ targetCompatibility = rootProject.sourceCompatibility dependencies { api project(':fork-client') + api project(':fork-stat-common') api "com.google.code.findbugs:jsr305:3.0.1" api "com.android.tools.ddms:ddmlib:25.1.0" api "commons-io:commons-io:2.5" diff --git a/fork-common/src/main/java/com/shazam/fork/model/TestCaseEvent.java b/fork-common/src/main/java/com/shazam/fork/model/TestCaseEvent.java index c0e1efb2..af91270d 100644 --- a/fork-common/src/main/java/com/shazam/fork/model/TestCaseEvent.java +++ b/fork-common/src/main/java/com/shazam/fork/model/TestCaseEvent.java @@ -1,15 +1,11 @@ package com.shazam.fork.model; -import com.android.ddmlib.testrunner.TestIdentifier; +import com.agoda.fork.stat.TestMetric; import com.google.common.base.Objects; import java.util.List; import java.util.Map; -import javax.annotation.Nonnull; - -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; import static org.apache.commons.lang3.builder.ToStringStyle.SIMPLE_STYLE; @@ -20,21 +16,15 @@ public class TestCaseEvent { private final boolean isIgnored; private final List permissionsToRevoke; private final Map properties; + private final TestMetric testMetric; - private TestCaseEvent(String testMethod, String testClass, boolean isIgnored, List permissionsToRevoke, Map properties) { + TestCaseEvent(String testMethod, String testClass, boolean isIgnored, List permissionsToRevoke, Map properties, TestMetric testMetric) { this.testMethod = testMethod; this.testClass = testClass; this.isIgnored = isIgnored; this.permissionsToRevoke = permissionsToRevoke; this.properties = properties; - } - - public static TestCaseEvent newTestCase(String testMethod, String testClass, boolean isIgnored, List permissionsToRevoke, Map properties) { - return new TestCaseEvent(testMethod, testClass, isIgnored, permissionsToRevoke, properties); - } - - public static TestCaseEvent newTestCase(@Nonnull TestIdentifier testIdentifier) { - return new TestCaseEvent(testIdentifier.getTestName(), testIdentifier.getClassName(), false, emptyList(), emptyMap()); + this.testMetric = testMetric; } public String getTestMethod() { @@ -57,6 +47,10 @@ public Map getProperties() { return properties; } + public TestMetric getTestMetric() { + return testMetric; + } + @Override public int hashCode() { return Objects.hashCode(this.testMethod, this.testClass); diff --git a/fork-common/src/main/java/com/shazam/fork/model/TestCaseEventFactory.java b/fork-common/src/main/java/com/shazam/fork/model/TestCaseEventFactory.java new file mode 100644 index 00000000..bdf60160 --- /dev/null +++ b/fork-common/src/main/java/com/shazam/fork/model/TestCaseEventFactory.java @@ -0,0 +1,31 @@ +package com.shazam.fork.model; + +import com.android.ddmlib.testrunner.TestIdentifier; +import com.shazam.fork.stat.TestStatsLoader; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class TestCaseEventFactory { + + private final TestStatsLoader statsLoader; + + public TestCaseEventFactory(TestStatsLoader statsLoader) { + this.statsLoader = statsLoader; + } + + public TestCaseEvent newTestCase(@Nonnull TestIdentifier testIdentifier) { + return new TestCaseEvent(testIdentifier.getTestName(), + testIdentifier.getClassName(), + false, + Collections.emptyList(), + Collections.emptyMap(), + statsLoader.findMetric(testIdentifier.getClassName(), testIdentifier.getClassName())); + } + + public TestCaseEvent newTestCase(String testMethod, String testClass, boolean isIgnored, List permissionsToRevoke, Map properties) { + return new TestCaseEvent(testMethod, testClass, isIgnored, permissionsToRevoke, properties, statsLoader.findMetric(testClass, testMethod)); + } +} \ No newline at end of file diff --git a/fork-common/src/main/java/com/shazam/fork/stat/StatServiceLoader.java b/fork-common/src/main/java/com/shazam/fork/stat/StatServiceLoader.java new file mode 100644 index 00000000..63029d48 --- /dev/null +++ b/fork-common/src/main/java/com/shazam/fork/stat/StatServiceLoader.java @@ -0,0 +1,39 @@ +package com.shazam.fork.stat; + +import com.agoda.fork.stat.StatLoader; +import com.agoda.fork.stat.StatLoaderProvider; +import com.agoda.fork.stat.TestHistory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class StatServiceLoader { + + private static final Logger logger = LoggerFactory.getLogger(StatServiceLoader.class); + + private final String path; + + public StatServiceLoader(String path) { + this.path = path; + } + + public List load() { + return StreamSupport.stream(ServiceLoader.load(StatLoaderProvider.class).spliterator(), true) + .flatMap(loader -> { + List histories = new ArrayList<>(); + try { + histories.addAll(loader.create(path).loadHistory()); + } catch (FileNotFoundException e) { + logger.error("can't load history", e); + } + return histories.stream(); + }) + .collect(Collectors.toList()); + } +} diff --git a/fork-common/src/main/java/com/shazam/fork/stat/TestStatsLoader.java b/fork-common/src/main/java/com/shazam/fork/stat/TestStatsLoader.java new file mode 100644 index 00000000..91dd871c --- /dev/null +++ b/fork-common/src/main/java/com/shazam/fork/stat/TestStatsLoader.java @@ -0,0 +1,56 @@ +package com.shazam.fork.stat; + +import com.agoda.fork.stat.TestHistory; +import com.agoda.fork.stat.TestMetric; +import com.android.ddmlib.testrunner.TestIdentifier; +import com.shazam.fork.model.TestCaseEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.util.stream.Collectors.toMap; + +public class TestStatsLoader { + + StatServiceLoader loader; + + public TestStatsLoader(StatServiceLoader loader) { + this.loader = loader; + } + + private final List testHistories = new ArrayList<>(); + private final Map testMetris = new HashMap<>(); + + public void load() { + testHistories.addAll(loader.load()); + testMetris.putAll(testHistories + .stream() + .collect(toMap(this::calculateTestKey, TestHistory::getTestMetric))); + } + + public TestMetric findMetric(String className, String methodName) { + return testMetris.getOrDefault(calculateTestKey(className, methodName), TestMetric.empty()); + } + + public TestMetric findMetric(TestIdentifier testIdentifier) { + return testMetris.getOrDefault(calculateTestKey(testIdentifier), TestMetric.empty()); + } + + private String calculateTestKey(TestIdentifier testIdentifier) { + return calculateTestKey(testIdentifier.getClassName(),testIdentifier.getTestName()); + } + + private String calculateTestKey(TestHistory history) { + return calculateTestKey(history.getTestClass(), history.getTestMethod()); + } + + private String calculateTestKey(TestCaseEvent event) { + return calculateTestKey(event.getTestClass(), event.getTestMethod()); + } + + private String calculateTestKey(String testClass, String testMethod) { + return testClass + "#" + testMethod; + } +} diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index 46ccb988..d4c6010f 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -10,9 +10,10 @@ package com.shazam.fork.suite; -import com.google.common.base.Strings; import com.shazam.fork.io.DexFileExtractor; import com.shazam.fork.model.TestCaseEvent; +import com.shazam.fork.model.TestCaseEventFactory; +import com.shazam.fork.stat.TestStatsLoader; import org.jf.dexlib.*; import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue; import org.jf.dexlib.EncodedValue.ArrayEncodedValue; @@ -24,12 +25,12 @@ import java.util.*; import java.util.stream.Stream; -import static com.shazam.fork.model.TestCaseEvent.newTestCase; import static com.shazam.fork.suite.AnnotationParser.parseAnnotation; import static java.lang.Math.min; import static java.util.Arrays.stream; import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; public class TestSuiteLoader { private static final String TEST_ANNOTATION = "Lorg/junit/Test;"; @@ -42,20 +43,24 @@ public class TestSuiteLoader { private final TestClassMatcher testClassMatcher; private final List includedAnnotations; private final List excludedAnnotations; + private final TestCaseEventFactory factory; public TestSuiteLoader(File instrumentationApkFile, DexFileExtractor dexFileExtractor, TestClassMatcher testClassMatcher, String includedAnnotation, - String excludedAnnotation) { + String excludedAnnotation, + TestCaseEventFactory testCaseEventFactory) { this.instrumentationApkFile = instrumentationApkFile; this.dexFileExtractor = dexFileExtractor; this.testClassMatcher = testClassMatcher; this.includedAnnotations = parseAnnotation().apply(includedAnnotation); this.excludedAnnotations = parseAnnotation().apply(excludedAnnotation); + this.factory = testCaseEventFactory; } public Collection loadTestSuite() throws NoTestCasesFoundException { + List testCaseEvents = dexFileExtractor.getDexFiles(instrumentationApkFile).stream() .map(dexFile -> dexFile.ClassDefsSection.getItems()) .flatMap(Collection::stream) @@ -126,7 +131,7 @@ private TestCaseEvent convertToTestCaseEvent(ClassDefItem classDefItem, boolean ignored = isClassIgnored(annotationDirectoryItem) || isMethodIgnored(annotations); List permissionsToRevoke = getPermissionsToRevoke(annotations); Map properties = getTestProperties(annotations); - return newTestCase(testMethod, testClass, ignored, permissionsToRevoke, properties); + return factory.newTestCase(testMethod, testClass, ignored, permissionsToRevoke, properties); } private String getClassName(ClassDefItem classDefItem) { diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java index feebfbee..71caf7f0 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java @@ -3,30 +3,23 @@ import com.shazam.fork.io.DexFileExtractor; import com.shazam.fork.model.TestCaseEvent; -import org.hamcrest.Matcher; +import com.shazam.fork.model.TestCaseEventFactory; +import com.shazam.fork.stat.StatServiceLoader; +import com.shazam.fork.stat.TestStatsLoader; import org.jf.dexlib.DexFile; import org.junit.Before; import org.junit.Test; -import javax.annotation.Nonnull; import java.io.File; import java.net.URL; import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import static com.shazam.fork.io.FakeDexFileExtractor.fakeDexFileExtractor; import static com.shazam.fork.io.Files.convertFileToDexFile; -import static com.shazam.fork.model.TestCaseEvent.newTestCase; import static com.shazam.fork.suite.FakeTestClassMatcher.fakeTestClassMatcher; import static com.shazam.fork.suite.TestSuiteLoaderTestUtils.sameTestEventAs; import static com.shazam.shazamcrest.MatcherAssert.assertThat; -import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; -import static java.util.Arrays.asList; -import static java.util.Collections.*; import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.not; public class TestSuiteLoaderExcludeTest { @@ -45,7 +38,8 @@ private DexFile testDexFile() { @Before public void setUp() throws Exception { - testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, "", "com.shazam.annotations.CustomTestAnnotation1"); + testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, + fakeTestClassMatcher, "", "com.shazam.annotations.CustomTestAnnotation1",new TestCaseEventFactory(new TestStatsLoader(new StatServiceLoader("")))); } @Test diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java index ca63a3e1..d6eacdbd 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java @@ -3,6 +3,9 @@ import com.shazam.fork.io.DexFileExtractor; import com.shazam.fork.model.TestCaseEvent; +import com.shazam.fork.model.TestCaseEventFactory; +import com.shazam.fork.stat.StatServiceLoader; +import com.shazam.fork.stat.TestStatsLoader; import org.jf.dexlib.DexFile; import org.junit.Before; import org.junit.Test; @@ -36,7 +39,9 @@ private DexFile testDexFile() { @Before public void setUp() throws Exception { - testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, "com.shazam.annotations.CustomTestAnnotation2", ""); + testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, + "com.shazam.annotations.CustomTestAnnotation2", + "",new TestCaseEventFactory(new TestStatsLoader(new StatServiceLoader("")))); } @Test diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java index 4c8e1a55..918faac7 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTest.java @@ -11,13 +11,13 @@ package com.shazam.fork.suite; import com.shazam.fork.io.DexFileExtractor; -import com.shazam.fork.model.TestCaseEvent; -import org.hamcrest.Matcher; +import com.shazam.fork.model.TestCaseEventFactory; +import com.shazam.fork.stat.StatServiceLoader; +import com.shazam.fork.stat.TestStatsLoader; import org.jf.dexlib.DexFile; import org.junit.Before; import org.junit.Test; -import javax.annotation.Nonnull; import java.io.File; import java.net.URL; import java.util.HashMap; @@ -26,11 +26,9 @@ import static com.shazam.fork.io.FakeDexFileExtractor.fakeDexFileExtractor; import static com.shazam.fork.io.Files.convertFileToDexFile; -import static com.shazam.fork.model.TestCaseEvent.newTestCase; import static com.shazam.fork.suite.FakeTestClassMatcher.fakeTestClassMatcher; import static com.shazam.fork.suite.TestSuiteLoaderTestUtils.sameTestEventAs; import static com.shazam.shazamcrest.MatcherAssert.assertThat; -import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; import static java.util.Arrays.asList; import static java.util.Collections.*; import static org.hamcrest.Matchers.hasItems; @@ -38,33 +36,33 @@ /** * This test is based on the tests.dex file, which contains test classes with the following code: *

- *{@literal}@Ignore
- *public class IgnoredClassTest {
+ * {@literal}@Ignore
+ * public class IgnoredClassTest {
  *    {@literal}@Test
  *    public void methodOfAnIgnoredTestClass() {
  *    }
- *}
- *
- *public class ClassWithNoIgnoredMethodsTest {
+ * }
+ * 

+ * public class ClassWithNoIgnoredMethodsTest { * {@literal}@Test * public void firstTestMethod() { * } - * + *

* {@literal}@Test * public void secondTestMethod() { * } - *} - * - *public class ClassWithSomeIgnoredMethodsTest { + * } + *

+ * public class ClassWithSomeIgnoredMethodsTest { * {@literal}@Test * public void nonIgnoredTestMethod() { * } - * + *

* {@literal}@Test * {@literal}@Ignore * public void ignoredTestMethod() { * } - *} + * } *

*/ public class TestSuiteLoaderTest { @@ -83,7 +81,7 @@ private DexFile testDexFile() { @Before public void setUp() throws Exception { - testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, "", ""); + testSuiteLoader = new TestSuiteLoader(ANY_INSTRUMENTATION_APK_FILE, fakeDexFileExtractor, fakeTestClassMatcher, "", "", new TestCaseEventFactory(new TestStatsLoader(new StatServiceLoader("")))); } @SuppressWarnings("unchecked") @@ -95,7 +93,7 @@ public void setsIgnoredFlag() throws Exception { sameTestEventAs("secondTestMethod", "com.shazam.forktest.ClassWithNoIgnoredMethodsTest", false), sameTestEventAs("nonIgnoredTestMethod", "com.shazam.forktest.ClassWithSomeIgnoredMethodsTest", false), sameTestEventAs("ignoredTestMethod", "com.shazam.forktest.ClassWithSomeIgnoredMethodsTest", true), - sameTestEventAs("methodOfAnCustomTestAnnotation1TestClass","com.shazam.forktest.CustomTestAnnotation1ClassTest",false))); + sameTestEventAs("methodOfAnCustomTestAnnotation1TestClass", "com.shazam.forktest.CustomTestAnnotation1ClassTest", false))); } @SuppressWarnings("unchecked") diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java index 61b1a43d..e6fc3407 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java @@ -1,30 +1,36 @@ package com.shazam.fork.suite; +import com.agoda.fork.stat.TestMetric; import com.shazam.fork.model.TestCaseEvent; +import com.shazam.fork.model.TestCaseEventFactory; +import com.shazam.fork.stat.StatServiceLoader; +import com.shazam.fork.stat.TestStatsLoader; import org.hamcrest.Matcher; import javax.annotation.Nonnull; import java.util.List; import java.util.Map; -import static com.shazam.fork.model.TestCaseEvent.newTestCase; import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; public class TestSuiteLoaderTestUtils { + + private static final TestCaseEventFactory factory = new TestCaseEventFactory(new TestStatsLoader(new StatServiceLoader(""))); + @Nonnull static Matcher sameTestEventAs(String testMethod, String testClass, Map properties) { - return sameBeanAs(newTestCase(testMethod, testClass, false, emptyList(), properties)); + return sameBeanAs(factory.newTestCase(testMethod, testClass, false, emptyList(), properties)); } @Nonnull static Matcher sameTestEventAs(String testMethod, String testClass, boolean isIgnored) { - return sameBeanAs(newTestCase(testMethod, testClass, isIgnored, emptyList(), emptyMap())); + return sameBeanAs(factory.newTestCase(testMethod, testClass, isIgnored, emptyList(), emptyMap())); } @Nonnull static Matcher sameTestEventAs(String testMethod, String testClass, boolean isIgnored, List permissions) { - return sameBeanAs(newTestCase(testMethod, testClass, isIgnored, permissions, emptyMap())); + return sameBeanAs(factory.newTestCase(testMethod, testClass, isIgnored, permissions, emptyMap())); } } diff --git a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy index 56cd5b78..6167ad93 100644 --- a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy +++ b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy @@ -84,6 +84,7 @@ class ForkPlugin implements Plugin { ignoreFailures = config.ignoreFailures excludedAnnotation = config.excludedAnnotation includedAnnotation = config.includedAnnotation + sortingStrategy = config.sortingStrategy applicationApk = new File(baseVariantOutput.packageApplication.outputDirectory.path + "/" + baseVariantOutput.outputFileName) diff --git a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy index e526b1ec..af9dbef9 100644 --- a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy +++ b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy @@ -15,6 +15,7 @@ package com.shazam.fork.gradle import com.shazam.fork.Configuration import com.shazam.fork.Fork import com.shazam.fork.PoolingStrategy +import com.shazam.fork.SortingStrategy import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.tasks.InputFile @@ -79,6 +80,8 @@ class ForkRunTask extends DefaultTask implements VerificationTask { String includedAnnotation + SortingStrategy sortingStrategy + @TaskAction void runFork() { LOG.info("Run instrumentation tests $instrumentationApk for app $applicationApk") @@ -105,6 +108,7 @@ class ForkRunTask extends DefaultTask implements VerificationTask { .withAutoGrantPermissions(autoGrantPermissions) .withExcludedAnnotation(excludedAnnotation) .withIncludedAnnotation(includedAnnotation) + .withSortingStrategy(sortingStrategy) .build(); boolean success = new Fork(configuration).run() diff --git a/fork-runner/build.gradle b/fork-runner/build.gradle index 13c692d9..053ee8df 100644 --- a/fork-runner/build.gradle +++ b/fork-runner/build.gradle @@ -19,6 +19,7 @@ targetCompatibility = rootProject.sourceCompatibility dependencies { api project(':fork-common') + implementation project(':fork-stat-common') implementation 'org.codehaus.groovy:groovy-all:2.4.12' implementation( "com.beust:jcommander:$JCOMMANDER_VERSION", diff --git a/fork-runner/src/main/java/com/shazam/fork/Configuration.java b/fork-runner/src/main/java/com/shazam/fork/Configuration.java index 5b6400d6..327728ed 100644 --- a/fork-runner/src/main/java/com/shazam/fork/Configuration.java +++ b/fork-runner/src/main/java/com/shazam/fork/Configuration.java @@ -62,6 +62,7 @@ public class Configuration { private final String includedAnnotation; private ApplicationInfo applicationInfo; + private SortingStrategy sortingStrategy; private Configuration(Builder builder) { androidSdk = builder.androidSdk; @@ -87,6 +88,7 @@ private Configuration(Builder builder) { this.excludedAnnotation = builder.excludedAnnotation; this.includedAnnotation = builder.includedAnnotation; this.applicationInfo = builder.applicationInfo; + this.sortingStrategy = builder.sortingStrategy; } @Nonnull @@ -194,6 +196,10 @@ public ApplicationInfo getApplicationInfo() { return applicationInfo; } + public SortingStrategy getSortingStrategy() { + return sortingStrategy; + } + public static class Builder { private File androidSdk; private File applicationApk; @@ -218,6 +224,7 @@ public static class Builder { private String excludedAnnotation; private String includedAnnotation; private ApplicationInfo applicationInfo; + public SortingStrategy sortingStrategy; public static Builder configuration() { return new Builder(); @@ -318,6 +325,11 @@ public Builder withIncludedAnnotation(String includedAnnotation) { return this; } + public Builder withSortingStrategy(@Nullable SortingStrategy sortingStrategy) { + this.sortingStrategy = sortingStrategy; + return this; + } + public Configuration build() { checkNotNull(androidSdk, "SDK is required."); checkArgument(androidSdk.exists(), "SDK directory does not exist."); @@ -345,6 +357,7 @@ public Configuration build() { retryPerTestCaseQuota = assignValueOrDefaultIfZero(retryPerTestCaseQuota, Defaults.RETRY_QUOTA_PER_TEST_CASE); logArgumentsBadInteractions(); poolingStrategy = validatePoolingStrategy(poolingStrategy); + sortingStrategy = validateSortingStrategy(sortingStrategy); applicationInfo = ApplicationInfoFactory.parseFromFile(applicationApk); return new Configuration(this); } @@ -391,5 +404,13 @@ private PoolingStrategy validatePoolingStrategy(PoolingStrategy poolingStrategy) return poolingStrategy; } + + private SortingStrategy validateSortingStrategy(SortingStrategy sortingStrategy) { + if (sortingStrategy == null) { + sortingStrategy = new SortingStrategy(); + sortingStrategy.defaultStrategy = true; + } + return sortingStrategy; + } } } diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkCli.java b/fork-runner/src/main/java/com/shazam/fork/ForkCli.java index 8e8e9ef3..96057895 100644 --- a/fork-runner/src/main/java/com/shazam/fork/ForkCli.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkCli.java @@ -101,6 +101,7 @@ public static void main(String... args) { .withAutoGrantPermissions(forkConfiguration.autoGrantPermissions) .withExcludedAnnotation(forkConfiguration.excludedAnnotation) .withIncludedAnnotation(forkConfiguration.includedAnnotation) + .withSortingStrategy(forkConfiguration.sortingStrategy) .build(); Fork fork = new Fork(configuration); diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java b/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java index b93eb2e2..c5249984 100644 --- a/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java @@ -100,10 +100,21 @@ public class ForkConfiguration { public String excludedAnnotation; /** - * Filter test run to tests without given annotation + * Filter test run to tests with given annotation */ public String includedAnnotation; + /** + * The strategy that will be used to calculate execution order. + */ + public SortingStrategy sortingStrategy; + + public void sortingStrategy(Closure sortingStrategyClosure){ + sortingStrategy = new SortingStrategy(); + sortingStrategyClosure.setDelegate(sortingStrategy); + sortingStrategyClosure.call(); + } + public void poolingStrategy(Closure poolingStrategyClosure) { poolingStrategy = new PoolingStrategy(); poolingStrategyClosure.setDelegate(poolingStrategy); diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java index 428215b0..c67a3a71 100755 --- a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java @@ -17,6 +17,8 @@ import com.shazam.fork.pooling.*; import com.shazam.fork.runner.PoolTestRunnerFactory; import com.shazam.fork.runner.ProgressReporter; +import com.shazam.fork.sorting.QueueProvider; +import com.shazam.fork.stat.TestStatsLoader; import com.shazam.fork.suite.NoTestCasesFoundException; import com.shazam.fork.suite.TestSuiteLoader; import com.shazam.fork.summary.SummaryGeneratorHook; @@ -25,6 +27,7 @@ import org.slf4j.LoggerFactory; import java.util.Collection; +import java.util.Queue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -38,17 +41,23 @@ public class ForkRunner { private final PoolTestRunnerFactory poolTestRunnerFactory; private final ProgressReporter progressReporter; private final SummaryGeneratorHook summaryGeneratorHook; + private final TestStatsLoader testStatsLoader; + private final QueueProvider queueProvider; public ForkRunner(PoolLoader poolLoader, TestSuiteLoader testClassLoader, PoolTestRunnerFactory poolTestRunnerFactory, ProgressReporter progressReporter, - SummaryGeneratorHook summaryGeneratorHook) { + SummaryGeneratorHook summaryGeneratorHook, + TestStatsLoader testStatsLoader, + QueueProvider queueProvider) { this.poolLoader = poolLoader; this.testClassLoader = testClassLoader; this.poolTestRunnerFactory = poolTestRunnerFactory; this.progressReporter = progressReporter; this.summaryGeneratorHook = summaryGeneratorHook; + this.testStatsLoader = testStatsLoader; + this.queueProvider = queueProvider; } public boolean run() { @@ -59,13 +68,22 @@ public boolean run() { CountDownLatch poolCountDownLatch = new CountDownLatch(numberOfPools); poolExecutor = namedExecutor(numberOfPools, "PoolExecutor-%d"); + testStatsLoader.load(); + Collection testCases = testClassLoader.loadTestSuite(); + + Queue testCasesQueue = queueProvider.create(); + + testCasesQueue.addAll(testCases); + summaryGeneratorHook.registerHook(pools, testCases); progressReporter.start(); for (Pool pool : pools) { - Runnable poolTestRunner = poolTestRunnerFactory.createPoolTestRunner(pool, testCases, - poolCountDownLatch, progressReporter); + Runnable poolTestRunner = poolTestRunnerFactory.createPoolTestRunner(pool, + testCasesQueue, + poolCountDownLatch, + progressReporter); poolExecutor.execute(poolTestRunner); } poolCountDownLatch.await(); diff --git a/fork-runner/src/main/java/com/shazam/fork/SortingStrategy.java b/fork-runner/src/main/java/com/shazam/fork/SortingStrategy.java new file mode 100644 index 00000000..99430349 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/SortingStrategy.java @@ -0,0 +1,16 @@ +package com.shazam.fork; + +import com.shazam.fork.sorting.Stats; +import groovy.lang.Closure; + +public class SortingStrategy { + public Boolean defaultStrategy; + public Stats statistics; + + + public void stats(Closure manualClosure) { + statistics = new Stats(); + manualClosure.setDelegate(statistics); + manualClosure.call(); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java index ea38aefc..b302f362 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java @@ -20,6 +20,8 @@ import static com.shazam.fork.injector.pooling.PoolLoaderInjector.poolLoader; import static com.shazam.fork.injector.runner.PoolTestRunnerFactoryInjector.poolTestRunnerFactory; import static com.shazam.fork.injector.runner.ProgressReporterInjector.progressReporter; +import static com.shazam.fork.injector.sorting.QueueProviderInjector.queueProvider; +import static com.shazam.fork.injector.stat.TestStatLoaderInjector.testStatsLoader; import static com.shazam.fork.injector.suite.TestSuiteLoaderInjector.testSuiteLoader; import static com.shazam.fork.injector.summary.SummaryGeneratorHookInjector.summaryGeneratorHook; import static com.shazam.fork.utils.Utils.millisSinceNanoTime; @@ -39,7 +41,9 @@ public static ForkRunner forkRunner() { testSuiteLoader(), poolTestRunnerFactory(), progressReporter(), - summaryGeneratorHook()); + summaryGeneratorHook(), + testStatsLoader(), + queueProvider()); logger.debug("Bootstrap of ForkRunner took: {} milliseconds", millisSinceNanoTime(startNanos)); diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/listeners/TestRunListenersFactoryInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/listeners/TestRunListenersFactoryInjector.java index 75542474..c969a5e5 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/listeners/TestRunListenersFactoryInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/listeners/TestRunListenersFactoryInjector.java @@ -13,14 +13,16 @@ import com.shazam.fork.runner.listeners.TestRunListenersFactory; import static com.shazam.fork.injector.ConfigurationInjector.configuration; +import static com.shazam.fork.injector.stat.TestExecutionReporterInjector.testExecutionReporter; import static com.shazam.fork.injector.system.FileManagerInjector.fileManager; import static com.shazam.fork.injector.GsonInjector.gson; public class TestRunListenersFactoryInjector { - private TestRunListenersFactoryInjector() {} + private TestRunListenersFactoryInjector() { + } public static TestRunListenersFactory testRunListenersFactory() { - return new TestRunListenersFactory(configuration(), fileManager(), gson()); + return new TestRunListenersFactory(configuration(), fileManager(), gson(), testExecutionReporter()); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/model/TestCaseEventFactoryInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/model/TestCaseEventFactoryInjector.java new file mode 100644 index 00000000..d56038dd --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/injector/model/TestCaseEventFactoryInjector.java @@ -0,0 +1,11 @@ +package com.shazam.fork.injector.model; + +import com.shazam.fork.model.TestCaseEventFactory; + +import static com.shazam.fork.injector.stat.TestStatLoaderInjector.testStatsLoader; + +public class TestCaseEventFactoryInjector { + public static TestCaseEventFactory testCaseEventFactory(){ + return new TestCaseEventFactory(testStatsLoader()); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/runner/TestRunFactoryInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/runner/TestRunFactoryInjector.java index b71e07e9..fa71b75d 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/runner/TestRunFactoryInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/runner/TestRunFactoryInjector.java @@ -14,12 +14,13 @@ import static com.shazam.fork.injector.ConfigurationInjector.configuration; import static com.shazam.fork.injector.listeners.TestRunListenersFactoryInjector.testRunListenersFactory; +import static com.shazam.fork.injector.model.TestCaseEventFactoryInjector.testCaseEventFactory; public class TestRunFactoryInjector { private TestRunFactoryInjector() {} public static TestRunFactory testRunFactory() { - return new TestRunFactory(configuration(), testRunListenersFactory()); + return new TestRunFactory(configuration(), testRunListenersFactory(), testCaseEventFactory()); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/sorting/QueueProviderInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/sorting/QueueProviderInjector.java new file mode 100644 index 00000000..055bf948 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/injector/sorting/QueueProviderInjector.java @@ -0,0 +1,11 @@ +package com.shazam.fork.injector.sorting; + +import com.shazam.fork.sorting.QueueProvider; + +import static com.shazam.fork.injector.ConfigurationInjector.configuration; + +public class QueueProviderInjector { + public static QueueProvider queueProvider(){ + return new QueueProvider(configuration()); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/stat/ExecutionTimeLineSummaryPrinterInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/stat/ExecutionTimeLineSummaryPrinterInjector.java new file mode 100644 index 00000000..1eaa6fd2 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/injector/stat/ExecutionTimeLineSummaryPrinterInjector.java @@ -0,0 +1,27 @@ +package com.shazam.fork.injector.stat; + +import com.shazam.fork.summary.SummaryPrinter; +import com.shazam.fork.summary.executiontimeline.HtmlStatsSummaryPrinter; +import com.shazam.fork.summary.executiontimeline.JsonStatsSummarySerializer; +import com.shazam.fork.summary.executiontimeline.StatSummarySerializer; + +import static com.shazam.fork.injector.ConfigurationInjector.configuredOutput; +import static com.shazam.fork.injector.GsonInjector.gson; +import static com.shazam.fork.injector.stat.TestExecutionReporterInjector.testExecutionReporter; +import static com.shazam.fork.injector.stat.TestStatLoaderInjector.testStatsLoader; +import static com.shazam.fork.injector.summary.HtmlGeneratorInjector.htmlGenerator; +import static com.shazam.fork.injector.system.FileManagerInjector.fileManager; + +public class ExecutionTimeLineSummaryPrinterInjector { + public static SummaryPrinter jsonSummaryStatsSerializer() { + return new JsonStatsSummarySerializer(fileManager(), gson(), statSummarySerializer()); + } + + public static SummaryPrinter htmlStatsSummaryPrinter() { + return new HtmlStatsSummaryPrinter(configuredOutput(), htmlGenerator(), statSummarySerializer(), gson()); + } + + public static StatSummarySerializer statSummarySerializer() { + return new StatSummarySerializer(testExecutionReporter(), testStatsLoader()); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/stat/StatServiceLoaderInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/stat/StatServiceLoaderInjector.java new file mode 100644 index 00000000..ee9570ec --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/injector/stat/StatServiceLoaderInjector.java @@ -0,0 +1,17 @@ +package com.shazam.fork.injector.stat; + +import com.shazam.fork.stat.StatServiceLoader; + +import static com.shazam.fork.injector.ConfigurationInjector.configuration; + +public class StatServiceLoaderInjector { + + private static StatServiceLoader INSTANCE = null; + + public static synchronized StatServiceLoader statServiceLoader() { + if (INSTANCE == null) { + INSTANCE = new StatServiceLoader(configuration().getSortingStrategy().statistics.path); + } + return INSTANCE; + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/stat/TestExecutionReporterInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/stat/TestExecutionReporterInjector.java new file mode 100644 index 00000000..ce585942 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/injector/stat/TestExecutionReporterInjector.java @@ -0,0 +1,11 @@ +package com.shazam.fork.injector.stat; + +import com.shazam.fork.stat.TestExecutionReporter; + +public class TestExecutionReporterInjector { + private static final TestExecutionReporter instance = new TestExecutionReporter(); + + public static TestExecutionReporter testExecutionReporter(){ + return instance; + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/stat/TestStatLoaderInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/stat/TestStatLoaderInjector.java new file mode 100644 index 00000000..9cfcb4b3 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/injector/stat/TestStatLoaderInjector.java @@ -0,0 +1,13 @@ +package com.shazam.fork.injector.stat; + +import com.shazam.fork.stat.TestStatsLoader; + +import static com.shazam.fork.injector.stat.StatServiceLoaderInjector.statServiceLoader; + +public class TestStatLoaderInjector { + private static final TestStatsLoader INSTANCE = new TestStatsLoader(statServiceLoader()); + + public static TestStatsLoader testStatsLoader() { + return INSTANCE; + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java index e13ec893..fda93bc6 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java @@ -10,10 +10,14 @@ package com.shazam.fork.injector.suite; +import com.shazam.fork.stat.StatServiceLoader; +import com.shazam.fork.stat.TestStatsLoader; import com.shazam.fork.suite.TestSuiteLoader; import static com.shazam.fork.injector.ConfigurationInjector.configuration; import static com.shazam.fork.injector.io.DexFileExtractorInjector.dexFileExtractor; +import static com.shazam.fork.injector.model.TestCaseEventFactoryInjector.testCaseEventFactory; +import static com.shazam.fork.injector.stat.TestStatLoaderInjector.testStatsLoader; import static com.shazam.fork.injector.suite.TestClassMatcherInjector.testClassMatcher; public class TestSuiteLoaderInjector { @@ -25,6 +29,7 @@ public static TestSuiteLoader testSuiteLoader() { dexFileExtractor(), testClassMatcher(), configuration().getIncludedAnnotation(), - configuration().getExcludedAnnotation()); + configuration().getExcludedAnnotation(), + testCaseEventFactory()); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/summary/SummaryPrinterInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/summary/SummaryPrinterInjector.java index d7f1c062..85d553f3 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/summary/SummaryPrinterInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/summary/SummaryPrinterInjector.java @@ -16,6 +16,8 @@ import static com.shazam.fork.injector.ConfigurationInjector.configuredOutput; import static com.shazam.fork.injector.GsonInjector.gson; +import static com.shazam.fork.injector.stat.ExecutionTimeLineSummaryPrinterInjector.htmlStatsSummaryPrinter; +import static com.shazam.fork.injector.stat.ExecutionTimeLineSummaryPrinterInjector.jsonSummaryStatsSerializer; import static com.shazam.fork.injector.summary.HtmlGeneratorInjector.htmlGenerator; import static com.shazam.fork.injector.summary.LogCatRetrieverInjector.logCatRetriever; import static com.shazam.fork.injector.system.FileManagerInjector.fileManager; @@ -25,7 +27,11 @@ public class SummaryPrinterInjector { private SummaryPrinterInjector() {} public static SummaryPrinter summaryPrinter() { - return new CompositeSummaryPrinter(consoleSummaryPrinter(), htmlSummaryPrinter(), jsonSummarySerializer()); + return new CompositeSummaryPrinter(consoleSummaryPrinter(), + htmlSummaryPrinter(), + jsonSummarySerializer(), + jsonSummaryStatsSerializer(), + htmlStatsSummaryPrinter()); } private static SummaryPrinter consoleSummaryPrinter() { diff --git a/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java b/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java index 58aaeedf..84bea560 100644 --- a/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java +++ b/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java @@ -15,7 +15,6 @@ import com.shazam.fork.device.DeviceLoader; import com.shazam.fork.model.Devices; import com.shazam.fork.model.Pool; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java index 642f0959..9a07dfc2 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java @@ -15,6 +15,7 @@ import java.util.Collection; import java.util.LinkedList; +import java.util.Queue; import java.util.concurrent.CountDownLatch; public class PoolTestRunnerFactory { @@ -25,7 +26,7 @@ public PoolTestRunnerFactory(DeviceTestRunnerFactory deviceTestRunnerFactory) { } public Runnable createPoolTestRunner(Pool pool, - Collection testCases, + Queue testCases, CountDownLatch poolCountDownLatch, ProgressReporter progressReporter) { @@ -35,7 +36,7 @@ public Runnable createPoolTestRunner(Pool pool, return new PoolTestRunner( deviceTestRunnerFactory, pool, - new LinkedList<>(testCases), + testCases, poolCountDownLatch, progressReporter); } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java index ae6fba46..48fb6d39 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java @@ -25,10 +25,14 @@ public class TestRunFactory { private final Configuration configuration; private final TestRunListenersFactory testRunListenersFactory; + private final TestCaseEventFactory factory; - public TestRunFactory(Configuration configuration, TestRunListenersFactory testRunListenersFactory) { + public TestRunFactory(Configuration configuration, + TestRunListenersFactory testRunListenersFactory, + TestCaseEventFactory factory) { this.configuration = configuration; this.testRunListenersFactory = testRunListenersFactory; + this.factory = factory; } public TestRun createTestRun(TestCaseEvent testCase, @@ -52,7 +56,8 @@ public TestRun createTestRun(TestCaseEvent testCase, device, pool, progressReporter, - queueOfTestsInPool); + queueOfTestsInPool, + factory); return new TestRun( pool.getName(), diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.java index b5a6d092..b2d80402 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.java @@ -18,6 +18,7 @@ import com.shazam.fork.model.Device; import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; +import com.shazam.fork.model.TestCaseEventFactory; import com.shazam.fork.runner.ProgressReporter; import com.shazam.fork.system.io.FileManager; import com.shazam.fork.system.io.FileType; @@ -27,7 +28,6 @@ import javax.annotation.Nonnull; -import static com.shazam.fork.model.TestCaseEvent.newTestCase; import static com.shazam.fork.summary.TestResult.SUMMARY_KEY_TOTAL_FAILURE_COUNT; public class ForkXmlTestRunListener extends XmlTestRunListener { @@ -36,6 +36,7 @@ public class ForkXmlTestRunListener extends XmlTestRunListener { private final Pool pool; private final Device device; private final TestCaseEvent testCase; + private final TestCaseEventFactory factory; @Nonnull private final ProgressReporter progressReporter; @@ -45,12 +46,14 @@ public ForkXmlTestRunListener(FileManager fileManager, Pool pool, Device device, TestCaseEvent testCase, - @Nonnull ProgressReporter progressReporter) { + @Nonnull ProgressReporter progressReporter, + TestCaseEventFactory factory) { this.fileManager = fileManager; this.pool = pool; this.device = device; this.testCase = testCase; this.progressReporter = progressReporter; + this.factory = factory; } @Override @@ -69,7 +72,7 @@ protected Map getPropertiesAttributes() { ImmutableMap.Builder mapBuilder = ImmutableMap.builder() .putAll(super.getPropertiesAttributes()); if (test != null) { - int testFailuresCount = progressReporter.getTestFailuresCount(pool, newTestCase(test)); + int testFailuresCount = progressReporter.getTestFailuresCount(pool, factory.newTestCase(test)); if (testFailuresCount > 0) { mapBuilder.put(SUMMARY_KEY_TOTAL_FAILURE_COUNT, Integer.toString(testFailuresCount)); } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java index 75abda9e..b6a9ad57 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java @@ -14,6 +14,7 @@ import com.shazam.fork.model.Device; import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; +import com.shazam.fork.model.TestCaseEventFactory; import com.shazam.fork.runner.ProgressReporter; import com.shazam.fork.system.io.FileManager; import com.shazam.fork.system.io.FileType; @@ -28,7 +29,6 @@ import javax.annotation.Nonnull; import static com.google.common.base.Preconditions.checkNotNull; -import static com.shazam.fork.model.TestCaseEvent.newTestCase; public class RetryListener extends NoOpITestRunListener { @@ -44,12 +44,14 @@ public class RetryListener extends NoOpITestRunListener { private ProgressReporter progressReporter; private FileManager fileManager; private Pool pool; + private final TestCaseEventFactory testCaseEventFactory; public RetryListener(@Nonnull Pool pool, @Nonnull Device device, @Nonnull Queue queueOfTestsInPool, @Nonnull TestCaseEvent currentTestCaseEvent, @Nonnull ProgressReporter progressReporter, - FileManager fileManager) { + FileManager fileManager, + TestCaseEventFactory testCaseEventFactory) { checkNotNull(device); checkNotNull(queueOfTestsInPool); checkNotNull(currentTestCaseEvent); @@ -61,19 +63,20 @@ public RetryListener(@Nonnull Pool pool, @Nonnull Device device, this.progressReporter = progressReporter; this.pool = pool; this.fileManager = fileManager; + this.testCaseEventFactory = testCaseEventFactory; } @Override public void testFailed(TestIdentifier test, String trace) { failedTest = test; - progressReporter.recordFailedTestCase(pool, newTestCase(failedTest)); + progressReporter.recordFailedTestCase(pool, testCaseEventFactory.newTestCase(failedTest)); } @Override public void testRunEnded(long elapsedTime, Map runMetrics) { super.testRunEnded(elapsedTime, runMetrics); if (failedTest != null) { - if (progressReporter.requestRetry(pool, newTestCase(failedTest))) { + if (progressReporter.requestRetry(pool, testCaseEventFactory.newTestCase(failedTest))) { queueOfTestsInPool.add(currentTestCaseEvent); logger.info("Test " + failedTest.toString() + " enqueued again into pool:" + pool.getName()); removeFailureTraceFiles(); diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java new file mode 100644 index 00000000..f3fa1ea8 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java @@ -0,0 +1,72 @@ +package com.shazam.fork.runner.listeners; + +import com.android.ddmlib.testrunner.ITestRunListener; +import com.android.ddmlib.testrunner.TestIdentifier; +import com.shazam.fork.model.Device; +import com.shazam.fork.stat.TestExecution; +import com.shazam.fork.stat.TestExecutionReporter; + +import java.util.Map; + +import static java.lang.System.currentTimeMillis; + +public class TestExecutionListener implements ITestRunListener { + + private long startTime = 0; + + private final Device device; + private final TestExecutionReporter executionReporter; + + private boolean failed; + + TestExecutionListener(Device device, + TestExecutionReporter executionReporter) { + this.device = device; + this.executionReporter = executionReporter; + } + + @Override + public void testRunStarted(String runName, int testCount) { + } + + @Override + public void testStarted(TestIdentifier test) { + startTime = currentTimeMillis(); + failed = false; + } + + @Override + public void testFailed(TestIdentifier test, String trace) { + failed = true; + } + + @Override + public void testAssumptionFailure(TestIdentifier test, String trace) { + } + + @Override + public void testIgnored(TestIdentifier test) { + } + + @Override + public void testEnded(TestIdentifier test, Map testMetrics) { + long endedAfter = currentTimeMillis() - startTime; + TestExecution execution = new TestExecution(test, + startTime, + endedAfter, + failed ? TestExecution.Status.FAILED : TestExecution.Status.ENDED); + executionReporter.add(device, execution); + } + + @Override + public void testRunFailed(String errorMessage) { + } + + @Override + public void testRunStopped(long elapsedTime) { + } + + @Override + public void testRunEnded(long elapsedTime, Map runMetrics) { + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java index 2b8569cb..2742fc70 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java @@ -16,7 +16,9 @@ import com.shazam.fork.model.Device; import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; +import com.shazam.fork.model.TestCaseEventFactory; import com.shazam.fork.runner.ProgressReporter; +import com.shazam.fork.stat.TestExecutionReporter; import com.shazam.fork.system.io.FileManager; import java.io.File; @@ -32,40 +34,46 @@ public class TestRunListenersFactory { private final Configuration configuration; private final FileManager fileManager; private final Gson gson; + private final TestExecutionReporter testExecutionReporter; public TestRunListenersFactory(Configuration configuration, FileManager fileManager, - Gson gson) { + Gson gson, + TestExecutionReporter testExecutionReporter) { this.configuration = configuration; this.fileManager = fileManager; this.gson = gson; + this.testExecutionReporter = testExecutionReporter; } public List createTestListeners(TestCaseEvent testCase, Device device, Pool pool, ProgressReporter progressReporter, - Queue testCaseEventQueue) { + Queue testCaseEventQueue, + TestCaseEventFactory factory) { return asList( new ProgressTestRunListener(pool, progressReporter), - getForkXmlTestRunListener(fileManager, configuration.getOutput(), pool, device, testCase, progressReporter), + getForkXmlTestRunListener(fileManager, configuration.getOutput(), pool, device, testCase, progressReporter, factory), new ConsoleLoggingTestRunListener(configuration.getTestPackage(), device.getSerial(), device.getModelName(), progressReporter), new LogCatTestRunListener(gson, fileManager, pool, device), new SlowWarningTestRunListener(), + new TestExecutionListener(device, testExecutionReporter), getScreenTraceTestRunListener(fileManager, pool, device), - new RetryListener(pool, device, testCaseEventQueue, testCase, progressReporter, fileManager), + new RetryListener(pool, device, testCaseEventQueue, testCase, progressReporter, fileManager, factory), getCoverageTestRunListener(configuration, device, fileManager, pool, testCase)); } private ForkXmlTestRunListener getForkXmlTestRunListener(FileManager fileManager, - File output, - Pool pool, - Device device, - TestCaseEvent testCase, - ProgressReporter progressReporter) { - ForkXmlTestRunListener xmlTestRunListener = new ForkXmlTestRunListener(fileManager, pool, device, testCase, progressReporter); + File output, + Pool pool, + Device device, + TestCaseEvent testCase, + ProgressReporter progressReporter, + TestCaseEventFactory factory) { + ForkXmlTestRunListener xmlTestRunListener = new ForkXmlTestRunListener(fileManager, pool, device, testCase, progressReporter, factory); xmlTestRunListener.setReportDir(output); return xmlTestRunListener; } diff --git a/fork-runner/src/main/java/com/shazam/fork/sorting/QueueProvider.java b/fork-runner/src/main/java/com/shazam/fork/sorting/QueueProvider.java new file mode 100644 index 00000000..3b773868 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/sorting/QueueProvider.java @@ -0,0 +1,24 @@ +package com.shazam.fork.sorting; + +import com.shazam.fork.Configuration; +import com.shazam.fork.model.TestCaseEvent; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.Queue; + +public class QueueProvider { + + private final Configuration configuration; + + public QueueProvider(Configuration configuration) { + this.configuration = configuration; + } + + public Queue create() { + if (configuration.getSortingStrategy().statistics != null) { + return new SortedTestQueue(); + } + return new LinkedList<>(); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/sorting/SortedTestQueue.java b/fork-runner/src/main/java/com/shazam/fork/sorting/SortedTestQueue.java new file mode 100644 index 00000000..ff4516ef --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/sorting/SortedTestQueue.java @@ -0,0 +1,19 @@ +package com.shazam.fork.sorting; + +import com.shazam.fork.model.TestCaseEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.PriorityBlockingQueue; + +class SortedTestQueue extends PriorityBlockingQueue { + private static final TestComparator comparator = new TestComparator(); + private static final int DEFAULT_INITIAL_CAPACITY = 100; + + SortedTestQueue() { + super(DEFAULT_INITIAL_CAPACITY, comparator); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/sorting/Stats.java b/fork-runner/src/main/java/com/shazam/fork/sorting/Stats.java new file mode 100644 index 00000000..f3de59e0 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/sorting/Stats.java @@ -0,0 +1,5 @@ +package com.shazam.fork.sorting; + +public class Stats { + public String path; +} diff --git a/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java b/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java new file mode 100644 index 00000000..8432c259 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java @@ -0,0 +1,24 @@ +package com.shazam.fork.sorting; + +import com.shazam.fork.model.TestCaseEvent; + +import java.util.Comparator; + +class TestComparator implements Comparator { + private static Comparator getDefaultComparator() { + return Comparator.comparingDouble(value -> + Math.sqrt(value.getTestMetric().getVariance()) * 2 + value.getTestMetric().getExpectedValue() + ).reversed(); + } + + @Override + public int compare(TestCaseEvent o1, TestCaseEvent o2) { + if (o1.getTestMetric().getVariance() == 0 || o1.getTestMetric().getExpectedValue() == 0) { + return -1; + } else if (o2.getTestMetric().getVariance() == 0 || o2.getTestMetric().getExpectedValue() == 0) { + return 1; + } else { + return getDefaultComparator().compare(o1, o2); + } + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java new file mode 100644 index 00000000..1a92dfe7 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java @@ -0,0 +1,39 @@ +package com.shazam.fork.stat; + +import com.android.ddmlib.testrunner.TestIdentifier; + +public class TestExecution { + + public enum Status { + FAILED, + ENDED + } + + private final TestIdentifier test; + private final long startTime; + private final long endTime; + private final Status status; + + public TestExecution(TestIdentifier test, long startTime, long endTime, Status status) { + this.test = test; + this.startTime = startTime; + this.endTime = endTime; + this.status = status; + } + + public TestIdentifier getTest() { + return test; + } + + public long getStartTime() { + return startTime; + } + + public long getEndTime() { + return endTime; + } + + public Status getStatus() { + return status; + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/stat/TestExecutionReporter.java b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecutionReporter.java new file mode 100644 index 00000000..d003628d --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecutionReporter.java @@ -0,0 +1,25 @@ +package com.shazam.fork.stat; + +import com.shazam.fork.model.Device; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +public class TestExecutionReporter { + + private final ConcurrentHashMap> tests = new ConcurrentHashMap<>(); + + public void add(Device device, TestExecution time) { + tests.computeIfPresent(device, (testIdentifier, testExecutionTimes) -> { + testExecutionTimes.add(time); + return testExecutionTimes; + }); + tests.computeIfAbsent(device, testIdentifier -> new ArrayList<>()); + } + + public List getTests(Device device) { + return tests.get(device); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/stat/TestHistoryManager.java b/fork-runner/src/main/java/com/shazam/fork/stat/TestHistoryManager.java new file mode 100644 index 00000000..be6b0f67 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/stat/TestHistoryManager.java @@ -0,0 +1,27 @@ +package com.shazam.fork.stat; + +import com.agoda.fork.stat.TestHistory; +import com.android.ddmlib.testrunner.TestIdentifier; + +import java.util.Collection; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +public class TestHistoryManager { + private final ConcurrentHashMap map = new ConcurrentHashMap<>(); + + public void addTestHistories(Collection testHistoryList) { + for (TestHistory history : testHistoryList) { + addTestHistory(history); + } + } + + public void addTestHistory(TestHistory testHistory) { + TestIdentifier testIdentifier = new TestIdentifier(testHistory.getTestClass(), testHistory.getTestMethod()); + map.put(testIdentifier, testHistory); + } + + public Optional getTestHistory(TestIdentifier testIdentifier) { + return Optional.ofNullable(map.get(testIdentifier)); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Data.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Data.java new file mode 100644 index 00000000..7b32df3c --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Data.java @@ -0,0 +1,43 @@ +package com.shazam.fork.summary.executiontimeline; + +public class Data { + private final String testName; + private final int status; + private final long startDate; + private final long endDate; + private final double expectedValue; + private final double variance; + + public Data(String testName, int status, long startDate, long endDate, double expectedValue, double variance) { + this.testName = testName; + this.status = status; + this.startDate = startDate; + this.endDate = endDate; + this.expectedValue = expectedValue; + this.variance = variance; + } + + public String getTestName() { + return testName; + } + + public int getStatus() { + return status; + } + + public long getStartDate() { + return startDate; + } + + public long getEndDate() { + return endDate; + } + + public double getExpectedValue() { + return expectedValue; + } + + public double getVariance() { + return variance; + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/DateSerializer.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/DateSerializer.java new file mode 100644 index 00000000..15410eb9 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/DateSerializer.java @@ -0,0 +1,24 @@ +package com.shazam.fork.summary.executiontimeline; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DateSerializer extends TypeAdapter { + + private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + + @Override + public void write(JsonWriter out, Date value) throws IOException { + out.value(format.format(value)); + } + + @Override + public Date read(JsonReader in) throws IOException { + throw new UnsupportedOperationException(); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/ExecutionResult.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/ExecutionResult.java new file mode 100644 index 00000000..4a80af29 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/ExecutionResult.java @@ -0,0 +1,33 @@ +package com.shazam.fork.summary.executiontimeline; + +import java.util.List; + +public class ExecutionResult { + private final int passedTests; + private final int failedTests; + private final ExecutionStats executionStats; + private final List measures; + + public ExecutionResult(int passedTests, int failedTests, ExecutionStats executionStats, List measures) { + this.passedTests = passedTests; + this.failedTests = failedTests; + this.executionStats = executionStats; + this.measures = measures; + } + + public int getPassedTests() { + return passedTests; + } + + public int getFailedTests() { + return failedTests; + } + + public ExecutionStats getExecutionStats() { + return executionStats; + } + + public List getMeasures() { + return measures; + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/ExecutionStats.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/ExecutionStats.java new file mode 100644 index 00000000..ef3888f0 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/ExecutionStats.java @@ -0,0 +1,19 @@ +package com.shazam.fork.summary.executiontimeline; + +public class ExecutionStats { + private long idleTimeMillis; + private long averageTestExecutionTimeMillis; + + public ExecutionStats(long idleTimeMillis, long averageTestExecutionTimeMillis) { + this.idleTimeMillis = idleTimeMillis; + this.averageTestExecutionTimeMillis = averageTestExecutionTimeMillis; + } + + public long getIdleTimeMillis() { + return idleTimeMillis; + } + + public long getAverageTestExecutionTimeMillis() { + return averageTestExecutionTimeMillis; + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/HtmlStatsSummaryPrinter.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/HtmlStatsSummaryPrinter.java new file mode 100644 index 00000000..1ecb38bf --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/HtmlStatsSummaryPrinter.java @@ -0,0 +1,56 @@ +package com.shazam.fork.summary.executiontimeline; + +import com.google.gson.Gson; +import com.shazam.fork.io.HtmlGenerator; +import com.shazam.fork.summary.Summary; +import com.shazam.fork.summary.SummaryPrinter; + +import java.io.File; + +import static com.shazam.fork.io.Files.copyResource; + +public class HtmlStatsSummaryPrinter implements SummaryPrinter { + private static final String HTML_OUTPUT = "html"; + private static final String STATIC = "static"; + private static final String INDEX_FILENAME = "stat.html"; + private static final String[] STATIC_ASSETS = { + "chart.css", + "chart.js" + }; + private final File htmlOutput; + private final File staticOutput; + private final HtmlGenerator htmlGenerator; + private final StatSummarySerializer serializer; + private final Gson gson; + + public HtmlStatsSummaryPrinter(File rootOutput, HtmlGenerator htmlGenerator, + StatSummarySerializer serializer, + Gson gson) { + this.htmlGenerator = htmlGenerator; + htmlOutput = new File(rootOutput, HTML_OUTPUT); + staticOutput = new File(htmlOutput, STATIC); + this.serializer = serializer; + this.gson = gson; + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Override + public void print(Summary summary) { + htmlOutput.mkdirs(); + copyAssets(); + StatHtmlSummary statHtmlSummary = toStatHtmlSummary(summary); + htmlGenerator.generateHtml("stat/index.html", htmlOutput, INDEX_FILENAME, statHtmlSummary); + } + + private StatHtmlSummary toStatHtmlSummary(Summary summary) { + StatHtmlSummary statHtmlSummary = new StatHtmlSummary(); + statHtmlSummary.dataset = gson.toJson(serializer.parse(summary)); + return statHtmlSummary; + } + + private void copyAssets() { + for (String asset : STATIC_ASSETS) { + copyResource("/static/", asset, staticOutput); + } + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/JsonStatsSummarySerializer.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/JsonStatsSummarySerializer.java new file mode 100644 index 00000000..bf5666f5 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/JsonStatsSummarySerializer.java @@ -0,0 +1,44 @@ +package com.shazam.fork.summary.executiontimeline; + +import com.google.gson.Gson; +import com.shazam.fork.summary.Summary; +import com.shazam.fork.summary.SummaryPrinter; +import com.shazam.fork.system.io.FileManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import static org.apache.commons.io.IOUtils.closeQuietly; + +public class JsonStatsSummarySerializer implements SummaryPrinter { + + private static final Logger logger = LoggerFactory.getLogger(JsonStatsSummarySerializer.class); + private final FileManager fileManager; + private final Gson gson; + private final StatSummarySerializer serializer; + + public JsonStatsSummarySerializer(FileManager fileManager, Gson gson, StatSummarySerializer serializer) { + this.fileManager = fileManager; + this.gson = gson; + this.serializer = serializer; + } + + @Override + public void print(Summary summary) { + ExecutionResult result = serializer.parse(summary); + FileWriter writer = null; + try { + File summaryFile = fileManager.createSummaryFile(); + writer = new FileWriter(summaryFile); + gson.toJson(result, writer); + writer.flush(); + } catch (IOException e) { + logger.error("Could not serialize the summary.", e); + } finally { + closeQuietly(writer); + } + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Measure.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Measure.java new file mode 100644 index 00000000..4a91307f --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Measure.java @@ -0,0 +1,35 @@ +package com.shazam.fork.summary.executiontimeline; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + + +public class Measure { + @SerializedName("measure") + private final String measure; + + @SerializedName("stats") + private final ExecutionStats executionStats; + + @SerializedName("data") + private final List data; + + public Measure(String measure, ExecutionStats executionStats, List data) { + this.measure = measure; + this.executionStats = executionStats; + this.data = data; + } + + public String getMeasure() { + return measure; + } + + public ExecutionStats getExecutionStats() { + return executionStats; + } + + public List getData() { + return data; + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatHtmlSummary.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatHtmlSummary.java new file mode 100644 index 00000000..fd6f5476 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatHtmlSummary.java @@ -0,0 +1,5 @@ +package com.shazam.fork.summary.executiontimeline; + +public class StatHtmlSummary { + public String dataset; +} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java new file mode 100644 index 00000000..9e5b6a1c --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java @@ -0,0 +1,137 @@ +package com.shazam.fork.summary.executiontimeline; + +import com.agoda.fork.stat.TestHistory; +import com.agoda.fork.stat.TestMetric; +import com.android.ddmlib.testrunner.TestIdentifier; +import com.shazam.fork.model.Device; +import com.shazam.fork.stat.TestExecution; +import com.shazam.fork.stat.TestExecutionReporter; +import com.shazam.fork.stat.TestHistoryManager; +import com.shazam.fork.stat.TestStatsLoader; +import com.shazam.fork.summary.PoolSummary; +import com.shazam.fork.summary.Summary; +import com.shazam.fork.summary.TestResult; + +import java.util.List; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; + +public class StatSummarySerializer { + + private final TestExecutionReporter reporter; + private final TestStatsLoader testStatsLoader; + + public StatSummarySerializer(TestExecutionReporter reporter, + TestStatsLoader testStatsLoader) { + this.reporter = reporter; + this.testStatsLoader = testStatsLoader; + } + + private String prepareTestName(String fullTestName) { + return fullTestName.substring(fullTestName.lastIndexOf('.') + 1); + } + + private Stream parseData(Device device) { + List executions = reporter.getTests(device); + return executions.stream().map(this::convertToData); + } + + private Data convertToData(TestExecution execution) { + int status = convertStatus(execution); + String preparedTestName = prepareTestName(execution.getTest().toString()); + TestMetric testMetric = getTestMetric(execution); + return createData(execution, status, preparedTestName, testMetric); + } + + private int convertStatus(TestExecution execution) { + return execution.getStatus() == TestExecution.Status.ENDED ? 1 : 0; + } + + private Data createData(TestExecution execution, int status, String preparedTestName, TestMetric testMetric) { + return new Data(preparedTestName, status, + execution.getStartTime(), + execution.getStartTime() + execution.getEndTime(), + testMetric.getExpectedValue(), testMetric.getVariance()); + } + + private TestMetric getTestMetric(TestExecution execution) { + return testStatsLoader.findMetric(execution.getTest()); + } + + private ExecutionStats calculateExecutionStats(List data) { + + return new ExecutionStats(calculateIdle(data), calculateAverageExecutionTime(data)); + } + + private long calculateAverageExecutionTime(List data) { + return (long) data.stream() + .mapToLong(this::calculateDuration) + .average() + .orElse(0.0); + } + + private long calculateDuration(Data a) { + return a.getEndDate() - a.getStartDate(); + } + + private Long calculateIdle(List data) { + if (data.size() == 0) return 0L; + long time = 0; + for (int i = 1; i < data.size(); i++) { + time += data.get(i).getStartDate() - data.get(i - 1).getEndDate(); + } + return time; + } + + private Measure createMeasure(Device device) { + List data = parseData(device).collect(toList()); + return new Measure(device.getSerial(), calculateExecutionStats(data), data); + } + + private Stream parsePoolSummary(PoolSummary poolSummary) { + return poolSummary.getTestResults() + .stream() + .map(TestResult::getDevice) + .distinct() + .map(this::createMeasure); + } + + + private List parseList(List poolSummaries) { + return poolSummaries.stream().flatMap(this::parsePoolSummary).collect(toList()); + } + + private Stream extractIdentifiers(PoolSummary summary) { + return summary.getTestResults() + .stream() + .map(result -> new TestIdentifier(result.getTestClass(), result.getTestMethod())); + } + + private int passedTestCount(Summary summary) { + return (int) summary.getPoolSummaries() + .stream() + .flatMap(this::extractIdentifiers) + .distinct() + .count(); + } + + private ExecutionStats aggregateExecutionStats(List list) { + long summaryIdle = 0; + long avgTestExecutionTime = 0; + for (Measure measure : list) { + summaryIdle += measure.getExecutionStats().getIdleTimeMillis(); + avgTestExecutionTime += measure.getExecutionStats().getAverageTestExecutionTimeMillis(); + } + avgTestExecutionTime = avgTestExecutionTime / list.size(); + return new ExecutionStats(summaryIdle, avgTestExecutionTime); + } + + public ExecutionResult parse(Summary summary) { + int failedTests = summary.getFailedTests().size(); + int ignoredTests = summary.getIgnoredTests().size(); + int passedTestCount = passedTestCount(summary) - ignoredTests - failedTests; + List measures = parseList(summary.getPoolSummaries()); + return new ExecutionResult(passedTestCount, failedTests, aggregateExecutionStats(measures), measures); + } +} diff --git a/fork-runner/src/main/resources/stat/index.html b/fork-runner/src/main/resources/stat/index.html new file mode 100755 index 00000000..86fa71d2 --- /dev/null +++ b/fork-runner/src/main/resources/stat/index.html @@ -0,0 +1,38 @@ + + + + + + Test Execution + + + + + + + +

Test execution result

+ +

+ + + + + + + + + + + + + diff --git a/fork-runner/src/main/resources/static/chart.css b/fork-runner/src/main/resources/static/chart.css new file mode 100755 index 00000000..96e68dd2 --- /dev/null +++ b/fork-runner/src/main/resources/static/chart.css @@ -0,0 +1,85 @@ +.rect_passed_test { + fill: #5cb85c; +} + +.rect_passed_test:hover { + fill: #449d44 +} + +.rect_failed_test { + fill: #d9534d; +} + +.rect_failed_test:hover { + fill: #c9302c; +} + +.tooltip_passed_test { + color: #449d44; +} + +.tooltip_failed_test { + color: #c9302c; +} + +div.tooltip { + position: absolute; + text-align: left; + font-size: 10px; + padding-left: 0; + width: auto; + border: 0; + border-left: thin solid #000000; + pointer-events: none; + line-height: 12px; + padding-top: 0; + display: block; +} + +.ytitle { + dominant-baseline: central; + font-size: 12px; +} + +.ytitle.link { + cursor: pointer; + fill: #07C; +} + +.axis path, +.axis line { + display: none; +} + +.axis text { + font-size: 12px; + fill: #777; +} + +.vert_grid { + fill: none; + stroke: #dddddd; + stroke-width: 1px; +} + +.horz_grid { + fill: none; + stroke: #dddddd; + stroke-width: 1px; +} + +.heading { + font-size: 16px; + font-weight: bold; +} + +.subheading { + font-size: 12px; + fill: #777; +} + +.legend { + dominant-baseline: central; + font-size: 12px; + fill: #777; +} \ No newline at end of file diff --git a/fork-runner/src/main/resources/static/chart.js b/fork-runner/src/main/resources/static/chart.js new file mode 100755 index 00000000..af51b03b --- /dev/null +++ b/fork-runner/src/main/resources/static/chart.js @@ -0,0 +1,328 @@ +function testsChart() { + var margin = { + top: 70, + right: 40, + bottom: 20, + left: 150 + }; + + var dataHeight = 18; + var lineSpacing = 30; + var paddingTopHeading = -50; + var paddingBottom = 10; + var paddingLeft = -150; + var width = 1200 - margin.left - margin.right; + + var div = d3.select('body').append('div') + .attr('class', 'tooltip') + .style('opacity', 0); + + function renderLegend(svg, success, failed, dataset) { + var legend = svg.select('#g_title') + .append('g') + .attr('id', 'g_legend') + .attr('transform', 'translate(0,-12)'); + + legend.append('rect') + .attr('x', width + margin.right - 150) + .attr('y', paddingTopHeading) + .attr('height', 15) + .attr('width', 15) + .attr('class', 'rect_passed_test'); + + legend.append('text') + .attr('x', width + margin.right - 150 + 20) + .attr('y', paddingTopHeading + 8.5) + .text('Passed test = ' + success) + .attr('class', 'legend'); + + legend.append('rect') + .attr('x', width + margin.right - 150) + .attr('y', paddingTopHeading + 17) + .attr('height', 15) + .attr('width', 15) + .attr('class', 'rect_failed_test'); + + legend.append('text') + .attr('x', width + margin.right - 150 + 20) + .attr('y', paddingTopHeading + 8.5 + 15 + 2) + .text('Failed test = ' + failed) + .attr('class', 'legend'); + + var deviceCount = dataset.measures.length; + var idle = dataset.executionStats.idleTimeMillis; + var averageIdle = idle / deviceCount; + + legend.append('text') + .attr('x', width + margin.right - 350) + .attr('y', paddingTopHeading + 8.5 + 15 + 2) + .text('Summary idle: ' + Math.round(moment.duration(idle).asSeconds()).toFixed(2) + " sec") + .attr('class', 'legend'); + + legend.append('text') + .attr('x', width + margin.right - 350) + .attr('y', paddingTopHeading + 8.5) + .text('Average Idle: ' + Math.round(moment.duration(averageIdle).asSeconds()).toFixed(2) + " sec") + .attr('class', 'legend'); + } + + function convertDate(date) { + var dateFormat = d3.time.format('%Y-%m-%d %H:%M:%S'); + return dateFormat(date) + } + + function renderTitle(svg, startDate, finishDate) { + svg.select('#g_title') + .append('text') + .attr('x', paddingLeft) + .attr('y', paddingTopHeading) + .text('Test run results') + .attr('class', 'heading'); + + var subtitleText = 'from ' + moment(convertDate(startDate)).format('l') + ' ' + + moment(convertDate(startDate)).format('LTS') + ' to ' + + moment(convertDate(finishDate)).format('l') + ' ' + + moment(convertDate(finishDate)).format('LTS'); + + svg.select('#g_title') + .append('text') + .attr('x', paddingLeft) + .attr('y', paddingTopHeading + 17) + .text(subtitleText) + .attr('class', 'subheading'); + } + + function renderTests(svg, dataset, startSet, endSet, xScale) { + var g = svg.select('#g_data').selectAll('.g_data') + .data(dataset.measures.slice(startSet, endSet)) + .enter() + .append('g') + .attr('transform', function (d, i) { + return 'translate(0,' + ((lineSpacing + dataHeight) * i) + ')'; + }) + .attr('class', 'dataset'); + + g.selectAll('rect') + .data(function (d) { + return d.data; + }) + .enter() + .append('rect') + .attr('x', function (d) { + return xScale(d.startDate); + }) + .attr('y', lineSpacing) + .attr('width', function (d) { + return (xScale(d.endDate) - xScale(d.startDate)); + }) + .attr('height', dataHeight) + .attr('class', function (d) { + if (d.status === 1) { + return 'rect_passed_test'; + } else { + return 'rect_failed_test'; + } + }) + .on('mouseover', function (d, i) { + var matrix = this.getScreenCTM().translate(+this.getAttribute('x'), +this.getAttribute('y')); + div.transition() + .duration(200) + .style('opacity', 0.9); + div.html(function () { + var output = ''; + if (d.status === 1) { + output = ''; + } else { + output = ''; + } + return output + d.testName + '
' + + moment(convertDate(d.startDate)).format('LTS') + ' - ' + + moment(convertDate(d.endDate)).format('LTS') + '| variance = ' + d.variance.toFixed(2) + ' expected = ' + d.expectedValue.toFixed(2); + }).style('left', function () { + return window.pageXOffset + matrix.e + 'px'; + }).style('top', function () { + return window.pageYOffset + matrix.f - 25 + 'px'; + }).style('height', dataHeight + 25 + 'px'); + }) + .on('mouseout', function () { + div.transition() + .duration(500) + .style('opacity', 0); + }); + } + + function renderTime(svg, xAxis) { + svg.select('#g_axis').append('g') + .attr('class', 'axis') + .call(xAxis); + } + + function renderGrid(svg, xScale, noOfDatasets, dataset) { + svg.select('#g_axis').selectAll('line.vert_grid').data(xScale.ticks().concat(xScale.domain())) + .enter() + .append('line') + .attr({ + 'class': 'vert_grid', + 'x1': function (d) { + return xScale(d); + }, + 'x2': function (d) { + return xScale(d); + }, + 'y1': 0, + 'y2': dataHeight * noOfDatasets + lineSpacing * noOfDatasets - 1 + paddingBottom + }); + + svg.select('#g_axis').selectAll('line.horz_grid').data(dataset.measures) + .enter() + .append('line') + .attr({ + 'class': 'horz_grid', + 'x1': 0, + 'x2': width, + 'y1': function (d, i) { + return ((lineSpacing + dataHeight) * i) + lineSpacing + dataHeight / 2; + }, + 'y2': function (d, i) { + return ((lineSpacing + dataHeight) * i) + lineSpacing + dataHeight / 2; + } + }); + } + + function calculateScale(startDate, finishDate) { + return d3.time.scale() + .domain([startDate, finishDate]) + .range([0, width]) + .clamp(1); + } + + function calculateAxis(xScale) { + return d3.svg.axis() + .scale(xScale) + .tickFormat(d3.time.format("%M:%S")) + .orient('top'); + } + + function prepareDates(dataset) { + dataset.measures.forEach(function (d) { + d.data.forEach(function (d1) { + d1.startDate = new Date(d1.startDate); + d1.endDate = new Date(d1.endDate); + }); + d.data.sort(function (a, b) { + return a.startDate - b.startDate; + }); + }); + } + + function chart(selection) { + selection.each(function drawGraph(dataset) { + var startSet = 0; + var endSet = dataset.measures.length; + + var noOfDatasets = endSet - startSet; + var height = dataHeight * noOfDatasets + lineSpacing * noOfDatasets - 1; + + var success = dataset.passedTests; + var failed = dataset.failedTests; + + prepareDates(dataset); + + var startDate = 0; + var finishDate = 0; + var firstFinishDate = 0; + + dataset.measures.forEach(function (series) { + if (series.data.length > 0) { + if (startDate === 0) { + startDate = series.data[0].startDate; + finishDate = series.data[series.data.length - 1].endDate; + firstFinishDate = series.data[series.data.length - 1].endDate; + } else { + if (series.data[0].startDate < startDate) { + startDate = series.data[0].startDate; + } + if (series.data[series.data.length - 1].endDate > finishDate) { + finishDate = series.data[series.data.length - 1].endDate; + } + if (series.data[series.data.length - 1].endDate < firstFinishDate) { + firstFinishDate = series.data[series.data.length - 1].endDate; + } + } + } + }); + + var scale = calculateScale(startDate, finishDate); + + var axis = calculateAxis(scale); + + axis.tickValues(scale.ticks().concat(scale.domain())); + + var svg = d3.select(this).append('svg') + .attr('width', width + margin.left + margin.right) + .attr('height', height + margin.top + margin.bottom) + .append('g') + .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); + + svg.append('g').attr('id', 'g_title'); + svg.append('g').attr('id', 'g_axis'); + svg.append('g').attr('id', 'g_data'); + + var labels = svg.select('#g_axis').selectAll('text') + .data(dataset.measures) + .enter(); + + labels.append('text') + .attr('x', paddingLeft) + .attr('y', lineSpacing + dataHeight / 2) + .text(function (d) { + if (!(d.measure_html != null)) { + return d.measure; + } + }) + .attr('transform', function (d, i) { + return 'translate(0,' + ((lineSpacing + dataHeight) * i) + ')'; + }) + .attr('class', function (d) { + var returnCSSClass = 'ytitle'; + if (d.measure_url != null) { + returnCSSClass = returnCSSClass + ' link'; + } + return returnCSSClass; + }) + .on('click', function (d) { + if (d.measure_url != null) { + return window.open(d.measure_url); + } + return null; + }); + + labels.append('foreignObject') + .attr('x', paddingLeft) + .attr('y', lineSpacing) + .attr('transform', function (d, i) { + return 'translate(0,' + ((lineSpacing + dataHeight) * i) + ')'; + }) + .attr('width', -1 * paddingLeft) + .attr('height', dataHeight) + .attr('class', 'ytitle') + .html(function (d) { + if (d.measure_html != null) { + return d.measure_html; + } + }); + + renderGrid(svg, scale, noOfDatasets, dataset); + + renderTime(svg, axis); + + renderTests(svg, dataset, startSet, endSet, scale); + + renderTitle(svg, startDate, finishDate); + + renderLegend(svg, success, failed, dataset); + }); + } + + return chart; +} diff --git a/fork-runner/src/test/java/com/shazam/fork/model/PoolTestCaseAccumulatorTestFailure.java b/fork-runner/src/test/java/com/shazam/fork/model/PoolTestCaseAccumulatorTestFailure.java index 9369a33c..8c54e000 100644 --- a/fork-runner/src/test/java/com/shazam/fork/model/PoolTestCaseAccumulatorTestFailure.java +++ b/fork-runner/src/test/java/com/shazam/fork/model/PoolTestCaseAccumulatorTestFailure.java @@ -1,10 +1,11 @@ package com.shazam.fork.model; +import com.shazam.fork.stat.StatServiceLoader; +import com.shazam.fork.stat.TestStatsLoader; import org.junit.Before; import org.junit.Test; import static com.shazam.fork.model.Device.Builder.aDevice; -import static com.shazam.fork.model.TestCaseEvent.newTestCase; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static org.hamcrest.CoreMatchers.equalTo; @@ -28,9 +29,10 @@ public class PoolTestCaseAccumulatorTestFailure { .withName("another_pool") .addDevice(ANOTHER_DEVICE) .build(); - - private final TestCaseEvent A_TEST_CASE = newTestCase("a_method", "a_class", false, emptyList(), emptyMap()); - private final TestCaseEvent ANOTHER_TEST_CASE = newTestCase("another_method", "a_class", false, emptyList(), emptyMap()); + + private final TestCaseEventFactory factory = new TestCaseEventFactory(new TestStatsLoader(new StatServiceLoader(""))); + private final TestCaseEvent A_TEST_CASE = factory.newTestCase("a_method", "a_class", false, emptyList(), emptyMap()); + private final TestCaseEvent ANOTHER_TEST_CASE = factory.newTestCase("another_method", "a_class", false, emptyList(), emptyMap()); PoolTestCaseFailureAccumulator subject; diff --git a/fork-runner/src/test/java/com/shazam/fork/runner/OverallProgressReporterTest.java b/fork-runner/src/test/java/com/shazam/fork/runner/OverallProgressReporterTest.java index d96a1c5a..811e499e 100644 --- a/fork-runner/src/test/java/com/shazam/fork/runner/OverallProgressReporterTest.java +++ b/fork-runner/src/test/java/com/shazam/fork/runner/OverallProgressReporterTest.java @@ -4,6 +4,9 @@ import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; +import com.shazam.fork.model.TestCaseEventFactory; +import com.shazam.fork.stat.StatServiceLoader; +import com.shazam.fork.stat.TestStatsLoader; import org.jmock.Expectations; import org.jmock.auto.Mock; import org.jmock.integration.junit4.JUnitRuleMockery; @@ -12,7 +15,6 @@ import static com.shazam.fork.model.Device.Builder.aDevice; import static com.shazam.fork.model.Pool.Builder.aDevicePool; -import static com.shazam.fork.model.TestCaseEvent.newTestCase; import static com.shazam.fork.runner.FakePoolTestCaseAccumulator.aFakePoolTestCaseAccumulator; import static com.shazam.fork.runner.FakeProgressReporterTrackers.aFakeProgressReporterTrackers; import static java.util.Collections.emptyList; @@ -20,15 +22,18 @@ public class OverallProgressReporterTest { - @Rule public JUnitRuleMockery mockery = new JUnitRuleMockery(); - @Mock private PoolProgressTracker mockPoolProgressTracker; + @Rule + public JUnitRuleMockery mockery = new JUnitRuleMockery(); + @Mock + private PoolProgressTracker mockPoolProgressTracker; private final FakePoolTestCaseAccumulator fakeTestCasesAccumulator = aFakePoolTestCaseAccumulator(); private final Device A_DEVICE = aDevice().build(); private final Pool A_POOL = aDevicePool() .addDevice(A_DEVICE) .build(); - private final TestCaseEvent A_TEST_CASE = newTestCase("aTestMethod", "aTestClass", false, emptyList(), emptyMap()); + private final TestCaseEventFactory factory = new TestCaseEventFactory(new TestStatsLoader(new StatServiceLoader(""))); + private final TestCaseEvent A_TEST_CASE = factory.newTestCase("aTestMethod", "aTestClass", false, emptyList(), emptyMap()); private OverallProgressReporter overallProgressReporter; diff --git a/fork-stat-common/build.gradle b/fork-stat-common/build.gradle new file mode 100644 index 00000000..8621c1d3 --- /dev/null +++ b/fork-stat-common/build.gradle @@ -0,0 +1,23 @@ +apply plugin: 'java-library' +apply from: '../build-scripts/gradle-mvn-push.gradle' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + api "com.google.code.findbugs:jsr305:3.0.1" +} + +jar { + manifest { + attributes 'Implementation-Title': POM_NAME, + 'Implementation-Version': VERSION_NAME, + 'Built-By': System.getProperty('user.name'), + 'Built-Date': new Date(), + 'Built-JDK': System.getProperty('java.version'), + 'Built-Gradle': gradle.gradleVersion + } +} diff --git a/fork-stat-common/gradle.properties b/fork-stat-common/gradle.properties new file mode 100644 index 00000000..f251cbbc --- /dev/null +++ b/fork-stat-common/gradle.properties @@ -0,0 +1,4 @@ +POM_ARTIFACT_ID=fork-stat-common +POM_NAME=Fork Stat Common +POM_PACKAGING=jar +POM_DESCRIPTION=A library that parallelizes Android Test execution to all connected devices and emulators diff --git a/fork-stat-common/src/main/java/com/agoda/fork/stat/MathUtils.java b/fork-stat-common/src/main/java/com/agoda/fork/stat/MathUtils.java new file mode 100644 index 00000000..744c3360 --- /dev/null +++ b/fork-stat-common/src/main/java/com/agoda/fork/stat/MathUtils.java @@ -0,0 +1,39 @@ +package com.agoda.fork.stat; + +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class MathUtils { + public static double expectedValue(List list) { + return prepareData(list).entrySet() + .stream() + .map(e -> e.getKey() * e.getValue()) + .reduce((acc, v) -> acc + v) + .orElse(0.0); + } + + public static double variance(List list, double expectedValue) { + return prepareData(list).entrySet() + .stream() + .map(e -> Math.pow(e.getKey() - expectedValue, 2.0) * e.getValue()) + .reduce((acc, value) -> acc + value) + .orElse(0.0); + } + + private static Map prepareData(List list) { + double defP = 1.0 / list.size(); + + return list.stream() + .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) + .entrySet() + .stream() + .map(entry -> { + double p = entry.getValue() * defP; + return new AbstractMap.SimpleEntry<>(entry.getKey(), p); + }) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } +} \ No newline at end of file diff --git a/fork-stat-common/src/main/java/com/agoda/fork/stat/StatLoader.java b/fork-stat-common/src/main/java/com/agoda/fork/stat/StatLoader.java new file mode 100644 index 00000000..5b5685f8 --- /dev/null +++ b/fork-stat-common/src/main/java/com/agoda/fork/stat/StatLoader.java @@ -0,0 +1,7 @@ +package com.agoda.fork.stat; + +import java.util.List; + +public interface StatLoader { + List loadHistory(); +} diff --git a/fork-stat-common/src/main/java/com/agoda/fork/stat/StatLoaderProvider.java b/fork-stat-common/src/main/java/com/agoda/fork/stat/StatLoaderProvider.java new file mode 100644 index 00000000..abed2a5d --- /dev/null +++ b/fork-stat-common/src/main/java/com/agoda/fork/stat/StatLoaderProvider.java @@ -0,0 +1,7 @@ +package com.agoda.fork.stat; + +import java.io.FileNotFoundException; + +public interface StatLoaderProvider { + StatLoader create(String path) throws FileNotFoundException; +} diff --git a/fork-stat-common/src/main/java/com/agoda/fork/stat/TestExecution.java b/fork-stat-common/src/main/java/com/agoda/fork/stat/TestExecution.java new file mode 100644 index 00000000..28146293 --- /dev/null +++ b/fork-stat-common/src/main/java/com/agoda/fork/stat/TestExecution.java @@ -0,0 +1,13 @@ +package com.agoda.fork.stat; + +public class TestExecution { + private final int duration; + + public TestExecution(int duration) { + this.duration = duration; + } + + public int getDuration() { + return duration; + } +} \ No newline at end of file diff --git a/fork-stat-common/src/main/java/com/agoda/fork/stat/TestHistory.java b/fork-stat-common/src/main/java/com/agoda/fork/stat/TestHistory.java new file mode 100644 index 00000000..78c3e256 --- /dev/null +++ b/fork-stat-common/src/main/java/com/agoda/fork/stat/TestHistory.java @@ -0,0 +1,34 @@ +package com.agoda.fork.stat; + +import java.util.List; + +public class TestHistory { + private final String testClass; + private final String testMethod; + private final List executions; + private final TestMetric testMetric; + + public TestHistory(String testClass, String testMethod, + List executions, TestMetric testMetric) { + this.testClass = testClass; + this.testMethod = testMethod; + this.executions = executions; + this.testMetric = testMetric; + } + + public String getTestClass() { + return testClass; + } + + public String getTestMethod() { + return testMethod; + } + + public List getExecutions() { + return executions; + } + + public TestMetric getTestMetric() { + return testMetric; + } +} \ No newline at end of file diff --git a/fork-stat-common/src/main/java/com/agoda/fork/stat/TestMetric.java b/fork-stat-common/src/main/java/com/agoda/fork/stat/TestMetric.java new file mode 100644 index 00000000..e9cadfcb --- /dev/null +++ b/fork-stat-common/src/main/java/com/agoda/fork/stat/TestMetric.java @@ -0,0 +1,36 @@ +package com.agoda.fork.stat; + +public class TestMetric { + + public static TestMetric empty() { + return new TestMetric(0.0, 0.0); + } + + public static TestMetric create(double expectedValue, double variance) { + return new TestMetric(expectedValue, variance); + } + + private final double expectedValue; + private final double variance; + + public TestMetric(double expectedValue, double variance) { + this.expectedValue = expectedValue; + this.variance = variance; + } + + public double getExpectedValue() { + return expectedValue; + } + + public double getVariance() { + return variance; + } + + @Override + public String toString() { + return "TestMetric{" + + "expectedValue=" + expectedValue + + ", variance=" + variance + + '}'; + } +} diff --git a/fork-stat-teamcity/build.gradle b/fork-stat-teamcity/build.gradle new file mode 100644 index 00000000..356d8bc4 --- /dev/null +++ b/fork-stat-teamcity/build.gradle @@ -0,0 +1,30 @@ +apply plugin: 'java-library' +apply from: '../build-scripts/gradle-mvn-push.gradle' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + implementation "org.yaml:snakeyaml:1.18" + implementation project(':fork-stat-common') + + implementation 'com.squareup.retrofit2:converter-gson:2.3.0' + implementation 'io.reactivex.rxjava2:rxjava:2.1.0' + implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0' + implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' + implementation 'com.squareup.retrofit2:retrofit:2.3.0' +} + +jar { + manifest { + attributes 'Implementation-Title': POM_NAME, + 'Implementation-Version': VERSION_NAME, + 'Built-By': System.getProperty('user.name'), + 'Built-Date': new Date(), + 'Built-JDK': System.getProperty('java.version'), + 'Built-Gradle': gradle.gradleVersion + } +} diff --git a/fork-stat-teamcity/gradle.properties b/fork-stat-teamcity/gradle.properties new file mode 100644 index 00000000..ae111a33 --- /dev/null +++ b/fork-stat-teamcity/gradle.properties @@ -0,0 +1,4 @@ +POM_ARTIFACT_ID=fork-stat-teamcity +POM_NAME=Fork Sorting TeamCity +POM_PACKAGING=jar +POM_DESCRIPTION=A library that parallelizes Android Test execution to all connected devices and emulators diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityClient.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityClient.java new file mode 100644 index 00000000..bc580e17 --- /dev/null +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityClient.java @@ -0,0 +1,56 @@ +package com.agoda.fork.teamcity; + +import io.reactivex.schedulers.Schedulers; +import okhttp3.Credentials; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +public final class TeamCityClient { + + private static final String AUTHORIZATION_HEADER = "Authorization"; + private static final String ACCEPT_HEADER = "Accept"; + private static final String ACCEPT_TYPE = "application/json"; + + private final TeamCityConfig config; + + private final Interceptor authInterceptor = chain -> { + Request original = chain.request(); + Request request = original.newBuilder() + .header(AUTHORIZATION_HEADER, credentials()) + .header(ACCEPT_HEADER, ACCEPT_TYPE).build(); + return chain.proceed(request); + }; + + public TeamCityClient(TeamCityConfig config) { + this.config = config; + } + + private String credentials() { + return Credentials.basic(config.getUser(), config.getPassword()); + } + + private OkHttpClient createHttpClient() { + OkHttpClient.Builder builder = new OkHttpClient.Builder().addInterceptor(authInterceptor); + if (config.isDebug()) { + builder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)); + } + return builder.build(); + } + + private Retrofit createRetrofit() { + return new Retrofit.Builder().client(createHttpClient()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())) + .addConverterFactory(GsonConverterFactory.create()) + .baseUrl(config.getUrl()) + .build(); + } + + public TeamCityService teamCityService() { + return createRetrofit().create(TeamCityService.class); + } +} diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityConfig.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityConfig.java new file mode 100644 index 00000000..890ec2bf --- /dev/null +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityConfig.java @@ -0,0 +1,49 @@ +package com.agoda.fork.teamcity; + +public class TeamCityConfig { + private String url; + private String configuration; + private boolean debug; + private String user; + private String password; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getConfiguration() { + return configuration; + } + + public void setConfiguration(String configuration) { + this.configuration = configuration; + } + + public boolean isDebug() { + return debug; + } + + public void setDebug(boolean debug) { + this.debug = debug; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityService.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityService.java new file mode 100644 index 00000000..ae6cf4ff --- /dev/null +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityService.java @@ -0,0 +1,18 @@ +package com.agoda.fork.teamcity; + +import com.agoda.fork.teamcity.entities.Builds; +import com.agoda.fork.teamcity.entities.TestResult; +import io.reactivex.Single; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Streaming; + +public interface TeamCityService { + @GET("/httpAuth/app/rest/buildTypes/id:{configuration}/builds/?locator=count:10&fields=build:id") + Single builds(@Path("configuration") String configuration); + + @GET("/httpAuth/app/rest/testOccurrences") + Single tests(@Query("locator") String locator); +} diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoader.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoader.java new file mode 100644 index 00000000..f666f255 --- /dev/null +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoader.java @@ -0,0 +1,96 @@ +package com.agoda.fork.teamcity; + +import com.agoda.fork.stat.*; +import com.agoda.fork.teamcity.entities.Build; +import com.agoda.fork.teamcity.entities.Test; +import com.agoda.fork.teamcity.entities.TestResult; +import io.reactivex.Single; +import io.reactivex.Observable; +import io.reactivex.functions.Function; +import okhttp3.ResponseBody; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.nodes.Tag; + +import java.util.*; + +import static java.util.stream.Collectors.toList; + +public class TeamCityStatLoader implements StatLoader { + + private final TeamCityService teamCityService; + private final TeamCityConfig teamCityConfig; + + public TeamCityStatLoader(TeamCityService teamCityService, TeamCityConfig teamCityConfig) { + this.teamCityService = teamCityService; + this.teamCityConfig = teamCityConfig; + } + + @Override + public List loadHistory() { + return testHistories(teamCityConfig.getConfiguration()); + } + + private TestHistory createTestHistory(Test test) { + String testClassName = test.getName().substring(test.getName().lastIndexOf(':') + 2, test.getName().lastIndexOf('.')); + String testMethodName = test.getName().substring(test.getName().lastIndexOf('.') + 1); + return new TestHistory(testClassName, testMethodName, new ArrayList<>(), TestMetric.empty()); + } + + private TestExecution parseTestExecution(Test test) { + return new TestExecution(test.getDuration()); + } + + private TestHistory fillExpectedAndVariance(TestHistory testHistory) { + List ints = + testHistory.getExecutions().stream().map(TestExecution::getDuration).collect(toList()); + double expectedValue = MathUtils.expectedValue(ints); + double variance = MathUtils.variance(ints, expectedValue); + return new TestHistory(testHistory.getTestClass(), + testHistory.getTestMethod(), testHistory.getExecutions(), TestMetric.create(expectedValue, variance)); + } + + private List testHistories(String configuration) { + List results = requestTestResults(configuration); + Map historyMap = new HashMap<>(); + results.forEach(testResult -> parseResult(testResult, historyMap)); + + return historyMap.values() + .parallelStream() + .map(this::fillExpectedAndVariance) + .collect(toList()); + } + + private void parseResult(TestResult testResult, Map historyMap) { + List tests = testResult.getTestOccurrence(); + if (tests != null) { + tests.forEach(test -> { + historyMap.computeIfAbsent(test.getName(), s -> createTestHistory(test)); + historyMap.computeIfPresent(test.getName(), (s, testHistory) -> { + testHistory.getExecutions().add(parseTestExecution(test)); + return testHistory; + }); + }); + } + } + + + private List requestTestResults(String configuration) { + return teamCityService.builds(configuration).retry(3) + .flatMapObservable(builds1 -> Observable.fromIterable(builds1.getBuild())) + .flatMapSingle(this::requestTestResult) + .toList() + .blockingGet(); + } + + private Single requestTestResult(Build build) { + return teamCityService.tests("build:(id:" + build.getId() + "),status:SUCCESS,count:10000") + .retry(3) + .map(testResult -> new TestResult( + testResult.getCount(), + testResult.getHref(), + testResult.getTestOccurrence()) + ); + + } +} diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoaderProvider.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoaderProvider.java new file mode 100644 index 00000000..1d7003a5 --- /dev/null +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoaderProvider.java @@ -0,0 +1,21 @@ +package com.agoda.fork.teamcity; + +import com.agoda.fork.stat.StatLoader; +import com.agoda.fork.stat.StatLoaderProvider; +import org.yaml.snakeyaml.Yaml; + +import java.io.FileNotFoundException; +import java.io.FileReader; + +public class TeamCityStatLoaderProvider implements StatLoaderProvider { + @Override + public StatLoader create(String path) throws FileNotFoundException { + TeamCityConfig config = parseConfig(path); + return new TeamCityStatLoader(new TeamCityClient(config).teamCityService(), config); + } + + private TeamCityConfig parseConfig(String path) throws FileNotFoundException { + Yaml yaml = new Yaml(); + return yaml.loadAs(new FileReader(path), TeamCityConfig.class); + } +} diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Build.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Build.java new file mode 100644 index 00000000..d2ddf32f --- /dev/null +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Build.java @@ -0,0 +1,13 @@ +package com.agoda.fork.teamcity.entities; + +public class Build { + private int id; + + public Build(int id) { + this.id = id; + } + + public int getId() { + return id; + } +} \ No newline at end of file diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Builds.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Builds.java new file mode 100644 index 00000000..1b0b19ef --- /dev/null +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Builds.java @@ -0,0 +1,15 @@ +package com.agoda.fork.teamcity.entities; + +import java.util.List; + +public class Builds { + private final List build; + + public Builds(List build) { + this.build = build; + } + + public List getBuild() { + return build; + } +} \ No newline at end of file diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Test.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Test.java new file mode 100644 index 00000000..099a6e79 --- /dev/null +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/Test.java @@ -0,0 +1,37 @@ +package com.agoda.fork.teamcity.entities; + +public class Test { + private final String id; + private final String name; + private final String status; + private final int duration; + private final String href; + + public Test(String id, String name, String status, int duration, String href) { + this.id = id; + this.name = name; + this.status = status; + this.duration = duration; + this.href = href; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getStatus() { + return status; + } + + public int getDuration() { + return duration; + } + + public String getHref() { + return href; + } +} diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/TestResult.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/TestResult.java new file mode 100644 index 00000000..4fd5dfa5 --- /dev/null +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/entities/TestResult.java @@ -0,0 +1,27 @@ +package com.agoda.fork.teamcity.entities; + +import java.util.List; + +public class TestResult { + private final int count; + private final String href; + private final List testOccurrence; + + public TestResult(int count, String href, List testOccurrence) { + this.count = count; + this.href = href; + this.testOccurrence = testOccurrence; + } + + public int getCount() { + return count; + } + + public String getHref() { + return href; + } + + public List getTestOccurrence() { + return testOccurrence; + } +} \ No newline at end of file diff --git a/fork-stat-teamcity/src/main/resources/META-INF/services/com.agoda.fork.stat.StatLoaderProvider b/fork-stat-teamcity/src/main/resources/META-INF/services/com.agoda.fork.stat.StatLoaderProvider new file mode 100644 index 00000000..9b06e3b0 --- /dev/null +++ b/fork-stat-teamcity/src/main/resources/META-INF/services/com.agoda.fork.stat.StatLoaderProvider @@ -0,0 +1 @@ +com.agoda.fork.teamcity.TeamCityStatLoaderProvider \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 4c540898..4099cd94 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,3 +16,6 @@ include ':fork-reporter' include ':fork-reporter-jenkins-gradle-plugin' include ':chimprunner' include ':chimprunner-gradle-plugin' +include 'fork-stat-common' +include 'fork-stat-teamcity' + From 5576179163730603ba5cba61500aae03d089c143 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Fri, 15 Dec 2017 13:13:05 +0800 Subject: [PATCH 17/51] integrate kotlin --- build.gradle | 26 +++++++++++++++++++ chimprunner/build.gradle | 24 +++++++++++++++++ fork-client/build.gradle | 26 +++++++++++++++++++ fork-common/build.gradle | 24 +++++++++++++++++ .../build.gradle | 22 ++++++++++++++++ fork-reporter/build.gradle | 24 +++++++++++++++++ fork-runner/build.gradle | 24 +++++++++++++++++ fork-stat-common/build.gradle | 21 +++++++++++++++ fork-stat-teamcity/build.gradle | 21 +++++++++++++++ 9 files changed, 212 insertions(+) diff --git a/build.gradle b/build.gradle index 33395674..7f1e384b 100644 --- a/build.gradle +++ b/build.gradle @@ -63,3 +63,29 @@ task jacocoMergedReport(type: JacocoReport, dependsOn: jacocoMergeExecutions) { xml.enabled true } } +buildscript { + ext.kotlin_version = '1.2.10' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +apply plugin: 'kotlin' +repositories { + mavenCentral() +} +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/chimprunner/build.gradle b/chimprunner/build.gradle index 52644269..bfa596cc 100644 --- a/chimprunner/build.gradle +++ b/chimprunner/build.gradle @@ -9,6 +9,7 @@ */ apply plugin: 'java-library' +apply plugin: 'kotlin' apply plugin: 'application' apply from: '../build-scripts/gradle-mvn-push.gradle' @@ -32,6 +33,7 @@ dependencies { testImplementation( "org.jmock:jmock:$JMOCK_VERSION", "org.jmock:jmock-junit4:$JMOCK_VERSION") + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" } jar { @@ -53,3 +55,25 @@ run { args project.args.split('\\s+') } } +buildscript { + ext.kotlin_version = '1.2.10' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +repositories { + mavenCentral() +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/fork-client/build.gradle b/fork-client/build.gradle index 4a414846..94cc903d 100644 --- a/fork-client/build.gradle +++ b/fork-client/build.gradle @@ -1,5 +1,31 @@ apply plugin: 'java-library' +apply plugin: 'kotlin' apply from: '../build-scripts/gradle-mvn-push.gradle' sourceCompatibility = JavaVersion.VERSION_1_7 targetCompatibility = JavaVersion.VERSION_1_7 +buildscript { + ext.kotlin_version = '1.2.10' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +repositories { + mavenCentral() +} +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/fork-common/build.gradle b/fork-common/build.gradle index 8d408e8a..a6a53929 100644 --- a/fork-common/build.gradle +++ b/fork-common/build.gradle @@ -9,6 +9,7 @@ */ apply plugin: 'java-library' +apply plugin: 'kotlin' apply from: '../build-scripts/gradle-mvn-push.gradle' //noinspection GroovyUnusedAssignment @@ -40,6 +41,7 @@ dependencies { testImplementation("junit:junit:$JUNIT_VERSION") { exclude module:'hamcrest-core' } + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" } jar { @@ -52,3 +54,25 @@ jar { 'Built-Gradle': gradle.gradleVersion } } +buildscript { + ext.kotlin_version = '1.2.10' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +repositories { + mavenCentral() +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/fork-reporter-jenkins-gradle-plugin/build.gradle b/fork-reporter-jenkins-gradle-plugin/build.gradle index 8511692d..7f9308fa 100644 --- a/fork-reporter-jenkins-gradle-plugin/build.gradle +++ b/fork-reporter-jenkins-gradle-plugin/build.gradle @@ -9,6 +9,7 @@ */ apply plugin: 'java-gradle-plugin' +apply plugin: 'kotlin' apply from: '../build-scripts/gradle-mvn-push.gradle' sourceCompatibility = JavaVersion.VERSION_1_8 @@ -16,11 +17,13 @@ targetCompatibility = JavaVersion.VERSION_1_8 repositories { maven { url "http://repo.jenkins-ci.org/public/" } + mavenCentral() } dependencies { implementation project(':fork-reporter') implementation "com.offbytwo.jenkins:jenkins-client:0.3.4" + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" } jar { @@ -33,3 +36,22 @@ jar { 'Built-Gradle': gradle.gradleVersion } } +buildscript { + ext.kotlin_version = '1.2.10' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/fork-reporter/build.gradle b/fork-reporter/build.gradle index 2763dd36..39e520b1 100644 --- a/fork-reporter/build.gradle +++ b/fork-reporter/build.gradle @@ -9,6 +9,7 @@ */ apply plugin: 'java-library' +apply plugin: 'kotlin' apply plugin: 'application' apply from: '../build-scripts/gradle-mvn-push.gradle' @@ -24,6 +25,7 @@ dependencies { "org.slf4j:slf4j-log4j12:$SLF4J_VERSION", "com.google.code.gson:gson:$GSON_VERSION", ) + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" } jar { @@ -45,3 +47,25 @@ run { args project.args.split('\\s+') } } +buildscript { + ext.kotlin_version = '1.2.10' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +repositories { + mavenCentral() +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/fork-runner/build.gradle b/fork-runner/build.gradle index 053ee8df..71bbebcb 100644 --- a/fork-runner/build.gradle +++ b/fork-runner/build.gradle @@ -9,6 +9,7 @@ */ apply plugin: 'java-library' +apply plugin: 'kotlin' apply plugin: 'application' apply from: '../build-scripts/gradle-mvn-push.gradle' @@ -40,6 +41,7 @@ dependencies { testImplementation( "org.jmock:jmock:$JMOCK_VERSION", "org.jmock:jmock-junit4:$JMOCK_VERSION") + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" } jar { @@ -61,3 +63,25 @@ run { args project.args.split('\\s+') } } +buildscript { + ext.kotlin_version = '1.2.10' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +repositories { + mavenCentral() +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/fork-stat-common/build.gradle b/fork-stat-common/build.gradle index 8621c1d3..13c949b7 100644 --- a/fork-stat-common/build.gradle +++ b/fork-stat-common/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'java-library' +apply plugin: 'kotlin' apply from: '../build-scripts/gradle-mvn-push.gradle' sourceCompatibility = 1.8 @@ -9,6 +10,7 @@ repositories { dependencies { api "com.google.code.findbugs:jsr305:3.0.1" + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" } jar { @@ -21,3 +23,22 @@ jar { 'Built-Gradle': gradle.gradleVersion } } +buildscript { + ext.kotlin_version = '1.2.10' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/fork-stat-teamcity/build.gradle b/fork-stat-teamcity/build.gradle index 356d8bc4..2f38bfd3 100644 --- a/fork-stat-teamcity/build.gradle +++ b/fork-stat-teamcity/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'java-library' +apply plugin: 'kotlin' apply from: '../build-scripts/gradle-mvn-push.gradle' sourceCompatibility = 1.8 @@ -16,6 +17,7 @@ dependencies { implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' implementation 'com.squareup.retrofit2:retrofit:2.3.0' + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" } jar { @@ -28,3 +30,22 @@ jar { 'Built-Gradle': gradle.gradleVersion } } +buildscript { + ext.kotlin_version = '1.2.10' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} From 24ecbf40dd38e663aaa46bb1958554461c16b48a Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Fri, 15 Dec 2017 13:42:54 +0800 Subject: [PATCH 18/51] add batch test queue --- .../shazam/fork/batch/BatchQueueProvider.kt | 12 ++++++ .../com/shazam/fork/batch/BatchTestQueue.kt | 6 +++ .../com/shazam/fork/batch/TestBatchFactory.kt | 14 +++++++ .../shazam/fork/batch/TestTaskComparator.kt | 37 +++++++++++++++++++ .../com/shazam/fork/batch/tasks/TestTask.kt | 9 +++++ 5 files changed, 78 insertions(+) create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/BatchTestQueue.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/tasks/TestTask.kt diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt b/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt new file mode 100644 index 00000000..8175a0ee --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt @@ -0,0 +1,12 @@ +package com.shazam.fork.batch + +import com.shazam.fork.model.TestCaseEvent + +class BatchQueueProvider { + fun provide(list: List): BatchTestQueue { + val tasks = TestBatchFactory().tasks(list) + val queue = BatchTestQueue() + queue.addAll(tasks) + return queue + } +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/BatchTestQueue.kt b/fork-runner/src/main/java/com/shazam/fork/batch/BatchTestQueue.kt new file mode 100644 index 00000000..c7d5029b --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/BatchTestQueue.kt @@ -0,0 +1,6 @@ +package com.shazam.fork.batch + +import com.shazam.fork.batch.tasks.TestTask +import java.util.concurrent.PriorityBlockingQueue + +class BatchTestQueue : PriorityBlockingQueue(100, TestTaskComparator()) \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt new file mode 100644 index 00000000..b53b5c01 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt @@ -0,0 +1,14 @@ +package com.shazam.fork.batch + +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.TestCaseEvent + +class TestBatchFactory { + fun tasks(list: List): List { + val average = list.map { it.testMetric.expectedValue }.average() + val grouped = list.groupBy { it.testMetric.expectedValue < average } + val single = grouped[false].orEmpty().map { TestTask.SingleTestTask(it) } + val multi = listOf(TestTask.MultiTestTask(grouped[true].orEmpty())) + return multi + single + } +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt new file mode 100644 index 00000000..a950796a --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt @@ -0,0 +1,37 @@ +package com.shazam.fork.batch + +import com.agoda.fork.stat.TestMetric +import com.shazam.fork.batch.tasks.TestTask + +class TestTaskComparator : Comparator { + + private fun getDefaultComparator(): java.util.Comparator { + return Comparator.comparingDouble { value -> + Math.sqrt(value.variance) * 2 + value.expectedValue + }.reversed() + } + + private fun compareMetrics(o1: TestMetric, o2: TestMetric): Int { + return if (o1.variance == 0.0 || o1.expectedValue == 0.0) { + -1 + } else if (o2.variance == 0.0 || o2.expectedValue == 0.0) { + 1 + } else { + getDefaultComparator().compare(o1, o2) + } + } + + override fun compare(o1: TestTask, o2: TestTask): Int { + val testMetric1 = extractTestMetric(o1) + val testMetric2 = extractTestMetric(o2) + return compareMetrics(testMetric1, testMetric2) + } + + private fun extractTestMetric(task: TestTask) = when (task) { + is TestTask.SingleTestTask -> task.event.testMetric + is TestTask.MultiTestTask -> task.list.fold(TestMetric.empty(), { acc, case -> + TestMetric.create(acc.expectedValue + case.testMetric.expectedValue, + acc.variance + case.testMetric.variance) + }) + } +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/tasks/TestTask.kt b/fork-runner/src/main/java/com/shazam/fork/batch/tasks/TestTask.kt new file mode 100644 index 00000000..dfbab15e --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/tasks/TestTask.kt @@ -0,0 +1,9 @@ +package com.shazam.fork.batch.tasks + +import com.shazam.fork.model.TestCaseEvent + +sealed class TestTask { + data class SingleTestTask(val event: TestCaseEvent) : TestTask() + + data class MultiTestTask(val list: List) : TestTask() +} \ No newline at end of file From aeeb5cf5cf8ac6aed0e12e02d253f16313598c88 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Mon, 18 Dec 2017 18:21:09 +0800 Subject: [PATCH 19/51] add batch --- .../main/java/com/shazam/fork/ForkRunner.java | 14 +- .../shazam/fork/batch/BatchQueueProvider.kt | 2 +- .../com/shazam/fork/batch/TestBatchFactory.kt | 23 +++- .../shazam/fork/batch/TestTaskComparator.kt | 19 ++- .../shazam/fork/batch/watcher/BatchWatcher.kt | 91 +++++++++++++ .../shazam/fork/batch/watcher/XmlService.kt | 28 ++++ .../fork/injector/ForkRunnerInjector.java | 5 +- .../shazam/fork/runner/DeviceTestRunner.java | 90 ------------- .../shazam/fork/runner/DeviceTestRunner.kt | 93 ++++++++++++++ .../fork/runner/DeviceTestRunnerFactory.java | 3 +- .../shazam/fork/runner/PoolTestRunner.java | 5 +- .../fork/runner/PoolTestRunnerFactory.java | 3 +- .../java/com/shazam/fork/runner/TestRun.java | 90 ------------- .../java/com/shazam/fork/runner/TestRun.kt | 120 ++++++++++++++++++ .../shazam/fork/runner/TestRunFactory.java | 5 +- .../shazam/fork/runner/TestRunParameters.java | 10 +- .../runner/listeners/CoverageListener.java | 75 ----------- .../fork/runner/listeners/CoverageListener.kt | 65 ++++++++++ .../listeners/ForkXmlTestRunListener.java | 85 ------------- .../listeners/ForkXmlTestRunListener.kt | 65 ++++++++++ .../fork/runner/listeners/RetryListener.java | 36 +++--- .../listeners/TestExecutionListener.java | 8 ++ .../listeners/TestRunListenersFactory.java | 12 +- .../com/shazam/fork/summary/TestCase.java | 2 +- .../com/shazam/fork/summary/TestSuite.java | 2 +- .../shazam/fork/system/io/FileManager.java | 20 ++- .../com/shazam/fork/system/io/FileType.java | 1 + 27 files changed, 577 insertions(+), 395 deletions(-) create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/watcher/BatchWatcher.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/watcher/XmlService.kt delete mode 100755 fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.java create mode 100755 fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt delete mode 100755 fork-runner/src/main/java/com/shazam/fork/runner/TestRun.java create mode 100755 fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt delete mode 100644 fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.kt delete mode 100755 fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.java create mode 100755 fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.kt diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java index c67a3a71..0daf8e31 100755 --- a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java @@ -12,6 +12,9 @@ */ package com.shazam.fork; +import com.shazam.fork.batch.BatchQueueProvider; +import com.shazam.fork.batch.tasks.TestTask; +import com.shazam.fork.batch.watcher.BatchWatcher; import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; import com.shazam.fork.pooling.*; @@ -43,6 +46,7 @@ public class ForkRunner { private final SummaryGeneratorHook summaryGeneratorHook; private final TestStatsLoader testStatsLoader; private final QueueProvider queueProvider; + private final BatchWatcher batchWatcher; public ForkRunner(PoolLoader poolLoader, TestSuiteLoader testClassLoader, @@ -50,7 +54,8 @@ public ForkRunner(PoolLoader poolLoader, ProgressReporter progressReporter, SummaryGeneratorHook summaryGeneratorHook, TestStatsLoader testStatsLoader, - QueueProvider queueProvider) { + QueueProvider queueProvider, + BatchWatcher batchWatcher) { this.poolLoader = poolLoader; this.testClassLoader = testClassLoader; this.poolTestRunnerFactory = poolTestRunnerFactory; @@ -58,6 +63,7 @@ public ForkRunner(PoolLoader poolLoader, this.summaryGeneratorHook = summaryGeneratorHook; this.testStatsLoader = testStatsLoader; this.queueProvider = queueProvider; + this.batchWatcher = batchWatcher; } public boolean run() { @@ -72,13 +78,12 @@ public boolean run() { Collection testCases = testClassLoader.loadTestSuite(); - Queue testCasesQueue = queueProvider.create(); - - testCasesQueue.addAll(testCases); + Queue testCasesQueue = new BatchQueueProvider().provide(testCases); summaryGeneratorHook.registerHook(pools, testCases); progressReporter.start(); + batchWatcher.start(); for (Pool pool : pools) { Runnable poolTestRunner = poolTestRunnerFactory.createPoolTestRunner(pool, testCasesQueue, @@ -88,6 +93,7 @@ public boolean run() { } poolCountDownLatch.await(); progressReporter.stop(); + batchWatcher.stop(); boolean overallSuccess = summaryGeneratorHook.defineOutcome(); logger.info("Overall success: " + overallSuccess); diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt b/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt index 8175a0ee..7cb11a04 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt @@ -3,7 +3,7 @@ package com.shazam.fork.batch import com.shazam.fork.model.TestCaseEvent class BatchQueueProvider { - fun provide(list: List): BatchTestQueue { + fun provide(list: Collection): BatchTestQueue { val tasks = TestBatchFactory().tasks(list) val queue = BatchTestQueue() queue.addAll(tasks) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt index b53b5c01..b55b8e81 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt @@ -1,14 +1,27 @@ package com.shazam.fork.batch +import com.google.common.collect.Lists import com.shazam.fork.batch.tasks.TestTask import com.shazam.fork.model.TestCaseEvent +import java.util.* class TestBatchFactory { - fun tasks(list: List): List { - val average = list.map { it.testMetric.expectedValue }.average() - val grouped = list.groupBy { it.testMetric.expectedValue < average } + fun tasks(list: Collection): List { + val average = list.map { it.testMetric.variance }.average() + val grouped = list.groupBy { it.testMetric.variance < average } + val short = grouped[true].orEmpty() + val resultArray = ArrayList() + val tempArray = ArrayList() + short.forEach { + if (tempArray.sumByDouble { it.testMetric.variance } < average*2) { + tempArray.add(it) + } else { + resultArray.add(TestTask.MultiTestTask(Lists.newArrayList(tempArray))) + tempArray.clear() + } + } val single = grouped[false].orEmpty().map { TestTask.SingleTestTask(it) } - val multi = listOf(TestTask.MultiTestTask(grouped[true].orEmpty())) - return multi + single + + return resultArray + single } } \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt index a950796a..db526c3d 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt @@ -2,9 +2,13 @@ package com.shazam.fork.batch import com.agoda.fork.stat.TestMetric import com.shazam.fork.batch.tasks.TestTask +import org.slf4j.Logger +import org.slf4j.LoggerFactory class TestTaskComparator : Comparator { + val logger: Logger = LoggerFactory.getLogger(TestTaskComparator::class.java) + private fun getDefaultComparator(): java.util.Comparator { return Comparator.comparingDouble { value -> Math.sqrt(value.variance) * 2 + value.expectedValue @@ -22,9 +26,18 @@ class TestTaskComparator : Comparator { } override fun compare(o1: TestTask, o2: TestTask): Int { - val testMetric1 = extractTestMetric(o1) - val testMetric2 = extractTestMetric(o2) - return compareMetrics(testMetric1, testMetric2) + val res = when { + o1 is TestTask.MultiTestTask -> -1 + o2 is TestTask.MultiTestTask -> 1 + else -> { + val testMetric1 = extractTestMetric(o1) + val testMetric2 = extractTestMetric(o2) + compareMetrics(testMetric1, testMetric2) + } + } + logger.error("Compare result for o1 is TestTask.MultiTestTask = ${o1 is TestTask.MultiTestTask}" + + "o2 is TestTask.MultiTestTask = ${o2 is TestTask.MultiTestTask} res = $res") + return res } private fun extractTestMetric(task: TestTask) = when (task) { diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/watcher/BatchWatcher.kt b/fork-runner/src/main/java/com/shazam/fork/batch/watcher/BatchWatcher.kt new file mode 100644 index 00000000..c62cfd68 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/watcher/BatchWatcher.kt @@ -0,0 +1,91 @@ +package com.shazam.fork.batch.watcher + +import com.shazam.fork.system.io.FileManager +import com.shazam.fork.system.io.FileType +import com.sun.nio.file.SensitivityWatchEventModifier +import org.slf4j.LoggerFactory + +import java.io.IOException +import java.nio.file.FileSystems +import java.nio.file.FileVisitResult +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.SimpleFileVisitor +import java.nio.file.WatchEvent +import java.nio.file.WatchKey +import java.nio.file.WatchService +import java.nio.file.attribute.BasicFileAttributes +import java.util.HashMap +import java.util.concurrent.Executors + +import java.nio.file.StandardWatchEventKinds.ENTRY_CREATE +import java.nio.file.StandardWatchEventKinds.OVERFLOW + +class BatchWatcher(fileManager: FileManager) { + + private val xmlService = XmlService(fileManager) + + private val logger = LoggerFactory.getLogger(BatchWatcher::class.java) + private val folder = fileManager.createDirectory(FileType.TEST_BATCH) + + private val watcher: WatchService = FileSystems.getDefault().newWatchService() + private val executor = Executors.newSingleThreadExecutor() + + fun stop() { + try { + watcher.close() + } catch (e: IOException) { + logger.error("Can't close watcher", e) + } + executor.shutdown() + } + + fun start() { + + val keys = HashMap() + + val register = { p: Path -> + if (!p.toFile().exists() || !p.toFile().isDirectory) { + throw RuntimeException("folder $p does not exist or is not a directory") + } + Files.walkFileTree(p, object : SimpleFileVisitor() { + override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult { + val watchKey = dir.register(watcher, arrayOf>(ENTRY_CREATE), SensitivityWatchEventModifier.HIGH) + keys.put(watchKey, dir) + return FileVisitResult.CONTINUE + } + }) + } + + register.invoke(folder) + + executor.submit { + while (true) { + val key: WatchKey = watcher.take() + + val dir = keys[key] + if (dir == null) { + System.err.println("WatchKey $key not recognized!") + continue + } + + key.pollEvents().stream() + .filter { e -> e.kind() !== OVERFLOW } + .map { e -> (e as WatchEvent).context() } + .forEach { p -> + val absPath = dir.resolve(p) + if (absPath.toFile().isDirectory) { + register(absPath) + } else { + xmlService.splitAndSave(absPath.toFile()) + } + } + + val valid = key.reset() + if (!valid) { + break + } + } + } + } +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/watcher/XmlService.kt b/fork-runner/src/main/java/com/shazam/fork/batch/watcher/XmlService.kt new file mode 100644 index 00000000..387ea57e --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/watcher/XmlService.kt @@ -0,0 +1,28 @@ +package com.shazam.fork.batch.watcher + +import com.android.ddmlib.testrunner.TestIdentifier +import com.shazam.fork.model.Device +import com.shazam.fork.model.Pool +import com.shazam.fork.summary.TestSuite +import com.shazam.fork.system.io.FileManager +import com.shazam.fork.system.io.FileType +import org.simpleframework.xml.core.Persister +import java.io.File + +class XmlService(private val fileManager: FileManager) { + private val parser = Persister() + + fun splitAndSave(file: File) { + val suite = parser.read(TestSuite::class.java, file, false) + suite.testCase.forEach { + val arr = file.absolutePath.split('/').dropLast(1) + val serial = arr.last() + val poolName = arr.dropLast(1).last() + val device = Device.Builder().withSerial(serial).build() + val pool = Pool.Builder().withName(poolName).build() + val output = fileManager.createFile(FileType.TEST, pool, device, TestIdentifier(it.classname, it.name)) + parser.write(it, output) + file.delete() + } + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java index b302f362..49b14563 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java @@ -14,6 +14,7 @@ import com.shazam.fork.ForkRunner; +import com.shazam.fork.batch.watcher.BatchWatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,6 +25,7 @@ import static com.shazam.fork.injector.stat.TestStatLoaderInjector.testStatsLoader; import static com.shazam.fork.injector.suite.TestSuiteLoaderInjector.testSuiteLoader; import static com.shazam.fork.injector.summary.SummaryGeneratorHookInjector.summaryGeneratorHook; +import static com.shazam.fork.injector.system.FileManagerInjector.fileManager; import static com.shazam.fork.utils.Utils.millisSinceNanoTime; import static java.lang.System.nanoTime; @@ -43,7 +45,8 @@ public static ForkRunner forkRunner() { progressReporter(), summaryGeneratorHook(), testStatsLoader(), - queueProvider()); + queueProvider(), + new BatchWatcher(fileManager())); logger.debug("Bootstrap of ForkRunner took: {} milliseconds", millisSinceNanoTime(startNanos)); diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.java b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.java deleted file mode 100755 index 79083f02..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2014 Shazam Entertainment Limited - * - * 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.shazam.fork.runner; - -import com.android.ddmlib.*; -import com.shazam.fork.model.Device; -import com.shazam.fork.model.*; -import com.shazam.fork.system.adb.Installer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.Queue; -import java.util.concurrent.CountDownLatch; - -import static com.shazam.fork.system.io.RemoteFileManager.*; - -public class DeviceTestRunner implements Runnable { - private static final Logger logger = LoggerFactory.getLogger(DeviceTestRunner.class); - - private final Installer installer; - private final Pool pool; - private final Device device; - private final Queue queueOfTestsInPool; - private final CountDownLatch deviceCountDownLatch; - private final ProgressReporter progressReporter; - private final TestRunFactory testRunFactory; - - public DeviceTestRunner(Installer installer, - Pool pool, - Device device, - Queue queueOfTestsInPool, - CountDownLatch deviceCountDownLatch, - ProgressReporter progressReporter, - TestRunFactory testRunFactory) { - this.installer = installer; - this.pool = pool; - this.device = device; - this.queueOfTestsInPool = queueOfTestsInPool; - this.deviceCountDownLatch = deviceCountDownLatch; - this.progressReporter = progressReporter; - this.testRunFactory = testRunFactory; - } - - @Override - public void run() { - IDevice deviceInterface = device.getDeviceInterface(); - try { - DdmPreferences.setTimeOut(30000); - installer.prepareInstallation(deviceInterface); - // For when previous run crashed/disconnected and left files behind - removeRemoteDirectory(deviceInterface); - createRemoteDirectory(deviceInterface); - createCoverageDirectory(deviceInterface); - clearLogcat(deviceInterface); - - TestCaseEvent testCaseEvent; - while ((testCaseEvent = queueOfTestsInPool.poll()) != null) { - TestRun testRun = testRunFactory.createTestRun(testCaseEvent, - device, - pool, - progressReporter, - queueOfTestsInPool); - testRun.execute(); - } - } finally { - logger.info("Device {} from pool {} finished", device.getSerial(), pool.getName()); - deviceCountDownLatch.countDown(); - } - } - - private void clearLogcat(final IDevice device) { - try { - device.executeShellCommand("logcat -c", new NullOutputReceiver()); - } catch (TimeoutException | AdbCommandRejectedException | ShellCommandUnresponsiveException | IOException e) { - logger.warn("Could not clear logcat on device: " + device.getSerialNumber(), e); - } - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt new file mode 100755 index 00000000..6f213392 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt @@ -0,0 +1,93 @@ +/* + * Copyright 2014 Shazam Entertainment Limited + * + * 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.shazam.fork.runner + +import com.android.ddmlib.* +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.Device +import com.shazam.fork.model.* +import com.shazam.fork.system.adb.Installer + +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +import java.io.IOException +import java.util.Queue +import java.util.concurrent.CountDownLatch + +import com.shazam.fork.system.io.RemoteFileManager.* + +class DeviceTestRunner(private val installer: Installer, + private val pool: Pool, + private val device: Device, + private val queueOfTestsInPool: Queue, + private val deviceCountDownLatch: CountDownLatch, + private val progressReporter: ProgressReporter, + private val testRunFactory: TestRunFactory) : Runnable { + + override fun run() { + val deviceInterface = device.deviceInterface + try { + DdmPreferences.setTimeOut(30000) + installer.prepareInstallation(deviceInterface) + // For when previous run crashed/disconnected and left files behind + removeRemoteDirectory(deviceInterface) + createRemoteDirectory(deviceInterface) + createCoverageDirectory(deviceInterface) + clearLogcat(deviceInterface) + + while (true) { + val testCaseEvent = queueOfTestsInPool.poll() + if (testCaseEvent != null) { + val text = when(testCaseEvent){ + is TestTask.MultiTestTask -> "MultiTestTask started ${testCaseEvent.list}" + is TestTask.SingleTestTask -> "SingleTestTask started" + } + + logger.error(text) + + val testRun = testRunFactory.createTestRun(testCaseEvent, + device, + pool, + progressReporter, + queueOfTestsInPool) + testRun.execute() + } else { + break + } + } + } finally { + logger.info("Device {} from pool {} finished", device.serial, pool.name) + deviceCountDownLatch.countDown() + } + } + + private fun clearLogcat(device: IDevice) { + try { + device.executeShellCommand("logcat -c", NullOutputReceiver()) + } catch (e: TimeoutException) { + logger.warn("Could not clear logcat on device: " + device.serialNumber, e) + } catch (e: AdbCommandRejectedException) { + logger.warn("Could not clear logcat on device: " + device.serialNumber, e) + } catch (e: ShellCommandUnresponsiveException) { + logger.warn("Could not clear logcat on device: " + device.serialNumber, e) + } catch (e: IOException) { + logger.warn("Could not clear logcat on device: " + device.serialNumber, e) + } + + } + + companion object { + private val logger = LoggerFactory.getLogger(DeviceTestRunner::class.java) + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunnerFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunnerFactory.java index 14c7d18c..1d5dee3d 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunnerFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunnerFactory.java @@ -10,6 +10,7 @@ package com.shazam.fork.runner; +import com.shazam.fork.batch.tasks.TestTask; import com.shazam.fork.model.*; import com.shazam.fork.system.adb.Installer; @@ -27,7 +28,7 @@ public DeviceTestRunnerFactory(Installer installer, TestRunFactory testRunFactor } public Runnable createDeviceTestRunner(Pool pool, - Queue testClassQueue, + Queue testClassQueue, CountDownLatch deviceInPoolCountDownLatch, Device device, ProgressReporter progressReporter diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunner.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunner.java index c44db1e4..defd0ec1 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunner.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunner.java @@ -12,6 +12,7 @@ */ package com.shazam.fork.runner; +import com.shazam.fork.batch.tasks.TestTask; import com.shazam.fork.model.Device; import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; @@ -30,13 +31,13 @@ public class PoolTestRunner implements Runnable { public static final String DROPPED_BY = "DroppedBy-"; private final Pool pool; - private final Queue testCases; + private final Queue testCases; private final CountDownLatch poolCountDownLatch; private final DeviceTestRunnerFactory deviceTestRunnerFactory; private final ProgressReporter progressReporter; public PoolTestRunner(DeviceTestRunnerFactory deviceTestRunnerFactory, Pool pool, - Queue testCases, + Queue testCases, CountDownLatch poolCountDownLatch, ProgressReporter progressReporter) { this.pool = pool; diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java index 9a07dfc2..da4fdd6a 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java @@ -10,6 +10,7 @@ package com.shazam.fork.runner; +import com.shazam.fork.batch.tasks.TestTask; import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; @@ -26,7 +27,7 @@ public PoolTestRunnerFactory(DeviceTestRunnerFactory deviceTestRunnerFactory) { } public Runnable createPoolTestRunner(Pool pool, - Queue testCases, + Queue testCases, CountDownLatch poolCountDownLatch, ProgressReporter progressReporter) { diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.java b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.java deleted file mode 100755 index abdbf4e7..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2016 Shazam Entertainment Limited - * - * 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.shazam.fork.runner; - -import com.android.ddmlib.AdbCommandRejectedException; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.ShellCommandUnresponsiveException; -import com.android.ddmlib.TimeoutException; -import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; -import com.android.ddmlib.testrunner.ITestRunListener; -import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; -import com.android.ddmlib.testrunner.TestIdentifier; -import com.google.common.base.Strings; -import com.shazam.fork.model.TestCaseEvent; -import com.shazam.fork.system.PermissionGrantingManager; -import com.shazam.fork.system.io.RemoteFileManager; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.List; - -import static java.lang.String.format; - -class TestRun { - private static final Logger logger = LoggerFactory.getLogger(TestRun.class); - private final String poolName; - private final TestRunParameters testRunParameters; - private final List testRunListeners; - private final PermissionGrantingManager permissionGrantingManager; - - public TestRun(String poolName, - TestRunParameters testRunParameters, - List testRunListeners, - PermissionGrantingManager permissionGrantingManager) { - this.poolName = poolName; - this.testRunParameters = testRunParameters; - this.testRunListeners = testRunListeners; - this.permissionGrantingManager = permissionGrantingManager; - } - - public void execute() { - String applicationPackage = testRunParameters.getApplicationPackage(); - IDevice device = testRunParameters.getDeviceInterface(); - - RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner( - testRunParameters.getTestPackage(), - testRunParameters.getTestRunner(), - device); - - TestCaseEvent test = testRunParameters.getTest(); - String testClassName = test.getTestClass(); - String testMethodName = test.getTestMethod(); - IRemoteAndroidTestRunner.TestSize testSize = testRunParameters.getTestSize(); - if (testSize != null) { - runner.setTestSize(testSize); - } - runner.setRunName(poolName); - runner.setMethodName(testClassName, testMethodName); - runner.setMaxtimeToOutputResponse(testRunParameters.getTestOutputTimeout()); - - if (testRunParameters.isCoverageEnabled()) { - runner.setCoverage(true); - runner.addInstrumentationArg("coverageFile", RemoteFileManager.getCoverageFileName(new TestIdentifier(testClassName, testMethodName))); - } - - List permissionsToRevoke = testRunParameters.getTest().getPermissionsToRevoke(); - - permissionGrantingManager.revokePermissions(applicationPackage, device, permissionsToRevoke); - - try { - runner.run(testRunListeners); - } catch (ShellCommandUnresponsiveException | TimeoutException e) { - logger.warn("Test: " + testClassName + " got stuck. You can increase the timeout in settings if it's too strict"); - } catch (AdbCommandRejectedException | IOException e) { - throw new RuntimeException(format("Error while running test %s %s", test.getTestClass(), test.getTestMethod()), e); - } finally { - permissionGrantingManager.restorePermissions(applicationPackage, device, permissionsToRevoke); - } - - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt new file mode 100755 index 00000000..01e3454a --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt @@ -0,0 +1,120 @@ +/* + * Copyright 2016 Shazam Entertainment Limited + * + * 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.shazam.fork.runner + +import com.android.ddmlib.AdbCommandRejectedException +import com.android.ddmlib.ShellCommandUnresponsiveException +import com.android.ddmlib.TimeoutException +import com.android.ddmlib.testrunner.ITestRunListener +import com.android.ddmlib.testrunner.RemoteAndroidTestRunner +import com.android.ddmlib.testrunner.TestIdentifier +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.system.PermissionGrantingManager +import com.shazam.fork.system.io.RemoteFileManager + +import org.slf4j.LoggerFactory + +import java.io.IOException + +import java.lang.String.format +import java.util.* + +internal class TestRun(private val poolName: String, + private val testRunParameters: TestRunParameters, + private val testRunListeners: List, + private val permissionGrantingManager: PermissionGrantingManager) { + + val logger = LoggerFactory.getLogger(TestRun::class.java) + + fun execute() { + val applicationPackage = testRunParameters.applicationPackage + val device = testRunParameters.deviceInterface + + val runner = RemoteAndroidTestRunner( + testRunParameters.testPackage, + testRunParameters.testRunner, + device) + + val test = testRunParameters.test + + runner.setRunName(poolName) + val testSize = testRunParameters.testSize + if (testSize != null) { + logger.error("TestSize = $testSize") + runner.setTestSize(testSize) + } + + runner.setMaxtimeToOutputResponse(testRunParameters.testOutputTimeout) + + runner.apply { + when (test) { + is TestTask.SingleTestTask -> executeSingle(test, runner) + is TestTask.MultiTestTask -> executeMultiple(test, runner) + } + } + + + try { + runner.run(testRunListeners) + } catch (e: ShellCommandUnresponsiveException) { + logger.warn("Test got stuck. You can increase the timeout in settings if it's too strict") +// logger.warn("Test: $testClassName got stuck. You can increase the timeout in settings if it's too strict") + } catch (e: TimeoutException) { + logger.warn("Test got stuck. You can increase the timeout in settings if it's too strict") +// logger.warn("Test: $testClassName got stuck. You can increase the timeout in settings if it's too strict") + } catch (e: AdbCommandRejectedException) { +// throw RuntimeException(format("Error while running test %s %s", test.getTestClass(), test.getTestMethod()), e) + throw RuntimeException("Error while running test") + } catch (e: IOException) { + throw RuntimeException("Error while running test") +// throw RuntimeException(format("Error while running test %s %s", test.getTestClass(), test.getTestMethod()), e) + } finally { +// permissionGrantingManager.restorePermissions(applicationPackage, device, permissionsToRevoke) + } + + } + + private fun executeMultiple(test: TestTask.MultiTestTask, runner: RemoteAndroidTestRunner) { + val classes = test.list.map { + "${it.testClass}#${it.testMethod}" + }.toTypedArray() + + if (testRunParameters.isCoverageEnabled) { + runner.setCoverage(true) + runner.addInstrumentationArg("coverageFile", "/sdcard/fork/coverage.ec") + } + + logger.error("executeMultiple ${Arrays.toString(classes)}") + runner.setClassNames(classes) + } + + + private fun executeSingle(test: TestTask.SingleTestTask, runner: RemoteAndroidTestRunner) { + logger.error("executeSingle ${test.event.testClass}#${test.event.testMethod}") + val testClassName = test.event.testClass + val testMethodName = test.event.testMethod + + runner.setMethodName(testClassName, testMethodName) + + if (testRunParameters.isCoverageEnabled) { + runner.setCoverage(true) + runner.addInstrumentationArg("coverageFile", RemoteFileManager.getCoverageFileName(TestIdentifier(testClassName, testMethodName))) + } + + val permissionsToRevoke = test.event.permissionsToRevoke + val applicationPackage = testRunParameters.applicationPackage + val device = testRunParameters.deviceInterface + permissionGrantingManager.revokePermissions(applicationPackage, device, permissionsToRevoke) + } + + companion object { + private val logger = LoggerFactory.getLogger(TestRun::class.java) + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java index 48fb6d39..c012d727 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java @@ -12,6 +12,7 @@ import com.android.ddmlib.testrunner.ITestRunListener; import com.shazam.fork.Configuration; +import com.shazam.fork.batch.tasks.TestTask; import com.shazam.fork.model.*; import com.shazam.fork.runner.listeners.TestRunListenersFactory; @@ -35,11 +36,11 @@ public TestRunFactory(Configuration configuration, this.factory = factory; } - public TestRun createTestRun(TestCaseEvent testCase, + public TestRun createTestRun(TestTask testCase, Device device, Pool pool, ProgressReporter progressReporter, - Queue queueOfTestsInPool) { + Queue queueOfTestsInPool) { TestRunParameters testRunParameters = testRunParameters() .withDeviceInterface(device.getDeviceInterface()) .withTest(testCase) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunParameters.java b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunParameters.java index dbdcdfb2..fab0f6d7 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunParameters.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunParameters.java @@ -14,12 +14,12 @@ import com.android.ddmlib.IDevice; import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; -import com.shazam.fork.model.TestCaseEvent; +import com.shazam.fork.batch.tasks.TestTask; import javax.annotation.Nullable; public class TestRunParameters { - private final TestCaseEvent test; + private final TestTask test; private final String testPackage; private final String testRunner; private final boolean isCoverageEnabled; @@ -28,7 +28,7 @@ public class TestRunParameters { private final IDevice deviceInterface; private final String applicationPackage; - public TestCaseEvent getTest() { + public TestTask getTest() { return test; } @@ -62,7 +62,7 @@ public String getApplicationPackage() { } public static class Builder { - private TestCaseEvent test; + private TestTask test; private String testPackage; private String testRunner; private boolean isCoverageEnabled; @@ -75,7 +75,7 @@ public static Builder testRunParameters() { return new Builder(); } - public Builder withTest(TestCaseEvent test) { + public Builder withTest(TestTask test) { this.test = test; return this; } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.java deleted file mode 100644 index 8d7e502c..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.shazam.fork.runner.listeners; - -import com.android.ddmlib.testrunner.ITestRunListener; -import com.android.ddmlib.testrunner.TestIdentifier; -import com.shazam.fork.model.*; -import com.shazam.fork.system.io.FileManager; -import com.shazam.fork.system.io.RemoteFileManager; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.util.Map; - -import static com.shazam.fork.system.io.FileType.COVERAGE; - -public class CoverageListener implements ITestRunListener { - - private final Device device; - private final FileManager fileManager; - private final Pool pool; - private final Logger logger = LoggerFactory.getLogger(CoverageListener.class); - private final TestCaseEvent testCase; - - public CoverageListener(Device device, FileManager fileManager, Pool pool, TestCaseEvent testCase) { - this.device = device; - this.fileManager = fileManager; - this.pool = pool; - this.testCase = testCase; - } - - @Override - public void testRunStarted(String runName, int testCount) { - } - - @Override - public void testStarted(TestIdentifier test) { - } - - @Override - public void testFailed(TestIdentifier test, String trace) { - } - - @Override - public void testAssumptionFailure(TestIdentifier test, String trace) { - } - - @Override - public void testIgnored(TestIdentifier test) { - } - - @Override - public void testEnded(TestIdentifier test, Map testMetrics) { - } - - @Override - public void testRunFailed(String errorMessage) { - } - - @Override - public void testRunStopped(long elapsedTime) { - } - - @Override - public void testRunEnded(long elapsedTime, Map runMetrics) { - TestIdentifier testIdentifier = new TestIdentifier(testCase.getTestClass(), testCase.getTestMethod()); - final String remoteFile = RemoteFileManager.getCoverageFileName(testIdentifier); - final File file = fileManager.createFile(COVERAGE, pool, device, testIdentifier); - try { - device.getDeviceInterface().pullFile(remoteFile, file.getAbsolutePath()); - } catch (Exception e) { - logger.error("Something went wrong while pulling coverage file", e); - } - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.kt new file mode 100644 index 00000000..134323ed --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.kt @@ -0,0 +1,65 @@ +package com.shazam.fork.runner.listeners + +import com.android.ddmlib.testrunner.ITestRunListener +import com.android.ddmlib.testrunner.TestIdentifier +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.* +import com.shazam.fork.system.io.FileManager +import com.shazam.fork.system.io.RemoteFileManager + +import org.slf4j.LoggerFactory + +import com.shazam.fork.system.io.FileType.COVERAGE + +class CoverageListener(private val device: Device, private val fileManager: FileManager, private val pool: Pool, private val testCase: TestTask) : ITestRunListener { + private val logger = LoggerFactory.getLogger(CoverageListener::class.java) + + override fun testRunStarted(runName: String, testCount: Int) {} + + override fun testStarted(test: TestIdentifier) {} + + override fun testFailed(test: TestIdentifier, trace: String) {} + + override fun testAssumptionFailure(test: TestIdentifier, trace: String) {} + + override fun testIgnored(test: TestIdentifier) {} + + override fun testEnded(test: TestIdentifier, testMetrics: Map) { + if (testCase is TestTask.MultiTestTask) { + saveCoverageFile("/sdcard/fork/coverage.ec", test) + } + } + + override fun testRunFailed(errorMessage: String) {} + + override fun testRunStopped(elapsedTime: Long) {} + + override fun testRunEnded(elapsedTime: Long, runMetrics: Map) { + when (testCase) { + is TestTask.SingleTestTask -> { + saveCoverageFile(testCase.event) + } + } + } + + private fun saveCoverageFile(testCase: TestCaseEvent) { + val testIdentifier = TestIdentifier(testCase.testClass, testCase.testMethod) + + val remoteFile = RemoteFileManager.getCoverageFileName(testIdentifier) + val file = fileManager.createFile(COVERAGE, pool, device, testIdentifier) + try { + device.deviceInterface.pullFile(remoteFile, file.absolutePath) + } catch (e: Exception) { + logger.error("Something went wrong while pulling coverage file", e) + } + } + + private fun saveCoverageFile(path: String, test: TestIdentifier) { + val file = fileManager.createFile(COVERAGE, pool, device, test) + try { + device.deviceInterface.pullFile(path, file.absolutePath) + } catch (e: Exception) { + logger.error("Something went wrong while pulling coverage file", e) + } + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.java deleted file mode 100755 index b2d80402..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2014 Shazam Entertainment Limited - * - * 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.shazam.fork.runner.listeners; - -import com.android.ddmlib.testrunner.TestIdentifier; -import com.android.ddmlib.testrunner.XmlTestRunListener; -import com.google.common.collect.ImmutableMap; -import com.shazam.fork.model.Device; -import com.shazam.fork.model.Pool; -import com.shazam.fork.model.TestCaseEvent; -import com.shazam.fork.model.TestCaseEventFactory; -import com.shazam.fork.runner.ProgressReporter; -import com.shazam.fork.system.io.FileManager; -import com.shazam.fork.system.io.FileType; - -import java.io.File; -import java.util.Map; - -import javax.annotation.Nonnull; - -import static com.shazam.fork.summary.TestResult.SUMMARY_KEY_TOTAL_FAILURE_COUNT; - -public class ForkXmlTestRunListener extends XmlTestRunListener { - - private final FileManager fileManager; - private final Pool pool; - private final Device device; - private final TestCaseEvent testCase; - private final TestCaseEventFactory factory; - - @Nonnull - private final ProgressReporter progressReporter; - private TestIdentifier test; - - public ForkXmlTestRunListener(FileManager fileManager, - Pool pool, - Device device, - TestCaseEvent testCase, - @Nonnull ProgressReporter progressReporter, - TestCaseEventFactory factory) { - this.fileManager = fileManager; - this.pool = pool; - this.device = device; - this.testCase = testCase; - this.progressReporter = progressReporter; - this.factory = factory; - } - - @Override - protected File getResultFile(File reportDir) { - return fileManager.createFile(FileType.TEST, pool, device, testCase); - } - - @Override - public void testStarted(TestIdentifier test) { - this.test = test; - super.testStarted(test); - } - - @Override - protected Map getPropertiesAttributes() { - ImmutableMap.Builder mapBuilder = ImmutableMap.builder() - .putAll(super.getPropertiesAttributes()); - if (test != null) { - int testFailuresCount = progressReporter.getTestFailuresCount(pool, factory.newTestCase(test)); - if (testFailuresCount > 0) { - mapBuilder.put(SUMMARY_KEY_TOTAL_FAILURE_COUNT, Integer.toString(testFailuresCount)); - } - } - if (testCase != null) { - mapBuilder.putAll(testCase.getProperties()); - } - return mapBuilder.build(); - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.kt new file mode 100755 index 00000000..2d11cb10 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2014 Shazam Entertainment Limited + * + * 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.shazam.fork.runner.listeners + +import com.android.ddmlib.testrunner.TestIdentifier +import com.android.ddmlib.testrunner.XmlTestRunListener +import com.google.common.collect.ImmutableMap +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.Device +import com.shazam.fork.model.Pool +import com.shazam.fork.model.TestCaseEvent +import com.shazam.fork.model.TestCaseEventFactory +import com.shazam.fork.runner.ProgressReporter +import com.shazam.fork.system.io.FileManager +import com.shazam.fork.system.io.FileType + +import java.io.File + +import com.shazam.fork.summary.TestResult.SUMMARY_KEY_TOTAL_FAILURE_COUNT + +class ForkXmlTestRunListener(private val fileManager: FileManager, + private val pool: Pool, + private val device: Device, + private val testCase: TestTask, + private val progressReporter: ProgressReporter, + private val factory: TestCaseEventFactory) : XmlTestRunListener() { + private var test: TestIdentifier? = null + + override fun getResultFile(reportDir: File): File { + return when (testCase) { + is TestTask.SingleTestTask -> fileManager.createFile(FileType.TEST, pool, device, testCase.event) + is TestTask.MultiTestTask -> fileManager.createFile(FileType.TEST, pool, device, testCase.list.hashCode().toString()) + } + } + + override fun testStarted(test: TestIdentifier) { + this.test = test + super.testStarted(test) + } + + override fun getPropertiesAttributes(): Map { + val mapBuilder = ImmutableMap.builder() + .putAll(super.getPropertiesAttributes()) + if (test != null) { + val testFailuresCount = progressReporter.getTestFailuresCount(pool, factory.newTestCase(test!!)) + if (testFailuresCount > 0) { + mapBuilder.put(SUMMARY_KEY_TOTAL_FAILURE_COUNT, Integer.toString(testFailuresCount)) + } + } + // if (testCase != null) { + // mapBuilder.putAll(testCase.getProperties()); + // } + return mapBuilder.build() + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java index b6a9ad57..04a04cc7 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java @@ -11,6 +11,7 @@ package com.shazam.fork.runner.listeners; import com.android.ddmlib.testrunner.TestIdentifier; +import com.shazam.fork.batch.tasks.TestTask; import com.shazam.fork.model.Device; import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; @@ -36,19 +37,18 @@ public class RetryListener extends NoOpITestRunListener { @Nonnull private final Device device; - private TestIdentifier failedTest; @Nonnull - private final Queue queueOfTestsInPool; + private final Queue queueOfTestsInPool; @Nonnull - private final TestCaseEvent currentTestCaseEvent; + private final TestTask currentTestCaseEvent; private ProgressReporter progressReporter; private FileManager fileManager; private Pool pool; private final TestCaseEventFactory testCaseEventFactory; public RetryListener(@Nonnull Pool pool, @Nonnull Device device, - @Nonnull Queue queueOfTestsInPool, - @Nonnull TestCaseEvent currentTestCaseEvent, + @Nonnull Queue queueOfTestsInPool, + @Nonnull TestTask currentTestCaseEvent, @Nonnull ProgressReporter progressReporter, FileManager fileManager, TestCaseEventFactory testCaseEventFactory) { @@ -68,26 +68,20 @@ public RetryListener(@Nonnull Pool pool, @Nonnull Device device, @Override public void testFailed(TestIdentifier test, String trace) { - failedTest = test; - progressReporter.recordFailedTestCase(pool, testCaseEventFactory.newTestCase(failedTest)); - } + progressReporter.recordFailedTestCase(pool, testCaseEventFactory.newTestCase(test)); - @Override - public void testRunEnded(long elapsedTime, Map runMetrics) { - super.testRunEnded(elapsedTime, runMetrics); - if (failedTest != null) { - if (progressReporter.requestRetry(pool, testCaseEventFactory.newTestCase(failedTest))) { - queueOfTestsInPool.add(currentTestCaseEvent); - logger.info("Test " + failedTest.toString() + " enqueued again into pool:" + pool.getName()); - removeFailureTraceFiles(); - } else { - logger.info("Test " + failedTest.toString() + " failed on device " + device.getSafeSerial() + " but retry is not allowed."); - } + if (progressReporter.requestRetry(pool, testCaseEventFactory.newTestCase(test))) { + queueOfTestsInPool.add(currentTestCaseEvent); + logger.info("Test " + test.toString() + " enqueued again into pool:" + pool.getName()); + removeFailureTraceFiles(test); + } else { + logger.info("Test " + test.toString() + " failed on device " + device.getSafeSerial() + " but retry is not allowed."); } } - public void removeFailureTraceFiles() { - final File file = fileManager.getFile(FileType.TEST, pool.getName(), device.getSafeSerial(), failedTest); + + private void removeFailureTraceFiles(TestIdentifier test) { + final File file = fileManager.getFile(FileType.TEST, pool.getName(), device.getSafeSerial(), test); boolean deleted = file.delete(); if (!deleted) { logger.warn("Failed to remove file " + file.getAbsoluteFile() + " for a failed but enqueued again test"); diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java index f3fa1ea8..a0527616 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java @@ -5,6 +5,8 @@ import com.shazam.fork.model.Device; import com.shazam.fork.stat.TestExecution; import com.shazam.fork.stat.TestExecutionReporter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Map; @@ -12,6 +14,8 @@ public class TestExecutionListener implements ITestRunListener { + Logger logger = LoggerFactory.getLogger(TestExecutionListener.class); + private long startTime = 0; private final Device device; @@ -27,12 +31,14 @@ public class TestExecutionListener implements ITestRunListener { @Override public void testRunStarted(String runName, int testCount) { + logger.error("testRunStarted = " + runName + " testCount = " + testCount); } @Override public void testStarted(TestIdentifier test) { startTime = currentTimeMillis(); failed = false; + logger.error("testStarted= " + test.toString()); } @Override @@ -55,6 +61,7 @@ public void testEnded(TestIdentifier test, Map testMetrics) { startTime, endedAfter, failed ? TestExecution.Status.FAILED : TestExecution.Status.ENDED); + logger.error("testEnded = " + test.toString()); executionReporter.add(device, execution); } @@ -68,5 +75,6 @@ public void testRunStopped(long elapsedTime) { @Override public void testRunEnded(long elapsedTime, Map runMetrics) { + logger.error("testEnded"); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java index 2742fc70..77a695e8 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java @@ -13,9 +13,9 @@ import com.android.ddmlib.testrunner.ITestRunListener; import com.google.gson.Gson; import com.shazam.fork.Configuration; +import com.shazam.fork.batch.tasks.TestTask; import com.shazam.fork.model.Device; import com.shazam.fork.model.Pool; -import com.shazam.fork.model.TestCaseEvent; import com.shazam.fork.model.TestCaseEventFactory; import com.shazam.fork.runner.ProgressReporter; import com.shazam.fork.stat.TestExecutionReporter; @@ -46,11 +46,11 @@ public TestRunListenersFactory(Configuration configuration, this.testExecutionReporter = testExecutionReporter; } - public List createTestListeners(TestCaseEvent testCase, + public List createTestListeners(TestTask testCase, Device device, Pool pool, ProgressReporter progressReporter, - Queue testCaseEventQueue, + Queue testCaseEventQueue, TestCaseEventFactory factory) { return asList( new ProgressTestRunListener(pool, progressReporter), @@ -70,7 +70,7 @@ private ForkXmlTestRunListener getForkXmlTestRunListener(FileManager fileManager File output, Pool pool, Device device, - TestCaseEvent testCase, + TestTask testCase, ProgressReporter progressReporter, TestCaseEventFactory factory) { ForkXmlTestRunListener xmlTestRunListener = new ForkXmlTestRunListener(fileManager, pool, device, testCase, progressReporter, factory); @@ -78,11 +78,11 @@ private ForkXmlTestRunListener getForkXmlTestRunListener(FileManager fileManager return xmlTestRunListener; } - private ITestRunListener getCoverageTestRunListener(Configuration configuration, + private ITestRunListener getCoverageTestRunListener(Configuration configuration, Device device, FileManager fileManager, Pool pool, - TestCaseEvent testCase) { + TestTask testCase) { if (configuration.isCoverageEnabled()) { return new CoverageListener(device, fileManager, pool, testCase); } diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/TestCase.java b/fork-runner/src/main/java/com/shazam/fork/summary/TestCase.java index d49f9e8a..cf999d3f 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/TestCase.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/TestCase.java @@ -17,7 +17,7 @@ import org.simpleframework.xml.Root; @Root(name="testcase", strict=false) -class TestCase { +public class TestCase { @Attribute private String name; diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/TestSuite.java b/fork-runner/src/main/java/com/shazam/fork/summary/TestSuite.java index ecd22bc1..576c7e9d 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/TestSuite.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/TestSuite.java @@ -22,7 +22,7 @@ @Root -class TestSuite { +public class TestSuite { @ElementList(inline=true, type=TestCase.class, required=false) private List testCases; diff --git a/fork-runner/src/main/java/com/shazam/fork/system/io/FileManager.java b/fork-runner/src/main/java/com/shazam/fork/system/io/FileManager.java index 46d1909f..e934b181 100644 --- a/fork-runner/src/main/java/com/shazam/fork/system/io/FileManager.java +++ b/fork-runner/src/main/java/com/shazam/fork/system/io/FileManager.java @@ -37,7 +37,7 @@ public File[] getTestFilesForDevice(Pool pool, Device serial) { return path.toFile().listFiles(); } - public File createFile(FileType fileType, Pool pool, Device device, TestCaseEvent testCaseEvent){ + public File createFile(FileType fileType, Pool pool, Device device, TestCaseEvent testCaseEvent) { return createFile(fileType, pool, device, new TestIdentifier(testCaseEvent.getTestClass(), testCaseEvent.getTestMethod())); } @@ -61,6 +61,16 @@ public File createFile(FileType fileType, Pool pool, Device device, TestIdentifi } } + public File createFile(FileType fileType, Pool pool, Device device, String file) { + try { + Path directory = createDirectory(fileType, pool, device); + String filename = String.format("%s.%s", file, fileType.getSuffix()); + return createFile(directory, filename); + } catch (IOException e) { + throw new CouldNotCreateDirectoryException(e); + } + } + public File createSummaryFile() { try { Path path = get(output.getAbsolutePath(), "summary"); @@ -86,10 +96,18 @@ public File getFile(FileType fileType, String pool, String safeSerial, TestIdent return path.toFile(); } + public Path createDirectory(FileType test) throws IOException { + return createDirectories(getDirectory(test)); + } + private Path createDirectory(FileType test, Pool pool, Device device) throws IOException { return createDirectories(getDirectory(test, pool, device)); } + private Path getDirectory(FileType fileType) { + return get(output.getAbsolutePath(), fileType.getDirectory()); + } + private Path getDirectory(FileType fileType, Pool pool, Device device) { return get(output.getAbsolutePath(), fileType.getDirectory(), pool.getName(), device.getSafeSerial()); } diff --git a/fork-runner/src/main/java/com/shazam/fork/system/io/FileType.java b/fork-runner/src/main/java/com/shazam/fork/system/io/FileType.java index 3e5a230e..ad4e139b 100644 --- a/fork-runner/src/main/java/com/shazam/fork/system/io/FileType.java +++ b/fork-runner/src/main/java/com/shazam/fork/system/io/FileType.java @@ -2,6 +2,7 @@ public enum FileType { TEST ("tests", "xml"), + TEST_BATCH ("test_batches", "xml"), RAW_LOG("logcat", "log"), JSON_LOG("logcat_json", "json"), SCREENSHOT ("screenshot", "png"), From 33b036e65d2fb5faf24721bc15f5a90688e8f880 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 19 Dec 2017 14:31:15 +0800 Subject: [PATCH 20/51] cleanup, rework ForkXmlTestRunListener --- .../main/java/com/shazam/fork/ForkRunner.java | 8 +- .../shazam/fork/batch/watcher/BatchWatcher.kt | 91 -------- .../shazam/fork/batch/watcher/XmlService.kt | 28 --- .../fork/injector/ForkRunnerInjector.java | 4 +- .../ConsoleLoggingTestRunListener.java | 14 +- .../fork/runner/listeners/CoverageListener.kt | 20 +- .../listeners/ForkXmlTestRunListener.kt | 65 ------ .../listeners/LogCatTestRunListener.java | 26 +-- .../listeners/ProgressTestRunListener.java | 38 +--- .../ScreenCaptureTestRunListener.java | 18 +- .../ScreenRecorderTestRunListener.java | 17 +- .../listeners/SingleForkXmlTestRunListener.kt | 214 ++++++++++++++++++ .../listeners/SlowWarningTestRunListener.java | 41 +--- .../listeners/TestExecutionListener.java | 80 ------- .../runner/listeners/TestExecutionListener.kt | 35 +++ .../listeners/TestRunListenersFactory.java | 25 +- 16 files changed, 277 insertions(+), 447 deletions(-) delete mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/watcher/BatchWatcher.kt delete mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/watcher/XmlService.kt delete mode 100755 fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.kt create mode 100755 fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt delete mode 100644 fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java index 0daf8e31..fa956c94 100755 --- a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java @@ -14,7 +14,6 @@ import com.shazam.fork.batch.BatchQueueProvider; import com.shazam.fork.batch.tasks.TestTask; -import com.shazam.fork.batch.watcher.BatchWatcher; import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; import com.shazam.fork.pooling.*; @@ -46,7 +45,6 @@ public class ForkRunner { private final SummaryGeneratorHook summaryGeneratorHook; private final TestStatsLoader testStatsLoader; private final QueueProvider queueProvider; - private final BatchWatcher batchWatcher; public ForkRunner(PoolLoader poolLoader, TestSuiteLoader testClassLoader, @@ -54,8 +52,7 @@ public ForkRunner(PoolLoader poolLoader, ProgressReporter progressReporter, SummaryGeneratorHook summaryGeneratorHook, TestStatsLoader testStatsLoader, - QueueProvider queueProvider, - BatchWatcher batchWatcher) { + QueueProvider queueProvider) { this.poolLoader = poolLoader; this.testClassLoader = testClassLoader; this.poolTestRunnerFactory = poolTestRunnerFactory; @@ -63,7 +60,6 @@ public ForkRunner(PoolLoader poolLoader, this.summaryGeneratorHook = summaryGeneratorHook; this.testStatsLoader = testStatsLoader; this.queueProvider = queueProvider; - this.batchWatcher = batchWatcher; } public boolean run() { @@ -83,7 +79,6 @@ public boolean run() { summaryGeneratorHook.registerHook(pools, testCases); progressReporter.start(); - batchWatcher.start(); for (Pool pool : pools) { Runnable poolTestRunner = poolTestRunnerFactory.createPoolTestRunner(pool, testCasesQueue, @@ -93,7 +88,6 @@ public boolean run() { } poolCountDownLatch.await(); progressReporter.stop(); - batchWatcher.stop(); boolean overallSuccess = summaryGeneratorHook.defineOutcome(); logger.info("Overall success: " + overallSuccess); diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/watcher/BatchWatcher.kt b/fork-runner/src/main/java/com/shazam/fork/batch/watcher/BatchWatcher.kt deleted file mode 100644 index c62cfd68..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/batch/watcher/BatchWatcher.kt +++ /dev/null @@ -1,91 +0,0 @@ -package com.shazam.fork.batch.watcher - -import com.shazam.fork.system.io.FileManager -import com.shazam.fork.system.io.FileType -import com.sun.nio.file.SensitivityWatchEventModifier -import org.slf4j.LoggerFactory - -import java.io.IOException -import java.nio.file.FileSystems -import java.nio.file.FileVisitResult -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.SimpleFileVisitor -import java.nio.file.WatchEvent -import java.nio.file.WatchKey -import java.nio.file.WatchService -import java.nio.file.attribute.BasicFileAttributes -import java.util.HashMap -import java.util.concurrent.Executors - -import java.nio.file.StandardWatchEventKinds.ENTRY_CREATE -import java.nio.file.StandardWatchEventKinds.OVERFLOW - -class BatchWatcher(fileManager: FileManager) { - - private val xmlService = XmlService(fileManager) - - private val logger = LoggerFactory.getLogger(BatchWatcher::class.java) - private val folder = fileManager.createDirectory(FileType.TEST_BATCH) - - private val watcher: WatchService = FileSystems.getDefault().newWatchService() - private val executor = Executors.newSingleThreadExecutor() - - fun stop() { - try { - watcher.close() - } catch (e: IOException) { - logger.error("Can't close watcher", e) - } - executor.shutdown() - } - - fun start() { - - val keys = HashMap() - - val register = { p: Path -> - if (!p.toFile().exists() || !p.toFile().isDirectory) { - throw RuntimeException("folder $p does not exist or is not a directory") - } - Files.walkFileTree(p, object : SimpleFileVisitor() { - override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult { - val watchKey = dir.register(watcher, arrayOf>(ENTRY_CREATE), SensitivityWatchEventModifier.HIGH) - keys.put(watchKey, dir) - return FileVisitResult.CONTINUE - } - }) - } - - register.invoke(folder) - - executor.submit { - while (true) { - val key: WatchKey = watcher.take() - - val dir = keys[key] - if (dir == null) { - System.err.println("WatchKey $key not recognized!") - continue - } - - key.pollEvents().stream() - .filter { e -> e.kind() !== OVERFLOW } - .map { e -> (e as WatchEvent).context() } - .forEach { p -> - val absPath = dir.resolve(p) - if (absPath.toFile().isDirectory) { - register(absPath) - } else { - xmlService.splitAndSave(absPath.toFile()) - } - } - - val valid = key.reset() - if (!valid) { - break - } - } - } - } -} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/watcher/XmlService.kt b/fork-runner/src/main/java/com/shazam/fork/batch/watcher/XmlService.kt deleted file mode 100644 index 387ea57e..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/batch/watcher/XmlService.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.shazam.fork.batch.watcher - -import com.android.ddmlib.testrunner.TestIdentifier -import com.shazam.fork.model.Device -import com.shazam.fork.model.Pool -import com.shazam.fork.summary.TestSuite -import com.shazam.fork.system.io.FileManager -import com.shazam.fork.system.io.FileType -import org.simpleframework.xml.core.Persister -import java.io.File - -class XmlService(private val fileManager: FileManager) { - private val parser = Persister() - - fun splitAndSave(file: File) { - val suite = parser.read(TestSuite::class.java, file, false) - suite.testCase.forEach { - val arr = file.absolutePath.split('/').dropLast(1) - val serial = arr.last() - val poolName = arr.dropLast(1).last() - val device = Device.Builder().withSerial(serial).build() - val pool = Pool.Builder().withName(poolName).build() - val output = fileManager.createFile(FileType.TEST, pool, device, TestIdentifier(it.classname, it.name)) - parser.write(it, output) - file.delete() - } - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java index 49b14563..b7fd232d 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java @@ -14,7 +14,6 @@ import com.shazam.fork.ForkRunner; -import com.shazam.fork.batch.watcher.BatchWatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,8 +44,7 @@ public static ForkRunner forkRunner() { progressReporter(), summaryGeneratorHook(), testStatsLoader(), - queueProvider(), - new BatchWatcher(fileManager())); + queueProvider()); logger.debug("Bootstrap of ForkRunner took: {} milliseconds", millisSinceNanoTime(startNanos)); diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ConsoleLoggingTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ConsoleLoggingTestRunListener.java index 5dabf6e1..9a5ec104 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ConsoleLoggingTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ConsoleLoggingTestRunListener.java @@ -26,7 +26,7 @@ import static java.lang.String.format; @SuppressWarnings("UseOfSystemOutOrSystemErr") -class ConsoleLoggingTestRunListener implements ITestRunListener { +class ConsoleLoggingTestRunListener extends NoOpITestRunListener { private static final Logger logger = LoggerFactory.getLogger(ConsoleLoggingTestRunListener.class); private static final SimpleDateFormat TEST_TIME = new SimpleDateFormat("mm.ss"); private static final String PERCENT = "%02d%%"; @@ -43,10 +43,6 @@ public ConsoleLoggingTestRunListener(String testPackage, String serial, String m this.testPackage = testPackage; } - @Override - public void testRunStarted(String runName, int testCount) { - } - @Override public void testStarted(TestIdentifier test) { System.out.println(format("%s %s %s %s [%s] %s", runningTime(), progress(), failures(), modelName, serial, testCase(test))); @@ -68,10 +64,6 @@ public void testIgnored(TestIdentifier test) { logger.debug("ignored test {}", testCase(test)); } - @Override - public void testEnded(TestIdentifier test, Map testMetrics) { - } - @Override public void testRunFailed(String errorMessage) { System.out.println(format("%s %s %s %s [%s] Test run failed: %s", runningTime(), progress(), failures(), modelName, serial, errorMessage)); @@ -82,10 +74,6 @@ public void testRunStopped(long elapsedTime) { System.out.println(format("%s %s %s %s [%s] Test run stopped after %s ms", runningTime(), progress(), failures(), modelName, serial, elapsedTime)); } - @Override - public void testRunEnded(long elapsedTime, Map runMetrics) { - } - private String runningTime() { return TEST_TIME.format(new Date(progressReporter.millisSinceTestsStarted())); } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.kt index 134323ed..7c3f1cb4 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/CoverageListener.kt @@ -1,6 +1,5 @@ package com.shazam.fork.runner.listeners -import com.android.ddmlib.testrunner.ITestRunListener import com.android.ddmlib.testrunner.TestIdentifier import com.shazam.fork.batch.tasks.TestTask import com.shazam.fork.model.* @@ -11,29 +10,18 @@ import org.slf4j.LoggerFactory import com.shazam.fork.system.io.FileType.COVERAGE -class CoverageListener(private val device: Device, private val fileManager: FileManager, private val pool: Pool, private val testCase: TestTask) : ITestRunListener { +class CoverageListener(private val device: Device, + private val fileManager: FileManager, + private val pool: Pool, + private val testCase: TestTask) : NoOpITestRunListener() { private val logger = LoggerFactory.getLogger(CoverageListener::class.java) - override fun testRunStarted(runName: String, testCount: Int) {} - - override fun testStarted(test: TestIdentifier) {} - - override fun testFailed(test: TestIdentifier, trace: String) {} - - override fun testAssumptionFailure(test: TestIdentifier, trace: String) {} - - override fun testIgnored(test: TestIdentifier) {} - override fun testEnded(test: TestIdentifier, testMetrics: Map) { if (testCase is TestTask.MultiTestTask) { saveCoverageFile("/sdcard/fork/coverage.ec", test) } } - override fun testRunFailed(errorMessage: String) {} - - override fun testRunStopped(elapsedTime: Long) {} - override fun testRunEnded(elapsedTime: Long, runMetrics: Map) { when (testCase) { is TestTask.SingleTestTask -> { diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.kt deleted file mode 100755 index 2d11cb10..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ForkXmlTestRunListener.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2014 Shazam Entertainment Limited - * - * 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.shazam.fork.runner.listeners - -import com.android.ddmlib.testrunner.TestIdentifier -import com.android.ddmlib.testrunner.XmlTestRunListener -import com.google.common.collect.ImmutableMap -import com.shazam.fork.batch.tasks.TestTask -import com.shazam.fork.model.Device -import com.shazam.fork.model.Pool -import com.shazam.fork.model.TestCaseEvent -import com.shazam.fork.model.TestCaseEventFactory -import com.shazam.fork.runner.ProgressReporter -import com.shazam.fork.system.io.FileManager -import com.shazam.fork.system.io.FileType - -import java.io.File - -import com.shazam.fork.summary.TestResult.SUMMARY_KEY_TOTAL_FAILURE_COUNT - -class ForkXmlTestRunListener(private val fileManager: FileManager, - private val pool: Pool, - private val device: Device, - private val testCase: TestTask, - private val progressReporter: ProgressReporter, - private val factory: TestCaseEventFactory) : XmlTestRunListener() { - private var test: TestIdentifier? = null - - override fun getResultFile(reportDir: File): File { - return when (testCase) { - is TestTask.SingleTestTask -> fileManager.createFile(FileType.TEST, pool, device, testCase.event) - is TestTask.MultiTestTask -> fileManager.createFile(FileType.TEST, pool, device, testCase.list.hashCode().toString()) - } - } - - override fun testStarted(test: TestIdentifier) { - this.test = test - super.testStarted(test) - } - - override fun getPropertiesAttributes(): Map { - val mapBuilder = ImmutableMap.builder() - .putAll(super.getPropertiesAttributes()) - if (test != null) { - val testFailuresCount = progressReporter.getTestFailuresCount(pool, factory.newTestCase(test!!)) - if (testFailuresCount > 0) { - mapBuilder.put(SUMMARY_KEY_TOTAL_FAILURE_COUNT, Integer.toString(testFailuresCount)) - } - } - // if (testCase != null) { - // mapBuilder.putAll(testCase.getProperties()); - // } - return mapBuilder.build() - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/LogCatTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/LogCatTestRunListener.java index 9f6406c8..0a16401e 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/LogCatTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/LogCatTestRunListener.java @@ -22,7 +22,7 @@ import java.util.*; -class LogCatTestRunListener implements ITestRunListener { +class LogCatTestRunListener extends NoOpITestRunListener { private final FileManager fileManager; private final Pool pool; private final Device device; @@ -47,22 +47,6 @@ public void testRunStarted(String runName, int testCount) { new Thread(logCatReceiverTask, "CatLogger-" + runName + "-" + device.getSerial()).start(); } - @Override - public void testStarted(TestIdentifier test) { - } - - @Override - public void testFailed(TestIdentifier test, String trace) { - } - - @Override - public void testAssumptionFailure(TestIdentifier test, String trace) { - } - - @Override - public void testIgnored(TestIdentifier test) { - } - @Override public void testEnded(TestIdentifier test, Map testMetrics) { List copyOfLogCatMessages; @@ -78,14 +62,6 @@ public void testEnded(TestIdentifier test, Map testMetrics) { logCatSerializer.serializeLogs(copyOfLogCatMessages); } - @Override - public void testRunFailed(String errorMessage) { - } - - @Override - public void testRunStopped(long elapsedTime) { - } - @Override public void testRunEnded(long elapsedTime, Map runMetrics) { logCatReceiverTask.stop(); diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ProgressTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ProgressTestRunListener.java index 0069e83c..f14a9392 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ProgressTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ProgressTestRunListener.java @@ -10,7 +10,6 @@ package com.shazam.fork.runner.listeners; -import com.android.ddmlib.testrunner.ITestRunListener; import com.android.ddmlib.testrunner.TestIdentifier; import com.shazam.fork.model.Pool; import com.shazam.fork.runner.PoolProgressTracker; @@ -18,7 +17,7 @@ import java.util.Map; -class ProgressTestRunListener implements ITestRunListener { +class ProgressTestRunListener extends NoOpITestRunListener{ private final PoolProgressTracker poolProgressTracker; @@ -26,48 +25,13 @@ class ProgressTestRunListener implements ITestRunListener { poolProgressTracker = progressReporter.getProgressTrackerFor(pool); } - @Override - public void testRunStarted(String runName, int testCount) { - - } - - @Override - public void testStarted(TestIdentifier test) { - - } - @Override public void testFailed(TestIdentifier test, String trace) { poolProgressTracker.failedTest(); } - @Override - public void testAssumptionFailure(TestIdentifier test, String trace) { - - } - - @Override - public void testIgnored(TestIdentifier test) { - - } - @Override public void testEnded(TestIdentifier test, Map testMetrics) { poolProgressTracker.completedTest(); } - - @Override - public void testRunFailed(String errorMessage) { - - } - - @Override - public void testRunStopped(long elapsedTime) { - - } - - @Override - public void testRunEnded(long elapsedTime, Map runMetrics) { - - } } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenCaptureTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenCaptureTestRunListener.java index 39824b28..0ffcdb8d 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenCaptureTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenCaptureTestRunListener.java @@ -18,7 +18,7 @@ import java.util.Map; -class ScreenCaptureTestRunListener implements ITestRunListener { +class ScreenCaptureTestRunListener extends NoOpITestRunListener { private final FileManager fileManager; private final IDevice deviceInterface; private final Pool pool; @@ -34,10 +34,6 @@ public ScreenCaptureTestRunListener(FileManager fileManager, Pool pool, Device d this.device = device; } - @Override - public void testRunStarted(String runName, int testCount) { - } - @Override public void testStarted(TestIdentifier test) { hasFailed = false; @@ -64,16 +60,4 @@ public void testIgnored(TestIdentifier test) { public void testEnded(TestIdentifier test, Map testMetrics) { screenCapturer.stopCapturing(hasFailed); } - - @Override - public void testRunFailed(String errorMessage) { - } - - @Override - public void testRunStopped(long elapsedTime) { - } - - @Override - public void testRunEnded(long elapsedTime, Map runMetrics) { - } } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenRecorderTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenRecorderTestRunListener.java index 7716254f..7eb3bbd4 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenRecorderTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenRecorderTestRunListener.java @@ -21,7 +21,7 @@ import static com.shazam.fork.system.io.FileType.SCREENRECORD; -class ScreenRecorderTestRunListener implements ITestRunListener { +class ScreenRecorderTestRunListener extends NoOpITestRunListener { private final FileManager fileManager; private final Pool pool; private final Device device; @@ -37,9 +37,6 @@ public ScreenRecorderTestRunListener(FileManager fileManager, Pool pool, Device deviceInterface = device.getDeviceInterface(); } - @Override - public void testRunStarted(String runName, int testCount) { - } @Override public void testStarted(TestIdentifier test) { @@ -69,16 +66,4 @@ public void testIgnored(TestIdentifier test) { public void testEnded(TestIdentifier test, Map testMetrics) { screenRecorderStopper.stopScreenRecord(hasFailed); } - - @Override - public void testRunFailed(String errorMessage) { - } - - @Override - public void testRunStopped(long elapsedTime) { - } - - @Override - public void testRunEnded(long elapsedTime, Map runMetrics) { - } } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt new file mode 100755 index 00000000..ffe2cf81 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt @@ -0,0 +1,214 @@ +package com.shazam.fork.runner.listeners + +import com.android.SdkConstants +import com.android.ddmlib.Log +import com.android.ddmlib.testrunner.TestIdentifier +import com.android.ddmlib.testrunner.TestResult +import com.android.ddmlib.testrunner.TestRunResult +import com.google.common.collect.ImmutableMap +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.Device +import com.shazam.fork.model.Pool +import com.shazam.fork.model.TestCaseEventFactory +import com.shazam.fork.runner.ProgressReporter +import com.shazam.fork.summary.TestResult.SUMMARY_KEY_TOTAL_FAILURE_COUNT +import com.shazam.fork.system.io.FileManager +import com.shazam.fork.system.io.FileType +import org.kxml2.io.KXmlSerializer +import java.io.BufferedOutputStream +import java.io.File +import java.io.FileOutputStream +import java.io.OutputStream +import java.text.SimpleDateFormat +import java.util.* + +class SingleForkXmlTestRunListener(val fileManager: FileManager, + val pool: Pool, + val device: Device, + val testCase: TestTask, + val progressReporter: ProgressReporter, + val factory: TestCaseEventFactory, + val output: File) : NoOpITestRunListener() { + + private lateinit var runResult: TestRunResult + private var startTime: Long = 0L + + override fun testStarted(test: TestIdentifier) { + runResult = TestRunResult() + runResult.testStarted(test) + startTime = System.currentTimeMillis() + } + + override fun testAssumptionFailure(test: TestIdentifier, trace: String) { + runResult.testAssumptionFailure(test, trace) + generateDocument(runResult, test, elapsedTime()) + } + + override fun testFailed(test: TestIdentifier, trace: String) { + runResult.testFailed(test, trace) + generateDocument(runResult, test, elapsedTime()) + } + + override fun testEnded(test: TestIdentifier, testMetrics: MutableMap) { + runResult.testEnded(test, testMetrics) + generateDocument(runResult, test, elapsedTime()) + } + + private fun elapsedTime() = System.currentTimeMillis() - startTime + + override fun testIgnored(test: TestIdentifier?) { + runResult.testIgnored(test) + } + + fun getResultFile(test: TestIdentifier): File { + return fileManager.createFile(FileType.TEST, pool, device, test) + } + + private fun getAbsoluteReportPath(): String { + return output.absolutePath + } + + private fun generateDocument(runResult: TestRunResult, test: TestIdentifier, elapsedTime: Long) { + val timestamp = getTimestamp() + + createOutputResultStream(test).use { + val serializer = KXmlSerializer() + serializer.setOutput(it, SdkConstants.UTF_8) + serializer.startDocument(SdkConstants.UTF_8, null) + serializer.setFeature( + "http://xmlpull.org/v1/doc/features.html#indent-output", true) + printTestResults(serializer, timestamp, elapsedTime, runResult, test) + serializer.endDocument() + val msg = String.format("XML test result file generated at %s. %s", + getAbsoluteReportPath(), runResult.textSummary) + Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG, msg) + } + } + + private fun getTimestamp(): String { + val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", + Locale.getDefault()) + val gmt = TimeZone.getTimeZone("UTC") + dateFormat.timeZone = gmt + dateFormat.isLenient = true + return dateFormat.format(Date()) + } + + private fun createOutputResultStream(test: TestIdentifier): OutputStream { + val reportFile = getResultFile(test) + return BufferedOutputStream(FileOutputStream(reportFile)) + } + + private fun getTestSuiteName(): String? { + return pool.name + } + + private fun printTestResults(serializer: KXmlSerializer, + timestamp: String, + elapsedTime: Long, + runResult: TestRunResult, test: TestIdentifier) { + serializer.startTag(ns, TESTSUITE) + val name = getTestSuiteName() + if (name != null) { + serializer.attribute(ns, ATTR_NAME, name) + } + serializer.attribute(ns, ATTR_TESTS, Integer.toString(runResult.numTests)) + serializer.attribute(ns, ATTR_FAILURES, Integer.toString( + runResult.numAllFailedTests)) + // legacy - there are no errors in JUnit4 + serializer.attribute(ns, ATTR_ERRORS, "0") + serializer.attribute(ns, ATTR_SKIPPED, Integer.toString(runResult.getNumTestsInState( + TestResult.TestStatus.IGNORED))) + + serializer.attribute(ns, ATTR_TIME, java.lang.Double.toString(elapsedTime.toDouble() / 1000f)) + serializer.attribute(ns, TIMESTAMP, timestamp) + serializer.attribute(ns, HOSTNAME, hostName) + + serializer.startTag(ns, PROPERTIES) + for ((key, value) in getPropertiesAttributes(test)) { + serializer.startTag(ns, PROPERTY) + serializer.attribute(ns, "name", key) + serializer.attribute(ns, "value", value) + serializer.endTag(ns, PROPERTY) + } + serializer.endTag(ns, PROPERTIES) + + val testResults = runResult.testResults + for (testEntry in testResults.entries) { + print(serializer, testEntry.key, testEntry.value) + } + + serializer.endTag(ns, TESTSUITE) + } + + fun getPropertiesAttributes(test: TestIdentifier): Map { + val mapBuilder = ImmutableMap.builder() + + val testFailuresCount = progressReporter.getTestFailuresCount(pool, factory.newTestCase(test)) + if (testFailuresCount > 0) { + mapBuilder.put(SUMMARY_KEY_TOTAL_FAILURE_COUNT, Integer.toString(testFailuresCount)) + } + + when (testCase) { + is TestTask.SingleTestTask -> mapBuilder.putAll(testCase.event.properties) + } + return mapBuilder.build() + } + + private fun getTestName(testId: TestIdentifier): String { + return testId.testName + } + + fun print(serializer: KXmlSerializer, testId: TestIdentifier, testResult: TestResult) { + + serializer.startTag(ns, TESTCASE) + serializer.attribute(ns, ATTR_NAME, getTestName(testId)) + serializer.attribute(ns, ATTR_CLASSNAME, testId.className) + val elapsedTimeMs = testResult.endTime - testResult.startTime + serializer.attribute(ns, ATTR_TIME, java.lang.Double.toString(elapsedTimeMs.toDouble() / 1000f)) + + when (testResult.status) { + TestResult.TestStatus.FAILURE -> printFailedTest(serializer, FAILURE, testResult.stackTrace) + TestResult.TestStatus.ASSUMPTION_FAILURE -> printFailedTest(serializer, SKIPPED_TAG, testResult.stackTrace) + TestResult.TestStatus.IGNORED -> { + serializer.startTag(ns, SKIPPED_TAG) + serializer.endTag(ns, SKIPPED_TAG) + } + } + + serializer.endTag(ns, TESTCASE) + } + + private fun printFailedTest(serializer: KXmlSerializer, tag: String, stack: String) { + serializer.startTag(ns, tag) + serializer.text(sanitize(stack)) + serializer.endTag(ns, tag) + } + + private fun sanitize(text: String): String { + return text.replace("\u0000", "<\\0>") + } + + companion object { + + private val LOG_TAG = "XmlResultReporter" + + private val TESTSUITE = "testsuite" + private val TESTCASE = "testcase" + private val FAILURE = "failure" + private val SKIPPED_TAG = "skipped" + private val ATTR_NAME = "name" + private val ATTR_TIME = "time" + private val ATTR_ERRORS = "errors" + private val ATTR_FAILURES = "failures" + private val ATTR_SKIPPED = "skipped" + private val ATTR_TESTS = "tests" + private val PROPERTIES = "properties" + private val PROPERTY = "property" + private val ATTR_CLASSNAME = "classname" + private val TIMESTAMP = "timestamp" + private val HOSTNAME = "hostname" + private var hostName = "localhost" + private val ns: String? = null + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SlowWarningTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SlowWarningTestRunListener.java index 37116b85..f2860d64 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SlowWarningTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SlowWarningTestRunListener.java @@ -10,9 +10,7 @@ package com.shazam.fork.runner.listeners; -import com.android.ddmlib.testrunner.ITestRunListener; import com.android.ddmlib.testrunner.TestIdentifier; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,56 +19,21 @@ import static com.shazam.fork.utils.Utils.millisSinceNanoTime; import static java.lang.System.nanoTime; -class SlowWarningTestRunListener implements ITestRunListener { +class SlowWarningTestRunListener extends NoOpITestRunListener { private static final Logger logger = LoggerFactory.getLogger(SlowWarningTestRunListener.class); private static final long TEST_LENGTH_THRESHOLD_MILLIS = 30 * 1000; private long startTime; - @Override - public void testRunStarted(String runName, int testCount) { - } - @Override public void testStarted(TestIdentifier test) { startTime = nanoTime(); } - @Override - public void testFailed(TestIdentifier test, String trace) { - - } - - @Override - public void testAssumptionFailure(TestIdentifier test, String trace) { - - } - - @Override - public void testIgnored(TestIdentifier test) { - - } - @Override public void testEnded(TestIdentifier test, Map testMetrics) { long testDuration = millisSinceNanoTime(startTime); if (testDuration > TEST_LENGTH_THRESHOLD_MILLIS) { - logger.warn("Slow test ({}ms): {} {}" , testDuration, test.getClassName(), test.getTestName()); - + logger.warn("Slow test ({}ms): {} {}", testDuration, test.getClassName(), test.getTestName()); } } - - @Override - public void testRunFailed(String errorMessage) { - - } - - @Override - public void testRunStopped(long elapsedTime) { - - } - - @Override - public void testRunEnded(long elapsedTime, Map runMetrics) { - - } } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java deleted file mode 100644 index a0527616..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.shazam.fork.runner.listeners; - -import com.android.ddmlib.testrunner.ITestRunListener; -import com.android.ddmlib.testrunner.TestIdentifier; -import com.shazam.fork.model.Device; -import com.shazam.fork.stat.TestExecution; -import com.shazam.fork.stat.TestExecutionReporter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Map; - -import static java.lang.System.currentTimeMillis; - -public class TestExecutionListener implements ITestRunListener { - - Logger logger = LoggerFactory.getLogger(TestExecutionListener.class); - - private long startTime = 0; - - private final Device device; - private final TestExecutionReporter executionReporter; - - private boolean failed; - - TestExecutionListener(Device device, - TestExecutionReporter executionReporter) { - this.device = device; - this.executionReporter = executionReporter; - } - - @Override - public void testRunStarted(String runName, int testCount) { - logger.error("testRunStarted = " + runName + " testCount = " + testCount); - } - - @Override - public void testStarted(TestIdentifier test) { - startTime = currentTimeMillis(); - failed = false; - logger.error("testStarted= " + test.toString()); - } - - @Override - public void testFailed(TestIdentifier test, String trace) { - failed = true; - } - - @Override - public void testAssumptionFailure(TestIdentifier test, String trace) { - } - - @Override - public void testIgnored(TestIdentifier test) { - } - - @Override - public void testEnded(TestIdentifier test, Map testMetrics) { - long endedAfter = currentTimeMillis() - startTime; - TestExecution execution = new TestExecution(test, - startTime, - endedAfter, - failed ? TestExecution.Status.FAILED : TestExecution.Status.ENDED); - logger.error("testEnded = " + test.toString()); - executionReporter.add(device, execution); - } - - @Override - public void testRunFailed(String errorMessage) { - } - - @Override - public void testRunStopped(long elapsedTime) { - } - - @Override - public void testRunEnded(long elapsedTime, Map runMetrics) { - logger.error("testEnded"); - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt new file mode 100644 index 00000000..b6929767 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt @@ -0,0 +1,35 @@ +package com.shazam.fork.runner.listeners + +import com.android.ddmlib.testrunner.TestIdentifier +import com.shazam.fork.model.Device +import com.shazam.fork.stat.TestExecution +import com.shazam.fork.stat.TestExecutionReporter + +import java.lang.System.currentTimeMillis + +class TestExecutionListener internal constructor(private val device: Device, + private val executionReporter: TestExecutionReporter) : NoOpITestRunListener() { + + private var startTime: Long = 0 + + private var failed: Boolean = false + + override fun testStarted(test: TestIdentifier) { + startTime = currentTimeMillis() + failed = false + } + + override fun testFailed(test: TestIdentifier, trace: String) { + failed = true + } + + override fun testEnded(test: TestIdentifier, testMetrics: Map) { + val endedAfter = currentTimeMillis() - startTime + val status = when (failed) { + true -> TestExecution.Status.FAILED + false -> TestExecution.Status.ENDED + } + val execution = TestExecution(test, startTime, endedAfter, status) + executionReporter.add(device, execution) + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java index 77a695e8..ee7bed45 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java @@ -66,19 +66,24 @@ public List createTestListeners(TestTask testCase, } - private ForkXmlTestRunListener getForkXmlTestRunListener(FileManager fileManager, - File output, - Pool pool, - Device device, - TestTask testCase, - ProgressReporter progressReporter, - TestCaseEventFactory factory) { - ForkXmlTestRunListener xmlTestRunListener = new ForkXmlTestRunListener(fileManager, pool, device, testCase, progressReporter, factory); - xmlTestRunListener.setReportDir(output); + private SingleForkXmlTestRunListener getForkXmlTestRunListener(FileManager fileManager, + File output, + Pool pool, + Device device, + TestTask testCase, + ProgressReporter progressReporter, + TestCaseEventFactory factory) { + SingleForkXmlTestRunListener xmlTestRunListener = new SingleForkXmlTestRunListener(fileManager, + pool, + device, + testCase, + progressReporter, + factory, + output); return xmlTestRunListener; } - private ITestRunListener getCoverageTestRunListener(Configuration configuration, + private ITestRunListener getCoverageTestRunListener(Configuration configuration, Device device, FileManager fileManager, Pool pool, From 9ab45862474134aac8b2cc5b0548e05f17d004f5 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 19 Dec 2017 14:35:29 +0800 Subject: [PATCH 21/51] fix problem with tests count --- fork-runner/src/main/java/com/shazam/fork/ForkRunner.java | 3 ++- .../java/com/shazam/fork/runner/PoolTestRunnerFactory.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java index fa956c94..88267438 100755 --- a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java @@ -73,7 +73,7 @@ public boolean run() { testStatsLoader.load(); Collection testCases = testClassLoader.loadTestSuite(); - + int totalTests = testCases.size(); Queue testCasesQueue = new BatchQueueProvider().provide(testCases); summaryGeneratorHook.registerHook(pools, testCases); @@ -82,6 +82,7 @@ public boolean run() { for (Pool pool : pools) { Runnable poolTestRunner = poolTestRunnerFactory.createPoolTestRunner(pool, testCasesQueue, + totalTests, poolCountDownLatch, progressReporter); poolExecutor.execute(poolTestRunner); diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java index da4fdd6a..4f492bb2 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java @@ -28,10 +28,10 @@ public PoolTestRunnerFactory(DeviceTestRunnerFactory deviceTestRunnerFactory) { public Runnable createPoolTestRunner(Pool pool, Queue testCases, + int totalTests, CountDownLatch poolCountDownLatch, ProgressReporter progressReporter) { - int totalTests = testCases.size(); progressReporter.addPoolProgress(pool, new PoolProgressTrackerImpl(totalTests)); return new PoolTestRunner( From 7aff0d2817a967e9dc3b8ee24a2639ed780f9ae9 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 19 Dec 2017 14:55:07 +0800 Subject: [PATCH 22/51] comment debug comparator code --- .../src/main/java/com/shazam/fork/batch/TestTaskComparator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt index db526c3d..202b962a 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt @@ -27,8 +27,8 @@ class TestTaskComparator : Comparator { override fun compare(o1: TestTask, o2: TestTask): Int { val res = when { - o1 is TestTask.MultiTestTask -> -1 - o2 is TestTask.MultiTestTask -> 1 + /*o1 is TestTask.MultiTestTask -> -1 + o2 is TestTask.MultiTestTask -> 1*/ else -> { val testMetric1 = extractTestMetric(o1) val testMetric2 = extractTestMetric(o2) From 8d26851c15b2aaaaf5c54d7df20126c5120daed0 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 19 Dec 2017 14:56:03 +0800 Subject: [PATCH 23/51] alpha1 release --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 02e9ac42..ad0665a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ # 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. # -VERSION_NAME=3.0.0-SNAPSHOT +VERSION_NAME=3.0.0-alpha1 GROUP=com.shazam.fork POM_LICENCE_NAME=The Apache Software License, Version 2.0 From 10706be97aef6c88413758ce20814a0beacbf786 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 19 Dec 2017 16:20:32 +0800 Subject: [PATCH 24/51] use atomics for ProgressTracker --- .../fork/runner/PoolProgressTrackerImpl.java | 21 ++++++++++++------- .../fork/runner/listeners/RetryListener.java | 12 ++++------- .../listeners/TestRunListenersFactory.java | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java index a4725207..6dd9ac40 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java @@ -10,39 +10,44 @@ package com.shazam.fork.runner; +import java.util.concurrent.atomic.AtomicInteger; + public class PoolProgressTrackerImpl implements PoolProgressTracker { private final int totalTests; - private int failedTests; - private int completedTests; + private AtomicInteger failedTests; + private AtomicInteger completedTests; public PoolProgressTrackerImpl(int totalTests) { this.totalTests = totalTests; + this.failedTests = new AtomicInteger(0); + this.completedTests = new AtomicInteger(0); + } @Override public void completedTest() { - completedTests++; + completedTests.incrementAndGet(); } @Override public void failedTest() { - failedTests++; + failedTests.incrementAndGet(); } @Override public void trackTestEnqueuedAgain() { - completedTests--; - failedTests--; + completedTests.decrementAndGet(); + failedTests.decrementAndGet(); } @Override public float getProgress() { - return (float) completedTests / (float) totalTests; + return (float) completedTests.get() / (float) totalTests; } @Override public int getNumberOfFailedTests() { - return failedTests; + return failedTests.get(); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java index 04a04cc7..a8551374 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java @@ -39,8 +39,6 @@ public class RetryListener extends NoOpITestRunListener { private final Device device; @Nonnull private final Queue queueOfTestsInPool; - @Nonnull - private final TestTask currentTestCaseEvent; private ProgressReporter progressReporter; private FileManager fileManager; private Pool pool; @@ -48,18 +46,15 @@ public class RetryListener extends NoOpITestRunListener { public RetryListener(@Nonnull Pool pool, @Nonnull Device device, @Nonnull Queue queueOfTestsInPool, - @Nonnull TestTask currentTestCaseEvent, @Nonnull ProgressReporter progressReporter, FileManager fileManager, TestCaseEventFactory testCaseEventFactory) { checkNotNull(device); checkNotNull(queueOfTestsInPool); - checkNotNull(currentTestCaseEvent); checkNotNull(progressReporter); checkNotNull(pool); this.device = device; this.queueOfTestsInPool = queueOfTestsInPool; - this.currentTestCaseEvent = currentTestCaseEvent; this.progressReporter = progressReporter; this.pool = pool; this.fileManager = fileManager; @@ -68,10 +63,11 @@ public RetryListener(@Nonnull Pool pool, @Nonnull Device device, @Override public void testFailed(TestIdentifier test, String trace) { - progressReporter.recordFailedTestCase(pool, testCaseEventFactory.newTestCase(test)); + TestCaseEvent event = testCaseEventFactory.newTestCase(test); + progressReporter.recordFailedTestCase(pool, event); - if (progressReporter.requestRetry(pool, testCaseEventFactory.newTestCase(test))) { - queueOfTestsInPool.add(currentTestCaseEvent); + if (progressReporter.requestRetry(pool, event)) { + queueOfTestsInPool.add(new TestTask.SingleTestTask(event)); logger.info("Test " + test.toString() + " enqueued again into pool:" + pool.getName()); removeFailureTraceFiles(test); } else { diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java index ee7bed45..291e5273 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java @@ -61,7 +61,7 @@ public List createTestListeners(TestTask testCase, new SlowWarningTestRunListener(), new TestExecutionListener(device, testExecutionReporter), getScreenTraceTestRunListener(fileManager, pool, device), - new RetryListener(pool, device, testCaseEventQueue, testCase, progressReporter, fileManager, factory), + new RetryListener(pool, device, testCaseEventQueue, progressReporter, fileManager, factory), getCoverageTestRunListener(configuration, device, fileManager, pool, testCase)); } From 81b992993214589902fb8fb5853d529fd1cf8d69 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Wed, 20 Dec 2017 11:54:47 +0800 Subject: [PATCH 25/51] add more logs --- .../model/PoolTestCaseFailureAccumulator.java | 3 +- .../fork/runner/PoolProgressTrackerImpl.java | 1 - .../fork/runner/listeners/RetryListener.java | 86 -------------- .../fork/runner/listeners/RetryListener.kt | 108 ++++++++++++++++++ .../runner/listeners/TestExecutionListener.kt | 20 +++- .../listeners/TestRunListenersFactory.java | 2 +- 6 files changed, 129 insertions(+), 91 deletions(-) delete mode 100644 fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.kt diff --git a/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java b/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java index 8966b0d3..a6a4c73d 100644 --- a/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java +++ b/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java @@ -3,6 +3,7 @@ import com.google.common.base.Predicate; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multimaps; import com.google.common.collect.SetMultimap; import static com.google.common.collect.FluentIterable.from; @@ -12,7 +13,7 @@ */ public class PoolTestCaseFailureAccumulator implements PoolTestCaseAccumulator { - private SetMultimap map = HashMultimap.create(); + private SetMultimap map = Multimaps.synchronizedSetMultimap(HashMultimap.create()); @Override public void record(Pool pool, TestCaseEvent testCaseEvent) { diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java index 6dd9ac40..8c31fcf0 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java @@ -22,7 +22,6 @@ public PoolProgressTrackerImpl(int totalTests) { this.totalTests = totalTests; this.failedTests = new AtomicInteger(0); this.completedTests = new AtomicInteger(0); - } @Override diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java deleted file mode 100644 index a8551374..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2016 Shazam Entertainment Limited - * - * 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.shazam.fork.runner.listeners; - -import com.android.ddmlib.testrunner.TestIdentifier; -import com.shazam.fork.batch.tasks.TestTask; -import com.shazam.fork.model.Device; -import com.shazam.fork.model.Pool; -import com.shazam.fork.model.TestCaseEvent; -import com.shazam.fork.model.TestCaseEventFactory; -import com.shazam.fork.runner.ProgressReporter; -import com.shazam.fork.system.io.FileManager; -import com.shazam.fork.system.io.FileType; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.util.Map; -import java.util.Queue; - -import javax.annotation.Nonnull; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class RetryListener extends NoOpITestRunListener { - - private static final Logger logger = LoggerFactory.getLogger(RetryListener.class); - - @Nonnull - private final Device device; - @Nonnull - private final Queue queueOfTestsInPool; - private ProgressReporter progressReporter; - private FileManager fileManager; - private Pool pool; - private final TestCaseEventFactory testCaseEventFactory; - - public RetryListener(@Nonnull Pool pool, @Nonnull Device device, - @Nonnull Queue queueOfTestsInPool, - @Nonnull ProgressReporter progressReporter, - FileManager fileManager, - TestCaseEventFactory testCaseEventFactory) { - checkNotNull(device); - checkNotNull(queueOfTestsInPool); - checkNotNull(progressReporter); - checkNotNull(pool); - this.device = device; - this.queueOfTestsInPool = queueOfTestsInPool; - this.progressReporter = progressReporter; - this.pool = pool; - this.fileManager = fileManager; - this.testCaseEventFactory = testCaseEventFactory; - } - - @Override - public void testFailed(TestIdentifier test, String trace) { - TestCaseEvent event = testCaseEventFactory.newTestCase(test); - progressReporter.recordFailedTestCase(pool, event); - - if (progressReporter.requestRetry(pool, event)) { - queueOfTestsInPool.add(new TestTask.SingleTestTask(event)); - logger.info("Test " + test.toString() + " enqueued again into pool:" + pool.getName()); - removeFailureTraceFiles(test); - } else { - logger.info("Test " + test.toString() + " failed on device " + device.getSafeSerial() + " but retry is not allowed."); - } - } - - - private void removeFailureTraceFiles(TestIdentifier test) { - final File file = fileManager.getFile(FileType.TEST, pool.getName(), device.getSafeSerial(), test); - boolean deleted = file.delete(); - if (!deleted) { - logger.warn("Failed to remove file " + file.getAbsoluteFile() + " for a failed but enqueued again test"); - } - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.kt new file mode 100644 index 00000000..4f0b217d --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.kt @@ -0,0 +1,108 @@ +package com.shazam.fork.runner.listeners + +import com.android.ddmlib.testrunner.TestIdentifier +import com.android.ddmlib.testrunner.TestResult +import com.android.ddmlib.testrunner.TestRunResult +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.Device +import com.shazam.fork.model.Pool +import com.shazam.fork.model.TestCaseEvent +import com.shazam.fork.model.TestCaseEventFactory +import com.shazam.fork.runner.ProgressReporter +import com.shazam.fork.system.io.FileManager +import com.shazam.fork.system.io.FileType +import org.ietf.jgss.GSSException.FAILURE +import org.slf4j.LoggerFactory +import java.util.* +import kotlin.collections.ArrayList +import kotlin.math.log + +class RetryListener(private val pool: Pool, private val device: Device, + private val queueOfTestsInPool: Queue, + private val progressReporter: ProgressReporter, + private val testTask: TestTask, + private val fileManager: FileManager, + private val testCaseEventFactory: TestCaseEventFactory) : NoOpITestRunListener() { + + private val logger = LoggerFactory.getLogger(RetryListener::class.java) + + + private val testResults = TestRunResult() + + override fun testStarted(test: TestIdentifier?) { + testResults.testStarted(test) + } + + override fun testFailed(test: TestIdentifier?, trace: String?) { + testResults.testFailed(test, trace) + } + + override fun testAssumptionFailure(test: TestIdentifier?, trace: String?) { + testResults.testAssumptionFailure(test, trace) + } + + override fun testIgnored(test: TestIdentifier?) { + testResults.testIgnored(test) + } + + override fun testEnded(test: TestIdentifier?, testMetrics: MutableMap?) { + testResults.testEnded(test, testMetrics) + } + + override fun testRunFailed(errorMessage: String) { + testResults.testRunFailed(errorMessage) + logger.error("testRunFailed") + } + + override fun testRunEnded(elapsedTime: Long, runMetrics: Map) { + super.testRunEnded(elapsedTime, runMetrics) + logger.error("testRunStopped") + restartFailedTests() + } + + private fun restartFailedTests() { + val failed = listOf(TestResult.TestStatus.FAILURE, TestResult.TestStatus.INCOMPLETE, TestResult.TestStatus.ASSUMPTION_FAILURE) + if (testResults.testResults.any { failed.contains(it.value.status) }) { + when (testTask) { + is TestTask.SingleTestTask -> { + restartFailedTest(testTask.event) + } + is TestTask.MultiTestTask -> { + testResults.testResults.filterValues { + failed.contains(it.status) + }.keys.map { + logger.error("$it event is failed") + testCaseEventFactory.newTestCase(it) + }.forEach { + restartFailedTest(it) + } + } + } + } + } + + private fun restartFailedTest(event: TestCaseEvent) { + val test = TestIdentifier(event.testClass, event.testMethod) + logger.error("restartFailedTest $test") + + progressReporter.recordFailedTestCase(pool, event) + + if (progressReporter.requestRetry(pool, event)) { + queueOfTestsInPool.add(TestTask.SingleTestTask(event)) + logger.info("Test " + test.toString() + " enqueued again into pool:" + pool.name) + removeFailureTraceFiles(test) + } else { + logger.info("Test " + test.toString() + " failed on device " + device.safeSerial + " but retry is not allowed.") + } + } + + + private fun removeFailureTraceFiles(test: TestIdentifier) { + val file = fileManager.getFile(FileType.TEST, pool.name, device.safeSerial, test) + logger.error("removeFailureTraceFiles ${file.absolutePath} exists = ${file.exists()}") + val deleted = file.delete() + if (!deleted) { + logger.warn("Failed to remove file " + file.absoluteFile + " for a failed but enqueued again test") + } + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt index b6929767..d28b2ff5 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt @@ -4,11 +4,14 @@ import com.android.ddmlib.testrunner.TestIdentifier import com.shazam.fork.model.Device import com.shazam.fork.stat.TestExecution import com.shazam.fork.stat.TestExecutionReporter +import org.slf4j.LoggerFactory import java.lang.System.currentTimeMillis -class TestExecutionListener internal constructor(private val device: Device, - private val executionReporter: TestExecutionReporter) : NoOpITestRunListener() { +class TestExecutionListener(private val device: Device, + private val executionReporter: TestExecutionReporter) : NoOpITestRunListener() { + + private val logger = LoggerFactory.getLogger(TestExecutionListener::class.java) private var startTime: Long = 0 @@ -17,13 +20,26 @@ class TestExecutionListener internal constructor(private val device: Device, override fun testStarted(test: TestIdentifier) { startTime = currentTimeMillis() failed = false + logger.error("test $test started") } override fun testFailed(test: TestIdentifier, trace: String) { failed = true + logger.error("test $test failed") + } + + override fun testAssumptionFailure(test: TestIdentifier, trace: String?) { + failed = true + reportStatus(test) + logger.error("test $test assumptionFailure") } override fun testEnded(test: TestIdentifier, testMetrics: Map) { + reportStatus(test) + logger.error("test $test ended") + } + + private fun reportStatus(test: TestIdentifier) { val endedAfter = currentTimeMillis() - startTime val status = when (failed) { true -> TestExecution.Status.FAILED diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java index 291e5273..3a7b75eb 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java @@ -61,7 +61,7 @@ public List createTestListeners(TestTask testCase, new SlowWarningTestRunListener(), new TestExecutionListener(device, testExecutionReporter), getScreenTraceTestRunListener(fileManager, pool, device), - new RetryListener(pool, device, testCaseEventQueue, progressReporter, fileManager, factory), + new RetryListener(pool, device, testCaseEventQueue, progressReporter, testCase, fileManager, factory), getCoverageTestRunListener(configuration, device, fileManager, pool, testCase)); } From 5ee0d9c792f0345cf2b0db19258519721a412744 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Wed, 20 Dec 2017 11:56:00 +0800 Subject: [PATCH 26/51] remove empty line --- .../java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java index d6eacdbd..c46c49c9 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderIncludedTest.java @@ -1,4 +1,3 @@ - package com.shazam.fork.suite; import com.shazam.fork.io.DexFileExtractor; From 713caa36a29353b35e3024aaf912d680efbbd8d2 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Wed, 20 Dec 2017 11:56:15 +0800 Subject: [PATCH 27/51] remove empty line --- .../java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java index 71caf7f0..5406e219 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderExcludeTest.java @@ -1,4 +1,3 @@ - package com.shazam.fork.suite; import com.shazam.fork.io.DexFileExtractor; From 16a16b8ab44fc9a644cc7da3e75fdf4b0089ca3a Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Wed, 20 Dec 2017 11:56:34 +0800 Subject: [PATCH 28/51] fix typo --- .../main/java/com/shazam/fork/stat/TestStatsLoader.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fork-common/src/main/java/com/shazam/fork/stat/TestStatsLoader.java b/fork-common/src/main/java/com/shazam/fork/stat/TestStatsLoader.java index 91dd871c..e907bd64 100644 --- a/fork-common/src/main/java/com/shazam/fork/stat/TestStatsLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/stat/TestStatsLoader.java @@ -21,21 +21,21 @@ public TestStatsLoader(StatServiceLoader loader) { } private final List testHistories = new ArrayList<>(); - private final Map testMetris = new HashMap<>(); + private final Map testMetrics = new HashMap<>(); public void load() { testHistories.addAll(loader.load()); - testMetris.putAll(testHistories + testMetrics.putAll(testHistories .stream() .collect(toMap(this::calculateTestKey, TestHistory::getTestMetric))); } public TestMetric findMetric(String className, String methodName) { - return testMetris.getOrDefault(calculateTestKey(className, methodName), TestMetric.empty()); + return testMetrics.getOrDefault(calculateTestKey(className, methodName), TestMetric.empty()); } public TestMetric findMetric(TestIdentifier testIdentifier) { - return testMetris.getOrDefault(calculateTestKey(testIdentifier), TestMetric.empty()); + return testMetrics.getOrDefault(calculateTestKey(testIdentifier), TestMetric.empty()); } private String calculateTestKey(TestIdentifier testIdentifier) { From 82ddf730087ae6128a87f6449d6dbd7a2919f485 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Wed, 20 Dec 2017 11:58:22 +0800 Subject: [PATCH 29/51] add description for testcompartor --- .../src/main/java/com/shazam/fork/sorting/TestComparator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java b/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java index 8432c259..084e57d2 100644 --- a/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java +++ b/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java @@ -4,6 +4,10 @@ import java.util.Comparator; +/** + * Comparator based on test metrics. + */ + class TestComparator implements Comparator { private static Comparator getDefaultComparator() { return Comparator.comparingDouble(value -> From 1e9391bcdac9d9a4474474c449bc694472a06c9c Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 21 Dec 2017 12:50:39 +0800 Subject: [PATCH 30/51] upd version of ddmlib --- fork-common/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fork-common/build.gradle b/fork-common/build.gradle index a6a53929..2d352368 100644 --- a/fork-common/build.gradle +++ b/fork-common/build.gradle @@ -21,7 +21,7 @@ dependencies { api project(':fork-client') api project(':fork-stat-common') api "com.google.code.findbugs:jsr305:3.0.1" - api "com.android.tools.ddms:ddmlib:25.1.0" + api "com.android.tools.ddms:ddmlib:26.0.0" api "commons-io:commons-io:2.5" api "org.apache.commons:commons-lang3:3.4" api "com.github.spullara.mustache.java:compiler:0.8.0" From 1a1c4e9d790fb50911616f1fa2ebc372cf914f83 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 21 Dec 2017 12:51:00 +0800 Subject: [PATCH 31/51] experiments with batch factory --- .../shazam/fork/batch/BatchQueueProvider.kt | 12 +++ .../com/shazam/fork/batch/TestBatchFactory.kt | 3 + .../shazam/fork/batch/TestTaskComparator.kt | 15 +--- .../shazam/fork/runner/DeviceTestRunner.kt | 14 ++- .../shazam/fork/runner/TestRunFactory.java | 6 +- .../listeners/SingleForkXmlTestRunListener.kt | 85 ++++++++++++------- .../listeners/TestRunListenersFactory.java | 3 +- 7 files changed, 82 insertions(+), 56 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt b/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt index 7cb11a04..082c326a 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt @@ -1,10 +1,22 @@ package com.shazam.fork.batch +import com.shazam.fork.batch.tasks.TestTask import com.shazam.fork.model.TestCaseEvent +import org.slf4j.LoggerFactory class BatchQueueProvider { + + val logger = LoggerFactory.getLogger(BatchQueueProvider::class.java) + fun provide(list: Collection): BatchTestQueue { val tasks = TestBatchFactory().tasks(list) + val testsInBatches = tasks.map { + when (it) { + is TestTask.SingleTestTask -> 1 + is TestTask.MultiTestTask -> it.list.size + } + }.reduce { acc, n -> acc + n } + logger.error("tests = ${list.size}, batches = ${tasks.size}, tests in batches = $testsInBatches") val queue = BatchTestQueue() queue.addAll(tasks) return queue diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt index b55b8e81..35dbb9a9 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt @@ -20,6 +20,9 @@ class TestBatchFactory { tempArray.clear() } } + if(tempArray.isNotEmpty()){ + resultArray.add(TestTask.MultiTestTask(Lists.newArrayList(tempArray))) + } val single = grouped[false].orEmpty().map { TestTask.SingleTestTask(it) } return resultArray + single diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt index 202b962a..a9f538ef 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt @@ -26,18 +26,9 @@ class TestTaskComparator : Comparator { } override fun compare(o1: TestTask, o2: TestTask): Int { - val res = when { - /*o1 is TestTask.MultiTestTask -> -1 - o2 is TestTask.MultiTestTask -> 1*/ - else -> { - val testMetric1 = extractTestMetric(o1) - val testMetric2 = extractTestMetric(o2) - compareMetrics(testMetric1, testMetric2) - } - } - logger.error("Compare result for o1 is TestTask.MultiTestTask = ${o1 is TestTask.MultiTestTask}" + - "o2 is TestTask.MultiTestTask = ${o2 is TestTask.MultiTestTask} res = $res") - return res + val testMetric1 = extractTestMetric(o1) + val testMetric2 = extractTestMetric(o2) + return compareMetrics(testMetric1, testMetric2) } private fun extractTestMetric(task: TestTask) = when (task) { diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt index 6f213392..adc228d0 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt @@ -46,26 +46,24 @@ class DeviceTestRunner(private val installer: Installer, createCoverageDirectory(deviceInterface) clearLogcat(deviceInterface) - while (true) { - val testCaseEvent = queueOfTestsInPool.poll() - if (testCaseEvent != null) { - val text = when(testCaseEvent){ - is TestTask.MultiTestTask -> "MultiTestTask started ${testCaseEvent.list}" + while (queueOfTestsInPool.isNotEmpty()){ + queueOfTestsInPool.poll()?.run { + val text = when(this){ + is TestTask.MultiTestTask -> "MultiTestTask started $list" is TestTask.SingleTestTask -> "SingleTestTask started" } logger.error(text) - val testRun = testRunFactory.createTestRun(testCaseEvent, + val testRun = testRunFactory.createTestRun(this, device, pool, progressReporter, queueOfTestsInPool) testRun.execute() - } else { - break } } + } finally { logger.info("Device {} from pool {} finished", device.serial, pool.name) deviceCountDownLatch.countDown() diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java index c012d727..a8df0b70 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRunFactory.java @@ -36,14 +36,14 @@ public TestRunFactory(Configuration configuration, this.factory = factory; } - public TestRun createTestRun(TestTask testCase, + public TestRun createTestRun(TestTask testTask, Device device, Pool pool, ProgressReporter progressReporter, Queue queueOfTestsInPool) { TestRunParameters testRunParameters = testRunParameters() .withDeviceInterface(device.getDeviceInterface()) - .withTest(testCase) + .withTest(testTask) .withTestPackage(configuration.getInstrumentationPackage()) .withApplicationPackage(configuration.getApplicationPackage()) .withTestRunner(configuration.getTestRunnerClass()) @@ -53,7 +53,7 @@ public TestRun createTestRun(TestTask testCase, .build(); List testRunListeners = testRunListenersFactory.createTestListeners( - testCase, + testTask, device, pool, progressReporter, diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt index ffe2cf81..92a49244 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt @@ -2,9 +2,7 @@ package com.shazam.fork.runner.listeners import com.android.SdkConstants import com.android.ddmlib.Log -import com.android.ddmlib.testrunner.TestIdentifier -import com.android.ddmlib.testrunner.TestResult -import com.android.ddmlib.testrunner.TestRunResult +import com.android.ddmlib.testrunner.* import com.google.common.collect.ImmutableMap import com.shazam.fork.batch.tasks.TestTask import com.shazam.fork.model.Device @@ -28,36 +26,51 @@ class SingleForkXmlTestRunListener(val fileManager: FileManager, val testCase: TestTask, val progressReporter: ProgressReporter, val factory: TestCaseEventFactory, - val output: File) : NoOpITestRunListener() { + val output: File) : ITestRunListener { - private lateinit var runResult: TestRunResult - private var startTime: Long = 0L + private val runResult: TestRunResult = TestRunResult() + + override fun testRunStarted(runName: String, numTests: Int) { + runResult.testRunStarted(runName, numTests) + } override fun testStarted(test: TestIdentifier) { - runResult = TestRunResult() runResult.testStarted(test) - startTime = System.currentTimeMillis() + } + + override fun testFailed(test: TestIdentifier, trace: String) { + runResult.testFailed(test, trace) } override fun testAssumptionFailure(test: TestIdentifier, trace: String) { runResult.testAssumptionFailure(test, trace) - generateDocument(runResult, test, elapsedTime()) } - override fun testFailed(test: TestIdentifier, trace: String) { - runResult.testFailed(test, trace) - generateDocument(runResult, test, elapsedTime()) + override fun testIgnored(test: TestIdentifier) { + runResult.testIgnored(test) } - override fun testEnded(test: TestIdentifier, testMetrics: MutableMap) { + override fun testEnded(test: TestIdentifier, testMetrics: Map) { runResult.testEnded(test, testMetrics) - generateDocument(runResult, test, elapsedTime()) } - private fun elapsedTime() = System.currentTimeMillis() - startTime + override fun testRunFailed(errorMessage: String) { + runResult.testRunFailed(errorMessage) + } - override fun testIgnored(test: TestIdentifier?) { - runResult.testIgnored(test) + override fun testRunStopped(elapsedTime: Long) { + runResult.testRunStopped(elapsedTime) + } + + override fun testRunEnded(elapsedTime: Long, runMetrics: Map) { + runResult.testRunEnded(elapsedTime, runMetrics) + generateDocument() + } + + private fun generateDocument() { + runResult.testResults.forEach { + generateDocument(it.key, it.value) + } } fun getResultFile(test: TestIdentifier): File { @@ -68,7 +81,7 @@ class SingleForkXmlTestRunListener(val fileManager: FileManager, return output.absolutePath } - private fun generateDocument(runResult: TestRunResult, test: TestIdentifier, elapsedTime: Long) { + private fun generateDocument(test: TestIdentifier, testResult: TestResult) { val timestamp = getTimestamp() createOutputResultStream(test).use { @@ -77,14 +90,18 @@ class SingleForkXmlTestRunListener(val fileManager: FileManager, serializer.startDocument(SdkConstants.UTF_8, null) serializer.setFeature( "http://xmlpull.org/v1/doc/features.html#indent-output", true) - printTestResults(serializer, timestamp, elapsedTime, runResult, test) + printTestResults(serializer, timestamp, test, testResult) serializer.endDocument() val msg = String.format("XML test result file generated at %s. %s", - getAbsoluteReportPath(), runResult.textSummary) + getAbsoluteReportPath(), getTextSummary(testResult)) Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG, msg) } } + fun getTextSummary(testResult: TestResult): String { + return "Total tests 1, ${testResult.toString().toLowerCase()} 1" + } + private fun getTimestamp(): String { val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()) @@ -105,21 +122,30 @@ class SingleForkXmlTestRunListener(val fileManager: FileManager, private fun printTestResults(serializer: KXmlSerializer, timestamp: String, - elapsedTime: Long, - runResult: TestRunResult, test: TestIdentifier) { + test: TestIdentifier, + testResult: TestResult) { serializer.startTag(ns, TESTSUITE) val name = getTestSuiteName() if (name != null) { serializer.attribute(ns, ATTR_NAME, name) } - serializer.attribute(ns, ATTR_TESTS, Integer.toString(runResult.numTests)) - serializer.attribute(ns, ATTR_FAILURES, Integer.toString( - runResult.numAllFailedTests)) + + serializer.attribute(ns, ATTR_TESTS, Integer.toString(1)) + val failed = when (testResult.status) { + TestResult.TestStatus.PASSED -> 0 + TestResult.TestStatus.IGNORED -> 0 + else -> 1 + } + serializer.attribute(ns, ATTR_FAILURES, Integer.toString(failed)) // legacy - there are no errors in JUnit4 serializer.attribute(ns, ATTR_ERRORS, "0") - serializer.attribute(ns, ATTR_SKIPPED, Integer.toString(runResult.getNumTestsInState( - TestResult.TestStatus.IGNORED))) + val ignored = when (testResult.status) { + TestResult.TestStatus.IGNORED -> 1 + else -> 0 + } + serializer.attribute(ns, ATTR_SKIPPED, Integer.toString(ignored)) + val elapsedTime = testResult.endTime - testResult.endTime serializer.attribute(ns, ATTR_TIME, java.lang.Double.toString(elapsedTime.toDouble() / 1000f)) serializer.attribute(ns, TIMESTAMP, timestamp) serializer.attribute(ns, HOSTNAME, hostName) @@ -133,10 +159,7 @@ class SingleForkXmlTestRunListener(val fileManager: FileManager, } serializer.endTag(ns, PROPERTIES) - val testResults = runResult.testResults - for (testEntry in testResults.entries) { - print(serializer, testEntry.key, testEntry.value) - } + print(serializer, test, testResult) serializer.endTag(ns, TESTSUITE) } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java index 3a7b75eb..96f4f306 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestRunListenersFactory.java @@ -73,14 +73,13 @@ private SingleForkXmlTestRunListener getForkXmlTestRunListener(FileManager fileM TestTask testCase, ProgressReporter progressReporter, TestCaseEventFactory factory) { - SingleForkXmlTestRunListener xmlTestRunListener = new SingleForkXmlTestRunListener(fileManager, + return new SingleForkXmlTestRunListener(fileManager, pool, device, testCase, progressReporter, factory, output); - return xmlTestRunListener; } private ITestRunListener getCoverageTestRunListener(Configuration configuration, From 1792166f06e5769e1c39a9b00963a8bd1633b0c4 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 21 Dec 2017 17:43:43 +0800 Subject: [PATCH 32/51] temporary disable batches --- .../com/shazam/fork/batch/TestBatchFactory.kt | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt index 35dbb9a9..0acac00a 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt @@ -1,30 +1,21 @@ package com.shazam.fork.batch +import com.agoda.fork.stat.TestMetric import com.google.common.collect.Lists import com.shazam.fork.batch.tasks.TestTask import com.shazam.fork.model.TestCaseEvent import java.util.* +import kotlin.collections.ArrayList class TestBatchFactory { + fun tasks(list: Collection): List { val average = list.map { it.testMetric.variance }.average() val grouped = list.groupBy { it.testMetric.variance < average } - val short = grouped[true].orEmpty() - val resultArray = ArrayList() - val tempArray = ArrayList() - short.forEach { - if (tempArray.sumByDouble { it.testMetric.variance } < average*2) { - tempArray.add(it) - } else { - resultArray.add(TestTask.MultiTestTask(Lists.newArrayList(tempArray))) - tempArray.clear() - } - } - if(tempArray.isNotEmpty()){ - resultArray.add(TestTask.MultiTestTask(Lists.newArrayList(tempArray))) - } + val short = grouped[true].orEmpty().sortedByDescending { it.testMetric.variance } + val single = grouped[false].orEmpty().map { TestTask.SingleTestTask(it) } - return resultArray + single + return short.map { TestTask.SingleTestTask(it) } + single } } \ No newline at end of file From 15d4f19adeed685428d0f5a18858399ec7c1eb40 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 14:53:13 +0800 Subject: [PATCH 33/51] add batch execution strategies --- .../com/shazam/fork/gradle/ForkPlugin.groovy | 1 + .../com/shazam/fork/gradle/ForkRunTask.groovy | 4 + .../java/com/shazam/fork/BatchStrategy.java | 29 +++++++ .../java/com/shazam/fork/Configuration.java | 44 ++++++++++- .../com/shazam/fork/ExpectedTimeStrategy.java | 5 ++ .../main/java/com/shazam/fork/ForkCli.java | 1 + .../com/shazam/fork/ForkConfiguration.java | 14 +++- .../main/java/com/shazam/fork/ForkRunner.java | 9 ++- .../com/shazam/fork/VarianceStrategy.java | 5 ++ .../main/java/com/shazam/fork/batch/Batch.kt | 15 ++++ .../shazam/fork/batch/BatchFactoryStrategy.kt | 8 ++ .../shazam/fork/batch/BatchQueueProvider.kt | 24 ------ .../com/shazam/fork/batch/ChunkStrategy.java | 5 ++ .../com/shazam/fork/batch/TestBatchFactory.kt | 21 ------ .../fork/batch/TestTaskQueueProvider.kt | 39 ++++++++++ .../strategies/DefaultFactoryStrategy.kt | 11 +++ .../batch/strategies/SplitFactoryStrategy.kt | 11 +++ .../stat/ExpectedTimeFactoryStrategy.kt | 3 + .../stat/StatBasedFactoryStrategy.kt | 39 ++++++++++ .../stat/VarianceFactoryStrategy.kt | 3 + .../fork/injector/ForkRunnerInjector.java | 3 +- .../sorting/QueueProviderInjector.java | 11 --- .../TestTaskQueueProviderInjector.java | 12 +++ .../com/shazam/fork/pooling/PoolLoader.java | 5 +- .../fork/runner/PoolProgressTrackerImpl.java | 8 ++ .../java/com/shazam/fork/runner/TestRun.kt | 4 +- .../fork/runner/listeners/RetryListener.kt | 75 ++++++++++++------- .../runner/listeners/TestExecutionListener.kt | 66 ++++++++++------ .../com/shazam/fork/stat/TestExecution.java | 4 +- .../fork/summary/executiontimeline/Data.java | 8 +- .../StatSummarySerializer.java | 11 +-- .../src/main/resources/static/chart.css | 12 +++ .../src/main/resources/static/chart.js | 31 ++++++-- 33 files changed, 404 insertions(+), 137 deletions(-) create mode 100644 fork-runner/src/main/java/com/shazam/fork/BatchStrategy.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/ExpectedTimeStrategy.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/VarianceStrategy.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/BatchFactoryStrategy.kt delete mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/ChunkStrategy.java delete mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/strategies/DefaultFactoryStrategy.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/ExpectedTimeFactoryStrategy.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/StatBasedFactoryStrategy.kt create mode 100644 fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/VarianceFactoryStrategy.kt delete mode 100644 fork-runner/src/main/java/com/shazam/fork/injector/sorting/QueueProviderInjector.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/injector/sorting/TestTaskQueueProviderInjector.java diff --git a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy index 6167ad93..d0473a12 100644 --- a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy +++ b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkPlugin.groovy @@ -85,6 +85,7 @@ class ForkPlugin implements Plugin { excludedAnnotation = config.excludedAnnotation includedAnnotation = config.includedAnnotation sortingStrategy = config.sortingStrategy + batchStrategy = config.batchStrategy applicationApk = new File(baseVariantOutput.packageApplication.outputDirectory.path + "/" + baseVariantOutput.outputFileName) diff --git a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy index af9dbef9..907a6ba7 100644 --- a/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy +++ b/fork-gradle-plugin/src/main/groovy/com/shazam/fork/gradle/ForkRunTask.groovy @@ -12,6 +12,7 @@ */ package com.shazam.fork.gradle +import com.shazam.fork.BatchStrategy import com.shazam.fork.Configuration import com.shazam.fork.Fork import com.shazam.fork.PoolingStrategy @@ -82,6 +83,8 @@ class ForkRunTask extends DefaultTask implements VerificationTask { SortingStrategy sortingStrategy + BatchStrategy batchStrategy + @TaskAction void runFork() { LOG.info("Run instrumentation tests $instrumentationApk for app $applicationApk") @@ -109,6 +112,7 @@ class ForkRunTask extends DefaultTask implements VerificationTask { .withExcludedAnnotation(excludedAnnotation) .withIncludedAnnotation(includedAnnotation) .withSortingStrategy(sortingStrategy) + .withBatchStrategy(batchStrategy) .build(); boolean success = new Fork(configuration).run() diff --git a/fork-runner/src/main/java/com/shazam/fork/BatchStrategy.java b/fork-runner/src/main/java/com/shazam/fork/BatchStrategy.java new file mode 100644 index 00000000..ffcf912f --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/BatchStrategy.java @@ -0,0 +1,29 @@ +package com.shazam.fork; + +import com.shazam.fork.batch.ChunkStrategy; +import groovy.lang.Closure; + +public class BatchStrategy { + public Boolean defaultStrategy; + public ChunkStrategy chunkStrategy; + public ExpectedTimeStrategy expectedTimeBasedStrategy; + public VarianceStrategy varianceBasedStrategy; + + public void chunked(Closure manualClosure) { + chunkStrategy = new ChunkStrategy(); + manualClosure.setDelegate(chunkStrategy); + manualClosure.call(); + } + + public void expectedTime(Closure manualClosure) { + expectedTimeBasedStrategy = new ExpectedTimeStrategy(); + manualClosure.setDelegate(expectedTimeBasedStrategy); + manualClosure.call(); + } + + public void variance(Closure manualClosure) { + varianceBasedStrategy = new VarianceStrategy(); + manualClosure.setDelegate(varianceBasedStrategy); + manualClosure.call(); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/Configuration.java b/fork-runner/src/main/java/com/shazam/fork/Configuration.java index 327728ed..922264f2 100644 --- a/fork-runner/src/main/java/com/shazam/fork/Configuration.java +++ b/fork-runner/src/main/java/com/shazam/fork/Configuration.java @@ -33,7 +33,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.shazam.fork.system.axmlparser.InstrumentationInfoFactory.parseFromFile; -import static java.util.Arrays.asList; public class Configuration { private static final Logger logger = LoggerFactory.getLogger(Configuration.class); @@ -63,6 +62,7 @@ public class Configuration { private ApplicationInfo applicationInfo; private SortingStrategy sortingStrategy; + private BatchStrategy batchStrategy; private Configuration(Builder builder) { androidSdk = builder.androidSdk; @@ -89,6 +89,7 @@ private Configuration(Builder builder) { this.includedAnnotation = builder.includedAnnotation; this.applicationInfo = builder.applicationInfo; this.sortingStrategy = builder.sortingStrategy; + this.batchStrategy = builder.batchStrategy; } @Nonnull @@ -200,6 +201,10 @@ public SortingStrategy getSortingStrategy() { return sortingStrategy; } + public BatchStrategy getBatchStrategy() { + return batchStrategy; + } + public static class Builder { private File androidSdk; private File applicationApk; @@ -224,7 +229,8 @@ public static class Builder { private String excludedAnnotation; private String includedAnnotation; private ApplicationInfo applicationInfo; - public SortingStrategy sortingStrategy; + private SortingStrategy sortingStrategy; + private BatchStrategy batchStrategy; public static Builder configuration() { return new Builder(); @@ -330,6 +336,12 @@ public Builder withSortingStrategy(@Nullable SortingStrategy sortingStrategy) { return this; } + public Builder withBatchStrategy(@Nullable BatchStrategy batchStrategy) { + this.batchStrategy = batchStrategy; + return this; + } + + public Configuration build() { checkNotNull(androidSdk, "SDK is required."); checkArgument(androidSdk.exists(), "SDK directory does not exist."); @@ -358,10 +370,38 @@ public Configuration build() { logArgumentsBadInteractions(); poolingStrategy = validatePoolingStrategy(poolingStrategy); sortingStrategy = validateSortingStrategy(sortingStrategy); + batchStrategy = validateBatchStrategy(batchStrategy, sortingStrategy); applicationInfo = ApplicationInfoFactory.parseFromFile(applicationApk); return new Configuration(this); } + private BatchStrategy validateBatchStrategy(BatchStrategy batchStrategy, + SortingStrategy sortingStrategy) { + if (batchStrategy == null) { + batchStrategy = new BatchStrategy(); + batchStrategy.defaultStrategy = true; + } else { + long selectedStrategies = Stream.of( + batchStrategy.defaultStrategy, + batchStrategy.expectedTimeBasedStrategy, + batchStrategy.chunkStrategy, + batchStrategy.varianceBasedStrategy) + .filter(Objects::nonNull) + .count(); + if (selectedStrategies > Defaults.STRATEGY_LIMIT) { + throw new IllegalArgumentException("You have selected more than one strategies in configuration. " + + "You can only select up to one."); + } + if (batchStrategy.varianceBasedStrategy != null && sortingStrategy.statistics == null) { + throw new IllegalArgumentException("Variance based strategies can't work without stats"); + } + if (batchStrategy.expectedTimeBasedStrategy != null && sortingStrategy.statistics == null) { + throw new IllegalArgumentException("Expected time based strategies can't work without stats"); + } + } + return batchStrategy; + } + private static T assignValueOrDefaultIfNull(T value, T defaultValue) { return value != null ? value : defaultValue; } diff --git a/fork-runner/src/main/java/com/shazam/fork/ExpectedTimeStrategy.java b/fork-runner/src/main/java/com/shazam/fork/ExpectedTimeStrategy.java new file mode 100644 index 00000000..23edf46d --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/ExpectedTimeStrategy.java @@ -0,0 +1,5 @@ +package com.shazam.fork; + +public class ExpectedTimeStrategy { + public Integer percentile; +} diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkCli.java b/fork-runner/src/main/java/com/shazam/fork/ForkCli.java index 96057895..fa1559b1 100644 --- a/fork-runner/src/main/java/com/shazam/fork/ForkCli.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkCli.java @@ -102,6 +102,7 @@ public static void main(String... args) { .withExcludedAnnotation(forkConfiguration.excludedAnnotation) .withIncludedAnnotation(forkConfiguration.includedAnnotation) .withSortingStrategy(forkConfiguration.sortingStrategy) + .withBatchStrategy(forkConfiguration.batchStrategy) .build(); Fork fork = new Fork(configuration); diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java b/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java index c5249984..5b3f5f22 100644 --- a/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkConfiguration.java @@ -109,7 +109,13 @@ public class ForkConfiguration { */ public SortingStrategy sortingStrategy; - public void sortingStrategy(Closure sortingStrategyClosure){ + /** + * The strategy that will be used for batch generation + */ + public BatchStrategy batchStrategy; + + + public void sortingStrategy(Closure sortingStrategyClosure) { sortingStrategy = new SortingStrategy(); sortingStrategyClosure.setDelegate(sortingStrategy); sortingStrategyClosure.call(); @@ -120,4 +126,10 @@ public void poolingStrategy(Closure poolingStrategyClosure) { poolingStrategyClosure.setDelegate(poolingStrategy); poolingStrategyClosure.call(); } + + public void batchStrategy(Closure bachStrategyClosure) { + batchStrategy = new BatchStrategy(); + bachStrategyClosure.setDelegate(batchStrategy); + bachStrategyClosure.call(); + } } diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java index 88267438..ab4f9972 100755 --- a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java @@ -12,7 +12,7 @@ */ package com.shazam.fork; -import com.shazam.fork.batch.BatchQueueProvider; +import com.shazam.fork.batch.TestTaskQueueProvider; import com.shazam.fork.batch.tasks.TestTask; import com.shazam.fork.model.Pool; import com.shazam.fork.model.TestCaseEvent; @@ -44,7 +44,7 @@ public class ForkRunner { private final ProgressReporter progressReporter; private final SummaryGeneratorHook summaryGeneratorHook; private final TestStatsLoader testStatsLoader; - private final QueueProvider queueProvider; + private final TestTaskQueueProvider queueProvider; public ForkRunner(PoolLoader poolLoader, TestSuiteLoader testClassLoader, @@ -52,7 +52,7 @@ public ForkRunner(PoolLoader poolLoader, ProgressReporter progressReporter, SummaryGeneratorHook summaryGeneratorHook, TestStatsLoader testStatsLoader, - QueueProvider queueProvider) { + TestTaskQueueProvider queueProvider) { this.poolLoader = poolLoader; this.testClassLoader = testClassLoader; this.poolTestRunnerFactory = poolTestRunnerFactory; @@ -74,7 +74,8 @@ public boolean run() { Collection testCases = testClassLoader.loadTestSuite(); int totalTests = testCases.size(); - Queue testCasesQueue = new BatchQueueProvider().provide(testCases); + int maxDevicesPerPool = pools.stream().mapToInt(i -> i.getDevices().size()).max().orElse(0); + Queue testCasesQueue = queueProvider.create(maxDevicesPerPool, testCases); summaryGeneratorHook.registerHook(pools, testCases); diff --git a/fork-runner/src/main/java/com/shazam/fork/VarianceStrategy.java b/fork-runner/src/main/java/com/shazam/fork/VarianceStrategy.java new file mode 100644 index 00000000..6693eb06 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/VarianceStrategy.java @@ -0,0 +1,5 @@ +package com.shazam.fork; + +public class VarianceStrategy { + public Integer percentile; +} diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt b/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt new file mode 100644 index 00000000..95979ba1 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt @@ -0,0 +1,15 @@ +package com.shazam.fork.batch + +import com.shazam.fork.model.TestCaseEvent +import java.util.function.Predicate + +class Batch(val limit: Predicate>, + val list: MutableList = ArrayList()) { + fun add(event: TestCaseEvent): Boolean { + return if (limit.test(list)) { + list.add(event) + } else { + false + } + } +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/BatchFactoryStrategy.kt b/fork-runner/src/main/java/com/shazam/fork/batch/BatchFactoryStrategy.kt new file mode 100644 index 00000000..f5d13d7d --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/BatchFactoryStrategy.kt @@ -0,0 +1,8 @@ +package com.shazam.fork.batch + +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.TestCaseEvent + +interface BatchFactoryStrategy { + fun batches(poolSize : Int, input: Collection): List +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt b/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt deleted file mode 100644 index 082c326a..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/batch/BatchQueueProvider.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.shazam.fork.batch - -import com.shazam.fork.batch.tasks.TestTask -import com.shazam.fork.model.TestCaseEvent -import org.slf4j.LoggerFactory - -class BatchQueueProvider { - - val logger = LoggerFactory.getLogger(BatchQueueProvider::class.java) - - fun provide(list: Collection): BatchTestQueue { - val tasks = TestBatchFactory().tasks(list) - val testsInBatches = tasks.map { - when (it) { - is TestTask.SingleTestTask -> 1 - is TestTask.MultiTestTask -> it.list.size - } - }.reduce { acc, n -> acc + n } - logger.error("tests = ${list.size}, batches = ${tasks.size}, tests in batches = $testsInBatches") - val queue = BatchTestQueue() - queue.addAll(tasks) - return queue - } -} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/ChunkStrategy.java b/fork-runner/src/main/java/com/shazam/fork/batch/ChunkStrategy.java new file mode 100644 index 00000000..31677e4e --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/ChunkStrategy.java @@ -0,0 +1,5 @@ +package com.shazam.fork.batch; + +public class ChunkStrategy { + public Integer batchSize; +} diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt deleted file mode 100644 index 0acac00a..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestBatchFactory.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.shazam.fork.batch - -import com.agoda.fork.stat.TestMetric -import com.google.common.collect.Lists -import com.shazam.fork.batch.tasks.TestTask -import com.shazam.fork.model.TestCaseEvent -import java.util.* -import kotlin.collections.ArrayList - -class TestBatchFactory { - - fun tasks(list: Collection): List { - val average = list.map { it.testMetric.variance }.average() - val grouped = list.groupBy { it.testMetric.variance < average } - val short = grouped[true].orEmpty().sortedByDescending { it.testMetric.variance } - - val single = grouped[false].orEmpty().map { TestTask.SingleTestTask(it) } - - return short.map { TestTask.SingleTestTask(it) } + single - } -} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt new file mode 100644 index 00000000..e51c45a1 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt @@ -0,0 +1,39 @@ +package com.shazam.fork.batch + +import com.shazam.fork.BatchStrategy +import com.shazam.fork.batch.strategies.* +import com.shazam.fork.batch.strategies.stat.ExpectedTimeFactoryStrategy +import com.shazam.fork.batch.strategies.stat.VarianceFactoryStrategy +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.TestCaseEvent +import org.slf4j.LoggerFactory + +class TestTaskQueueProvider(private val batchStrategy: BatchStrategy) { + + private val logger = LoggerFactory.getLogger(TestTaskQueueProvider::class.java) + + fun create(maxDevicesPerPool: Int, list: Collection): BatchTestQueue { + val extractedStrategy = extractStrategy(batchStrategy) + + val tasks = extractedStrategy.batches(maxDevicesPerPool, list) + val testsInBatches = tasks.map { + when (it) { + is TestTask.SingleTestTask -> 1 + is TestTask.MultiTestTask -> it.list.size + } + }.reduce { acc, n -> acc + n } + logger.error("tests = ${list.size}, batches = ${tasks.size}, tests in batches = $testsInBatches") + val queue = BatchTestQueue() + queue.addAll(tasks) + return queue + } + + private fun extractStrategy(batchStrategy: BatchStrategy): BatchFactoryStrategy { + return when { + batchStrategy.chunkStrategy != null -> SplitFactoryStrategy(batchStrategy.chunkStrategy.batchSize) + batchStrategy.expectedTimeBasedStrategy != null -> ExpectedTimeFactoryStrategy(batchStrategy.expectedTimeBasedStrategy.percentile) + batchStrategy.varianceBasedStrategy != null -> VarianceFactoryStrategy(batchStrategy.varianceBasedStrategy.percentile) + else -> DefaultFactoryStrategy() + } + } +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/DefaultFactoryStrategy.kt b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/DefaultFactoryStrategy.kt new file mode 100644 index 00000000..dc1d927b --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/DefaultFactoryStrategy.kt @@ -0,0 +1,11 @@ +package com.shazam.fork.batch.strategies + +import com.shazam.fork.batch.BatchFactoryStrategy +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.TestCaseEvent + +class DefaultFactoryStrategy : BatchFactoryStrategy { + override fun batches(poolSize: Int, input: Collection): List { + return input.map { TestTask.SingleTestTask(it) } + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt new file mode 100644 index 00000000..a5e5348a --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt @@ -0,0 +1,11 @@ +package com.shazam.fork.batch.strategies + +import com.shazam.fork.batch.BatchFactoryStrategy +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.TestCaseEvent + +class SplitFactoryStrategy(private val count: Int) : BatchFactoryStrategy { + override fun batches(poolSize: Int, input: Collection): List { + return ArrayList(input).chunked(count).map { TestTask.MultiTestTask(it) } + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/ExpectedTimeFactoryStrategy.kt b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/ExpectedTimeFactoryStrategy.kt new file mode 100644 index 00000000..3ed0b413 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/ExpectedTimeFactoryStrategy.kt @@ -0,0 +1,3 @@ +package com.shazam.fork.batch.strategies.stat + +class ExpectedTimeFactoryStrategy(level: Int) : StatBasedFactoryStrategy(level, { it.testMetric.expectedValue }) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/StatBasedFactoryStrategy.kt b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/StatBasedFactoryStrategy.kt new file mode 100644 index 00000000..21b6c39f --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/StatBasedFactoryStrategy.kt @@ -0,0 +1,39 @@ +package com.shazam.fork.batch.strategies.stat + +import com.shazam.fork.batch.Batch +import com.shazam.fork.batch.BatchFactoryStrategy +import com.shazam.fork.batch.tasks.TestTask +import com.shazam.fork.model.TestCaseEvent +import java.util.* +import java.util.function.Predicate + + +abstract class StatBasedFactoryStrategy(val level: Int, + val extract: (TestCaseEvent) -> (Double)) : BatchFactoryStrategy { + override fun batches(poolSize: Int, input: Collection): List { + val expectedValues = input.sortedBy { extract(it) } + val percentile = expectedValues[((expectedValues.size * level) / 100)].let { extract(it) } + + val grouped = input.groupBy { extract(it) < percentile } + val short = LinkedList(grouped[true].orEmpty().sortedByDescending { extract(it) }) + val single = grouped[false].orEmpty().map { TestTask.SingleTestTask(it) } + + + val list = ArrayList(poolSize) + val predicate: Predicate> = Predicate { + percentile > it.sumByDouble { extract(it) } + } + list.fill(Batch(predicate)) + list.forEach { + it.add(short.poll()) + } + + short.forEach { value -> + if (list.none { it.add(value) }) { + list.add(Batch(predicate).apply { add(value) }) + } + } + + return list.map { TestTask.MultiTestTask(it.list) } + single + } +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/VarianceFactoryStrategy.kt b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/VarianceFactoryStrategy.kt new file mode 100644 index 00000000..7d2f2736 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/VarianceFactoryStrategy.kt @@ -0,0 +1,3 @@ +package com.shazam.fork.batch.strategies.stat + +class VarianceFactoryStrategy(level: Int) : StatBasedFactoryStrategy(level,{ it.testMetric.variance }) diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java index b7fd232d..7ac14eb0 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/ForkRunnerInjector.java @@ -20,11 +20,10 @@ import static com.shazam.fork.injector.pooling.PoolLoaderInjector.poolLoader; import static com.shazam.fork.injector.runner.PoolTestRunnerFactoryInjector.poolTestRunnerFactory; import static com.shazam.fork.injector.runner.ProgressReporterInjector.progressReporter; -import static com.shazam.fork.injector.sorting.QueueProviderInjector.queueProvider; +import static com.shazam.fork.injector.sorting.TestTaskQueueProviderInjector.queueProvider; import static com.shazam.fork.injector.stat.TestStatLoaderInjector.testStatsLoader; import static com.shazam.fork.injector.suite.TestSuiteLoaderInjector.testSuiteLoader; import static com.shazam.fork.injector.summary.SummaryGeneratorHookInjector.summaryGeneratorHook; -import static com.shazam.fork.injector.system.FileManagerInjector.fileManager; import static com.shazam.fork.utils.Utils.millisSinceNanoTime; import static java.lang.System.nanoTime; diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/sorting/QueueProviderInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/sorting/QueueProviderInjector.java deleted file mode 100644 index 055bf948..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/injector/sorting/QueueProviderInjector.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.shazam.fork.injector.sorting; - -import com.shazam.fork.sorting.QueueProvider; - -import static com.shazam.fork.injector.ConfigurationInjector.configuration; - -public class QueueProviderInjector { - public static QueueProvider queueProvider(){ - return new QueueProvider(configuration()); - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/sorting/TestTaskQueueProviderInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/sorting/TestTaskQueueProviderInjector.java new file mode 100644 index 00000000..6e5c6c28 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/injector/sorting/TestTaskQueueProviderInjector.java @@ -0,0 +1,12 @@ +package com.shazam.fork.injector.sorting; + +import com.shazam.fork.batch.TestTaskQueueProvider; +import com.shazam.fork.sorting.QueueProvider; + +import static com.shazam.fork.injector.ConfigurationInjector.configuration; + +public class TestTaskQueueProviderInjector { + public static TestTaskQueueProvider queueProvider(){ + return new TestTaskQueueProvider(configuration().getBatchStrategy()); + } +} diff --git a/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java b/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java index 84bea560..2f61af20 100644 --- a/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java +++ b/fork-runner/src/main/java/com/shazam/fork/pooling/PoolLoader.java @@ -56,6 +56,9 @@ public Collection loadPools() throws NoDevicesForPoolException, NoPoolLoad private void log(Collection configuredPools) { logger.info("Number of device pools: " + configuredPools.size()); + logger.info("Number of devices in pools: " + configuredPools.stream() + .map(Pool::size) + .reduce((a, b) -> a + b).orElse(0)); for (Pool pool : configuredPools) { logger.debug(pool.toString()); } @@ -80,7 +83,7 @@ private DevicePoolLoader pickPoolLoader(Configuration configuration) throws NoPo return new EveryoneGetsAPoolLoader(); } - if(poolingStrategy.common != null && poolingStrategy.common){ + if (poolingStrategy.common != null && poolingStrategy.common) { return new CommonDevicePoolLoader(); } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java index 8c31fcf0..41936da7 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java @@ -10,6 +10,9 @@ package com.shazam.fork.runner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.concurrent.atomic.AtomicInteger; public class PoolProgressTrackerImpl implements PoolProgressTracker { @@ -18,6 +21,8 @@ public class PoolProgressTrackerImpl implements PoolProgressTracker { private AtomicInteger failedTests; private AtomicInteger completedTests; + private static final Logger logger = LoggerFactory.getLogger(PoolProgressTrackerImpl.class); + public PoolProgressTrackerImpl(int totalTests) { this.totalTests = totalTests; this.failedTests = new AtomicInteger(0); @@ -26,16 +31,19 @@ public PoolProgressTrackerImpl(int totalTests) { @Override public void completedTest() { + logger.error("completedTest"); completedTests.incrementAndGet(); } @Override public void failedTest() { + logger.error("failedTest"); failedTests.incrementAndGet(); } @Override public void trackTestEnqueuedAgain() { + logger.error("trackTestEnqueuedAgain"); completedTests.decrementAndGet(); failedTests.decrementAndGet(); } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt index 01e3454a..90f46a9f 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt @@ -71,9 +71,9 @@ internal class TestRun(private val poolName: String, // logger.warn("Test: $testClassName got stuck. You can increase the timeout in settings if it's too strict") } catch (e: AdbCommandRejectedException) { // throw RuntimeException(format("Error while running test %s %s", test.getTestClass(), test.getTestMethod()), e) - throw RuntimeException("Error while running test") + throw RuntimeException("Error while running test",e) } catch (e: IOException) { - throw RuntimeException("Error while running test") + throw RuntimeException("Error while running test",e) // throw RuntimeException(format("Error while running test %s %s", test.getTestClass(), test.getTestMethod()), e) } finally { // permissionGrantingManager.restorePermissions(applicationPackage, device, permissionsToRevoke) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.kt index 4f0b217d..2fae3fa9 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/RetryListener.kt @@ -17,7 +17,8 @@ import java.util.* import kotlin.collections.ArrayList import kotlin.math.log -class RetryListener(private val pool: Pool, private val device: Device, +class RetryListener(private val pool: Pool, + private val device: Device, private val queueOfTestsInPool: Queue, private val progressReporter: ProgressReporter, private val testTask: TestTask, @@ -26,65 +27,88 @@ class RetryListener(private val pool: Pool, private val device: Device, private val logger = LoggerFactory.getLogger(RetryListener::class.java) - private val testResults = TestRunResult() - override fun testStarted(test: TestIdentifier?) { + override fun testStarted(test: TestIdentifier) { testResults.testStarted(test) } - override fun testFailed(test: TestIdentifier?, trace: String?) { + override fun testFailed(test: TestIdentifier, trace: String) { testResults.testFailed(test, trace) } - override fun testAssumptionFailure(test: TestIdentifier?, trace: String?) { + override fun testAssumptionFailure(test: TestIdentifier, trace: String) { testResults.testAssumptionFailure(test, trace) } - override fun testIgnored(test: TestIdentifier?) { + override fun testRunStarted(runName: String, testCount: Int) { + testResults.testRunStarted(runName, testCount) + } + + override fun testRunStopped(elapsedTime: Long) { + testResults.testRunStopped(elapsedTime) + } + + override fun testIgnored(test: TestIdentifier) { testResults.testIgnored(test) } - override fun testEnded(test: TestIdentifier?, testMetrics: MutableMap?) { + override fun testEnded(test: TestIdentifier, testMetrics: MutableMap) { testResults.testEnded(test, testMetrics) } override fun testRunFailed(errorMessage: String) { testResults.testRunFailed(errorMessage) - logger.error("testRunFailed") } override fun testRunEnded(elapsedTime: Long, runMetrics: Map) { - super.testRunEnded(elapsedTime, runMetrics) - logger.error("testRunStopped") restartFailedTests() } private fun restartFailedTests() { - val failed = listOf(TestResult.TestStatus.FAILURE, TestResult.TestStatus.INCOMPLETE, TestResult.TestStatus.ASSUMPTION_FAILURE) - if (testResults.testResults.any { failed.contains(it.value.status) }) { - when (testTask) { - is TestTask.SingleTestTask -> { + val allFinished = testResults.testResults.all { isSuccessful(it.value) } + when (testTask) { + is TestTask.SingleTestTask -> { + if (!allFinished) { restartFailedTest(testTask.event) } - is TestTask.MultiTestTask -> { - testResults.testResults.filterValues { - failed.contains(it.status) - }.keys.map { - logger.error("$it event is failed") - testCaseEventFactory.newTestCase(it) - }.forEach { - restartFailedTest(it) - } + } + is TestTask.MultiTestTask -> { + if (!allFinished || testResults.testResults.size != testTask.list.size) { + restartMultiTestTask(testTask) } } } } + private fun TestCaseEvent.identifier(): TestIdentifier { + return TestIdentifier(testClass, testMethod) + } + + private fun restartMultiTestTask(testTask: TestTask.MultiTestTask) { + val tests = testTask.list + val results = testResults.testResults + + val notExecuted = tests.filterNot { results.containsKey(it.identifier()) } + + val failed = results.filterValues { !isSuccessful(it) } + + failed.keys.map { + testCaseEventFactory.newTestCase(it) + }.forEach { restartFailedTest(it) } + + notExecuted.map { + TestTask.SingleTestTask(it) + }.forEach { + queueOfTestsInPool.add(it) + } + } + + private fun isSuccessful(it: TestResult) = + it.status == TestResult.TestStatus.PASSED || it.status == TestResult.TestStatus.IGNORED + private fun restartFailedTest(event: TestCaseEvent) { val test = TestIdentifier(event.testClass, event.testMethod) - logger.error("restartFailedTest $test") - progressReporter.recordFailedTestCase(pool, event) if (progressReporter.requestRetry(pool, event)) { @@ -99,7 +123,6 @@ class RetryListener(private val pool: Pool, private val device: Device, private fun removeFailureTraceFiles(test: TestIdentifier) { val file = fileManager.getFile(FileType.TEST, pool.name, device.safeSerial, test) - logger.error("removeFailureTraceFiles ${file.absolutePath} exists = ${file.exists()}") val deleted = file.delete() if (!deleted) { logger.warn("Failed to remove file " + file.absoluteFile + " for a failed but enqueued again test") diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt index d28b2ff5..c72777fe 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt @@ -1,51 +1,69 @@ package com.shazam.fork.runner.listeners import com.android.ddmlib.testrunner.TestIdentifier +import com.android.ddmlib.testrunner.TestResult +import com.android.ddmlib.testrunner.TestRunResult import com.shazam.fork.model.Device import com.shazam.fork.stat.TestExecution import com.shazam.fork.stat.TestExecutionReporter import org.slf4j.LoggerFactory -import java.lang.System.currentTimeMillis - class TestExecutionListener(private val device: Device, private val executionReporter: TestExecutionReporter) : NoOpITestRunListener() { - private val logger = LoggerFactory.getLogger(TestExecutionListener::class.java) - - private var startTime: Long = 0 + val runResult = TestRunResult() - private var failed: Boolean = false + override fun testRunStarted(runName: String, testCount: Int) { + runResult.testRunStarted(runName, testCount) + } override fun testStarted(test: TestIdentifier) { - startTime = currentTimeMillis() - failed = false - logger.error("test $test started") + runResult.testStarted(test) } override fun testFailed(test: TestIdentifier, trace: String) { - failed = true - logger.error("test $test failed") + runResult.testFailed(test, trace) + } + + override fun testAssumptionFailure(test: TestIdentifier, trace: String) { + runResult.testAssumptionFailure(test, trace) + } + + override fun testIgnored(test: TestIdentifier) { + runResult.testIgnored(test) } - override fun testAssumptionFailure(test: TestIdentifier, trace: String?) { - failed = true - reportStatus(test) - logger.error("test $test assumptionFailure") + override fun testEnded(test: TestIdentifier, testMetrics: MutableMap) { + runResult.testEnded(test, testMetrics) } - override fun testEnded(test: TestIdentifier, testMetrics: Map) { - reportStatus(test) - logger.error("test $test ended") + override fun testRunFailed(errorMessage: String) { + runResult.testRunFailed(errorMessage) + } + + override fun testRunStopped(elapsedTime: Long) { + runResult.testRunStopped(elapsedTime) + } + + override fun testRunEnded(elapsedTime: Long, runMetrics: MutableMap) { + runResult.testRunEnded(elapsedTime, runMetrics) + report() + } + + private fun report() { + runResult.testResults.forEach { + reportStatus(it.key, it.value) + } } - private fun reportStatus(test: TestIdentifier) { - val endedAfter = currentTimeMillis() - startTime - val status = when (failed) { - true -> TestExecution.Status.FAILED - false -> TestExecution.Status.ENDED + private fun reportStatus(test: TestIdentifier, value: TestResult) { + val endedAfter = value.endTime - value.startTime + val status = when (value.status) { + TestResult.TestStatus.IGNORED -> TestExecution.Status.IGNORED + TestResult.TestStatus.PASSED -> TestExecution.Status.PASSED + else -> TestExecution.Status.FAILED } - val execution = TestExecution(test, startTime, endedAfter, status) + val execution = TestExecution(test, value.startTime, endedAfter, status) executionReporter.add(device, execution) } } diff --git a/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java index 1a92dfe7..17a252d2 100644 --- a/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java +++ b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java @@ -1,12 +1,14 @@ package com.shazam.fork.stat; import com.android.ddmlib.testrunner.TestIdentifier; +import org.jetbrains.annotations.NotNull; public class TestExecution { public enum Status { FAILED, - ENDED + PASSED, + IGNORED } private final TestIdentifier test; diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Data.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Data.java index 7b32df3c..c493ab9e 100644 --- a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Data.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/Data.java @@ -1,14 +1,16 @@ package com.shazam.fork.summary.executiontimeline; +import com.shazam.fork.stat.TestExecution; + public class Data { private final String testName; - private final int status; + private final TestExecution.Status status; private final long startDate; private final long endDate; private final double expectedValue; private final double variance; - public Data(String testName, int status, long startDate, long endDate, double expectedValue, double variance) { + public Data(String testName, TestExecution.Status status, long startDate, long endDate, double expectedValue, double variance) { this.testName = testName; this.status = status; this.startDate = startDate; @@ -21,7 +23,7 @@ public String getTestName() { return testName; } - public int getStatus() { + public TestExecution.Status getStatus() { return status; } diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java index 9e5b6a1c..0385350f 100644 --- a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java @@ -1,12 +1,10 @@ package com.shazam.fork.summary.executiontimeline; -import com.agoda.fork.stat.TestHistory; import com.agoda.fork.stat.TestMetric; import com.android.ddmlib.testrunner.TestIdentifier; import com.shazam.fork.model.Device; import com.shazam.fork.stat.TestExecution; import com.shazam.fork.stat.TestExecutionReporter; -import com.shazam.fork.stat.TestHistoryManager; import com.shazam.fork.stat.TestStatsLoader; import com.shazam.fork.summary.PoolSummary; import com.shazam.fork.summary.Summary; @@ -38,17 +36,16 @@ private Stream parseData(Device device) { } private Data convertToData(TestExecution execution) { - int status = convertStatus(execution); String preparedTestName = prepareTestName(execution.getTest().toString()); TestMetric testMetric = getTestMetric(execution); - return createData(execution, status, preparedTestName, testMetric); + return createData(execution, execution.getStatus(), preparedTestName, testMetric); } private int convertStatus(TestExecution execution) { - return execution.getStatus() == TestExecution.Status.ENDED ? 1 : 0; + return execution.getStatus() == TestExecution.Status.PASSED ? 1 : 0; } - private Data createData(TestExecution execution, int status, String preparedTestName, TestMetric testMetric) { + private Data createData(TestExecution execution, TestExecution.Status status, String preparedTestName, TestMetric testMetric) { return new Data(preparedTestName, status, execution.getStartTime(), execution.getStartTime() + execution.getEndTime(), @@ -130,7 +127,7 @@ private ExecutionStats aggregateExecutionStats(List list) { public ExecutionResult parse(Summary summary) { int failedTests = summary.getFailedTests().size(); int ignoredTests = summary.getIgnoredTests().size(); - int passedTestCount = passedTestCount(summary) - ignoredTests - failedTests; + int passedTestCount = passedTestCount(summary) - failedTests; List measures = parseList(summary.getPoolSummaries()); return new ExecutionResult(passedTestCount, failedTests, aggregateExecutionStats(measures), measures); } diff --git a/fork-runner/src/main/resources/static/chart.css b/fork-runner/src/main/resources/static/chart.css index 96e68dd2..5d023966 100755 --- a/fork-runner/src/main/resources/static/chart.css +++ b/fork-runner/src/main/resources/static/chart.css @@ -14,6 +14,14 @@ fill: #c9302c; } +.rect_ignored_test { + fill: #cccccc; +} + +.rect_ignored_test:hover { + fill: #cccccc; +} + .tooltip_passed_test { color: #449d44; } @@ -22,6 +30,10 @@ color: #c9302c; } +.tooltip_ignored_test { + color: #cccccc; +} + div.tooltip { position: absolute; text-align: left; diff --git a/fork-runner/src/main/resources/static/chart.js b/fork-runner/src/main/resources/static/chart.js index af51b03b..0d70dde1 100755 --- a/fork-runner/src/main/resources/static/chart.js +++ b/fork-runner/src/main/resources/static/chart.js @@ -117,10 +117,16 @@ function testsChart() { }) .attr('height', dataHeight) .attr('class', function (d) { - if (d.status === 1) { - return 'rect_passed_test'; - } else { - return 'rect_failed_test'; + switch (d.status) { + case "PASSED": { + return 'rect_passed_test' + } + case "FAILED": { + return 'rect_failed_test' + } + case "IGNORED": { + return 'rect_ignored_test' + } } }) .on('mouseover', function (d, i) { @@ -130,10 +136,19 @@ function testsChart() { .style('opacity', 0.9); div.html(function () { var output = ''; - if (d.status === 1) { - output = ''; - } else { - output = ''; + switch (d.status) { + case "PASSED": { + output = ''; + break; + } + case "FAILED": { + output = ''; + break; + } + case "IGNORED": { + output = ''; + break; + } } return output + d.testName + '
' + moment(convertDate(d.startDate)).format('LTS') + ' - ' From ed6828e88b5b549ee6909e6906a1bbd7e1e22395 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 15:03:11 +0800 Subject: [PATCH 34/51] remove unused logs --- .../main/java/com/shazam/fork/runner/DeviceTestRunner.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt index adc228d0..10db9312 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt @@ -48,13 +48,6 @@ class DeviceTestRunner(private val installer: Installer, while (queueOfTestsInPool.isNotEmpty()){ queueOfTestsInPool.poll()?.run { - val text = when(this){ - is TestTask.MultiTestTask -> "MultiTestTask started $list" - is TestTask.SingleTestTask -> "SingleTestTask started" - } - - logger.error(text) - val testRun = testRunFactory.createTestRun(this, device, pool, From ae6fe2419686efb4c05c6ad81b5d42ea4466722e Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 15:16:22 +0800 Subject: [PATCH 35/51] block retries on same device --- .../shazam/fork/runner/DeviceTestRunner.kt | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt index 10db9312..933a28de 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt @@ -15,17 +15,17 @@ package com.shazam.fork.runner import com.android.ddmlib.* import com.shazam.fork.batch.tasks.TestTask import com.shazam.fork.model.Device -import com.shazam.fork.model.* +import com.shazam.fork.model.Pool import com.shazam.fork.system.adb.Installer - -import org.slf4j.Logger +import com.shazam.fork.system.io.RemoteFileManager.* import org.slf4j.LoggerFactory - import java.io.IOException -import java.util.Queue +import java.util.* import java.util.concurrent.CountDownLatch +import com.shazam.fork.injector.runner.ProgressReporterInjector.progressReporter +import sun.audio.AudioDevice.device +import com.shazam.fork.injector.runner.TestRunFactoryInjector.testRunFactory -import com.shazam.fork.system.io.RemoteFileManager.* class DeviceTestRunner(private val installer: Installer, private val pool: Pool, @@ -35,6 +35,12 @@ class DeviceTestRunner(private val installer: Installer, private val progressReporter: ProgressReporter, private val testRunFactory: TestRunFactory) : Runnable { + companion object { + private val logger = LoggerFactory.getLogger(DeviceTestRunner::class.java) + } + + var lastEvent = 0 + override fun run() { val deviceInterface = device.deviceInterface try { @@ -46,14 +52,19 @@ class DeviceTestRunner(private val installer: Installer, createCoverageDirectory(deviceInterface) clearLogcat(deviceInterface) - while (queueOfTestsInPool.isNotEmpty()){ + while (queueOfTestsInPool.isNotEmpty()) { queueOfTestsInPool.poll()?.run { - val testRun = testRunFactory.createTestRun(this, - device, - pool, - progressReporter, - queueOfTestsInPool) - testRun.execute() + if (hashCode() == lastEvent) { + val next = queueOfTestsInPool.poll() + if (next != null) { + queueOfTestsInPool.add(this) + runTest(next) + } else { + runTest(this) + } + } else { + runTest(this) + } } } @@ -63,6 +74,15 @@ class DeviceTestRunner(private val installer: Installer, } } + private fun runTest(testTask: TestTask) { + lastEvent = testTask.hashCode() + testRunFactory.createTestRun(testTask, + device, + pool, + progressReporter, + queueOfTestsInPool).execute() + } + private fun clearLogcat(device: IDevice) { try { device.executeShellCommand("logcat -c", NullOutputReceiver()) @@ -75,10 +95,5 @@ class DeviceTestRunner(private val installer: Installer, } catch (e: IOException) { logger.warn("Could not clear logcat on device: " + device.serialNumber, e) } - - } - - companion object { - private val logger = LoggerFactory.getLogger(DeviceTestRunner::class.java) } } From ecb804a6a2ac4948188c8a3fed8bc7ea8320571d Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 15:19:05 +0800 Subject: [PATCH 36/51] code cleanup --- .../shazam/fork/runner/DeviceTestRunner.kt | 6 +---- .../listeners/SingleForkXmlTestRunListener.kt | 22 +++++++++---------- .../runner/listeners/TestExecutionListener.kt | 2 +- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt index 933a28de..641447b1 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt @@ -22,10 +22,6 @@ import org.slf4j.LoggerFactory import java.io.IOException import java.util.* import java.util.concurrent.CountDownLatch -import com.shazam.fork.injector.runner.ProgressReporterInjector.progressReporter -import sun.audio.AudioDevice.device -import com.shazam.fork.injector.runner.TestRunFactoryInjector.testRunFactory - class DeviceTestRunner(private val installer: Installer, private val pool: Pool, @@ -39,7 +35,7 @@ class DeviceTestRunner(private val installer: Installer, private val logger = LoggerFactory.getLogger(DeviceTestRunner::class.java) } - var lastEvent = 0 + private var lastEvent = 0 override fun run() { val deviceInterface = device.deviceInterface diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt index 92a49244..02857d57 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/SingleForkXmlTestRunListener.kt @@ -20,13 +20,13 @@ import java.io.OutputStream import java.text.SimpleDateFormat import java.util.* -class SingleForkXmlTestRunListener(val fileManager: FileManager, - val pool: Pool, - val device: Device, - val testCase: TestTask, - val progressReporter: ProgressReporter, - val factory: TestCaseEventFactory, - val output: File) : ITestRunListener { +class SingleForkXmlTestRunListener(private val fileManager: FileManager, + private val pool: Pool, + private val device: Device, + private val testCase: TestTask, + private val progressReporter: ProgressReporter, + private val factory: TestCaseEventFactory, + private val output: File) : ITestRunListener { private val runResult: TestRunResult = TestRunResult() @@ -73,7 +73,7 @@ class SingleForkXmlTestRunListener(val fileManager: FileManager, } } - fun getResultFile(test: TestIdentifier): File { + private fun getResultFile(test: TestIdentifier): File { return fileManager.createFile(FileType.TEST, pool, device, test) } @@ -98,7 +98,7 @@ class SingleForkXmlTestRunListener(val fileManager: FileManager, } } - fun getTextSummary(testResult: TestResult): String { + private fun getTextSummary(testResult: TestResult): String { return "Total tests 1, ${testResult.toString().toLowerCase()} 1" } @@ -164,7 +164,7 @@ class SingleForkXmlTestRunListener(val fileManager: FileManager, serializer.endTag(ns, TESTSUITE) } - fun getPropertiesAttributes(test: TestIdentifier): Map { + private fun getPropertiesAttributes(test: TestIdentifier): Map { val mapBuilder = ImmutableMap.builder() val testFailuresCount = progressReporter.getTestFailuresCount(pool, factory.newTestCase(test)) @@ -182,7 +182,7 @@ class SingleForkXmlTestRunListener(val fileManager: FileManager, return testId.testName } - fun print(serializer: KXmlSerializer, testId: TestIdentifier, testResult: TestResult) { + private fun print(serializer: KXmlSerializer, testId: TestIdentifier, testResult: TestResult) { serializer.startTag(ns, TESTCASE) serializer.attribute(ns, ATTR_NAME, getTestName(testId)) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt index c72777fe..a395cce3 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/TestExecutionListener.kt @@ -11,7 +11,7 @@ import org.slf4j.LoggerFactory class TestExecutionListener(private val device: Device, private val executionReporter: TestExecutionReporter) : NoOpITestRunListener() { - val runResult = TestRunResult() + private val runResult = TestRunResult() override fun testRunStarted(runName: String, testCount: Int) { runResult.testRunStarted(runName, testCount) From 9e7fdafe714e7e2cf935e0e1d5621e503da85365 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 15:24:16 +0800 Subject: [PATCH 37/51] code cleanup --- .../main/java/com/shazam/fork/ForkRunner.java | 1 - .../main/java/com/shazam/fork/batch/Batch.kt | 4 +-- .../com/shazam/fork/batch/BatchTestQueue.kt | 2 +- .../fork/batch/TestTaskQueueProvider.kt | 12 +------- .../TestTaskQueueProviderInjector.java | 1 - .../shazam/fork/sorting/QueueProvider.java | 24 ---------------- .../shazam/fork/sorting/SortedTestQueue.java | 19 ------------- .../shazam/fork/sorting/TestComparator.java | 28 ------------------- 8 files changed, 4 insertions(+), 87 deletions(-) delete mode 100644 fork-runner/src/main/java/com/shazam/fork/sorting/QueueProvider.java delete mode 100644 fork-runner/src/main/java/com/shazam/fork/sorting/SortedTestQueue.java delete mode 100644 fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java diff --git a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java index ab4f9972..e33f211e 100755 --- a/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java +++ b/fork-runner/src/main/java/com/shazam/fork/ForkRunner.java @@ -19,7 +19,6 @@ import com.shazam.fork.pooling.*; import com.shazam.fork.runner.PoolTestRunnerFactory; import com.shazam.fork.runner.ProgressReporter; -import com.shazam.fork.sorting.QueueProvider; import com.shazam.fork.stat.TestStatsLoader; import com.shazam.fork.suite.NoTestCasesFoundException; import com.shazam.fork.suite.TestSuiteLoader; diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt b/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt index 95979ba1..f90d2fe8 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt @@ -3,8 +3,8 @@ package com.shazam.fork.batch import com.shazam.fork.model.TestCaseEvent import java.util.function.Predicate -class Batch(val limit: Predicate>, - val list: MutableList = ArrayList()) { +class Batch(private val limit: Predicate>, + private val list: MutableList = ArrayList()) { fun add(event: TestCaseEvent): Boolean { return if (limit.test(list)) { list.add(event) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/BatchTestQueue.kt b/fork-runner/src/main/java/com/shazam/fork/batch/BatchTestQueue.kt index c7d5029b..5a76be32 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/BatchTestQueue.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/BatchTestQueue.kt @@ -3,4 +3,4 @@ package com.shazam.fork.batch import com.shazam.fork.batch.tasks.TestTask import java.util.concurrent.PriorityBlockingQueue -class BatchTestQueue : PriorityBlockingQueue(100, TestTaskComparator()) \ No newline at end of file +class BatchTestQueue(initialCapacity : Int) : PriorityBlockingQueue(initialCapacity, TestTaskComparator()) \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt index e51c45a1..3150b9e5 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt @@ -10,20 +10,10 @@ import org.slf4j.LoggerFactory class TestTaskQueueProvider(private val batchStrategy: BatchStrategy) { - private val logger = LoggerFactory.getLogger(TestTaskQueueProvider::class.java) - fun create(maxDevicesPerPool: Int, list: Collection): BatchTestQueue { val extractedStrategy = extractStrategy(batchStrategy) - val tasks = extractedStrategy.batches(maxDevicesPerPool, list) - val testsInBatches = tasks.map { - when (it) { - is TestTask.SingleTestTask -> 1 - is TestTask.MultiTestTask -> it.list.size - } - }.reduce { acc, n -> acc + n } - logger.error("tests = ${list.size}, batches = ${tasks.size}, tests in batches = $testsInBatches") - val queue = BatchTestQueue() + val queue = BatchTestQueue(tasks.size) queue.addAll(tasks) return queue } diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/sorting/TestTaskQueueProviderInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/sorting/TestTaskQueueProviderInjector.java index 6e5c6c28..ec297c32 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/sorting/TestTaskQueueProviderInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/sorting/TestTaskQueueProviderInjector.java @@ -1,7 +1,6 @@ package com.shazam.fork.injector.sorting; import com.shazam.fork.batch.TestTaskQueueProvider; -import com.shazam.fork.sorting.QueueProvider; import static com.shazam.fork.injector.ConfigurationInjector.configuration; diff --git a/fork-runner/src/main/java/com/shazam/fork/sorting/QueueProvider.java b/fork-runner/src/main/java/com/shazam/fork/sorting/QueueProvider.java deleted file mode 100644 index 3b773868..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/sorting/QueueProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.shazam.fork.sorting; - -import com.shazam.fork.Configuration; -import com.shazam.fork.model.TestCaseEvent; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.Queue; - -public class QueueProvider { - - private final Configuration configuration; - - public QueueProvider(Configuration configuration) { - this.configuration = configuration; - } - - public Queue create() { - if (configuration.getSortingStrategy().statistics != null) { - return new SortedTestQueue(); - } - return new LinkedList<>(); - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/sorting/SortedTestQueue.java b/fork-runner/src/main/java/com/shazam/fork/sorting/SortedTestQueue.java deleted file mode 100644 index ff4516ef..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/sorting/SortedTestQueue.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.shazam.fork.sorting; - -import com.shazam.fork.model.TestCaseEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.PriorityBlockingQueue; - -class SortedTestQueue extends PriorityBlockingQueue { - private static final TestComparator comparator = new TestComparator(); - private static final int DEFAULT_INITIAL_CAPACITY = 100; - - SortedTestQueue() { - super(DEFAULT_INITIAL_CAPACITY, comparator); - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java b/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java deleted file mode 100644 index 084e57d2..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/sorting/TestComparator.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.shazam.fork.sorting; - -import com.shazam.fork.model.TestCaseEvent; - -import java.util.Comparator; - -/** - * Comparator based on test metrics. - */ - -class TestComparator implements Comparator { - private static Comparator getDefaultComparator() { - return Comparator.comparingDouble(value -> - Math.sqrt(value.getTestMetric().getVariance()) * 2 + value.getTestMetric().getExpectedValue() - ).reversed(); - } - - @Override - public int compare(TestCaseEvent o1, TestCaseEvent o2) { - if (o1.getTestMetric().getVariance() == 0 || o1.getTestMetric().getExpectedValue() == 0) { - return -1; - } else if (o2.getTestMetric().getVariance() == 0 || o2.getTestMetric().getExpectedValue() == 0) { - return 1; - } else { - return getDefaultComparator().compare(o1, o2); - } - } -} From 85e0256c872a6a0807bb1723115d855df8667de5 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 15:27:38 +0800 Subject: [PATCH 38/51] cleanup --- .../com/shazam/fork/runner/PoolProgressTrackerImpl.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java index 41936da7..8c31fcf0 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolProgressTrackerImpl.java @@ -10,9 +10,6 @@ package com.shazam.fork.runner; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.concurrent.atomic.AtomicInteger; public class PoolProgressTrackerImpl implements PoolProgressTracker { @@ -21,8 +18,6 @@ public class PoolProgressTrackerImpl implements PoolProgressTracker { private AtomicInteger failedTests; private AtomicInteger completedTests; - private static final Logger logger = LoggerFactory.getLogger(PoolProgressTrackerImpl.class); - public PoolProgressTrackerImpl(int totalTests) { this.totalTests = totalTests; this.failedTests = new AtomicInteger(0); @@ -31,19 +26,16 @@ public PoolProgressTrackerImpl(int totalTests) { @Override public void completedTest() { - logger.error("completedTest"); completedTests.incrementAndGet(); } @Override public void failedTest() { - logger.error("failedTest"); failedTests.incrementAndGet(); } @Override public void trackTestEnqueuedAgain() { - logger.error("trackTestEnqueuedAgain"); completedTests.decrementAndGet(); failedTests.decrementAndGet(); } From 6a194ef2c56e6985c1015c0ad60874cbcfdcec96 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 16:12:09 +0800 Subject: [PATCH 39/51] test with permissions to revoke should be executed as a SingleTestTask --- .../main/java/com/shazam/fork/batch/Batch.kt | 2 +- .../fork/batch/TestTaskQueueProvider.kt | 4 +++- .../stat/StatBasedFactoryStrategy.kt | 5 ++-- .../java/com/shazam/fork/runner/TestRun.kt | 24 ++++++++----------- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt b/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt index f90d2fe8..5f6fbbaf 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/Batch.kt @@ -4,7 +4,7 @@ import com.shazam.fork.model.TestCaseEvent import java.util.function.Predicate class Batch(private val limit: Predicate>, - private val list: MutableList = ArrayList()) { + val list: MutableList = ArrayList()) { fun add(event: TestCaseEvent): Boolean { return if (limit.test(list)) { list.add(event) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt index 3150b9e5..546ddf37 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskQueueProvider.kt @@ -12,9 +12,11 @@ class TestTaskQueueProvider(private val batchStrategy: BatchStrategy) { fun create(maxDevicesPerPool: Int, list: Collection): BatchTestQueue { val extractedStrategy = extractStrategy(batchStrategy) - val tasks = extractedStrategy.batches(maxDevicesPerPool, list) + val supportBatches = list.groupBy { it.permissionsToRevoke.isEmpty() } + val tasks = extractedStrategy.batches(maxDevicesPerPool, supportBatches[true] ?: emptyList()) val queue = BatchTestQueue(tasks.size) queue.addAll(tasks) + queue.addAll(supportBatches[false]?.map { TestTask.SingleTestTask(it) } ?: emptyList()) return queue } diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/StatBasedFactoryStrategy.kt b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/StatBasedFactoryStrategy.kt index 21b6c39f..0167c091 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/StatBasedFactoryStrategy.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/stat/StatBasedFactoryStrategy.kt @@ -8,8 +8,8 @@ import java.util.* import java.util.function.Predicate -abstract class StatBasedFactoryStrategy(val level: Int, - val extract: (TestCaseEvent) -> (Double)) : BatchFactoryStrategy { +abstract class StatBasedFactoryStrategy(private val level: Int, + private val extract: (TestCaseEvent) -> (Double)) : BatchFactoryStrategy { override fun batches(poolSize: Int, input: Collection): List { val expectedValues = input.sortedBy { extract(it) } val percentile = expectedValues[((expectedValues.size * level) / 100)].let { extract(it) } @@ -18,7 +18,6 @@ abstract class StatBasedFactoryStrategy(val level: Int, val short = LinkedList(grouped[true].orEmpty().sortedByDescending { extract(it) }) val single = grouped[false].orEmpty().map { TestTask.SingleTestTask(it) } - val list = ArrayList(poolSize) val predicate: Predicate> = Predicate { percentile > it.sumByDouble { extract(it) } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt index 90f46a9f..d59f007e 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt @@ -25,6 +25,7 @@ import java.io.IOException import java.lang.String.format import java.util.* +import java.util.concurrent.TimeUnit internal class TestRun(private val poolName: String, private val testRunParameters: TestRunParameters, @@ -34,7 +35,6 @@ internal class TestRun(private val poolName: String, val logger = LoggerFactory.getLogger(TestRun::class.java) fun execute() { - val applicationPackage = testRunParameters.applicationPackage val device = testRunParameters.deviceInterface val runner = RemoteAndroidTestRunner( @@ -47,11 +47,10 @@ internal class TestRun(private val poolName: String, runner.setRunName(poolName) val testSize = testRunParameters.testSize if (testSize != null) { - logger.error("TestSize = $testSize") runner.setTestSize(testSize) } - runner.setMaxtimeToOutputResponse(testRunParameters.testOutputTimeout) + runner.setMaxTimeToOutputResponse(testRunParameters.testOutputTimeout.toLong(), TimeUnit.MILLISECONDS) runner.apply { when (test) { @@ -60,25 +59,22 @@ internal class TestRun(private val poolName: String, } } - try { runner.run(testRunListeners) } catch (e: ShellCommandUnresponsiveException) { - logger.warn("Test got stuck. You can increase the timeout in settings if it's too strict") -// logger.warn("Test: $testClassName got stuck. You can increase the timeout in settings if it's too strict") + logger.warn("TestTask: $test stuck. You can increase the timeout in settings if it's too strict") } catch (e: TimeoutException) { - logger.warn("Test got stuck. You can increase the timeout in settings if it's too strict") -// logger.warn("Test: $testClassName got stuck. You can increase the timeout in settings if it's too strict") + logger.warn("TestTask: $test got stuck. You can increase the timeout in settings if it's too strict") } catch (e: AdbCommandRejectedException) { -// throw RuntimeException(format("Error while running test %s %s", test.getTestClass(), test.getTestMethod()), e) - throw RuntimeException("Error while running test",e) + throw RuntimeException("Error while running test task $test", e) } catch (e: IOException) { - throw RuntimeException("Error while running test",e) -// throw RuntimeException(format("Error while running test %s %s", test.getTestClass(), test.getTestMethod()), e) + throw RuntimeException("Error while running test task $test", e) } finally { -// permissionGrantingManager.restorePermissions(applicationPackage, device, permissionsToRevoke) + if (test is TestTask.SingleTestTask) { + val applicationPackage = testRunParameters.applicationPackage + permissionGrantingManager.restorePermissions(applicationPackage, device, test.event.permissionsToRevoke) + } } - } private fun executeMultiple(test: TestTask.MultiTestTask, runner: RemoteAndroidTestRunner) { From a2a4b9757ce76b0c4b4bbfd37381f30973ab844a Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 16:38:05 +0800 Subject: [PATCH 40/51] remove unnecessary wrapping to ArrayList --- .../com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt index a5e5348a..799107f2 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt @@ -6,6 +6,6 @@ import com.shazam.fork.model.TestCaseEvent class SplitFactoryStrategy(private val count: Int) : BatchFactoryStrategy { override fun batches(poolSize: Int, input: Collection): List { - return ArrayList(input).chunked(count).map { TestTask.MultiTestTask(it) } + return input.chunked(count).map { TestTask.MultiTestTask(it) } } } From dd93cd8a68f863b0b3e2719ed735748a97ce93d3 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 17:24:22 +0800 Subject: [PATCH 41/51] cleanup --- .../src/main/java/com/shazam/fork/batch/TestTaskComparator.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt index a9f538ef..a57d5d21 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/TestTaskComparator.kt @@ -7,8 +7,6 @@ import org.slf4j.LoggerFactory class TestTaskComparator : Comparator { - val logger: Logger = LoggerFactory.getLogger(TestTaskComparator::class.java) - private fun getDefaultComparator(): java.util.Comparator { return Comparator.comparingDouble { value -> Math.sqrt(value.variance) * 2 + value.expectedValue From d713555bbb9328aeca7efde84a56ab1dfd2bd19a Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 17:28:01 +0800 Subject: [PATCH 42/51] cleanup --- .../main/java/com/shazam/fork/runner/DeviceTestRunner.kt | 8 ++++---- .../src/main/java/com/shazam/fork/runner/TestRun.kt | 7 ++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt index 641447b1..44c9f1bf 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/DeviceTestRunner.kt @@ -83,13 +83,13 @@ class DeviceTestRunner(private val installer: Installer, try { device.executeShellCommand("logcat -c", NullOutputReceiver()) } catch (e: TimeoutException) { - logger.warn("Could not clear logcat on device: " + device.serialNumber, e) + logger.warn("Could not clear logcat on device: ${device.serialNumber}", e) } catch (e: AdbCommandRejectedException) { - logger.warn("Could not clear logcat on device: " + device.serialNumber, e) + logger.warn("Could not clear logcat on device: ${device.serialNumber}", e) } catch (e: ShellCommandUnresponsiveException) { - logger.warn("Could not clear logcat on device: " + device.serialNumber, e) + logger.warn("Could not clear logcat on device: ${device.serialNumber}", e) } catch (e: IOException) { - logger.warn("Could not clear logcat on device: " + device.serialNumber, e) + logger.warn("Could not clear logcat on device: ${device.serialNumber}", e) } } } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt index d59f007e..83853e66 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt @@ -18,6 +18,7 @@ import com.android.ddmlib.testrunner.TestIdentifier import com.shazam.fork.batch.tasks.TestTask import com.shazam.fork.system.PermissionGrantingManager import com.shazam.fork.system.io.RemoteFileManager +import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -32,7 +33,7 @@ internal class TestRun(private val poolName: String, private val testRunListeners: List, private val permissionGrantingManager: PermissionGrantingManager) { - val logger = LoggerFactory.getLogger(TestRun::class.java) + private val logger: Logger = LoggerFactory.getLogger(TestRun::class.java) fun execute() { val device = testRunParameters.deviceInterface @@ -109,8 +110,4 @@ internal class TestRun(private val poolName: String, val device = testRunParameters.deviceInterface permissionGrantingManager.revokePermissions(applicationPackage, device, permissionsToRevoke) } - - companion object { - private val logger = LoggerFactory.getLogger(TestRun::class.java) - } } From d168b7ed733307ba36b52723dc240ec07e477ca9 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Tue, 26 Dec 2017 17:45:44 +0800 Subject: [PATCH 43/51] convert to kotlin and refactor StatSummarySerializer --- .../StatSummarySerializer.java | 134 ------------------ .../StatSummarySerializer.kt | 105 ++++++++++++++ 2 files changed, 105 insertions(+), 134 deletions(-) delete mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java deleted file mode 100644 index 0385350f..00000000 --- a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.shazam.fork.summary.executiontimeline; - -import com.agoda.fork.stat.TestMetric; -import com.android.ddmlib.testrunner.TestIdentifier; -import com.shazam.fork.model.Device; -import com.shazam.fork.stat.TestExecution; -import com.shazam.fork.stat.TestExecutionReporter; -import com.shazam.fork.stat.TestStatsLoader; -import com.shazam.fork.summary.PoolSummary; -import com.shazam.fork.summary.Summary; -import com.shazam.fork.summary.TestResult; - -import java.util.List; -import java.util.stream.Stream; - -import static java.util.stream.Collectors.toList; - -public class StatSummarySerializer { - - private final TestExecutionReporter reporter; - private final TestStatsLoader testStatsLoader; - - public StatSummarySerializer(TestExecutionReporter reporter, - TestStatsLoader testStatsLoader) { - this.reporter = reporter; - this.testStatsLoader = testStatsLoader; - } - - private String prepareTestName(String fullTestName) { - return fullTestName.substring(fullTestName.lastIndexOf('.') + 1); - } - - private Stream parseData(Device device) { - List executions = reporter.getTests(device); - return executions.stream().map(this::convertToData); - } - - private Data convertToData(TestExecution execution) { - String preparedTestName = prepareTestName(execution.getTest().toString()); - TestMetric testMetric = getTestMetric(execution); - return createData(execution, execution.getStatus(), preparedTestName, testMetric); - } - - private int convertStatus(TestExecution execution) { - return execution.getStatus() == TestExecution.Status.PASSED ? 1 : 0; - } - - private Data createData(TestExecution execution, TestExecution.Status status, String preparedTestName, TestMetric testMetric) { - return new Data(preparedTestName, status, - execution.getStartTime(), - execution.getStartTime() + execution.getEndTime(), - testMetric.getExpectedValue(), testMetric.getVariance()); - } - - private TestMetric getTestMetric(TestExecution execution) { - return testStatsLoader.findMetric(execution.getTest()); - } - - private ExecutionStats calculateExecutionStats(List data) { - - return new ExecutionStats(calculateIdle(data), calculateAverageExecutionTime(data)); - } - - private long calculateAverageExecutionTime(List data) { - return (long) data.stream() - .mapToLong(this::calculateDuration) - .average() - .orElse(0.0); - } - - private long calculateDuration(Data a) { - return a.getEndDate() - a.getStartDate(); - } - - private Long calculateIdle(List data) { - if (data.size() == 0) return 0L; - long time = 0; - for (int i = 1; i < data.size(); i++) { - time += data.get(i).getStartDate() - data.get(i - 1).getEndDate(); - } - return time; - } - - private Measure createMeasure(Device device) { - List data = parseData(device).collect(toList()); - return new Measure(device.getSerial(), calculateExecutionStats(data), data); - } - - private Stream parsePoolSummary(PoolSummary poolSummary) { - return poolSummary.getTestResults() - .stream() - .map(TestResult::getDevice) - .distinct() - .map(this::createMeasure); - } - - - private List parseList(List poolSummaries) { - return poolSummaries.stream().flatMap(this::parsePoolSummary).collect(toList()); - } - - private Stream extractIdentifiers(PoolSummary summary) { - return summary.getTestResults() - .stream() - .map(result -> new TestIdentifier(result.getTestClass(), result.getTestMethod())); - } - - private int passedTestCount(Summary summary) { - return (int) summary.getPoolSummaries() - .stream() - .flatMap(this::extractIdentifiers) - .distinct() - .count(); - } - - private ExecutionStats aggregateExecutionStats(List list) { - long summaryIdle = 0; - long avgTestExecutionTime = 0; - for (Measure measure : list) { - summaryIdle += measure.getExecutionStats().getIdleTimeMillis(); - avgTestExecutionTime += measure.getExecutionStats().getAverageTestExecutionTimeMillis(); - } - avgTestExecutionTime = avgTestExecutionTime / list.size(); - return new ExecutionStats(summaryIdle, avgTestExecutionTime); - } - - public ExecutionResult parse(Summary summary) { - int failedTests = summary.getFailedTests().size(); - int ignoredTests = summary.getIgnoredTests().size(); - int passedTestCount = passedTestCount(summary) - failedTests; - List measures = parseList(summary.getPoolSummaries()); - return new ExecutionResult(passedTestCount, failedTests, aggregateExecutionStats(measures), measures); - } -} diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt new file mode 100644 index 00000000..e6432619 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt @@ -0,0 +1,105 @@ +package com.shazam.fork.summary.executiontimeline + +import com.agoda.fork.stat.TestMetric +import com.android.ddmlib.testrunner.TestIdentifier +import com.shazam.fork.model.Device +import com.shazam.fork.stat.TestExecution +import com.shazam.fork.stat.TestExecutionReporter +import com.shazam.fork.stat.TestStatsLoader +import com.shazam.fork.summary.PoolSummary +import com.shazam.fork.summary.Summary + +class StatSummarySerializer(private val reporter: TestExecutionReporter, + private val testStatsLoader: TestStatsLoader) { + + private fun prepareTestName(fullTestName: String): String { + return fullTestName.substring(fullTestName.lastIndexOf('.') + 1) + } + + private fun parseData(device: Device): List { + val executions = reporter.getTests(device) + return executions.map { this.convertToData(it) } + } + + private fun convertToData(execution: TestExecution): Data { + val preparedTestName = prepareTestName(execution.test.toString()) + val testMetric = getTestMetric(execution) + return createData(execution, execution.status, preparedTestName, testMetric) + } + + private fun createData(execution: TestExecution, status: TestExecution.Status, preparedTestName: String, testMetric: TestMetric): Data { + return Data(preparedTestName, status, + execution.startTime, + execution.startTime + execution.endTime, + testMetric.expectedValue, testMetric.variance) + } + + private fun getTestMetric(execution: TestExecution): TestMetric { + return testStatsLoader.findMetric(execution.test) + } + + private fun calculateExecutionStats(data: List): ExecutionStats { + return ExecutionStats(calculateIdle(data)!!, calculateAverageExecutionTime(data)) + } + + private fun calculateAverageExecutionTime(data: List): Long { + return data.map { this.calculateDuration(it) }.average().toLong() + } + + private fun calculateDuration(a: Data): Long { + return a.endDate - a.startDate + } + + private fun calculateIdle(data: List): Long? { + return data.windowed(2, 1).map { + it[1].startDate - it[0].endDate + }.sum() + } + + private fun createMeasure(device: Device): Measure { + val data = parseData(device) + return Measure(device.serial, calculateExecutionStats(data), data) + } + + private fun parsePoolSummary(poolSummary: PoolSummary): List { + return poolSummary.testResults + .map { it.device } + .distinct() + .map { this.createMeasure(it) } + } + + private fun parseList(poolSummaries: List): List { + return poolSummaries.flatMap { this.parsePoolSummary(it) } + } + + private fun extractIdentifiers(summary: PoolSummary): List { + return summary.testResults + .map { result -> TestIdentifier(result.testClass, result.testMethod) } + } + + private fun passedTestCount(summary: Summary): Int { + return summary.poolSummaries + .flatMap { this.extractIdentifiers(it) } + .distinct() + .count() + } + + private fun aggregateExecutionStats(list: List): ExecutionStats { + val summaryIdle = list + .map { it.executionStats.idleTimeMillis } + .sum() + val avgTestExecutionTime = list + .map { it.executionStats.averageTestExecutionTimeMillis } + .average() + .toLong() + return ExecutionStats(summaryIdle, avgTestExecutionTime) + } + + fun parse(summary: Summary): ExecutionResult { + val failedTests = summary.failedTests.size + val ignoredTests = summary.ignoredTests.size + val passedTestCount = passedTestCount(summary) - failedTests + val measures = parseList(summary.poolSummaries) + return ExecutionResult(passedTestCount, failedTests, aggregateExecutionStats(measures), measures) + } +} From 9d382b979f12783a1b430f78faf909bf335de5a7 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 28 Dec 2017 11:26:32 +0800 Subject: [PATCH 44/51] cleanup and refactoring --- fork-common/build.gradle | 2 +- .../batch/strategies/SplitFactoryStrategy.kt | 3 +- .../java/com/shazam/fork/runner/TestRun.kt | 2 - .../executiontimeline/SlidingCollector.java | 84 +++++++++++++++++++ .../StatSummarySerializer.kt | 7 +- 5 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/SlidingCollector.java diff --git a/fork-common/build.gradle b/fork-common/build.gradle index 2d352368..1f5eb51c 100644 --- a/fork-common/build.gradle +++ b/fork-common/build.gradle @@ -21,7 +21,7 @@ dependencies { api project(':fork-client') api project(':fork-stat-common') api "com.google.code.findbugs:jsr305:3.0.1" - api "com.android.tools.ddms:ddmlib:26.0.0" + api "com.android.tools.ddms:ddmlib:26.0.1" api "commons-io:commons-io:2.5" api "org.apache.commons:commons-lang3:3.4" api "com.github.spullara.mustache.java:compiler:0.8.0" diff --git a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt index 799107f2..b3013ee8 100644 --- a/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt +++ b/fork-runner/src/main/java/com/shazam/fork/batch/strategies/SplitFactoryStrategy.kt @@ -1,11 +1,12 @@ package com.shazam.fork.batch.strategies +import com.google.common.collect.Lists import com.shazam.fork.batch.BatchFactoryStrategy import com.shazam.fork.batch.tasks.TestTask import com.shazam.fork.model.TestCaseEvent class SplitFactoryStrategy(private val count: Int) : BatchFactoryStrategy { override fun batches(poolSize: Int, input: Collection): List { - return input.chunked(count).map { TestTask.MultiTestTask(it) } + return Lists.partition(input.toList(),count).map { TestTask.MultiTestTask(it) } } } diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt index 83853e66..47c293fb 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt +++ b/fork-runner/src/main/java/com/shazam/fork/runner/TestRun.kt @@ -88,13 +88,11 @@ internal class TestRun(private val poolName: String, runner.addInstrumentationArg("coverageFile", "/sdcard/fork/coverage.ec") } - logger.error("executeMultiple ${Arrays.toString(classes)}") runner.setClassNames(classes) } private fun executeSingle(test: TestTask.SingleTestTask, runner: RemoteAndroidTestRunner) { - logger.error("executeSingle ${test.event.testClass}#${test.event.testMethod}") val testClassName = test.event.testClass val testMethodName = test.event.testMethod diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/SlidingCollector.java b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/SlidingCollector.java new file mode 100644 index 00000000..48264c02 --- /dev/null +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/SlidingCollector.java @@ -0,0 +1,84 @@ +package com.shazam.fork.summary.executiontimeline; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +import static java.lang.Math.max; +import static java.util.stream.Collectors.toList; + +public class SlidingCollector implements Collector>, List>> { + + private final int size; + private final int step; + private final int window; + private final Queue buffer = new ArrayDeque<>(); + private int totalIn = 0; + + public SlidingCollector(int size, int step) { + this.size = size; + this.step = step; + this.window = max(size, step); + } + + @Override + public Supplier>> supplier() { + return ArrayList::new; + } + + @Override + public BiConsumer>, T> accumulator() { + return (lists, t) -> { + buffer.offer(t); + ++totalIn; + if (buffer.size() == window) { + dumpCurrent(lists); + shiftBy(step); + } + }; + } + + @Override + public Function>, List>> finisher() { + return lists -> { + if (!buffer.isEmpty()) { + final int totalOut = estimateTotalOut(); + if (totalOut > lists.size()) { + dumpCurrent(lists); + } + } + return lists; + }; + } + + private int estimateTotalOut() { + return max(0, (totalIn + step - size - 1) / step) + 1; + } + + private void dumpCurrent(List> lists) { + final List batch = buffer.stream().limit(size).collect(toList()); + lists.add(batch); + } + + private void shiftBy(int by) { + for (int i = 0; i < by; i++) { + buffer.remove(); + } + } + + @Override + public BinaryOperator>> combiner() { + return (l1, l2) -> { + throw new UnsupportedOperationException("Combining not possible"); + }; + } + + @Override + public Set characteristics() { + return EnumSet.noneOf(Characteristics.class); + } + +} \ No newline at end of file diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt index e6432619..03840b1d 100644 --- a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt @@ -2,6 +2,9 @@ package com.shazam.fork.summary.executiontimeline import com.agoda.fork.stat.TestMetric import com.android.ddmlib.testrunner.TestIdentifier +import com.google.common.collect.Collections2 +import com.google.common.collect.EvictingQueue +import com.google.common.collect.Lists import com.shazam.fork.model.Device import com.shazam.fork.stat.TestExecution import com.shazam.fork.stat.TestExecutionReporter @@ -50,8 +53,8 @@ class StatSummarySerializer(private val reporter: TestExecutionReporter, return a.endDate - a.startDate } - private fun calculateIdle(data: List): Long? { - return data.windowed(2, 1).map { + private fun calculateIdle(data: List): Long { + return data.stream().collect(SlidingCollector(2, 1)).map { it[1].startDate - it[0].endDate }.sum() } From 0c74e7e13174cb31b4f4290188ff491b13bda942 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 28 Dec 2017 11:28:04 +0800 Subject: [PATCH 45/51] remove unused file type --- .../src/main/java/com/shazam/fork/system/io/FileType.java | 1 - 1 file changed, 1 deletion(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/system/io/FileType.java b/fork-runner/src/main/java/com/shazam/fork/system/io/FileType.java index ad4e139b..3e5a230e 100644 --- a/fork-runner/src/main/java/com/shazam/fork/system/io/FileType.java +++ b/fork-runner/src/main/java/com/shazam/fork/system/io/FileType.java @@ -2,7 +2,6 @@ public enum FileType { TEST ("tests", "xml"), - TEST_BATCH ("test_batches", "xml"), RAW_LOG("logcat", "log"), JSON_LOG("logcat_json", "json"), SCREENSHOT ("screenshot", "png"), From cd08a79431f1833e18d38ff5d13b12323062e164 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 28 Dec 2017 11:30:43 +0800 Subject: [PATCH 46/51] remove unused functions --- .../shazam/fork/system/io/FileManager.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/system/io/FileManager.java b/fork-runner/src/main/java/com/shazam/fork/system/io/FileManager.java index e934b181..3da2f702 100644 --- a/fork-runner/src/main/java/com/shazam/fork/system/io/FileManager.java +++ b/fork-runner/src/main/java/com/shazam/fork/system/io/FileManager.java @@ -37,10 +37,6 @@ public File[] getTestFilesForDevice(Pool pool, Device serial) { return path.toFile().listFiles(); } - public File createFile(FileType fileType, Pool pool, Device device, TestCaseEvent testCaseEvent) { - return createFile(fileType, pool, device, new TestIdentifier(testCaseEvent.getTestClass(), testCaseEvent.getTestMethod())); - } - public File createFile(FileType fileType, Pool pool, Device device, TestIdentifier testIdentifier, int sequenceNumber) { try { Path directory = createDirectory(fileType, pool, device); @@ -61,16 +57,6 @@ public File createFile(FileType fileType, Pool pool, Device device, TestIdentifi } } - public File createFile(FileType fileType, Pool pool, Device device, String file) { - try { - Path directory = createDirectory(fileType, pool, device); - String filename = String.format("%s.%s", file, fileType.getSuffix()); - return createFile(directory, filename); - } catch (IOException e) { - throw new CouldNotCreateDirectoryException(e); - } - } - public File createSummaryFile() { try { Path path = get(output.getAbsolutePath(), "summary"); @@ -96,18 +82,10 @@ public File getFile(FileType fileType, String pool, String safeSerial, TestIdent return path.toFile(); } - public Path createDirectory(FileType test) throws IOException { - return createDirectories(getDirectory(test)); - } - private Path createDirectory(FileType test, Pool pool, Device device) throws IOException { return createDirectories(getDirectory(test, pool, device)); } - private Path getDirectory(FileType fileType) { - return get(output.getAbsolutePath(), fileType.getDirectory()); - } - private Path getDirectory(FileType fileType, Pool pool, Device device) { return get(output.getAbsolutePath(), fileType.getDirectory(), pool.getName(), device.getSafeSerial()); } From ca218ef2e7108b95aa50dc4b3960c01fa33352b2 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 28 Dec 2017 11:36:46 +0800 Subject: [PATCH 47/51] fix lint warnings --- .../java/com/shazam/chimprunner/PerformanceTestRunner.java | 3 ++- .../com/shazam/fork/reporter/gradle/JenkinsDownloader.java | 3 +-- .../shazam/fork/reporter/HtmlFlakinessReportPrinter.java | 6 ++++-- .../main/java/com/shazam/fork/reporter/model/TestScore.java | 4 +--- .../com/shazam/fork/pooling/ComputedPoolsCategorizer.java | 6 ++---- .../fork/pooling/geometry/GeometryCommandOutputLogger.java | 3 ++- .../java/com/shazam/fork/summary/HtmlSummaryPrinter.java | 3 ++- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/chimprunner/src/main/java/com/shazam/chimprunner/PerformanceTestRunner.java b/chimprunner/src/main/java/com/shazam/chimprunner/PerformanceTestRunner.java index 1a68c998..54f64421 100644 --- a/chimprunner/src/main/java/com/shazam/chimprunner/PerformanceTestRunner.java +++ b/chimprunner/src/main/java/com/shazam/chimprunner/PerformanceTestRunner.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.*; +import java.util.concurrent.TimeUnit; import static java.lang.String.format; @@ -57,7 +58,7 @@ private void runTest(Device device, TestCaseEvent testCaseEvent) throws TestFail String testClassName = testCaseEvent.getTestClass(); String testMethodName = testCaseEvent.getTestMethod(); androidTestRunner.setMethodName(testClassName, testMethodName); - androidTestRunner.setMaxtimeToOutputResponse(Defaults.ADB_MAX_TIME_TO_OUTPUT_RESPONSE); + androidTestRunner.setMaxTimeToOutputResponse(Defaults.ADB_MAX_TIME_TO_OUTPUT_RESPONSE, TimeUnit.MILLISECONDS); try { PerformanceTestListener performanceTestListener = new LoggingPerformanceTestListener(testCaseEvent, results); performanceTestListener.startOverall(); diff --git a/fork-reporter-jenkins-gradle-plugin/src/main/java/com/shazam/fork/reporter/gradle/JenkinsDownloader.java b/fork-reporter-jenkins-gradle-plugin/src/main/java/com/shazam/fork/reporter/gradle/JenkinsDownloader.java index d6f27b79..1150e1f7 100644 --- a/fork-reporter-jenkins-gradle-plugin/src/main/java/com/shazam/fork/reporter/gradle/JenkinsDownloader.java +++ b/fork-reporter-jenkins-gradle-plugin/src/main/java/com/shazam/fork/reporter/gradle/JenkinsDownloader.java @@ -209,8 +209,7 @@ private URI getArtifactUri(Build build, Artifact artifact) { try { URI uri = new URI(build.getUrl()); String artifactPath = uri.getPath() + "artifact/" + artifact.getRelativePath(); - URI artifactUri = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), artifactPath, "", ""); - return artifactUri; + return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), artifactPath, "", ""); } catch (URISyntaxException e) { throw new GradleException("Error when trying to construct artifact URL for: " + build.getUrl(), e); } diff --git a/fork-reporter/src/main/java/com/shazam/fork/reporter/HtmlFlakinessReportPrinter.java b/fork-reporter/src/main/java/com/shazam/fork/reporter/HtmlFlakinessReportPrinter.java index 399ac2c6..a4a056bd 100644 --- a/fork-reporter/src/main/java/com/shazam/fork/reporter/HtmlFlakinessReportPrinter.java +++ b/fork-reporter/src/main/java/com/shazam/fork/reporter/HtmlFlakinessReportPrinter.java @@ -24,6 +24,8 @@ public class HtmlFlakinessReportPrinter implements FlakinessReportPrinter { private static final String INDEX_FILENAME = "index.html"; private static final String STATIC = "static"; + public static final String TEMPLATES_POOL_HTML = "templates/pool.html"; + public static final String TEMPLATES_INDEX_HTML = "templates/index.html"; private final File output; private final HtmlGenerator htmlGenerator; private final TestToHtmlFlakinessReportConverter converter; @@ -44,10 +46,10 @@ public void printReport(FlakinessReport flakinessReport) { recreateOutputFolder(); copyAssets(); HtmlFlakyTestIndex htmlFlakyTestIndex = converter.convertToIndex(flakinessReport); - htmlGenerator.generateHtml("templates/index.html", output, INDEX_FILENAME, htmlFlakyTestIndex); + htmlGenerator.generateHtml(TEMPLATES_INDEX_HTML, output, INDEX_FILENAME, htmlFlakyTestIndex); List htmlFlakyTestPool = converter.convertToPools(flakinessReport); - generatePoolHtmls(htmlFlakyTestPool, "templates/pool.html", new File(output, "pools")); + generatePoolHtmls(htmlFlakyTestPool, TEMPLATES_POOL_HTML, new File(output, "pools")); } @SuppressWarnings("ResultOfMethodCallIgnored") diff --git a/fork-reporter/src/main/java/com/shazam/fork/reporter/model/TestScore.java b/fork-reporter/src/main/java/com/shazam/fork/reporter/model/TestScore.java index c9737bfb..56413110 100644 --- a/fork-reporter/src/main/java/com/shazam/fork/reporter/model/TestScore.java +++ b/fork-reporter/src/main/java/com/shazam/fork/reporter/model/TestScore.java @@ -55,8 +55,6 @@ private static char scoreCodeFor(@Nonnull Status resultStatus) { @Override public int compareTo(@Nonnull TestScore otherTestScore) { - String otherScore = otherTestScore.score; - - return score.compareTo(otherScore); + return score.compareTo(otherTestScore.score); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/pooling/ComputedPoolsCategorizer.java b/fork-runner/src/main/java/com/shazam/fork/pooling/ComputedPoolsCategorizer.java index 6264b494..ea99c14a 100644 --- a/fork-runner/src/main/java/com/shazam/fork/pooling/ComputedPoolsCategorizer.java +++ b/fork-runner/src/main/java/com/shazam/fork/pooling/ComputedPoolsCategorizer.java @@ -53,14 +53,12 @@ public Collection allPools() { } private List createBounds(ComputedPooling computedPooling) { - List boundList = computedPooling.groups + return computedPooling.groups .entrySet() .stream() .map(entry -> new Bound(entry.getKey(), entry.getValue())) + .sorted(Comparator.comparingInt(Bound::getLower)) .collect(toList()); - - boundList.sort((o1, o2) -> o1.getLower() - o2.getLower()); - return boundList; } private int findEnclosingBoundIndex(int parameter) { diff --git a/fork-runner/src/main/java/com/shazam/fork/pooling/geometry/GeometryCommandOutputLogger.java b/fork-runner/src/main/java/com/shazam/fork/pooling/geometry/GeometryCommandOutputLogger.java index b7d2a173..6ed6a2f2 100644 --- a/fork-runner/src/main/java/com/shazam/fork/pooling/geometry/GeometryCommandOutputLogger.java +++ b/fork-runner/src/main/java/com/shazam/fork/pooling/geometry/GeometryCommandOutputLogger.java @@ -16,6 +16,7 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.Charset; /** * Writes the geometry command output to a file for diagnostics. @@ -35,6 +36,6 @@ public GeometryCommandOutputLogger(File output, String command) { public void logCommandOutput(String deviceIdentifier, String commandOutput) throws IOException { strategyDir.mkdirs(); File file = new File(strategyDir, deviceIdentifier + "." + command.replaceAll("\\W+", "-") + ".txt"); - FileUtils.writeStringToFile(file, commandOutput); + FileUtils.writeStringToFile(file, commandOutput, Charset.defaultCharset(), false); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java index 2405d30e..09796f50 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java @@ -20,6 +20,7 @@ import org.lesscss.LessCompiler; import java.io.File; +import java.nio.charset.Charset; import java.util.List; import static com.google.common.base.Charsets.UTF_8; @@ -84,7 +85,7 @@ private void generateCssFromLess() { String less = Resources.toString(getClass().getResource("/spoon.less"), UTF_8); String css = compiler.compile(less); File cssFile = new File(staticOutput, "spoon.css"); - writeStringToFile(cssFile, css); + writeStringToFile(cssFile, css, Charset.defaultCharset(), false); } catch (Exception e) { throw new RuntimeException(e); } From f358b37bb798851f7b9f185f1eeaa2e99c513a73 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 28 Dec 2017 11:38:30 +0800 Subject: [PATCH 48/51] fix lint warnings --- .../fork/model/PoolTestCaseFailureAccumulator.java | 9 ++------- .../java/com/shazam/fork/summary/LogSummaryPrinter.java | 7 +------ .../summary/executiontimeline/StatSummarySerializer.kt | 5 +---- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java b/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java index a6a4c73d..d5d317f0 100644 --- a/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java +++ b/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java @@ -59,12 +59,7 @@ private static TestCaseEventCounter createNew(final TestCaseEvent testCaseEvent) } private static Predicate isSameTestCase(final TestCaseEvent testCaseEvent) { - return new Predicate() { - @Override - public boolean apply(TestCaseEventCounter input) { - return input.getTestCaseEvent() != null - && testCaseEvent.equals(input.getTestCaseEvent()); - } - }; + return input -> input.getTestCaseEvent() != null + && testCaseEvent.equals(input.getTestCaseEvent()); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/LogSummaryPrinter.java b/fork-runner/src/main/java/com/shazam/fork/summary/LogSummaryPrinter.java index 5fa393be..8a7e4214 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/LogSummaryPrinter.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/LogSummaryPrinter.java @@ -92,11 +92,6 @@ private StringBuilder printTestsWithStatus(PoolSummary poolSummary, ResultStatus } private Collection getResultsWithStatus(Collection testResults, final ResultStatus resultStatus) { - return filter(testResults, new Predicate() { - @Override - public boolean apply(@Nullable TestResult testResult) { - return testResult.getResultStatus().equals(resultStatus); - } - }); + return filter(testResults, testResult -> testResult.getResultStatus().equals(resultStatus)); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt index 03840b1d..ead3adaa 100644 --- a/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt +++ b/fork-runner/src/main/java/com/shazam/fork/summary/executiontimeline/StatSummarySerializer.kt @@ -2,9 +2,6 @@ package com.shazam.fork.summary.executiontimeline import com.agoda.fork.stat.TestMetric import com.android.ddmlib.testrunner.TestIdentifier -import com.google.common.collect.Collections2 -import com.google.common.collect.EvictingQueue -import com.google.common.collect.Lists import com.shazam.fork.model.Device import com.shazam.fork.stat.TestExecution import com.shazam.fork.stat.TestExecutionReporter @@ -42,7 +39,7 @@ class StatSummarySerializer(private val reporter: TestExecutionReporter, } private fun calculateExecutionStats(data: List): ExecutionStats { - return ExecutionStats(calculateIdle(data)!!, calculateAverageExecutionTime(data)) + return ExecutionStats(calculateIdle(data), calculateAverageExecutionTime(data)) } private fun calculateAverageExecutionTime(data: List): Long { From 460238fbba176e8fd776eb081b3756871623a735 Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 28 Dec 2017 11:51:11 +0800 Subject: [PATCH 49/51] fix lint warnings --- .../fork/io/ClassesDexFileExtractor.java | 7 +- .../reporter/gradle/JenkinsDownloader.java | 1 - .../shazam/fork/reporter/FlakinessSorter.java | 9 +- .../TestToHtmlFlakinessReportConverter.java | 2 +- .../shazam/fork/reporter/model/TestScore.java | 2 +- .../model/PoolTestCaseFailureAccumulator.java | 17 +- .../shazam/fork/summary/HtmlConverters.java | 156 +++++++++--------- .../fork/summary/HtmlSummaryPrinter.java | 4 +- .../fork/summary/OutcomeAggregator.java | 31 +--- 9 files changed, 105 insertions(+), 124 deletions(-) diff --git a/fork-common/src/main/java/com/shazam/fork/io/ClassesDexFileExtractor.java b/fork-common/src/main/java/com/shazam/fork/io/ClassesDexFileExtractor.java index 7051d177..ad5ee435 100644 --- a/fork-common/src/main/java/com/shazam/fork/io/ClassesDexFileExtractor.java +++ b/fork-common/src/main/java/com/shazam/fork/io/ClassesDexFileExtractor.java @@ -13,7 +13,9 @@ import org.jf.dexlib.DexFile; import java.io.*; +import java.util.Arrays; import java.util.Collection; +import java.util.Objects; import java.util.zip.*; import static com.shazam.fork.io.Files.convertFileToDexFile; @@ -35,10 +37,9 @@ public ClassesDexFileExtractor(File outputDirectory) { public Collection getDexFiles(File apkFile) { dumpDexFilesFromApk(apkFile, outputDirectory); File[] dexFiles = outputDirectory.listFiles((dir, name) -> name.startsWith("classes") && name.endsWith(".dex")); - return asList(dexFiles) - .stream() + return Arrays.stream(dexFiles) .map(convertFileToDexFile()) - .filter(f -> f != null) + .filter(Objects::nonNull) .collect(toList()); } diff --git a/fork-reporter-jenkins-gradle-plugin/src/main/java/com/shazam/fork/reporter/gradle/JenkinsDownloader.java b/fork-reporter-jenkins-gradle-plugin/src/main/java/com/shazam/fork/reporter/gradle/JenkinsDownloader.java index 1150e1f7..0887c6d1 100644 --- a/fork-reporter-jenkins-gradle-plugin/src/main/java/com/shazam/fork/reporter/gradle/JenkinsDownloader.java +++ b/fork-reporter-jenkins-gradle-plugin/src/main/java/com/shazam/fork/reporter/gradle/JenkinsDownloader.java @@ -62,7 +62,6 @@ String downloadJenkinsFiles() { jobWithDetails .getBuilds() - .stream() .forEach(build -> getDetailsFromBuild(build).stream() .filter(this::isForkSummaryArtifact) .forEach(artifact -> downloadArtifact(build, artifact))); diff --git a/fork-reporter/src/main/java/com/shazam/fork/reporter/FlakinessSorter.java b/fork-reporter/src/main/java/com/shazam/fork/reporter/FlakinessSorter.java index bfee5785..76f1d54d 100644 --- a/fork-reporter/src/main/java/com/shazam/fork/reporter/FlakinessSorter.java +++ b/fork-reporter/src/main/java/com/shazam/fork/reporter/FlakinessSorter.java @@ -104,12 +104,7 @@ private List reduceToUnsortedHistories( } private Table getOrCreateTable(HashMap> poolToFlakinessTableMap, String poolName) { - Table table = poolToFlakinessTableMap.get(poolName); - if (table == null) { - table = HashBasedTable.create(); - poolToFlakinessTableMap.put(poolName, table); - } - return table; + return poolToFlakinessTableMap.computeIfAbsent(poolName, k -> HashBasedTable.create()); } @Nonnull @@ -129,7 +124,7 @@ private TreeBasedTable sortTable(Table testLabelsFullIndex) { TreeBasedTable sortedTable = create( - (scoredTest1, scoredTest2) -> scoredTest1.getTestScore().compareTo(scoredTest2.getTestScore()), + Comparator.comparing(ScoredTestLabel::getTestScore), Build::compareTo); for (TestLabel testLabel : testLabelsFullIndex) { diff --git a/fork-reporter/src/main/java/com/shazam/fork/reporter/TestToHtmlFlakinessReportConverter.java b/fork-reporter/src/main/java/com/shazam/fork/reporter/TestToHtmlFlakinessReportConverter.java index 6596d642..ba46fc6f 100644 --- a/fork-reporter/src/main/java/com/shazam/fork/reporter/TestToHtmlFlakinessReportConverter.java +++ b/fork-reporter/src/main/java/com/shazam/fork/reporter/TestToHtmlFlakinessReportConverter.java @@ -42,7 +42,7 @@ public List convertToPools(FlakinessReport flakinessReport) { private HtmlFlakyTestPool convertToPoolHtml(PoolHistory poolHistory) { Table table = poolHistory.getHistoryTable(); - List buildList = table.columnKeySet().stream().collect(toList()); + List buildList = new ArrayList<>(table.columnKeySet()); Set testLabels = table.rowKeySet(); return new HtmlFlakyTestPool( diff --git a/fork-reporter/src/main/java/com/shazam/fork/reporter/model/TestScore.java b/fork-reporter/src/main/java/com/shazam/fork/reporter/model/TestScore.java index 56413110..50df1ecf 100644 --- a/fork-reporter/src/main/java/com/shazam/fork/reporter/model/TestScore.java +++ b/fork-reporter/src/main/java/com/shazam/fork/reporter/model/TestScore.java @@ -27,7 +27,7 @@ private TestScore(String score) { public static TestScore from(TestLabel testLabel, List testInstances) { StringBuilder score = new StringBuilder(testInstances.size()); - testInstances.stream().forEach(testInstance -> { + testInstances.forEach(testInstance -> { Status status = testInstance.getStatus(); char scoreCode = scoreCodeFor(status); score.append(scoreCode); diff --git a/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java b/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java index d5d317f0..90ea7061 100644 --- a/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java +++ b/fork-runner/src/main/java/com/shazam/fork/model/PoolTestCaseFailureAccumulator.java @@ -1,12 +1,12 @@ package com.shazam.fork.model; -import com.google.common.base.Predicate; import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimaps; import com.google.common.collect.SetMultimap; -import static com.google.common.collect.FluentIterable.from; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; /** * Class that keeps track of the number of times each testCase is executed for device. @@ -21,13 +21,12 @@ public void record(Pool pool, TestCaseEvent testCaseEvent) { map.put(pool, createNew(testCaseEvent)); } - if (!from(map.get(pool)).anyMatch(isSameTestCase(testCaseEvent))) { + if (map.get(pool).stream().noneMatch(isSameTestCase(testCaseEvent))) { map.get(pool).add( createNew(testCaseEvent) .withIncreasedCount()); } else { - from(map.get(pool)) - .firstMatch(isSameTestCase(testCaseEvent)).get() + map.get(pool).stream().filter(isSameTestCase(testCaseEvent)).findFirst().get() .increaseCount(); } } @@ -35,8 +34,7 @@ public void record(Pool pool, TestCaseEvent testCaseEvent) { @Override public int getCount(Pool pool, TestCaseEvent testCaseEvent) { if (map.containsKey(pool)) { - return from(map.get(pool)) - .firstMatch(isSameTestCase(testCaseEvent)).or(TestCaseEventCounter.EMPTY) + return map.get(pool).stream().filter(isSameTestCase(testCaseEvent)).findFirst().orElse(TestCaseEventCounter.EMPTY) .getCount(); } else { return 0; @@ -46,8 +44,7 @@ public int getCount(Pool pool, TestCaseEvent testCaseEvent) { @Override public int getCount(TestCaseEvent testCaseEvent) { int result = 0; - ImmutableList counters = from(map.values()) - .filter(isSameTestCase(testCaseEvent)).toList(); + List counters = map.values().stream().filter(isSameTestCase(testCaseEvent)).collect(Collectors.toList()); for (TestCaseEventCounter counter : counters) { result += counter.getCount(); } diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlConverters.java b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlConverters.java index b701a0ab..c6fb83e1 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlConverters.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlConverters.java @@ -13,7 +13,10 @@ package com.shazam.fork.summary; import com.android.ddmlib.logcat.LogCatMessage; -import com.google.common.base.Function; + +import java.util.function.Function; +import java.util.stream.Collectors; + import com.shazam.fork.model.Device; import com.shazam.fork.model.Diagnostics; @@ -23,97 +26,94 @@ import static com.shazam.fork.model.Diagnostics.SCREENSHOTS; import static com.shazam.fork.model.Diagnostics.VIDEO; import static com.shazam.fork.summary.OutcomeAggregator.toPoolOutcome; -import static com.shazam.fork.utils.ReadableNames.readableClassName; -import static com.shazam.fork.utils.ReadableNames.readablePoolName; -import static com.shazam.fork.utils.ReadableNames.readableTestMethodName; +import static com.shazam.fork.utils.ReadableNames.*; +import static java.util.stream.Collectors.*; class HtmlConverters { - public static HtmlSummary toHtmlSummary(Summary summary) { - HtmlSummary htmlSummary = new HtmlSummary(); - htmlSummary.title = summary.getTitle(); - htmlSummary.subtitle = summary.getSubtitle(); - htmlSummary.pools = transform(summary.getPoolSummaries(), toHtmlPoolSummary()); - htmlSummary.ignoredTests = summary.getIgnoredTests(); - htmlSummary.failedTests = summary.getFailedTests(); + public static HtmlSummary toHtmlSummary(Summary summary) { + HtmlSummary htmlSummary = new HtmlSummary(); + htmlSummary.title = summary.getTitle(); + htmlSummary.subtitle = summary.getSubtitle(); + htmlSummary.pools = summary.getPoolSummaries() + .stream() + .map(toHtmlPoolSummary()) + .collect(toList()); + htmlSummary.ignoredTests = summary.getIgnoredTests(); + htmlSummary.failedTests = summary.getFailedTests(); htmlSummary.overallStatus = new OutcomeAggregator().aggregate(summary) ? "pass" : "fail"; - return htmlSummary; - } + return htmlSummary; + } - private static Function toHtmlPoolSummary() { - return new Function () { - @Override - @Nullable - public HtmlPoolSummary apply(@Nullable PoolSummary poolSummary) { - HtmlPoolSummary htmlPoolSummary = new HtmlPoolSummary(); + private static Function toHtmlPoolSummary() { + return new Function() { + @Override + public HtmlPoolSummary apply(@Nullable PoolSummary poolSummary) { + HtmlPoolSummary htmlPoolSummary = new HtmlPoolSummary(); htmlPoolSummary.poolStatus = getPoolStatus(poolSummary); - String poolName = poolSummary.getPoolName(); - htmlPoolSummary.prettyPoolName = readablePoolName(poolName); + String poolName = poolSummary.getPoolName(); + htmlPoolSummary.prettyPoolName = readablePoolName(poolName); htmlPoolSummary.plainPoolName = poolName; htmlPoolSummary.testCount = poolSummary.getTestResults().size(); - htmlPoolSummary.testResults = transform(poolSummary.getTestResults(), toHtmlTestResult(poolName)); - return htmlPoolSummary; - } + htmlPoolSummary.testResults = poolSummary + .getTestResults() + .stream() + .map(a -> toHtmlTestResult(poolName).apply(a)) + .collect(toList()); + return htmlPoolSummary; + } private String getPoolStatus(PoolSummary poolSummary) { Boolean success = toPoolOutcome().apply(poolSummary); - return (success != null && success? "pass" : "fail"); + return (success != null && success ? "pass" : "fail"); } }; - } + } - private static Function toHtmlTestResult(final String poolName) { - return new Function(){ - @Override - @Nullable - public HtmlTestResult apply(@Nullable TestResult input) { - HtmlTestResult htmlTestResult = new HtmlTestResult(); - htmlTestResult.status = computeStatus(input); - htmlTestResult.prettyClassName = readableClassName(input.getTestClass()); - htmlTestResult.prettyMethodName = readableTestMethodName(input.getTestMethod()); - htmlTestResult.timeTaken = String.format("%.2f", input.getTimeTaken()); - htmlTestResult.plainMethodName = input.getTestMethod(); - htmlTestResult.plainClassName = input.getTestClass(); - htmlTestResult.poolName = poolName; - htmlTestResult.trace = input.getTrace().split("\n"); - // Keeping logcats in memory is hugely wasteful. Now they're read at page-creation. - // htmlTestResult.logcatMessages = transform(input.getLogCatMessages(), toHtmlLogCatMessages()); - Device device = input.getDevice(); - htmlTestResult.deviceSerial = device.getSerial(); - htmlTestResult.deviceSafeSerial = device.getSafeSerial(); - htmlTestResult.deviceModelDespaced = device.getModelName().replace(" ", "_"); - Diagnostics supportedDiagnostics = device.getSupportedDiagnostics(); - htmlTestResult.diagnosticVideo = VIDEO.equals(supportedDiagnostics); - htmlTestResult.diagnosticScreenshots = SCREENSHOTS.equals(supportedDiagnostics); - return htmlTestResult; - } - }; - } + private static Function toHtmlTestResult(final String poolName) { + return input -> { + HtmlTestResult htmlTestResult = new HtmlTestResult(); + htmlTestResult.status = computeStatus(input); + htmlTestResult.prettyClassName = readableClassName(input.getTestClass()); + htmlTestResult.prettyMethodName = readableTestMethodName(input.getTestMethod()); + htmlTestResult.timeTaken = String.format("%.2f", input.getTimeTaken()); + htmlTestResult.plainMethodName = input.getTestMethod(); + htmlTestResult.plainClassName = input.getTestClass(); + htmlTestResult.poolName = poolName; + htmlTestResult.trace = input.getTrace().split("\n"); + // Keeping logcats in memory is hugely wasteful. Now they're read at page-creation. + // htmlTestResult.logcatMessages = transform(input.getLogCatMessages(), toHtmlLogCatMessages()); + Device device = input.getDevice(); + htmlTestResult.deviceSerial = device.getSerial(); + htmlTestResult.deviceSafeSerial = device.getSafeSerial(); + htmlTestResult.deviceModelDespaced = device.getModelName().replace(" ", "_"); + Diagnostics supportedDiagnostics = device.getSupportedDiagnostics(); + htmlTestResult.diagnosticVideo = VIDEO.equals(supportedDiagnostics); + htmlTestResult.diagnosticScreenshots = SCREENSHOTS.equals(supportedDiagnostics); + return htmlTestResult; + }; + } - private static String computeStatus(@Nullable TestResult input) { - String result = input.getResultStatus().name().toLowerCase(); - if(input.getResultStatus() == ResultStatus.PASS - && input.getTotalFailureCount() > 0){ - result = "warn"; - } - return result; - } + private static String computeStatus(@Nullable TestResult input) { + String result = input.getResultStatus().name().toLowerCase(); + if (input.getResultStatus() == ResultStatus.PASS + && input.getTotalFailureCount() > 0) { + result = "warn"; + } + return result; + } - public static Function toHtmlLogCatMessages() { - return new Function() { - @Nullable - @Override - public HtmlLogCatMessage apply(@Nullable LogCatMessage logCatMessage) { - HtmlLogCatMessage htmlLogCatMessage = new HtmlLogCatMessage(); - htmlLogCatMessage.appName = logCatMessage.getAppName(); - htmlLogCatMessage.logLevel = logCatMessage.getLogLevel().getStringValue(); - htmlLogCatMessage.message = logCatMessage.getMessage(); - htmlLogCatMessage.pid = logCatMessage.getPid(); - htmlLogCatMessage.tag = logCatMessage.getTag(); - htmlLogCatMessage.tid = logCatMessage.getTid(); - htmlLogCatMessage.time = logCatMessage.getTimestamp().toString(); - return htmlLogCatMessage; - } - }; - } + public static Function toHtmlLogCatMessages() { + return logCatMessage -> { + HtmlLogCatMessage htmlLogCatMessage = new HtmlLogCatMessage(); + htmlLogCatMessage.appName = logCatMessage.getAppName(); + htmlLogCatMessage.logLevel = logCatMessage.getLogLevel().getStringValue(); + htmlLogCatMessage.message = logCatMessage.getMessage(); + htmlLogCatMessage.pid = logCatMessage.getPid(); + htmlLogCatMessage.tag = logCatMessage.getTag(); + htmlLogCatMessage.tid = logCatMessage.getTid(); + htmlLogCatMessage.time = logCatMessage.getTimestamp().toString(); + return htmlLogCatMessage; + }; + } } diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java index 09796f50..1057396a 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java @@ -22,12 +22,14 @@ import java.io.File; import java.nio.charset.Charset; import java.util.List; +import java.util.stream.Collectors; import static com.google.common.base.Charsets.UTF_8; import static com.google.common.collect.Collections2.transform; import static com.shazam.fork.io.Files.copyResource; import static com.shazam.fork.summary.HtmlConverters.toHtmlLogCatMessages; import static com.shazam.fork.summary.HtmlConverters.toHtmlSummary; +import static java.util.stream.Collectors.*; import static org.apache.commons.io.FileUtils.writeStringToFile; public class HtmlSummaryPrinter implements SummaryPrinter { @@ -127,6 +129,6 @@ private void generatePoolTestsHtml(HtmlSummary htmlSummary) { private void addLogcats(HtmlTestResult testResult, HtmlPoolSummary pool) { TestIdentifier testIdentifier = new TestIdentifier(testResult.plainClassName, testResult.plainMethodName); List logCatMessages = retriever.retrieveLogCat(pool.plainPoolName, testResult.deviceSafeSerial, testIdentifier); - testResult.logcatMessages = transform(logCatMessages, toHtmlLogCatMessages()); + testResult.logcatMessages = logCatMessages.stream().map(toHtmlLogCatMessages()).collect(toList()); } } diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/OutcomeAggregator.java b/fork-runner/src/main/java/com/shazam/fork/summary/OutcomeAggregator.java index 2dc57610..512ce600 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/OutcomeAggregator.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/OutcomeAggregator.java @@ -12,17 +12,14 @@ */ package com.shazam.fork.summary; -import com.google.common.base.Function; - import org.apache.commons.lang3.BooleanUtils; import java.util.Collection; import java.util.List; +import java.util.function.Function; -import javax.annotation.Nullable; - -import static com.google.common.collect.Collections2.transform; import static com.shazam.fork.summary.ResultStatus.PASS; +import static java.util.stream.Collectors.toList; public class OutcomeAggregator { @@ -32,30 +29,20 @@ public boolean aggregate(Summary summary) { } List poolSummaries = summary.getPoolSummaries(); - Collection poolOutcomes = transform(poolSummaries, toPoolOutcome()); + Collection poolOutcomes = poolSummaries.stream().map(toPoolOutcome()).collect(toList()); return and(poolOutcomes); } - public static Function toPoolOutcome() { - return new Function() { - @Override - @Nullable - public Boolean apply(@Nullable PoolSummary input) { - final Collection testResults = input.getTestResults(); - final Collection testOutcomes = transform(testResults, toTestOutcome()); - return !testOutcomes.isEmpty() && and(testOutcomes); - } + static Function toPoolOutcome() { + return (Function) input -> { + final Collection testResults = input.getTestResults(); + final Collection testOutcomes = testResults.stream().map(toTestOutcome()).collect(toList()); + return !testOutcomes.isEmpty() && and(testOutcomes); }; } private static Function toTestOutcome() { - return new Function() { - @Override - @Nullable - public Boolean apply(@Nullable TestResult input) { - return PASS.equals(input.getResultStatus()); - } - }; + return input -> PASS.equals(input.getResultStatus()); } private static Boolean and(final Collection booleans) { From 1c837c63bbcb0925c80f4cf4c6d31157b636453c Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 28 Dec 2017 11:58:07 +0800 Subject: [PATCH 50/51] remove unused imports --- .../chimprunner/injector/suite/TestSuiteLoaderInjector.java | 1 - .../java/com/shazam/fork/io/ClassesDexFileExtractor.java | 1 - .../main/java/com/shazam/fork/stat/StatServiceLoader.java | 1 - .../src/main/java/com/shazam/fork/suite/TestSuiteLoader.java | 2 -- .../java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java | 1 - .../shazam/fork/injector/suite/TestSuiteLoaderInjector.java | 3 --- .../src/main/java/com/shazam/fork/runner/PoolTestRunner.java | 1 - .../java/com/shazam/fork/runner/PoolTestRunnerFactory.java | 3 --- .../fork/runner/listeners/ConsoleLoggingTestRunListener.java | 2 -- .../shazam/fork/runner/listeners/LogCatTestRunListener.java | 1 - .../fork/runner/listeners/ScreenCaptureTestRunListener.java | 1 - .../fork/runner/listeners/ScreenRecorderTestRunListener.java | 1 - .../src/main/java/com/shazam/fork/stat/TestExecution.java | 1 - .../java/com/shazam/fork/stat/TestExecutionReporter.java | 1 - .../main/java/com/shazam/fork/summary/HtmlConverters.java | 2 -- .../java/com/shazam/fork/summary/HtmlSummaryPrinter.java | 2 -- .../main/java/com/shazam/fork/summary/LogSummaryPrinter.java | 4 ---- .../java/com/shazam/fork/system/io/RemoteFileManager.java | 1 - .../com/shazam/fork/runner/FakeProgressReporterTrackers.java | 3 ++- .../main/java/com/agoda/fork/teamcity/TeamCityService.java | 2 -- .../java/com/agoda/fork/teamcity/TeamCityStatLoader.java | 5 ----- 21 files changed, 2 insertions(+), 37 deletions(-) diff --git a/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java b/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java index 97ad9ec9..0032446c 100644 --- a/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java +++ b/chimprunner/src/main/java/com/shazam/chimprunner/injector/suite/TestSuiteLoaderInjector.java @@ -15,7 +15,6 @@ import static com.shazam.chimprunner.injector.ConfigurationInjector.configuration; import static com.shazam.chimprunner.injector.io.DexFileExtractorInjector.dexFileExtractor; import static com.shazam.chimprunner.injector.model.TestCaseEventFactoryInjector.testCaseEventFactory; -import static com.shazam.chimprunner.injector.stat.TestStatLoaderInjector.testStatsLoader; import static com.shazam.chimprunner.injector.suite.TestClassMatcherInjector.testClassMatcher; public class TestSuiteLoaderInjector { diff --git a/fork-common/src/main/java/com/shazam/fork/io/ClassesDexFileExtractor.java b/fork-common/src/main/java/com/shazam/fork/io/ClassesDexFileExtractor.java index ad5ee435..8cfeb524 100644 --- a/fork-common/src/main/java/com/shazam/fork/io/ClassesDexFileExtractor.java +++ b/fork-common/src/main/java/com/shazam/fork/io/ClassesDexFileExtractor.java @@ -19,7 +19,6 @@ import java.util.zip.*; import static com.shazam.fork.io.Files.convertFileToDexFile; -import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.apache.commons.io.IOUtils.closeQuietly; import static org.apache.commons.io.IOUtils.copyLarge; diff --git a/fork-common/src/main/java/com/shazam/fork/stat/StatServiceLoader.java b/fork-common/src/main/java/com/shazam/fork/stat/StatServiceLoader.java index 63029d48..4bb58692 100644 --- a/fork-common/src/main/java/com/shazam/fork/stat/StatServiceLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/stat/StatServiceLoader.java @@ -1,6 +1,5 @@ package com.shazam.fork.stat; -import com.agoda.fork.stat.StatLoader; import com.agoda.fork.stat.StatLoaderProvider; import com.agoda.fork.stat.TestHistory; import org.slf4j.Logger; diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index d4c6010f..914e765b 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -13,7 +13,6 @@ import com.shazam.fork.io.DexFileExtractor; import com.shazam.fork.model.TestCaseEvent; import com.shazam.fork.model.TestCaseEventFactory; -import com.shazam.fork.stat.TestStatsLoader; import org.jf.dexlib.*; import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue; import org.jf.dexlib.EncodedValue.ArrayEncodedValue; @@ -30,7 +29,6 @@ import static java.util.Arrays.stream; import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toMap; public class TestSuiteLoader { private static final String TEST_ANNOTATION = "Lorg/junit/Test;"; diff --git a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java index e6fc3407..675f4fb4 100644 --- a/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java +++ b/fork-common/src/test/java/com/shazam/fork/suite/TestSuiteLoaderTestUtils.java @@ -1,6 +1,5 @@ package com.shazam.fork.suite; -import com.agoda.fork.stat.TestMetric; import com.shazam.fork.model.TestCaseEvent; import com.shazam.fork.model.TestCaseEventFactory; import com.shazam.fork.stat.StatServiceLoader; diff --git a/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java b/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java index fda93bc6..b456a768 100644 --- a/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java +++ b/fork-runner/src/main/java/com/shazam/fork/injector/suite/TestSuiteLoaderInjector.java @@ -10,14 +10,11 @@ package com.shazam.fork.injector.suite; -import com.shazam.fork.stat.StatServiceLoader; -import com.shazam.fork.stat.TestStatsLoader; import com.shazam.fork.suite.TestSuiteLoader; import static com.shazam.fork.injector.ConfigurationInjector.configuration; import static com.shazam.fork.injector.io.DexFileExtractorInjector.dexFileExtractor; import static com.shazam.fork.injector.model.TestCaseEventFactoryInjector.testCaseEventFactory; -import static com.shazam.fork.injector.stat.TestStatLoaderInjector.testStatsLoader; import static com.shazam.fork.injector.suite.TestClassMatcherInjector.testClassMatcher; public class TestSuiteLoaderInjector { diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunner.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunner.java index defd0ec1..d879975d 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunner.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunner.java @@ -15,7 +15,6 @@ import com.shazam.fork.batch.tasks.TestTask; import com.shazam.fork.model.Device; import com.shazam.fork.model.Pool; -import com.shazam.fork.model.TestCaseEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java index 4f492bb2..308e77f7 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/PoolTestRunnerFactory.java @@ -12,10 +12,7 @@ import com.shazam.fork.batch.tasks.TestTask; import com.shazam.fork.model.Pool; -import com.shazam.fork.model.TestCaseEvent; -import java.util.Collection; -import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.CountDownLatch; diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ConsoleLoggingTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ConsoleLoggingTestRunListener.java index 9a5ec104..e52a3550 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ConsoleLoggingTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ConsoleLoggingTestRunListener.java @@ -12,7 +12,6 @@ */ package com.shazam.fork.runner.listeners; -import com.android.ddmlib.testrunner.ITestRunListener; import com.android.ddmlib.testrunner.TestIdentifier; import com.shazam.fork.runner.ProgressReporter; @@ -21,7 +20,6 @@ import java.text.SimpleDateFormat; import java.util.Date; -import java.util.Map; import static java.lang.String.format; diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/LogCatTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/LogCatTestRunListener.java index 0a16401e..69dd4397 100755 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/LogCatTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/LogCatTestRunListener.java @@ -13,7 +13,6 @@ package com.shazam.fork.runner.listeners; import com.android.ddmlib.logcat.*; -import com.android.ddmlib.testrunner.ITestRunListener; import com.android.ddmlib.testrunner.TestIdentifier; import com.google.gson.Gson; import com.shazam.fork.model.Device; diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenCaptureTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenCaptureTestRunListener.java index 0ffcdb8d..50e694ac 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenCaptureTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenCaptureTestRunListener.java @@ -10,7 +10,6 @@ package com.shazam.fork.runner.listeners; import com.android.ddmlib.IDevice; -import com.android.ddmlib.testrunner.ITestRunListener; import com.android.ddmlib.testrunner.TestIdentifier; import com.shazam.fork.model.Device; import com.shazam.fork.model.Pool; diff --git a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenRecorderTestRunListener.java b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenRecorderTestRunListener.java index 7eb3bbd4..659b7592 100644 --- a/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenRecorderTestRunListener.java +++ b/fork-runner/src/main/java/com/shazam/fork/runner/listeners/ScreenRecorderTestRunListener.java @@ -10,7 +10,6 @@ package com.shazam.fork.runner.listeners; import com.android.ddmlib.IDevice; -import com.android.ddmlib.testrunner.ITestRunListener; import com.android.ddmlib.testrunner.TestIdentifier; import com.shazam.fork.model.Device; import com.shazam.fork.model.Pool; diff --git a/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java index 17a252d2..12c9cbe4 100644 --- a/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java +++ b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecution.java @@ -1,7 +1,6 @@ package com.shazam.fork.stat; import com.android.ddmlib.testrunner.TestIdentifier; -import org.jetbrains.annotations.NotNull; public class TestExecution { diff --git a/fork-runner/src/main/java/com/shazam/fork/stat/TestExecutionReporter.java b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecutionReporter.java index d003628d..cc3cebc8 100644 --- a/fork-runner/src/main/java/com/shazam/fork/stat/TestExecutionReporter.java +++ b/fork-runner/src/main/java/com/shazam/fork/stat/TestExecutionReporter.java @@ -5,7 +5,6 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; public class TestExecutionReporter { diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlConverters.java b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlConverters.java index c6fb83e1..e45df7ab 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlConverters.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlConverters.java @@ -15,14 +15,12 @@ import com.android.ddmlib.logcat.LogCatMessage; import java.util.function.Function; -import java.util.stream.Collectors; import com.shazam.fork.model.Device; import com.shazam.fork.model.Diagnostics; import javax.annotation.Nullable; -import static com.google.common.collect.Collections2.transform; import static com.shazam.fork.model.Diagnostics.SCREENSHOTS; import static com.shazam.fork.model.Diagnostics.VIDEO; import static com.shazam.fork.summary.OutcomeAggregator.toPoolOutcome; diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java index 1057396a..49e30c91 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/HtmlSummaryPrinter.java @@ -22,10 +22,8 @@ import java.io.File; import java.nio.charset.Charset; import java.util.List; -import java.util.stream.Collectors; import static com.google.common.base.Charsets.UTF_8; -import static com.google.common.collect.Collections2.transform; import static com.shazam.fork.io.Files.copyResource; import static com.shazam.fork.summary.HtmlConverters.toHtmlLogCatMessages; import static com.shazam.fork.summary.HtmlConverters.toHtmlSummary; diff --git a/fork-runner/src/main/java/com/shazam/fork/summary/LogSummaryPrinter.java b/fork-runner/src/main/java/com/shazam/fork/summary/LogSummaryPrinter.java index 8a7e4214..b20e464f 100755 --- a/fork-runner/src/main/java/com/shazam/fork/summary/LogSummaryPrinter.java +++ b/fork-runner/src/main/java/com/shazam/fork/summary/LogSummaryPrinter.java @@ -12,16 +12,12 @@ */ package com.shazam.fork.summary; -import com.google.common.base.Predicate; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; -import javax.annotation.Nullable; - import static com.google.common.collect.Collections2.filter; import static com.shazam.fork.summary.ResultStatus.ERROR; import static com.shazam.fork.summary.ResultStatus.FAIL; diff --git a/fork-runner/src/main/java/com/shazam/fork/system/io/RemoteFileManager.java b/fork-runner/src/main/java/com/shazam/fork/system/io/RemoteFileManager.java index a3102f3f..41aa7aaa 100644 --- a/fork-runner/src/main/java/com/shazam/fork/system/io/RemoteFileManager.java +++ b/fork-runner/src/main/java/com/shazam/fork/system/io/RemoteFileManager.java @@ -16,7 +16,6 @@ import com.android.ddmlib.IDevice; import com.android.ddmlib.NullOutputReceiver; import com.android.ddmlib.ShellCommandUnresponsiveException; -import com.android.ddmlib.SyncException; import com.android.ddmlib.TimeoutException; import com.android.ddmlib.testrunner.TestIdentifier; import java.io.IOException; diff --git a/fork-runner/src/test/java/com/shazam/fork/runner/FakeProgressReporterTrackers.java b/fork-runner/src/test/java/com/shazam/fork/runner/FakeProgressReporterTrackers.java index 7a533df2..e552d275 100644 --- a/fork-runner/src/test/java/com/shazam/fork/runner/FakeProgressReporterTrackers.java +++ b/fork-runner/src/test/java/com/shazam/fork/runner/FakeProgressReporterTrackers.java @@ -3,6 +3,7 @@ import com.shazam.fork.model.Pool; import java.util.AbstractMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -21,7 +22,7 @@ public FakeProgressReporterTrackers thatAlwaysReturns(PoolProgressTracker poolPr @Override public Set> entrySet() { - return null; + return new HashSet<>(); } @Override diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityService.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityService.java index ae6cf4ff..d564ed95 100644 --- a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityService.java +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityService.java @@ -3,11 +3,9 @@ import com.agoda.fork.teamcity.entities.Builds; import com.agoda.fork.teamcity.entities.TestResult; import io.reactivex.Single; -import okhttp3.ResponseBody; import retrofit2.http.GET; import retrofit2.http.Path; import retrofit2.http.Query; -import retrofit2.http.Streaming; public interface TeamCityService { @GET("/httpAuth/app/rest/buildTypes/id:{configuration}/builds/?locator=count:10&fields=build:id") diff --git a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoader.java b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoader.java index f666f255..33ce57d2 100644 --- a/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoader.java +++ b/fork-stat-teamcity/src/main/java/com/agoda/fork/teamcity/TeamCityStatLoader.java @@ -6,11 +6,6 @@ import com.agoda.fork.teamcity.entities.TestResult; import io.reactivex.Single; import io.reactivex.Observable; -import io.reactivex.functions.Function; -import okhttp3.ResponseBody; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.nodes.Tag; import java.util.*; From bce94d37b62598ed93f3b793595dd7147285d2fd Mon Sep 17 00:00:00 2001 From: Ivan Balaksha Date: Thu, 28 Dec 2017 12:08:25 +0800 Subject: [PATCH 51/51] fix lint warnings --- .../shazam/fork/suite/TestSuiteLoader.java | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java index 914e765b..f1baf09e 100644 --- a/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java +++ b/fork-common/src/main/java/com/shazam/fork/suite/TestSuiteLoader.java @@ -190,27 +190,22 @@ private int indexOfName(AnnotationEncodedSubValue p, String key) { private boolean isClassIgnored(AnnotationDirectoryItem annotationDirectoryItem) { AnnotationSetItem classAnnotations = annotationDirectoryItem.getClassAnnotations(); - if (classAnnotations == null) { - return false; - } - return containsAnnotation(IGNORE_ANNOTATION, classAnnotations.getAnnotations()); + return classAnnotations != null && containsAnnotation(IGNORE_ANNOTATION, classAnnotations.getAnnotations()); } private boolean included(AnnotationItem... annotations) { - if (includedAnnotations.isEmpty()) { - return true; - } - return includedAnnotations.stream() - .anyMatch(included -> containsAnnotation(included, annotations)); + return includedAnnotations.isEmpty() || + containsAnnotation(annotations, includedAnnotations.stream()); + } + + private boolean containsAnnotation(AnnotationItem[] annotations, Stream stream) { + return stream.anyMatch(included -> containsAnnotation(included, annotations)); } private boolean excluded(AnnotationItem... annotations) { - if (excludedAnnotations.isEmpty()) { - return false; - } - return excludedAnnotations.stream() - .anyMatch(excluded -> containsAnnotation(excluded, annotations)); + return !excludedAnnotations.isEmpty() + && containsAnnotation(annotations, excludedAnnotations.stream()); } private boolean containsAnnotation(String comparisonAnnotation, AnnotationItem... annotations) {