| // Copyright 2020 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.dynamic; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.when; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Lists; |
| import com.google.common.eventbus.EventBus; |
| import com.google.devtools.build.lib.actions.ActionExecutionContext; |
| import com.google.devtools.build.lib.actions.Spawn; |
| import com.google.devtools.build.lib.analysis.BlazeDirectories; |
| import com.google.devtools.build.lib.analysis.ServerDirectories; |
| import com.google.devtools.build.lib.exec.BinTools; |
| import com.google.devtools.build.lib.exec.util.SpawnBuilder; |
| import com.google.devtools.build.lib.runtime.BlazeRuntime; |
| import com.google.devtools.build.lib.runtime.CommandEnvironment; |
| import com.google.devtools.build.lib.testutil.Scratch; |
| import com.google.devtools.build.lib.testutil.TestConstants; |
| import com.google.devtools.build.lib.util.AbruptExitException; |
| import com.google.devtools.build.lib.vfs.Path; |
| import com.google.devtools.build.lib.vfs.PathFragment; |
| import com.google.devtools.build.lib.vfs.Root; |
| import com.google.devtools.common.options.Converters; |
| import com.google.devtools.common.options.OptionsParsingException; |
| import com.google.devtools.common.options.OptionsParsingResult; |
| import java.io.IOException; |
| import java.util.Collections; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.Executors; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests for {@link com.google.devtools.build.lib.dynamic.DynamicExecutionModule}. */ |
| @RunWith(JUnit4.class) |
| public class DynamicExecutionModuleTest { |
| private static final PathFragment OUTPUT_BASE = PathFragment.create("blaze-out"); |
| |
| private DynamicExecutionModule module; |
| private DynamicExecutionOptions options; |
| private BlazeRuntime blazeRuntime; |
| |
| @Before |
| public void setUp() throws IOException, AbruptExitException { |
| module = new DynamicExecutionModule(Executors.newCachedThreadPool()); |
| options = new DynamicExecutionOptions(); |
| options.dynamicLocalStrategy = Collections.emptyList(); // default |
| options.dynamicRemoteStrategy = Collections.emptyList(); // default |
| } |
| |
| @Test |
| public void testGetLocalStrategies_getsDefaultWithNoOptions() |
| throws AbruptExitException, OptionsParsingException { |
| assertThat(module.getLocalStrategies(options)).isEqualTo(parseStrategies("worker,sandboxed")); |
| } |
| |
| @Test |
| public void testGetLocalStrategies_genericOptionOverridesFallbacks() |
| throws AbruptExitException, OptionsParsingException { |
| options.dynamicLocalStrategy = parseStrategiesToOptions("local,worker"); |
| assertThat(module.getLocalStrategies(options)).isEqualTo(parseStrategies("local,worker")); |
| } |
| |
| @Test |
| public void testGetLocalStrategies_specificOptionKeepsFallbacks() |
| throws AbruptExitException, OptionsParsingException { |
| options.dynamicLocalStrategy = parseStrategiesToOptions("Foo=local,worker"); |
| assertThat(module.getLocalStrategies(options)) |
| .isEqualTo(parseStrategies("Foo=local,worker", "worker,sandboxed")); |
| } |
| |
| @Test |
| public void testGetLocalStrategies_canMixSpecificsAndGenericOptions() |
| throws AbruptExitException, OptionsParsingException { |
| options.dynamicLocalStrategy = parseStrategiesToOptions("Foo=local,worker", "worker"); |
| assertThat(module.getLocalStrategies(options)) |
| .isEqualTo(parseStrategies("Foo=local,worker", "worker")); |
| } |
| |
| @Test |
| public void canIgnoreFailure_simpleCases() throws IOException, AbruptExitException { |
| setupRuntime(); |
| Spawn spawn = new SpawnBuilder().withOutput("output").build(); |
| CommandEnvironment mockCommandEnvironment = mock(CommandEnvironment.class); |
| OptionsParsingResult mockOptions = mock(OptionsParsingResult.class); |
| when(mockCommandEnvironment.getOptions()).thenReturn(mockOptions); |
| EventBus mockEventBus = mock(EventBus.class); |
| when(mockCommandEnvironment.getEventBus()).thenReturn(mockEventBus); |
| when(mockCommandEnvironment.getBlazeWorkspace()).thenReturn(blazeRuntime.getWorkspace()); |
| DynamicExecutionOptions options = new DynamicExecutionOptions(); |
| when(mockOptions.getOptions(DynamicExecutionOptions.class)).thenReturn(options); |
| ActionExecutionContext context = mock(ActionExecutionContext.class); |
| |
| options.ignoreLocalSignals = ImmutableSet.of(); |
| module.beforeCommand(mockCommandEnvironment); |
| assertThat(module.canIgnoreFailure(spawn, context, 130, "Failed", null, true)).isFalse(); |
| |
| options.ignoreLocalSignals = ImmutableSet.of(9); |
| module.beforeCommand(mockCommandEnvironment); |
| assertThat(module.canIgnoreFailure(spawn, context, 130, "Failed", null, true)).isFalse(); |
| |
| options.ignoreLocalSignals = ImmutableSet.of(2, 9); |
| module.beforeCommand(mockCommandEnvironment); |
| assertThat(module.canIgnoreFailure(spawn, context, 130, "Failed", null, false)).isFalse(); |
| assertThat(module.canIgnoreFailure(spawn, context, 0, "Failed", null, true)).isFalse(); |
| assertThat(module.canIgnoreFailure(spawn, context, 130, "Failed", null, true)).isTrue(); |
| assertThat(module.canIgnoreFailure(spawn, context, 137, "Failed", null, true)).isTrue(); |
| } |
| |
| private void setupRuntime() throws IOException, AbruptExitException { |
| Scratch scratch = new Scratch(); |
| Path execDir = scratch.dir("/foo"); |
| Root root = Root.fromPath(execDir); |
| ServerDirectories serverDirectories = |
| new ServerDirectories( |
| scratch.dir("/installBase"), |
| root.getRelative(OUTPUT_BASE), |
| scratch.dir("/output-user")); |
| blazeRuntime = |
| new BlazeRuntime.Builder() |
| .setFileSystem(scratch.getFileSystem()) |
| .setProductName(TestConstants.PRODUCT_NAME) |
| .setServerDirectories(serverDirectories) |
| .setStartupOptionsProvider(mock(OptionsParsingResult.class)) |
| .build(); |
| BinTools binTools = BinTools.forUnitTesting(execDir, ImmutableList.of()); |
| blazeRuntime.initWorkspace( |
| new BlazeDirectories( |
| serverDirectories, |
| scratch.dir(TestConstants.WORKSPACE_NAME), |
| null, |
| TestConstants.PRODUCT_NAME), |
| binTools); |
| } |
| |
| private static List<Map.Entry<String, List<String>>> parseStrategiesToOptions( |
| String... strategies) throws OptionsParsingException { |
| Map<String, List<String>> result = parseStrategies(strategies); |
| return Lists.newArrayList(result.entrySet()); |
| } |
| |
| private static Map<String, List<String>> parseStrategies(String... strategies) |
| throws OptionsParsingException { |
| Map<String, List<String>> result = new LinkedHashMap<>(); |
| Converters.StringToStringListConverter converter = new Converters.StringToStringListConverter(); |
| for (String s : strategies) { |
| Map.Entry<String, List<String>> converted = converter.convert(s); |
| // Have to avoid using Immutable* to allow overwriting elements. |
| result.put(converted.getKey(), Lists.newArrayList(converted.getValue())); |
| } |
| return result; |
| } |
| |
| } |