diff options
author | ulfjack <ulfjack@google.com> | 2017-04-07 11:21:38 +0000 |
---|---|---|
committer | Marcel Hlopko <hlopko@google.com> | 2017-04-07 16:44:43 +0200 |
commit | 3a081f7030616b7ccfbf56cb3955c9533d758f40 (patch) | |
tree | 6e4930d85adf5ad4407299094ae2ab98cb020616 /src/test | |
parent | 1fde2308afc7b323ca3c57b7176c0ea18ad52bbb (diff) |
Open source LocalSpawnRunner
The LocalSpawnRunner is a non-sandboxed local execution implementation, which
will replace the current StandaloneSpawnStrategy. The code has been around for
a long time and has seen a lot of bugfixes. It also supports local prefetching,
which is required for Google. I have a follow-up change to make it support
Windows, so it's not a drop-in replacement for StandaloneSpawnStrategy yet.
PiperOrigin-RevId: 152486973
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/BUILD | 1 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionTestCase.java | 2 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/exec/local/LocalSpawnRunnerTest.java | 324 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/exec/util/FakeOwner.java (renamed from src/test/java/com/google/devtools/build/lib/remote/FakeOwner.java) | 38 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/exec/util/SpawnBuilder.java | 118 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/remote/CachedLocalSpawnRunnerTest.java | 1 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteExecutionClientTest.java | 1 |
7 files changed, 473 insertions, 12 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD index a6ce260446..c2b5b8f2b5 100644 --- a/src/test/java/com/google/devtools/build/lib/BUILD +++ b/src/test/java/com/google/devtools/build/lib/BUILD @@ -1057,6 +1057,7 @@ java_test( srcs = glob(["remote/*.java"]), test_class = "com.google.devtools.build.lib.AllTests", deps = [ + ":analysis_testutil", ":foundations_testutil", ":test_runner", ":testutil", diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionTestCase.java index c2563f3920..c318413c05 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionTestCase.java @@ -42,7 +42,7 @@ public abstract class FileWriteActionTestCase extends BuildViewTestCase { private Artifact outputArtifact; private Path output; private Executor executor; - private ActionExecutionContext context; + protected ActionExecutionContext context; @Before public final void createAction() throws Exception { diff --git a/src/test/java/com/google/devtools/build/lib/exec/local/LocalSpawnRunnerTest.java b/src/test/java/com/google/devtools/build/lib/exec/local/LocalSpawnRunnerTest.java new file mode 100644 index 0000000000..8fba192e15 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/exec/local/LocalSpawnRunnerTest.java @@ -0,0 +1,324 @@ +// Copyright 2017 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.exec.local; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.google.common.io.ByteStreams; +import com.google.devtools.build.lib.actions.ActionInput; +import com.google.devtools.build.lib.actions.ActionInputFileCache; +import com.google.devtools.build.lib.actions.ResourceManager; +import com.google.devtools.build.lib.actions.ResourceSet; +import com.google.devtools.build.lib.actions.Spawn; +import com.google.devtools.build.lib.exec.ActionInputPrefetcher; +import com.google.devtools.build.lib.exec.SpawnResult; +import com.google.devtools.build.lib.exec.SpawnRunner.ProgressStatus; +import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionPolicy; +import com.google.devtools.build.lib.exec.util.SpawnBuilder; +import com.google.devtools.build.lib.shell.JavaSubprocessFactory; +import com.google.devtools.build.lib.shell.Subprocess; +import com.google.devtools.build.lib.shell.SubprocessBuilder; +import com.google.devtools.build.lib.util.NetUtil; +import com.google.devtools.build.lib.util.io.FileOutErr; +import com.google.devtools.build.lib.vfs.FileSystem; +import com.google.devtools.build.lib.vfs.PathFragment; +import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; +import com.google.devtools.common.options.Options; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.SortedMap; +import java.util.regex.Pattern; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; + +/** + * Unit tests for {@link LocalSpawnRunner}. + */ +@RunWith(JUnit4.class) +public class LocalSpawnRunnerTest { + private static class FinishedSubprocess implements Subprocess { + private final int exitCode; + + public FinishedSubprocess(int exitCode) { + this.exitCode = exitCode; + } + + @Override + public boolean destroy() { + return false; + } + + @Override + public int exitValue() { + return exitCode; + } + + @Override + public boolean finished() { + return true; + } + + @Override + public boolean timedout() { + return false; + } + + @Override + public void waitFor() throws InterruptedException { + // Do nothing. + } + + @Override + public OutputStream getOutputStream() { + return ByteStreams.nullOutputStream(); + } + + @Override + public InputStream getInputStream() { + return new ByteArrayInputStream(new byte[0]); + } + + @Override + public InputStream getErrorStream() { + return new ByteArrayInputStream(new byte[0]); + } + + @Override + public void close() { + // Do nothing. + } + } + + private static final Spawn SIMPLE_SPAWN = + new SpawnBuilder("/bin/echo", "Hi!").withEnvironment("VARIABLE", "value").build(); + + private static final class SubprocessInterceptor implements Subprocess.Factory { + @Override + public Subprocess create(SubprocessBuilder params) throws IOException { + throw new UnsupportedOperationException(); + } + } + + private FileSystem fs; + private final ActionInputFileCache mockFileCache = mock(ActionInputFileCache.class); + private final ResourceManager resourceManager = ResourceManager.instanceForTestingOnly(); + + private FileOutErr outErr; + private long timeoutMillis = 0; + private boolean calledLockOutputFiles; + + private final SpawnExecutionPolicy policy = new SpawnExecutionPolicy() { + @Override + public boolean shouldPrefetchInputsForLocalExecution(Spawn spawn) { + // TODO(ulfjack): Test local prefetching. + return false; + } + + @Override + public void lockOutputFiles() throws InterruptedException { + calledLockOutputFiles = true; + } + + @Override + public ActionInputFileCache getActionInputFileCache() { + return mockFileCache; + } + + @Override + public long getTimeoutMillis() { + return timeoutMillis; + } + + @Override + public FileOutErr getFileOutErr() { + return outErr; + } + + @Override + public SortedMap<PathFragment, ActionInput> getInputMapping() { + throw new UnsupportedOperationException(); + } + + @Override + public void report(ProgressStatus state) { + // TODO(ulfjack): Test that the right calls are made. + } + }; + + @Before + public final void setup() throws Exception { + fs = new InMemoryFileSystem(); + // Prevent any subprocess execution at all. + SubprocessBuilder.setSubprocessFactory(new SubprocessInterceptor()); + resourceManager.setAvailableResources( + ResourceSet.create(/*memoryMb=*/1, /*cpuUsage=*/1, /*ioUsage=*/1, /*localTestCount=*/1)); + } + + @After + public final void tearDown() { + SubprocessBuilder.setSubprocessFactory(JavaSubprocessFactory.INSTANCE); + } + + @Test + public void vanillaZeroExit() throws Exception { + Subprocess.Factory factory = mock(Subprocess.Factory.class); + ArgumentCaptor<SubprocessBuilder> captor = ArgumentCaptor.forClass(SubprocessBuilder.class); + when(factory.create(captor.capture())).thenReturn(new FinishedSubprocess(0)); + SubprocessBuilder.setSubprocessFactory(factory); + + LocalExecutionOptions options = Options.getDefaults(LocalExecutionOptions.class); + options.localSigkillGraceSeconds = 456; + LocalSpawnRunner runner = new LocalSpawnRunner( + fs.getPath("/execroot"), ActionInputPrefetcher.NONE, options, resourceManager); + + timeoutMillis = 123 * 1000L; + outErr = new FileOutErr(fs.getPath("/out/stdout"), fs.getPath("/out/stderr")); + SpawnResult result = runner.exec(SIMPLE_SPAWN, policy); + verify(factory).create(any(SubprocessBuilder.class)); + assertThat(result.status()).isEqualTo(SpawnResult.Status.SUCCESS); + assertThat(result.exitCode()).isEqualTo(0); + assertThat(result.setupSuccess()).isTrue(); + assertThat(result.getExecutorHostName()).isEqualTo(NetUtil.findShortHostName()); + + assertThat(captor.getValue().getArgv()) + .isEqualTo(ImmutableList.of( + // process-wrapper timeout grace_time stdout stderr + "/execroot/_bin/process-wrapper", "123.0", "456.0", "/out/stdout", "/out/stderr", + "/bin/echo", "Hi!")); + assertThat(captor.getValue().getEnv()).containsExactly("VARIABLE", "value"); + + assertThat(calledLockOutputFiles).isTrue(); + } + + @Test + public void nonZeroExit() throws Exception { + Subprocess.Factory factory = mock(Subprocess.Factory.class); + ArgumentCaptor<SubprocessBuilder> captor = ArgumentCaptor.forClass(SubprocessBuilder.class); + when(factory.create(captor.capture())).thenReturn(new FinishedSubprocess(3)); + SubprocessBuilder.setSubprocessFactory(factory); + + LocalExecutionOptions options = Options.getDefaults(LocalExecutionOptions.class); + LocalSpawnRunner runner = new LocalSpawnRunner( + fs.getPath("/execroot"), ActionInputPrefetcher.NONE, options, resourceManager); + + outErr = new FileOutErr(fs.getPath("/out/stdout"), fs.getPath("/out/stderr")); + SpawnResult result = runner.exec(SIMPLE_SPAWN, policy); + verify(factory).create(any(SubprocessBuilder.class)); + assertThat(result.status()).isEqualTo(SpawnResult.Status.SUCCESS); + assertThat(result.exitCode()).isEqualTo(3); + assertThat(result.setupSuccess()).isTrue(); + assertThat(result.getExecutorHostName()).isEqualTo(NetUtil.findShortHostName()); + + assertThat(captor.getValue().getArgv()) + .isEqualTo(ImmutableList.of( + // process-wrapper timeout grace_time stdout stderr + "/execroot/_bin/process-wrapper", "0.0", "15.0", "/out/stdout", "/out/stderr", + "/bin/echo", "Hi!")); + assertThat(captor.getValue().getEnv()).containsExactly("VARIABLE", "value"); + + assertThat(calledLockOutputFiles).isTrue(); + } + + @Test + public void processStartupThrows() throws Exception { + Subprocess.Factory factory = mock(Subprocess.Factory.class); + ArgumentCaptor<SubprocessBuilder> captor = ArgumentCaptor.forClass(SubprocessBuilder.class); + when(factory.create(captor.capture())).thenThrow(new IOException("I'm sorry, Dave")); + SubprocessBuilder.setSubprocessFactory(factory); + + LocalExecutionOptions options = Options.getDefaults(LocalExecutionOptions.class); + LocalSpawnRunner runner = new LocalSpawnRunner( + fs.getPath("/execroot"), ActionInputPrefetcher.NONE, options, resourceManager); + + outErr = new FileOutErr(fs.getPath("/out/stdout"), fs.getPath("/out/stderr")); + SpawnResult result = runner.exec(SIMPLE_SPAWN, policy); + verify(factory).create(any(SubprocessBuilder.class)); + assertThat(result.status()).isEqualTo(SpawnResult.Status.EXECUTION_FAILED); + assertThat(result.exitCode()).isEqualTo(-1); + assertThat(result.setupSuccess()).isFalse(); + assertThat(result.getWallTimeMillis()).isEqualTo(0); + assertThat(result.getExecutorHostName()).isEqualTo(NetUtil.findShortHostName()); + + assertThat(calledLockOutputFiles).isTrue(); + } + + @Test + public void disallowLocalExecution() throws Exception { + LocalExecutionOptions options = Options.getDefaults(LocalExecutionOptions.class); + options.allowedLocalAction = Pattern.compile("none"); + LocalSpawnRunner runner = new LocalSpawnRunner( + fs.getPath("/execroot"), ActionInputPrefetcher.NONE, options, resourceManager); + + outErr = new FileOutErr(); + SpawnResult reply = runner.exec(SIMPLE_SPAWN, policy); + assertThat(reply.status()).isEqualTo(SpawnResult.Status.LOCAL_ACTION_NOT_ALLOWED); + assertThat(reply.exitCode()).isEqualTo(-1); + assertThat(reply.setupSuccess()).isFalse(); + assertThat(reply.getWallTimeMillis()).isEqualTo(0); + assertThat(reply.getExecutorHostName()).isEqualTo(NetUtil.findShortHostName()); + + // TODO(ulfjack): Maybe we should only lock after checking? + assertThat(calledLockOutputFiles).isTrue(); + } + + @Test + public void interruptedException() throws Exception { + Subprocess.Factory factory = mock(Subprocess.Factory.class); + ArgumentCaptor<SubprocessBuilder> captor = ArgumentCaptor.forClass(SubprocessBuilder.class); + when(factory.create(captor.capture())).thenReturn(new FinishedSubprocess(3) { + private boolean destroyed; + + @Override + public boolean destroy() { + destroyed = true; + return true; + } + + @Override + public void waitFor() throws InterruptedException { + if (!destroyed) { + throw new InterruptedException(); + } + } + }); + SubprocessBuilder.setSubprocessFactory(factory); + + LocalExecutionOptions options = Options.getDefaults(LocalExecutionOptions.class); + LocalSpawnRunner runner = new LocalSpawnRunner( + fs.getPath("/execroot"), ActionInputPrefetcher.NONE, options, resourceManager); + + outErr = new FileOutErr(fs.getPath("/out/stdout"), fs.getPath("/out/stderr")); + try { + runner.exec(SIMPLE_SPAWN, policy); + fail(); + } catch (InterruptedException expected) { + // Clear the interrupted status or subsequent tests in the same process will fail. + Thread.interrupted(); + } + assertThat(calledLockOutputFiles).isTrue(); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/remote/FakeOwner.java b/src/test/java/com/google/devtools/build/lib/exec/util/FakeOwner.java index f1654b4727..20ec2b5af9 100644 --- a/src/test/java/com/google/devtools/build/lib/remote/FakeOwner.java +++ b/src/test/java/com/google/devtools/build/lib/exec/util/FakeOwner.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. +// Copyright 2017 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. @@ -11,9 +11,7 @@ // 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.remote; - -import static org.mockito.Mockito.mock; +package com.google.devtools.build.lib.exec.util; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -23,20 +21,38 @@ import com.google.devtools.build.lib.actions.ActionExecutionMetadata; import com.google.devtools.build.lib.actions.ActionOwner; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.RunfilesSupplier; - -/** A fake implementation of ActionExecutionMetadata as needed for SpawnRunner test. */ -final class FakeOwner implements ActionExecutionMetadata { +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.packages.AspectDescriptor; +import javax.annotation.Nullable; + +/** + * Fake implementation of {@link ActionExecutionMetadata} for testing. + */ +public final class FakeOwner implements ActionExecutionMetadata { private final String mnemonic; private final String progressMessage; + @Nullable private final String ownerLabel; - FakeOwner(String mnemonic, String progressMessage) { + public FakeOwner(String mnemonic, String progressMessage, @Nullable String ownerLabel) { this.mnemonic = mnemonic; this.progressMessage = progressMessage; + this.ownerLabel = ownerLabel; + } + + public FakeOwner(String mnemonic, String progressMessage) { + this(mnemonic, progressMessage, null); } @Override public ActionOwner getOwner() { - return mock(ActionOwner.class); + return ActionOwner.create( + ownerLabel == null ? null : Label.parseAbsoluteUnchecked(ownerLabel), + /*aspectDescriptors=*/ ImmutableList.<AspectDescriptor>of(), + /*location=*/ null, + mnemonic, + /*targetKind=*/ null, + "configurationChecksum", + "additionalProgressInfo"); } @Override @@ -101,7 +117,7 @@ final class FakeOwner implements ActionExecutionMetadata { @Override public String getKey() { - throw new UnsupportedOperationException(); + return "MockOwner.getKey"; } @Override @@ -117,7 +133,7 @@ final class FakeOwner implements ActionExecutionMetadata { @Override public Iterable<Artifact> getInputFilesForExtraAction( ActionExecutionContext actionExecutionContext) { - return ImmutableList.<Artifact>of(); + return ImmutableList.of(); } @Override diff --git a/src/test/java/com/google/devtools/build/lib/exec/util/SpawnBuilder.java b/src/test/java/com/google/devtools/build/lib/exec/util/SpawnBuilder.java new file mode 100644 index 0000000000..b98af7ea2a --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/exec/util/SpawnBuilder.java @@ -0,0 +1,118 @@ +// Copyright 2017 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.exec.util; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.actions.ActionExecutionMetadata; +import com.google.devtools.build.lib.actions.ActionInput; +import com.google.devtools.build.lib.actions.ActionInputHelper; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.EmptyRunfilesSupplier; +import com.google.devtools.build.lib.actions.ResourceSet; +import com.google.devtools.build.lib.actions.SimpleSpawn; +import com.google.devtools.build.lib.actions.Spawn; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * Builder class to create {@link Spawn} instances for testing. + */ +public final class SpawnBuilder { + private String mnemonic = "Mnemonic"; + private String progressMessage = "progress message"; + @Nullable private String ownerLabel; + private final List<String> args; + private final Map<String, String> environment = new HashMap<>(); + private final Map<String, String> executionInfo = new HashMap<>(); + private final List<ActionInput> inputs = new ArrayList<>(); + private final List<ActionInput> outputs = new ArrayList<>(); + + public SpawnBuilder(String... args) { + this.args = ImmutableList.copyOf(args); + } + + public Spawn build() { + ActionExecutionMetadata owner = new FakeOwner(mnemonic, progressMessage, ownerLabel); + return new SimpleSpawn( + owner, + ImmutableList.copyOf(args), + ImmutableMap.copyOf(environment), + ImmutableMap.copyOf(executionInfo), + /*runfilesSupplier=*/EmptyRunfilesSupplier.INSTANCE, + ImmutableList.copyOf(inputs), + /*tools=*/ImmutableList.<Artifact>of(), + /*filesetManifests=*/ImmutableList.<Artifact>of(), + ImmutableList.copyOf(outputs), + ResourceSet.ZERO); + } + + public SpawnBuilder withMnemonic(String mnemonic) { + this.mnemonic = Preconditions.checkNotNull(mnemonic); + return this; + } + + public SpawnBuilder withProgressMessage(String progressMessage) { + this.progressMessage = progressMessage; + return this; + } + + public SpawnBuilder withOwnerLabel(String ownerLabel) { + this.ownerLabel = ownerLabel; + return this; + } + + public SpawnBuilder withEnvironment(String key, String value) { + this.environment.put(key, value); + return this; + } + + public SpawnBuilder withExecutionInfo(String key, String value) { + this.executionInfo.put(key, value); + return this; + } + + public SpawnBuilder withInput(ActionInput input) { + this.inputs.add(input); + return this; + } + + public SpawnBuilder withInput(String name) { + this.inputs.add(ActionInputHelper.fromPath(name)); + return this; + } + + public SpawnBuilder withInputs(String... names) { + for (String name : names) { + this.inputs.add(ActionInputHelper.fromPath(name)); + } + return this; + } + + public SpawnBuilder withOutput(String name) { + this.outputs.add(ActionInputHelper.fromPath(name)); + return this; + } + + public SpawnBuilder withOutputs(String... names) { + for (String name : names) { + this.outputs.add(ActionInputHelper.fromPath(name)); + } + return this; + } +} diff --git a/src/test/java/com/google/devtools/build/lib/remote/CachedLocalSpawnRunnerTest.java b/src/test/java/com/google/devtools/build/lib/remote/CachedLocalSpawnRunnerTest.java index d27e7c06b3..1456239e55 100644 --- a/src/test/java/com/google/devtools/build/lib/remote/CachedLocalSpawnRunnerTest.java +++ b/src/test/java/com/google/devtools/build/lib/remote/CachedLocalSpawnRunnerTest.java @@ -34,6 +34,7 @@ import com.google.devtools.build.lib.exec.SpawnResult.Status; import com.google.devtools.build.lib.exec.SpawnRunner; import com.google.devtools.build.lib.exec.SpawnRunner.ProgressStatus; import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionPolicy; +import com.google.devtools.build.lib.exec.util.FakeOwner; import com.google.devtools.build.lib.remote.ContentDigests.ActionKey; import com.google.devtools.build.lib.remote.RemoteProtocol.ActionResult; import com.google.devtools.build.lib.remote.RemoteProtocol.ContentDigest; diff --git a/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteExecutionClientTest.java b/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteExecutionClientTest.java index 5957ef385f..54575cb311 100644 --- a/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteExecutionClientTest.java +++ b/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteExecutionClientTest.java @@ -32,6 +32,7 @@ import com.google.devtools.build.lib.exec.SpawnInputExpander; import com.google.devtools.build.lib.exec.SpawnResult; import com.google.devtools.build.lib.exec.SpawnRunner.ProgressStatus; import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionPolicy; +import com.google.devtools.build.lib.exec.util.FakeOwner; import com.google.devtools.build.lib.remote.RemoteProtocol.ActionResult; import com.google.devtools.build.lib.remote.RemoteProtocol.ContentDigest; import com.google.devtools.build.lib.remote.RemoteProtocol.ExecuteReply; |