Skip to content

Commit

Permalink
Merge pull request #23 from agoda-com/develop
Browse files Browse the repository at this point in the history
merge develop to master
  • Loading branch information
tagantroy committed Jan 9, 2018
2 parents 0455a15 + 887f8da commit 2b64b28
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ local.properties

# output files
fork-output

*/out
Original file line number Diff line number Diff line change
@@ -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 Inheritance {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.shazam.forktest;

import android.Manifest;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class TestA {

private final int a;
private final int b;
private final int res;

public TestA(int a, int b, int res) {
this.a = a;
this.b = b;
this.res = res;
}

@Test
public void methodTest() {
assertEquals(res, a + b);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.shazam.forktest;

import com.shazam.annotations.Inheritance;

@Inheritance
public class TestB extends TestA {
public TestB() {
super(2, 2, 4);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class TestSuiteLoader {
private static final String IGNORE_ANNOTATION = "Lorg/junit/Ignore;";
private static final String REVOKE_PERMISSION_ANNOTATION = "Lcom/shazam/fork/RevokePermission;";
private static final String TEST_PROPERTIES_ANNOTATION = "Lcom/shazam/fork/TestProperties;";
public static final String JAVA_LANG_OBJECT_SINGATURE = "Ljava/lang/Object;";

private final File instrumentationApkFile;
private final DexFileExtractor dexFileExtractor;
Expand All @@ -58,23 +59,30 @@ public TestSuiteLoader(File instrumentationApkFile,
}

public Collection<TestCaseEvent> loadTestSuite() throws NoTestCasesFoundException {
Collection<DexFile> dexFiles = dexFileExtractor.getDexFiles(instrumentationApkFile);
List<TestCaseEvent> testCaseEvents = extractTests(dexFiles);

List<TestCaseEvent> testCaseEvents = dexFileExtractor.getDexFiles(instrumentationApkFile).stream()
if (testCaseEvents.isEmpty()) {
throw new NoTestCasesFoundException("No tests cases were found in the test APK: " + instrumentationApkFile.getAbsolutePath());
}
return testCaseEvents;
}

private List<TestCaseEvent> extractTests(Collection<DexFile> dexFiles) {
List<ClassDefItem> classDefItems = dexFiles.stream()
.map(dexFile -> dexFile.ClassDefsSection.getItems())
.flatMap(Collection::stream)
.collect(toList());

return classDefItems.stream()
.filter(c -> testClassMatcher.matchesPatterns(c.getClassType().getTypeDescriptor()))
.map(this::convertClassToTestCaseEvents)
.map(item -> convertClassToTestCaseEvents(item, classDefItems))
.flatMap(Collection::stream)
.collect(toList());

if (testCaseEvents.isEmpty()) {
throw new NoTestCasesFoundException("No tests cases were found in the test APK: " + instrumentationApkFile.getAbsolutePath());
}
return testCaseEvents;
}

@Nonnull
private List<TestCaseEvent> convertClassToTestCaseEvents(ClassDefItem classDefItem) {
private List<TestCaseEvent> convertClassToTestCaseEvents(ClassDefItem classDefItem, List<ClassDefItem> classDefItems) {
boolean classIncluded = false;
AnnotationDirectoryItem annotationDirectoryItem = classDefItem.getAnnotations();
if (annotationDirectoryItem == null) {
Expand All @@ -91,16 +99,40 @@ private List<TestCaseEvent> convertClassToTestCaseEvents(ClassDefItem classDefIt
}
}

return parseMethods(classDefItem, annotationDirectoryItem, classIncluded);
return parseMethods(classDefItem, annotationDirectoryItem, classIncluded, classDefItems);
}

private List<TestCaseEvent> parseMethods(ClassDefItem classDefItem, AnnotationDirectoryItem annotationDirectory, boolean classIncluded) {
return annotationDirectory.getMethodAnnotations()
.stream()
private List<TestCaseEvent> parseMethods(ClassDefItem classDefItem,
AnnotationDirectoryItem annotationDirectory,
boolean classIncluded,
List<ClassDefItem> classDefItems) {
return recursiveSearch(classDefItem, annotationDirectory, classDefItems).stream()
.flatMap(method -> parseTestCaseEvents(classDefItem, annotationDirectory, method, classIncluded))
.collect(toList());
}

private List<AnnotationDirectoryItem.MethodAnnotation> recursiveSearch(ClassDefItem classDefItem,
AnnotationDirectoryItem directoryItem,
List<ClassDefItem> classDefItems) {
TypeIdItem superClassIdItem = classDefItem.getSuperclass();
String superClassDescriptor = superClassIdItem.getTypeDescriptor();
List<AnnotationDirectoryItem.MethodAnnotation> list = new ArrayList<>();
if (directoryItem != null) {
list.addAll(directoryItem.getMethodAnnotations());
}
if (!JAVA_LANG_OBJECT_SINGATURE.equals(superClassDescriptor)) {
findClassDef(classDefItems, superClassDescriptor)
.ifPresent(a -> list.addAll(recursiveSearch(a, a.getAnnotations(), classDefItems)));
}
return list;
}

private Optional<ClassDefItem> findClassDef(List<ClassDefItem> classDefItems, String identity) {
return classDefItems.stream()
.filter(a -> a.getClassType().getTypeDescriptor().equals(identity))
.findFirst();
}

private Stream<TestCaseEvent> parseTestCaseEvents(ClassDefItem classDefItem,
AnnotationDirectoryItem annotationDirectoryItem,
AnnotationDirectoryItem.MethodAnnotation methodAnnotation,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.shazam.fork.suite;

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;

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 TestSuiteLoaderInheritanceTest {
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.Inheritance",
"",new TestCaseEventFactory(new TestStatsLoader(new StatServiceLoader(""))));
}

@Test
public void testIncludeAnnotation() throws Exception {
Collection<TestCaseEvent> events = testSuiteLoader.loadTestSuite();
assertThat(events.size(),is(1));
assertThat(events, hasItem(sameTestEventAs("methodTest", "com.shazam.forktest.TestB", false)));
}
}
Binary file modified fork-common/src/test/resources/app-debug.apk
Binary file not shown.
Binary file modified fork-common/src/test/resources/tests.dex
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package com.shazam.fork.batch

import com.shazam.fork.BatchStrategy
import com.shazam.fork.batch.strategies.*
import com.shazam.fork.batch.strategies.DefaultFactoryStrategy
import com.shazam.fork.batch.strategies.SplitFactoryStrategy
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) {

fun create(maxDevicesPerPool: Int, list: Collection<TestCaseEvent>): BatchTestQueue {
val extractedStrategy = extractStrategy(batchStrategy)
val supportBatches = list.groupBy { it.permissionsToRevoke.isEmpty() }
val tasks = extractedStrategy.batches(maxDevicesPerPool, supportBatches[true] ?: emptyList())
val queue = BatchTestQueue(tasks.size)
val singleTestTasks = supportBatches[false]?.map { TestTask.SingleTestTask(it) } ?: emptyList()
val queue = BatchTestQueue(tasks.size + singleTestTasks.size)
queue.addAll(tasks)
queue.addAll(supportBatches[false]?.map { TestTask.SingleTestTask(it) } ?: emptyList())
queue.addAll(singleTestTasks)
return queue
}

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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-alpha2
VERSION_NAME=3.0.0-alpha3
GROUP=com.shazam.fork

POM_LICENCE_NAME=The Apache Software License, Version 2.0
Expand Down

0 comments on commit 2b64b28

Please sign in to comment.