blob: 9e1b08ab03f52dfa010618ad34cf5dc8b1dc5f3a [file] [log] [blame]
// Copyright 2016 The Bazel Authors. 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.runtime;
import static com.google.common.truth.Truth.assertWithMessage;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.ServerDirectories;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.FragmentOptions;
import com.google.devtools.build.lib.bazel.rules.DefaultBuildOptionsForDiffing;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.testutil.Scratch;
import com.google.devtools.build.lib.testutil.TestConstants;
import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.util.io.RecordingOutErr;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionDocumentationCategory;
import com.google.devtools.common.options.OptionEffectTag;
import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsProvider;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests the handling of rc-options in {@link BlazeCommandDispatcher}. */
@RunWith(JUnit4.class)
public class BlazeCommandDispatcherRcoptionsTest {
/**
* Example options to be used by the tests.
*/
public static class FooOptions extends OptionsBase {
@Option(
name = "numoption",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = "0"
)
public int numOption;
@Option(
name = "stringoption",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = "[unspecified]"
)
public String stringOption;
}
@Command(
name = "reportnum",
options = {FooOptions.class},
shortDescription = "",
help = ""
)
private static class ReportNumCommand implements BlazeCommand {
@Override
public BlazeCommandResult exec(CommandEnvironment env, OptionsProvider options) {
FooOptions fooOptions = options.getOptions(FooOptions.class);
env.getReporter().getOutErr().printOut("" + fooOptions.numOption);
return BlazeCommandResult.exitCode(ExitCode.SUCCESS);
}
@Override
public void editOptions(OptionsParser optionsParser) {}
}
@Command(
name = "reportall",
options = {FooOptions.class},
shortDescription = "",
help = ""
)
private static class ReportAllCommand implements BlazeCommand {
@Override
public BlazeCommandResult exec(CommandEnvironment env, OptionsProvider options) {
FooOptions fooOptions = options.getOptions(FooOptions.class);
env.getReporter()
.getOutErr()
.printOut("" + fooOptions.numOption + " " + fooOptions.stringOption);
return BlazeCommandResult.exitCode(ExitCode.SUCCESS);
}
@Override
public void editOptions(OptionsParser optionsParser) {}
}
@Command(
name = "reportallinherited",
options = {FooOptions.class},
shortDescription = "",
help = "",
inherits = ReportAllCommand.class
)
private static class ReportAllInheritedCommand extends ReportAllCommand {
}
private final Scratch scratch = new Scratch();
private final RecordingOutErr outErr = new RecordingOutErr();
private final ReportNumCommand reportNum = new ReportNumCommand();
private final ReportAllCommand reportAll = new ReportAllCommand();
private final ReportAllCommand reportAllInherited = new ReportAllInheritedCommand();
private BlazeRuntime runtime;
@Before
public final void initializeRuntime() throws Exception {
String productName = TestConstants.PRODUCT_NAME;
ServerDirectories serverDirectories =
new ServerDirectories(
scratch.dir("install_base"),
scratch.dir("output_base"),
scratch.dir("user_output_root"));
this.runtime =
new BlazeRuntime.Builder()
.setFileSystem(scratch.getFileSystem())
.setProductName(productName)
.setServerDirectories(serverDirectories)
.setStartupOptionsProvider(
OptionsParser.newOptionsParser(BlazeServerStartupOptions.class))
.addBlazeModule(
new BlazeModule() {
@Override
public void initializeRuleClasses(ConfiguredRuleClassProvider.Builder builder) {
// We must add these options so that the defaults package can be created.
builder.addConfigurationOptions(BuildConfiguration.Options.class);
// The defaults package asserts that it is not empty, so we provide options.
builder.addConfigurationOptions(MockFragmentOptions.class);
// The tools repository is needed for createGlobals
builder.setToolsRepository(TestConstants.TOOLS_REPOSITORY);
}
})
.addBlazeModule(
new BlazeModule() {
@Override
public BuildOptions getDefaultBuildOptions(BlazeRuntime runtime) {
return DefaultBuildOptionsForDiffing.getDefaultBuildOptionsForFragments(
runtime.getRuleClassProvider().getConfigurationOptions());
}
})
.build();
BlazeDirectories directories =
new BlazeDirectories(
serverDirectories, scratch.dir("pkg"), /* defaultSystemJavabase= */ null, productName);
this.runtime.initWorkspace(directories, /*binTools=*/null);
}
@Test
public void testCommonUsed() throws Exception {
List<String> blazercOpts =
ImmutableList.of(
"--rc_source=/home/jrluser/.blazerc", "--default_override=0:common=--numoption=99");
BlazeCommandDispatcher dispatch = new BlazeCommandDispatcher(runtime, reportNum);
List<String> cmdLine = Lists.newArrayList("reportnum");
cmdLine.addAll(blazercOpts);
dispatch.exec(cmdLine, "test", outErr);
String out = outErr.outAsLatin1();
assertWithMessage("Common options should be used").that(out).isEqualTo("99");
}
@Test
public void testSpecificOptionsWin() throws Exception {
List<String> blazercOpts =
ImmutableList.of(
"--rc_source=/home/jrluser/.blazerc",
"--default_override=0:reportnum=--numoption=42",
"--default_override=0:common=--numoption=99");
BlazeCommandDispatcher dispatch = new BlazeCommandDispatcher(runtime, reportNum);
List<String> cmdLine = Lists.newArrayList("reportnum");
cmdLine.addAll(blazercOpts);
dispatch.exec(cmdLine, "test", outErr);
String out = outErr.outAsLatin1();
assertWithMessage("Specific options should dominate common options").that(out).isEqualTo("42");
}
@Test
public void testSpecificOptionsWinOtherOrder() throws Exception {
List<String> blazercOpts =
ImmutableList.of(
"--rc_source=/home/jrluser/.blazerc",
"--default_override=0:common=--numoption=99",
"--default_override=0:reportnum=--numoption=42");
BlazeCommandDispatcher dispatch = new BlazeCommandDispatcher(runtime, reportNum);
List<String> cmdLine = Lists.newArrayList("reportnum");
cmdLine.addAll(blazercOpts);
dispatch.exec(cmdLine, "test", outErr);
String out = outErr.outAsLatin1();
assertWithMessage("Specific options should dominate common options").that(out).isEqualTo("42");
}
@Test
public void testOptionsCombined() throws Exception {
List<String> blazercOpts =
ImmutableList.of(
"--rc_source=/etc/bazelrc",
"--default_override=0:common=--stringoption=foo",
"--rc_source=/home/jrluser/.blazerc",
"--default_override=1:common=--numoption=99");
BlazeCommandDispatcher dispatch = new BlazeCommandDispatcher(runtime, reportNum, reportAll);
List<String> cmdLine = Lists.newArrayList("reportall");
cmdLine.addAll(blazercOpts);
dispatch.exec(cmdLine, "test", outErr);
String out = outErr.outAsLatin1();
assertWithMessage("Options should get accumulated over different rc files")
.that(out)
.isEqualTo("99 foo");
}
@Test
public void testOptionsCombinedWithOverride() throws Exception {
List<String> blazercOpts =
ImmutableList.of(
"--rc_source=/etc/bazelrc",
"--default_override=0:common=--stringoption=foo",
"--default_override=0:common=--numoption=42",
"--rc_source=/home/jrluser/.blazerc",
"--default_override=1:common=--numoption=99");
BlazeCommandDispatcher dispatch = new BlazeCommandDispatcher(runtime, reportNum, reportAll);
List<String> cmdLine = Lists.newArrayList("reportall");
cmdLine.addAll(blazercOpts);
dispatch.exec(cmdLine, "test", outErr);
String out = outErr.outAsLatin1();
assertWithMessage("The more specific rc-file should override").that(out).isEqualTo("99 foo");
}
@Test
public void testOptionsCombinedWithOverrideOtherName() throws Exception {
List<String> blazercOpts =
ImmutableList.of(
"--rc_source=/home/jrluser/.blazerc",
"--default_override=0:common=--stringoption=foo",
"--default_override=0:common=--numoption=42",
"--rc_source=/etc/bazelrc",
"--default_override=1:common=--numoption=99");
BlazeCommandDispatcher dispatch = new BlazeCommandDispatcher(runtime, reportNum, reportAll);
List<String> cmdLine = Lists.newArrayList("reportall");
cmdLine.addAll(blazercOpts);
dispatch.exec(cmdLine, "test", outErr);
String out = outErr.outAsLatin1();
assertWithMessage("The more specific rc-file should override irrespective of name")
.that(out)
.isEqualTo("99 foo");
}
@Test
public void testInheritedOptionsWithSpecificOverride() throws Exception {
ImmutableList<ImmutableList<String>> blazercOpts =
ImmutableList.of(
ImmutableList.of(
"--rc_source=/doesnt/matter/0/bazelrc",
"--default_override=0:common=--stringoption=common",
"--default_override=0:common=--numoption=42"),
ImmutableList.of(
"--rc_source=/doesnt/matter/1/bazelrc",
"--default_override=0:reportall=--stringoption=reportall"),
ImmutableList.of(
"--rc_source=/doesnt/matter/2/bazelrc",
"--default_override=0:reportallinherited=--stringoption=reportallinherited"));
for (List<ImmutableList<String>> e : Collections2.permutations(blazercOpts)) {
outErr.reset();
BlazeCommandDispatcher dispatch =
new BlazeCommandDispatcher(runtime, reportNum, reportAll, reportAllInherited);
List<String> cmdLine = Lists.newArrayList("reportallinherited");
List<String> orderedOpts = ImmutableList.copyOf(Iterables.concat(e));
cmdLine.addAll(orderedOpts);
dispatch.exec(cmdLine, "test", outErr);
String out = outErr.outAsLatin1();
assertWithMessage(String.format(
"The more specific option should override, irrespective of source file or order. %s",
orderedOpts))
.that(out)
.isEqualTo("42 reportallinherited");
}
}
/** Options class for testing, so that defaults package has some content. */
public static class MockFragmentOptions extends FragmentOptions {
public MockFragmentOptions() {}
@Option(
name = "fake_opt",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = "false"
)
public boolean fakeOpt;
@Override
public Map<String, Set<Label>> getDefaultsLabels() {
return ImmutableMap.<String, Set<Label>>of(
"mock_target", ImmutableSet.of(Label.parseAbsoluteUnchecked("//mock:target")));
}
}
}