| // 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 org.junit.Assert.assertEquals; |
| |
| 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.ConfigurationCollectionFactory; |
| 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.FragmentOptions; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.runtime.BlazeCommandDispatcher.LockingMode; |
| import com.google.devtools.build.lib.runtime.BlazeCommandDispatcher.ShutdownBlazeServerException; |
| 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.OptionsBase; |
| import com.google.devtools.common.options.OptionsParser; |
| import com.google.devtools.common.options.OptionsProvider; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| import org.mockito.Mockito; |
| |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * 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", defaultValue = "0") |
| public int numOption; |
| |
| @Option(name = "stringoption", defaultValue = "[unspecified]") |
| public String stringOption; |
| } |
| |
| @Command( |
| name = "reportnum", |
| options = {FooOptions.class}, |
| shortDescription = "", |
| help = "" |
| ) |
| private static class ReportNumCommand implements BlazeCommand { |
| |
| @Override |
| public ExitCode exec(CommandEnvironment env, OptionsProvider options) |
| throws ShutdownBlazeServerException { |
| FooOptions fooOptions = options.getOptions(FooOptions.class); |
| env.getReporter().getOutErr().printOut("" + fooOptions.numOption); |
| return ExitCode.SUCCESS; |
| } |
| |
| @Override |
| public void editOptions(CommandEnvironment env, OptionsParser optionsParser) {} |
| } |
| |
| @Command( |
| name = "reportall", |
| options = {FooOptions.class}, |
| shortDescription = "", |
| help = "" |
| ) |
| private static class ReportAllCommand implements BlazeCommand { |
| |
| @Override |
| public ExitCode exec(CommandEnvironment env, OptionsProvider options) |
| throws ShutdownBlazeServerException { |
| FooOptions fooOptions = options.getOptions(FooOptions.class); |
| env.getReporter() |
| .getOutErr() |
| .printOut("" + fooOptions.numOption + " " + fooOptions.stringOption); |
| return ExitCode.SUCCESS; |
| } |
| |
| @Override |
| public void editOptions(CommandEnvironment env, 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")); |
| this.runtime = |
| new BlazeRuntime.Builder() |
| .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); |
| builder.setConfigurationCollectionFactory( |
| Mockito.mock(ConfigurationCollectionFactory.class)); |
| } |
| }) |
| .build(); |
| |
| BlazeDirectories directories = |
| new BlazeDirectories(serverDirectories, scratch.dir("pkg"), 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, LockingMode.ERROR_OUT, "test", outErr); |
| String out = outErr.outAsLatin1(); |
| assertEquals("Common options should be used", "99", out); |
| } |
| |
| @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, LockingMode.ERROR_OUT, "test", outErr); |
| String out = outErr.outAsLatin1(); |
| assertEquals("Specific options should dominate common options", "42", out); |
| } |
| |
| @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, LockingMode.ERROR_OUT, "test", outErr); |
| String out = outErr.outAsLatin1(); |
| assertEquals("Specific options should dominate common options", "42", out); |
| } |
| |
| @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, LockingMode.ERROR_OUT, "test", outErr); |
| String out = outErr.outAsLatin1(); |
| assertEquals("Options should get accumulated over different rc files", "99 foo", out); |
| } |
| |
| @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, LockingMode.ERROR_OUT, "test", outErr); |
| String out = outErr.outAsLatin1(); |
| assertEquals("The more specific rc-file should override", "99 foo", out); |
| } |
| |
| @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, LockingMode.ERROR_OUT, "test", outErr); |
| String out = outErr.outAsLatin1(); |
| assertEquals("The more specific rc-file should override irrespective of name", "99 foo", out); |
| } |
| |
| @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, LockingMode.ERROR_OUT, "test", outErr); |
| String out = outErr.outAsLatin1(); |
| assertEquals( |
| String.format( |
| "The more specific option should override, irrespective of source file or order. %s", |
| orderedOpts), |
| "42 reportallinherited", |
| out); |
| } |
| } |
| |
| /** Options class for testing, so that defaults package has some content. */ |
| public static class MockFragmentOptions extends FragmentOptions { |
| public MockFragmentOptions() {} |
| |
| @Option(name = "fake_opt", defaultValue = "false") |
| public boolean fakeOpt; |
| |
| @Override |
| public Map<String, Set<Label>> getDefaultsLabels(BuildConfiguration.Options commonOptions) { |
| return ImmutableMap.<String, Set<Label>>of( |
| "mock_target", ImmutableSet.of(Label.parseAbsoluteUnchecked("//mock:target"))); |
| } |
| } |
| } |