Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Community.Wsa.Sdk.Tests/AdbClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -643,4 +643,19 @@ await AssertExecutedWith(
"1"
);
}

[Test]
public async Task ExecuteCommandAsync_ShouldExecute()
{
var actualOutput = await AssertExecutedWith(
"foobar",
(adb) => adb.ExecuteCommandAsync("test", new string[] { "a", "b" }),
"shell",
"test",
"a",
"b"
);

actualOutput.Should().BeEquivalentTo("foobar");
}
}
14 changes: 13 additions & 1 deletion Community.Wsa.Sdk.Tests/ProcessTestHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,26 @@ namespace Community.Wsa.Sdk.Tests;

internal static class ProcessTestHelpers
{
public static IProcess Exits(string output = "", int executionTime = 10, int exitCode = 0)
public static IProcess Exits(
string output = "",
string errorOutput = "",
int executionTime = 10,
int exitCode = 0
)
{
var p = A.Fake<IProcess>();

var stdOut = new StreamReader(
new MemoryStream(Encoding.UTF8.GetBytes(output)),
Encoding.UTF8
);
var stdErr = new StreamReader(
new MemoryStream(Encoding.UTF8.GetBytes(errorOutput)),
Encoding.UTF8
);

A.CallTo(() => p.StandardOutput).Returns(stdOut);
A.CallTo(() => p.StandardError).Returns(stdErr);
A.CallTo(() => p.WaitForExitAsync())
.Returns(Task.Delay(executionTime).ContinueWith((_) => exitCode));
A.CallTo(() => p.WaitForExitAsync(A<int>._))
Expand All @@ -35,7 +45,9 @@ public static IProcess TimesOut()
var p = A.Fake<IProcess>();

var stdOut = new StreamReader(Stream.Null, Encoding.UTF8);
var stdErr = new StreamReader(Stream.Null, Encoding.UTF8);

A.CallTo(() => p.StandardError).Returns(stdErr);
A.CallTo(() => p.StandardOutput).Returns(stdOut);
A.CallTo(() => p.WaitForExitAsync(A<int>._))
.Returns(Task.Delay(10).ContinueWith<int?>((_) => null));
Expand Down
44 changes: 35 additions & 9 deletions Community.Wsa.Sdk/AdbClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,13 @@ public Task DisconnectAsync(EndPoint endPoint)
}

/// <inheritdoc />
public Task<string> ExecuteCommandAsync(string command, string[] arguments)
public Task<string> ExecuteCommandAsync(string command, params string[] arguments)
{
var adbArguments = new string[arguments.Length + 1];
Array.Copy(arguments, 0, adbArguments, 1, arguments.Length);
var adbArguments = new string[arguments.Length + 2];
Array.Copy(arguments, 0, adbArguments, 2, arguments.Length);

adbArguments[0] = "shell";
adbArguments[1] = command;

return ExecuteAdbCommandAsync(adbArguments);
}
Expand Down Expand Up @@ -320,6 +321,7 @@ internal virtual async Task<string> ExecuteAdbCommandAsync(
var startInfo = new ProcessStartInfo(PathToAdb!)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
var strCommand = $"adb {string.Join(" ", arguments)}";
Expand All @@ -333,41 +335,65 @@ internal virtual async Task<string> ExecuteAdbCommandAsync(
_processManager.Start(startInfo) ?? throw new AdbException(AdbError.CannotStartAdb);

var stdOutTask = process.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
var stdErrTask = process.StandardError.ReadToEndAsync().ConfigureAwait(false);

var exitCode = await process.WaitForExitAsync(10_000).ConfigureAwait(false);

string stdOut;
string stdErr;

if (!exitCode.HasValue)
{
process.Kill();
stdOut = await stdOutTask;
throw new AdbException(AdbError.CommandTimedOut, strCommand, stdOut);
stdErr = await stdErrTask;
throw new AdbException(AdbError.CommandTimedOut, strCommand, stdOut + "\n" + stdErr);
}

stdOut = await stdOutTask;
stdErr = await stdErrTask;
var completeOutput = stdOut + "\n" + stdErr;

if (exitCode != 0)
{
throw new AdbException(AdbError.CommandFailed, strCommand, stdOut);
throw new AdbException(AdbError.CommandFailed, strCommand, completeOutput);
}

ValidateOutput(outputMustInclude, outputMustNotInclude, stdOut, strCommand, completeOutput);

return stdOut;
}

private static void ValidateOutput(
string? outputMustInclude,
string? outputMustNotInclude,
string stdOut,
string strCommand,
string completeOutput
)
{
if (
!string.IsNullOrEmpty(outputMustInclude)
&& !stdOut.Contains(outputMustInclude, StringComparison.OrdinalIgnoreCase)
)
{
throw new AdbException(AdbError.CommandFinishedWithInvalidOutput, strCommand, stdOut);
throw new AdbException(
AdbError.CommandFinishedWithInvalidOutput,
strCommand,
completeOutput
);
}

if (
!string.IsNullOrEmpty(outputMustNotInclude)
&& stdOut.Contains(outputMustNotInclude, StringComparison.OrdinalIgnoreCase)
)
{
throw new AdbException(AdbError.CommandFinishedWithInvalidOutput, strCommand, stdOut);
throw new AdbException(
AdbError.CommandFinishedWithInvalidOutput,
strCommand,
completeOutput
);
}

return stdOut;
}
}