blob: 44e0b89dc46854bb56cb9703707ae48802724b50 [file] [log] [blame]
/*
* Copyright 2014 Google Inc.
*
* 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.google.gwt.dev;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.cfg.LibraryGroup;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.cfg.ResourceLoader;
import com.google.gwt.dev.cfg.ResourceLoaders;
import com.google.gwt.dev.util.UnitTestTreeLogger;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.io.Files;
import com.google.gwt.thirdparty.guava.common.io.Resources;
import junit.framework.TestCase;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
* Test for {@link IncrementalBuilder}.
*/
public class IncrementalBuilderTest extends TestCase {
private static void assertBuildResult(String rootModuleName, boolean expectedBuildSuccess,
String... expectedErrorMessages) throws MalformedURLException {
UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
loggerBuilder.setLowestLogLevel(TreeLogger.INFO);
for (String expectedErrorMessage : expectedErrorMessages) {
loggerBuilder.expectError(expectedErrorMessage, null);
}
UnitTestTreeLogger testLogger = loggerBuilder.createLogger();
IncrementalBuilder incrementalBuilder =
createIncrementalBuilder(rootModuleName, createGwtClassPathResourceLoader());
incrementalBuilder.clean();
boolean actualBuildSuccess = incrementalBuilder.build(testLogger).isSuccess();
assertEquals(expectedBuildSuccess, actualBuildSuccess);
testLogger.assertLogEntriesContainExpected();
}
private static ResourceLoader createGwtClassPathResourceLoader() throws MalformedURLException {
String gwtClassPathProperty = System.getProperty("gwt.cp");
String[] gwtClassPathStrings = gwtClassPathProperty.split(";");
final List<URL> gwtClassPathEntries = Lists.newArrayList();
for (String gwtClassPathString : gwtClassPathStrings) {
gwtClassPathEntries.add(new File(gwtClassPathString).toURI().toURL());
}
ResourceLoader gwtClassPathResourceLoader = new ResourceLoader() {
@Override
public List<URL> getClassPath() {
return gwtClassPathEntries;
}
@Override
public URL getResource(String resourceName) {
return Thread.currentThread().getContextClassLoader().getResource(resourceName);
}
};
return gwtClassPathResourceLoader;
}
private static ResourceLoader createGwtClassPathResourceLoaderWithMocks(
String... mockResourceNames) throws FileNotFoundException, IOException {
final ResourceLoader gwtClassPathResourceLoader = createGwtClassPathResourceLoader();
File mockResourcesDirectory = Files.createTempDir();
for (String mockResourceName : mockResourceNames) {
File mockFooFile = new File(mockResourcesDirectory, mockResourceName);
mockFooFile.getParentFile().mkdirs();
URL realFooResource = gwtClassPathResourceLoader.getResource(mockResourceName);
Resources.copy(realFooResource, new FileOutputStream(mockFooFile));
}
return ResourceLoaders.forPathAndFallback(Lists.newArrayList(mockResourcesDirectory),
gwtClassPathResourceLoader);
}
private static IncrementalBuilder createIncrementalBuilder(String rootModuleName,
ResourceLoader resourceLoader) {
String warDir = Files.createTempDir().getAbsolutePath();
String libDir = "/tmp/gwt/lib";
String genDir = "/tmp/gwt/gen";
IncrementalBuilder incrementalBuilder =
new IncrementalBuilder(rootModuleName, warDir, libDir, genDir, resourceLoader);
return incrementalBuilder;
}
public void testBuildRebuildEditRebuild() throws FileNotFoundException, IOException {
// Setup logging expectations for a full compile with no caching.
UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
loggerBuilder.setLowestLogLevel(TreeLogger.INFO);
loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage("com.google.gwt.core.Core"),
null);
loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
"com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleBottom"), null);
loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
"com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleMid"), null);
loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
"com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleTop"), null);
UnitTestTreeLogger testLogger = loggerBuilder.createLogger();
// Prepare the compiler.
ResourceLoader resourceLoader = createGwtClassPathResourceLoaderWithMocks(
"com/google/gwt/dev/testdata/incrementalbuildsystem/Foo.java");
IncrementalBuilder incrementalBuilder = createIncrementalBuilder(
"com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleTop", resourceLoader);
incrementalBuilder.clean();
// Compile.
boolean actualBuildSuccess = incrementalBuilder.build(testLogger).isSuccess();
// Assert compile succeeded and was a full compile with no caching.
assertEquals(true, actualBuildSuccess);
testLogger.assertLogEntriesContainExpected();
// Setup logging expectations for a fully cached compile.
loggerBuilder = new UnitTestTreeLogger.Builder();
loggerBuilder.setLowestLogLevel(TreeLogger.INFO);
loggerBuilder.expectInfo(IncrementalBuilder.NO_FILES_HAVE_CHANGED, null);
testLogger = loggerBuilder.createLogger();
// Recompile without changes.
actualBuildSuccess = incrementalBuilder.rebuild(testLogger).isSuccess();
// Assert compile succeeded and was fully cached.
assertEquals(true, actualBuildSuccess);
testLogger.assertLogEntriesContainExpected();
// Change modification date of the Foo.java seen by SimpleMid.gwt.xml
File fooFile = new File(resourceLoader.getResource(
"com/google/gwt/dev/testdata/incrementalbuildsystem/Foo.java").getPath());
fooFile.setLastModified(System.currentTimeMillis() + 60 * 1000);
// Setup logging expectations for partially cached recompile.
loggerBuilder = new UnitTestTreeLogger.Builder();
loggerBuilder.setLowestLogLevel(TreeLogger.SPAM);
loggerBuilder.expectSpam(
BuildTarget.formatReusingCachedLibraryMessage("com.google.gwt.core.Core"), null);
loggerBuilder.expectSpam(BuildTarget.formatReusingCachedLibraryMessage(
"com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleBottom"), null);
loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
"com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleMid"), null);
loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
"com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleTop"), null);
testLogger = loggerBuilder.createLogger();
// Recompile with changes.
actualBuildSuccess = incrementalBuilder.rebuild(testLogger).isSuccess();
// Assert compile succeeded and was partially cached.
assertEquals(true, actualBuildSuccess);
testLogger.assertLogEntriesContainExpected();
}
public void testCircularReference() throws MalformedURLException {
List<String> circularModulePath = Arrays.asList(new String[] {
"com.google.gwt.dev.testdata.incrementalbuildsystem.CircularRoot",
"com.google.gwt.dev.testdata.incrementalbuildsystem.CircularB <loop>",
"com.google.gwt.dev.testdata.incrementalbuildsystem.CircularC",
"com.google.gwt.dev.testdata.incrementalbuildsystem.CircularFilesetD <fileset>",
"com.google.gwt.dev.testdata.incrementalbuildsystem.CircularB <loop>"});
assertBuildResult("com.google.gwt.dev.testdata.incrementalbuildsystem.CircularRoot", false,
IncrementalBuilder.formatCircularModulePathMessage(circularModulePath));
}
public void testContinuesAfterFirstFailure() throws MalformedURLException {
UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
loggerBuilder.setLowestLogLevel(TreeLogger.INFO);
loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
"com.google.gwt.dev.testdata.incrementalbuildsystem.MultipleFailLeft"), null);
loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
"com.google.gwt.dev.testdata.incrementalbuildsystem.MultipleFailRight"), null);
UnitTestTreeLogger testLogger = loggerBuilder.createLogger();
IncrementalBuilder incrementalBuilder = createIncrementalBuilder(
"com.google.gwt.dev.testdata.incrementalbuildsystem.MultipleFailTop",
createGwtClassPathResourceLoader());
incrementalBuilder.clean();
boolean buildSucceeded = incrementalBuilder.build(testLogger).isSuccess();
assertFalse(buildSucceeded);
testLogger.assertLogEntriesContainExpected();
}
// TODO: Behavior depends on the generator running multiple times. Re-enable after we introduce
// @RunsLocal again.
public void _disabled_testDuplicateGeneratorOutput() throws MalformedURLException {
String duplicateCompilationUnitError = LibraryGroup.formatDuplicateCompilationUnitMessage(
"com.google.gwt.dev.Bar", "com.google.gwt.dev.testdata.incrementalbuildsystem.ParallelLeft",
"com.google.gwt.dev.testdata.incrementalbuildsystem.ParallelRight");
assertBuildResult("com.google.gwt.dev.testdata.incrementalbuildsystem.ParallelRoot", false,
duplicateCompilationUnitError);
}
public void testDuplicateSourceInclusion() throws MalformedURLException {
String duplicateCompilationUnitError = LibraryGroup.formatDuplicateCompilationUnitMessage(
"com.google.gwt.dev.testdata.incrementalbuildsystem.Foo",
"com.google.gwt.dev.testdata.incrementalbuildsystem.DuplicateLeft",
"com.google.gwt.dev.testdata.incrementalbuildsystem.DuplicateRight");
assertBuildResult("com.google.gwt.dev.testdata.incrementalbuildsystem.DuplicateRoot", false,
duplicateCompilationUnitError);
}
public void testEntryPointWithFailedCrossModuleTypeReference() throws MalformedURLException {
String victimTypeName =
"com.google.gwt.dev.testdata.incrementalbuildsystem.EntryPointCompileFails";
UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
loggerBuilder.setLowestLogLevel(TreeLogger.TRACE);
loggerBuilder.expectTrace("Tracing compile failure path for type '" + victimTypeName + "'",
null);
loggerBuilder.expectError(Pattern.compile("Errors in '.*EntryPointCompileFails\\.java'"), null);
loggerBuilder.expectError("Line 24: ImmediateCompileFails cannot be resolved to a type", null);
loggerBuilder.expectError(Pattern.compile("Errors in '.*ImmediateCompileFails\\.java'"), null);
loggerBuilder.expectError("Line 20: List cannot be resolved to a type", null);
UnitTestTreeLogger testLogger = loggerBuilder.createLogger();
IncrementalBuilder incrementalBuilder = createIncrementalBuilder(
"com.google.gwt.dev.testdata.incrementalbuildsystem.CrossModuleCompileFails",
createGwtClassPathResourceLoader());
incrementalBuilder.clean();
boolean buildSucceeded = incrementalBuilder.build(testLogger).isSuccess();
assertFalse(buildSucceeded);
testLogger.assertLogEntriesContainExpected();
}
public void testEntryPointWithFailedSameModuleTypeReference() throws MalformedURLException {
String victimTypeName =
"com.google.gwt.dev.testdata.incrementalbuildsystem.EntryPointCompileFails";
String causeTypeName =
"com.google.gwt.dev.testdata.incrementalbuildsystem.ImmediateCompileFails";
UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
loggerBuilder.setLowestLogLevel(TreeLogger.TRACE);
loggerBuilder.expectTrace("Tracing compile failure path for type '" + victimTypeName + "'",
null);
loggerBuilder.expectError(Pattern.compile("Errors in '.*EntryPointCompileFails\\.java'"), null);
loggerBuilder.expectError(causeTypeName + " cannot be resolved to a type", null);
loggerBuilder.expectError(Pattern.compile("Errors in '.*ImmediateCompileFails\\.java'"), null);
loggerBuilder.expectError("Line 20: List cannot be resolved to a type", null);
UnitTestTreeLogger testLogger = loggerBuilder.createLogger();
IncrementalBuilder incrementalBuilder = createIncrementalBuilder(
"com.google.gwt.dev.testdata.incrementalbuildsystem.SameModuleCompileFails",
createGwtClassPathResourceLoader());
incrementalBuilder.clean();
boolean buildSucceeded = incrementalBuilder.build(testLogger).isSuccess();
assertFalse(buildSucceeded);
testLogger.assertLogEntriesContainExpected();
}
public void testIgnoresCompileFailuresInUnreachableTypes() throws MalformedURLException {
assertBuildResult(
"com.google.gwt.dev.testdata.incrementalbuildsystem.UnreachableTypeCompileFails", true);
}
public void testUnableToFindModule() throws MalformedURLException {
String unableToFindModuleMessage = ModuleDefLoader.formatUnableToFindModuleMessage(
"com/google/gwt/dev/testdata/incrementalbuildsystem/NoSuchModule.gwt.xml");
assertBuildResult("com.google.gwt.dev.testdata.incrementalbuildsystem.NoSuchModule", false,
unableToFindModuleMessage);
}
}