// Copyright 2014 Google Inc. All rights reserved. // // 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.devtools.build.lib.testutil; import com.google.common.io.Files; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventCollector; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.EventKind; import com.google.devtools.build.lib.events.Reporter; import com.google.devtools.build.lib.util.BlazeClock; import com.google.devtools.build.lib.vfs.FileSystem; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.List; import java.util.Set; /** * This is a specialization of {@link ChattyAssertsTestCase} that's useful for * implementing tests of the "foundation" library. */ public abstract class FoundationTestCase extends ChattyAssertsTestCase { protected Path rootDirectory; protected Path outputBase; protected Path actionOutputBase; // May be overridden by subclasses: protected Reporter reporter; protected EventCollector eventCollector; private Scratch scratch; // Individual tests can opt-out of this handler if they expect an error, by // calling reporter.removeHandler(failFastHandler). protected static final EventHandler failFastHandler = new EventHandler() { @Override public void handle(Event event) { if (EventKind.ERRORS.contains(event.getKind())) { fail(event.toString()); } } }; protected static final EventHandler printHandler = new EventHandler() { @Override public void handle(Event event) { System.out.println(event); } }; @Override protected void setUp() throws Exception { super.setUp(); scratch = new Scratch(createFileSystem()); outputBase = scratchDir("/usr/local/google/_blaze_jrluser/FAKEMD5/"); rootDirectory = scratchDir("/" + TestConstants.TEST_WORKSPACE_DIRECTORY); copySkylarkFilesIfExist(); actionOutputBase = scratchDir("/usr/local/google/_blaze_jrluser/FAKEMD5/action_out/"); eventCollector = new EventCollector(EventKind.ERRORS_AND_WARNINGS); reporter = new Reporter(eventCollector); reporter.addHandler(failFastHandler); } /* * Creates the file system; override to inject FS behavior. */ protected FileSystem createFileSystem() { return new InMemoryFileSystem(BlazeClock.instance()); } private void copySkylarkFilesIfExist() throws IOException { scratchFile(rootDirectory.getRelative("devtools/blaze/rules/BUILD").getPathString()); scratchFile(rootDirectory.getRelative("rules/BUILD").getPathString()); copySkylarkFilesIfExist("devtools/blaze/rules/staging", "devtools/blaze/rules"); copySkylarkFilesIfExist("devtools/blaze/bazel/base_workspace/tools/build_rules", "rules"); } private void copySkylarkFilesIfExist(String from, String to) throws IOException { File rulesDir = new File(from); if (rulesDir.exists() && rulesDir.isDirectory()) { for (String fileName : rulesDir.list()) { File file = new File(from + "/" + fileName); if (file.isFile() && fileName.endsWith(".bzl")) { String context = loadFile(file); Path path = rootDirectory.getRelative(to + "/" + fileName); if (path.exists()) { overwriteScratchFile(path.getPathString(), context); } else { scratchFile(path.getPathString(), context); } } } } } @Override protected void tearDown() throws Exception { Thread.interrupted(); // Clear any interrupt pending against this thread, // so that we don't cause later tests to fail. super.tearDown(); } /** * A scratch filesystem that is completely in-memory. Since this file system * is "cached" in a private (but *not* static) field in the test class, * each testFoo method in junit sees a fresh filesystem. */ protected FileSystem scratchFS() { return scratch.getFileSystem(); } /** * Create a scratch file in the scratch filesystem, with the given pathName, * consisting of a set of lines. The method returns a Path instance for the * scratch file. */ protected Path scratchFile(String pathName, String... lines) throws IOException { return scratch.file(pathName, lines); } /** * Like {@code scratchFile}, but the file is first deleted if it already * exists. */ protected Path overwriteScratchFile(String pathName, String... lines) throws IOException { return scratch.overwriteFile(pathName, lines); } /** * Deletes the specified scratch file, using the same specification as {@link Path#delete}. */ protected boolean deleteScratchFile(String pathName) throws IOException { return scratch.deleteFile(pathName); } /** * Create a scratch file in the given filesystem, with the given pathName, * consisting of a set of lines. The method returns a Path instance for the * scratch file. */ protected Path scratchFile(FileSystem fs, String pathName, String... lines) throws IOException { return scratch.file(fs, pathName, lines); } /** * Create a scratch file in the given filesystem, with the given pathName, * consisting of a set of lines. The method returns a Path instance for the * scratch file. */ protected Path scratchFile(FileSystem fs, String pathName, byte[] content) throws IOException { return scratch.file(fs, pathName, content); } /** * Create a directory in the scratch filesystem, with the given path name. */ public Path scratchDir(String pathName) throws IOException { return scratch.dir(pathName); } /** * If "expectedSuffix" is not a suffix of "actual", fails with an informative * assertion. */ protected void assertEndsWith(String expectedSuffix, String actual) { if (!actual.endsWith(expectedSuffix)) { fail("\"" + actual + "\" does not end with " + "\"" + expectedSuffix + "\""); } } /** * If "expectedPrefix" is not a prefix of "actual", fails with an informative * assertion. */ protected void assertStartsWith(String expectedPrefix, String actual) { if (!actual.startsWith(expectedPrefix)) { fail("\"" + actual + "\" does not start with " + "\"" + expectedPrefix + "\""); } } // Mix-in assertions: protected void assertNoEvents() { JunitTestUtils.assertNoEvents(eventCollector); } protected Event assertContainsEvent(String expectedMessage) { return JunitTestUtils.assertContainsEvent(eventCollector, expectedMessage); } protected Event assertContainsEvent(String expectedMessage, Set kinds) { return JunitTestUtils.assertContainsEvent(eventCollector, expectedMessage, kinds); } protected void assertContainsEventWithFrequency(String expectedMessage, int expectedFrequency) { JunitTestUtils.assertContainsEventWithFrequency(eventCollector, expectedMessage, expectedFrequency); } protected void assertDoesNotContainEvent(String expectedMessage) { JunitTestUtils.assertDoesNotContainEvent(eventCollector, expectedMessage); } protected Event assertContainsEventWithWordsInQuotes(String... words) { return JunitTestUtils.assertContainsEventWithWordsInQuotes( eventCollector, words); } protected void assertContainsEventsInOrder(String... expectedMessages) { JunitTestUtils.assertContainsEventsInOrder(eventCollector, expectedMessages); } @SuppressWarnings({"unchecked", "varargs"}) protected static void assertContainsSublist(List arguments, T... expectedSublist) { JunitTestUtils.assertContainsSublist(arguments, expectedSublist); } @SuppressWarnings({"unchecked", "varargs"}) protected static void assertDoesNotContainSublist(List arguments, T... expectedSublist) { JunitTestUtils.assertDoesNotContainSublist(arguments, expectedSublist); } protected static void assertContainsSubset(Iterable arguments, Iterable expectedSubset) { JunitTestUtils.assertContainsSubset(arguments, expectedSubset); } protected String loadFile(File file) throws IOException { return Files.toString(file, Charset.defaultCharset()); } }