blob: a4b002c8105eab5b03b95b5c7cf73617f56d91db [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.build.gradle.internal.transforms;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import com.android.annotations.NonNull;
import com.android.build.api.transform.Context;
import com.android.build.api.transform.QualifiedContent;
import com.android.build.api.transform.Status;
import com.android.build.api.transform.TransformException;
import com.android.build.api.transform.TransformInput;
import com.android.build.api.transform.TransformOutputProvider;
import com.android.build.gradle.internal.incremental.InstantRunBuildContext;
import com.android.build.gradle.internal.incremental.InstantRunVerifier;
import com.android.build.gradle.internal.incremental.InstantRunVerifierStatus;
import com.android.build.gradle.internal.pipeline.TaskTestUtils;
import com.android.build.gradle.internal.pipeline.TransformInvocationBuilder;
import com.android.build.gradle.internal.scope.GlobalScope;
import com.android.build.gradle.internal.scope.VariantScope;
import com.android.builder.model.OptionalCompilationStep;
import com.android.utils.FileUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
/**
* Tests for the {@link InstantRunVerifierTransform}
*/
public class InstantRunVerifierTransformTest {
@Rule public MockitoRule rule = MockitoJUnit.rule();
final Map<File, File> recordedVerification = new HashMap<>();
final Map<File, File> recordedCopies = new HashMap<>();
private File backupDir;
@Mock
VariantScope variantScope;
@Mock
GlobalScope globalScope;
@Mock
Context context;
@Mock
TransformOutputProvider transformOutputProvider;
@Mock InstantRunBuildContext buildContext;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Before
public void setUpMock() throws IOException {
backupDir = temporaryFolder.newFolder();
when(variantScope.getIncrementalVerifierDir()).thenReturn(backupDir);
when(variantScope.getInstantRunBuildContext()).thenReturn(buildContext);
when(variantScope.getGlobalScope()).thenReturn(globalScope);
when(buildContext.getVerifierResult()).thenReturn(
InstantRunVerifierStatus.NO_CHANGES);
when(globalScope.isActive(OptionalCompilationStep.RESTART_ONLY)).thenReturn(false);
}
@Test
public void testNonIncrementalModel()
throws TransformException, InterruptedException, IOException {
InstantRunVerifierTransform transform = getTransform();
final File tmpDir = temporaryFolder.newFolder();
final File inputClass = new File(tmpDir, "com/foo/bar/InputFile.class");
Files.createParentDirs(inputClass);
assertTrue(inputClass.createNewFile());
TransformInput transformInput =
TransformTestHelper.directoryBuilder(tmpDir)
.setContentType(QualifiedContent.DefaultContentType.CLASSES)
.setScope(QualifiedContent.Scope.PROJECT)
.putChangedFiles(ImmutableMap.of(inputClass, Status.ADDED))
.build();
transform.transform(
new TransformInvocationBuilder(context)
.addOutputProvider(transformOutputProvider)
.addReferencedInputs(ImmutableList.of(transformInput))
.build());
// clean up.
FileUtils.deletePath(tmpDir);
// input class should have been copied.
assertThat(recordedVerification).isEmpty();
assertThat(recordedCopies).hasSize(1);
assertThat(recordedCopies).containsEntry(inputClass,
new File(backupDir, "com/foo/bar/InputFile.class"));
}
@Test
public void testIncrementalMode_changedAndAdded() throws TransformException, IOException, InterruptedException {
InstantRunVerifierTransform transform = getTransform();
final File tmpDir = temporaryFolder.newFolder();
final File addedFile = new File(tmpDir, "com/foo/bar/NewInputFile.class");
Files.createParentDirs(addedFile);
assertTrue(addedFile.createNewFile());
final File changedFile = new File(tmpDir, "com/foo/bar/ChangedFile.class");
assertTrue(changedFile.createNewFile());
final File lastIterationChangedFile =
new File(backupDir, "com/foo/bar/ChangedFile.class");
Files.createParentDirs(lastIterationChangedFile);
assertTrue(lastIterationChangedFile.createNewFile());
TransformInput transformInput =
TransformTestHelper.directoryBuilder(tmpDir)
.setContentType(QualifiedContent.DefaultContentType.CLASSES)
.setScope(QualifiedContent.Scope.PROJECT)
.putChangedFiles(
ImmutableMap.<File, Status>builder()
.put(addedFile, Status.ADDED)
.put(changedFile, Status.CHANGED)
.build())
.build();
transform.transform(
new TransformInvocationBuilder(context)
.addOutputProvider(transformOutputProvider)
.addReferencedInputs(ImmutableList.of(transformInput))
.setIncrementalMode(true)
.build());
// clean up.
FileUtils.deletePath(tmpDir);
// changed class should have been verified
assertThat(recordedVerification).isEmpty();
// new classes should have been copied, and changed ones updated.
assertThat(recordedCopies).hasSize(2);
assertThat(recordedCopies).containsEntry(
changedFile, lastIterationChangedFile);
assertThat(recordedCopies).containsEntry(addedFile,
new File(backupDir, "com/foo/bar/NewInputFile.class"));
}
@Test
public void testIncrementalMode_changedAndDeleted() throws TransformException, IOException, InterruptedException {
InstantRunVerifierTransform transform = getTransform();
final File tmpDir = temporaryFolder.newFolder();
final File changedFile = new File(tmpDir, "com/foo/bar/ChangedFile.class");
Files.createParentDirs(changedFile);
assertTrue(changedFile.createNewFile());
final File lastIterationChangedFile =
new File(backupDir, "com/foo/bar/ChangedFile.class");
Files.createParentDirs(lastIterationChangedFile);
assertTrue(lastIterationChangedFile.createNewFile());
final File deletedFile = new File(tmpDir, "com/foo/bar/DeletedFile.class");
TransformInput transformInput =
TransformTestHelper.directoryBuilder(tmpDir)
.setScope(QualifiedContent.Scope.PROJECT)
.setContentType(QualifiedContent.DefaultContentType.CLASSES)
.putChangedFiles(
ImmutableMap.<File, Status>builder()
.put(changedFile, Status.CHANGED)
.put(deletedFile, Status.REMOVED)
.build())
.build();
transform.transform(
new TransformInvocationBuilder(context)
.addOutputProvider(transformOutputProvider)
.addReferencedInputs(ImmutableList.of(transformInput))
.setIncrementalMode(true)
.build());
// clean up.
FileUtils.deletePath(tmpDir);
// changed class should have been verified
assertThat(recordedVerification).hasSize(1);
assertThat(recordedVerification).containsEntry(
lastIterationChangedFile, changedFile);
// new classes should have been copied, and changed ones updated.
assertThat(recordedCopies).hasSize(1);
assertThat(recordedCopies).containsEntry(
changedFile, lastIterationChangedFile);
}
@Test
public void testSeveralAddedFilesInIncrementalMode()
throws IOException, TransformException, InterruptedException {
InstantRunVerifierTransform transform = getTransform();
final File tmpDir = temporaryFolder.newFolder();
final File[] files = new File[5];
for (int i = 0; i < 5; i++) {
files[i] = new File(tmpDir, "com/foo/bar/NewInputFile-" + i + ".class");
Files.createParentDirs(files[i]);
assertTrue(files[i].createNewFile());
}
ImmutableMap.Builder<File, Status> changesBuilder = ImmutableMap.builder();
for (int i = 0; i < 5; i++) {
changesBuilder.put(files[i], Status.ADDED);
}
TransformInput transformInput =
TransformTestHelper.directoryBuilder(tmpDir)
.setContentType(QualifiedContent.DefaultContentType.CLASSES)
.setScope(QualifiedContent.Scope.PROJECT)
.putChangedFiles(changesBuilder.build())
.build();
transform.transform(
new TransformInvocationBuilder(context)
.addOutputProvider(transformOutputProvider)
.addReferencedInputs(ImmutableList.of(transformInput))
.setIncrementalMode(true)
.build());
// clean up.
FileUtils.deletePath(tmpDir);
// input class should have been copied.
assertThat(recordedCopies).hasSize(5);
for (int i=0; i<5; i++) {
assertThat(recordedCopies).containsEntry(files[i],
new File(backupDir, "com/foo/bar/" + files[i].getName()));
}
assertThat(recordedVerification).isEmpty();
}
@Test
public void testSeveralChangedFilesInIncrementalMode()
throws IOException, TransformException, InterruptedException {
InstantRunVerifierTransform transform = getTransform();
final File tmpDir = temporaryFolder.newFolder();
final File[] files = new File[5];
final File[] lastIterationFiles = new File[5];
for (int i = 0; i < 5; i++) {
files[i] = new File(tmpDir, "com/foo/bar/NewInputFile-" + i + ".class");
Files.createParentDirs(files[i]);
assertTrue(files[i].createNewFile());
lastIterationFiles[i] = new File(backupDir, "com/foo/bar/NewInputFile-" + i + ".class");
Files.createParentDirs(lastIterationFiles[i]);
assertTrue(lastIterationFiles[i].createNewFile());
}
ImmutableMap.Builder<File, Status> changesBuilder = ImmutableMap.builder();
for (int i = 0; i < 5; i++) {
changesBuilder.put(files[i], Status.CHANGED);
}
TransformInput transformInput =
TransformTestHelper.directoryBuilder(tmpDir)
.setScope(QualifiedContent.Scope.PROJECT)
.setContentType(QualifiedContent.DefaultContentType.CLASSES)
.putChangedFiles(changesBuilder.build())
.build();
transform.transform(
new TransformInvocationBuilder(context)
.addOutputProvider(transformOutputProvider)
.addReferencedInputs(ImmutableList.of(transformInput))
.setIncrementalMode(true)
.build());
// clean up.
FileUtils.deletePath(tmpDir);
// input class should have been verified.
assertThat(recordedVerification).hasSize(5);
for (int i=0; i<5; i++) {
assertThat(recordedVerification).containsEntry(lastIterationFiles[i], files[i]);
}
// and updated...
assertThat(recordedCopies).hasSize(5);
for (int i=0; i<5; i++) {
assertThat(recordedCopies).containsEntry(files[i], lastIterationFiles[i]);
}
}
@Test
public void testStatusAlreadySet()
throws TransformException, InterruptedException, IOException {
when(buildContext.getVerifierResult()).thenReturn(
InstantRunVerifierStatus.DEPENDENCY_CHANGED);
final File inputDir = temporaryFolder.newFolder();
final File inputFile = new File(inputDir, "com/foo/bar/InputFile.class");
TransformInput transformInput =
TransformTestHelper.directoryBuilder(inputDir)
.setScope(QualifiedContent.Scope.PROJECT)
.setContentType(QualifiedContent.DefaultContentType.CLASSES)
.putChangedFiles(ImmutableMap.of(inputFile, Status.ADDED))
.build();
getTransform()
.transform(
new TransformInvocationBuilder(context)
.addOutputProvider(transformOutputProvider)
.addReferencedInputs(ImmutableList.of(transformInput))
.setIncrementalMode(true)
.build());
// check the verifier status is not reset.
assertThat(buildContext.getVerifierResult()).isEqualTo(
InstantRunVerifierStatus.DEPENDENCY_CHANGED);
}
private InstantRunVerifierTransform getTransform() {
return new InstantRunVerifierTransform(variantScope, new TaskTestUtils.FakeRecorder()) {
@NonNull
@Override
protected InstantRunVerifierStatus runVerifier(
String name,
@NonNull final InstantRunVerifier.ClassBytesProvider originalClass,
@NonNull final InstantRunVerifier.ClassBytesProvider updatedClass)
throws IOException {
recordedVerification.put(
((InstantRunVerifier.ClassBytesFileProvider) originalClass).getFile(),
((InstantRunVerifier.ClassBytesFileProvider) updatedClass).getFile());
return InstantRunVerifierStatus.COMPATIBLE;
}
@Override
protected void copyFile(File inputFile, File outputFile) {
recordedCopies.put(inputFile, outputFile);
}
};
}
}