Commit 649794a9 authored by Caleb Rouleau's avatar Caleb Rouleau Committed by Commit Bot

[ChromeDriver] More robust adb server socket protocol implementation

This implementation separates the reading of the socket from the
parsing of the data from the socket to avoid edge cases.

The existing implementation makes assumptions about how the result
will be pushed to the socket from the other end. It had different
behavior depending on whether we read in an output like
"OKAYOKAY0005abcde"
in separate chucks like
"OKAY"
"OKAY"
"0005abcde"
versus as larger chunks like
"OKAYOKAY"
"0005abcde"
or one big chunk like
"OKAYOKAY0005abcde"

Given that the adb server has some interesting edge cases (documented
in this new code), it was more complex to handle them with the old
implementation.

Note also that these edge cases were being hit when I tried to pass
port=0 to the adb server (so that it would allocate a remote forwarding
port itself so there would be no race condition). So that work is
blocked on this work.

Bug: chromedriver:2161
Change-Id: Ia83f8c3e4e0261a9467ab2814502c37f3f7e0645
Reviewed-on: https://chromium-review.googlesource.com/1011131
Commit-Queue: Caleb Rouleau <crouleau@chromium.org>
Reviewed-by: default avatarJohn Chen <johnchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#554886}
parent d0689dce
......@@ -388,6 +388,7 @@ test("chromedriver_unittests") {
"command_listener_proxy_unittest.cc",
"commands_unittest.cc",
"logging_unittest.cc",
"net/adb_client_socket_unittest.cc",
"net/timeout_unittest.cc",
"performance_logger_unittest.cc",
"server/http_handler_unittest.cc",
......@@ -409,6 +410,8 @@ test("chromedriver_unittests") {
"//base/test:run_all_unittests",
"//net",
"//net:http_server",
"//net:test_support",
"//testing/gmock",
"//testing/gtest",
"//ui/base",
"//ui/gfx",
......
......@@ -20,6 +20,7 @@
#include "base/time/time.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/net/adb_client_socket.h"
#include "net/base/net_errors.h"
namespace {
......@@ -48,11 +49,20 @@ class ResponseBuffer : public base::RefCountedThreadSafe<ResponseBuffer> {
static_cast<int>(timeout.InSeconds())));
ready_.TimedWait(timeout);
}
if (result_ < 0)
if (result_ < 0) {
return Status(kUnknownError,
"Failed to run adb command with networking error: " +
net::ErrorToString(result_) +
". Is the adb server running? Extra response: <" +
response_ + ">.");
}
if (result_ > 0) {
return Status(
// TODO(crouleau): Use an error code that can differentiate this from
// the above networking error.
kUnknownError,
"Failed to run adb command, is the adb server running? Error: " +
response_ + ".");
"The adb command failed. Extra response: <" + response_ + ">.");
}
*response = response_;
return Status(kOk);
}
......
......@@ -24,17 +24,22 @@
namespace {
const int kBufferSize = 16 * 1024;
const int kBufferGrowthRate = 16 * 1024;
const size_t kAdbDataChunkSize = 32 * 1024;
const char kOkayResponse[] = "OKAY";
const char kFailResponse[] = "FAIL";
const char kHostTransportCommand[] = "host:transport:%s";
const char kLocalAbstractCommand[] = "localabstract:%s";
const char kSyncCommand[] = "sync:";
const char kSendCommand[] = "SEND";
const char kDataCommand[] = "DATA";
const char kDoneCommand[] = "DONE";
const int kAdbFailure = 1;
const int kAdbSuccess = 0;
typedef base::Callback<void(int, const std::string&)> CommandCallback;
typedef base::Callback<void(int, net::StreamSocket*)> SocketCallback;
typedef base::Callback<void(const std::string&)> ParserCallback;
std::string EncodeMessage(const std::string& message) {
static const char kHexChars[] = "0123456789ABCDEF";
......@@ -71,7 +76,8 @@ class AdbTransportSocket : public AdbClientSocket {
if (!CheckNetResultOrDie(result))
return;
SendCommand(base::StringPrintf(kHostTransportCommand, serial_.c_str()),
true, true, base::Bind(&AdbTransportSocket::SendLocalAbstract,
false, true,
base::Bind(&AdbTransportSocket::SendLocalAbstract,
base::Unretained(this)));
}
......@@ -79,7 +85,8 @@ class AdbTransportSocket : public AdbClientSocket {
if (!CheckNetResultOrDie(result))
return;
SendCommand(base::StringPrintf(kLocalAbstractCommand, socket_name_.c_str()),
true, true, base::Bind(&AdbTransportSocket::OnSocketAvailable,
false, true,
base::Bind(&AdbTransportSocket::OnSocketAvailable,
base::Unretained(this)));
}
......@@ -276,12 +283,13 @@ class AdbQuerySocket : AdbClientSocket {
CheckNetResultOrDie(net::ERR_MSG_TOO_BIG);
return;
}
bool is_void = current_query_ < queries_.size() - 1;
bool has_output = current_query_ == queries_.size() - 1;
// The |shell| command is a special case because it is the only command that
// doesn't include a length at the beginning of the data stream.
bool has_length =
!base::StartsWith(query, "shell:", base::CompareCase::SENSITIVE);
SendCommand(query, is_void, has_length,
SendCommand(
query, has_output, has_length,
base::Bind(&AdbQuerySocket::OnResponse, base::Unretained(this)));
}
......@@ -341,7 +349,7 @@ class AdbSendFileSocket : AdbClientSocket {
if (!CheckNetResultOrDie(result))
return;
SendCommand(
base::StringPrintf(kHostTransportCommand, serial_.c_str()), true, true,
base::StringPrintf(kHostTransportCommand, serial_.c_str()), false, true,
base::Bind(&AdbSendFileSocket::SendSync, base::Unretained(this)));
}
......@@ -349,7 +357,7 @@ class AdbSendFileSocket : AdbClientSocket {
if (!CheckNetResultOrDie(result))
return;
SendCommand(
kSyncCommand, true, true,
kSyncCommand, false, true,
base::Bind(&AdbSendFileSocket::SendSend, base::Unretained(this)));
}
......@@ -388,7 +396,7 @@ class AdbSendFileSocket : AdbClientSocket {
}
void ReadFinalResponse(int result) {
ReadResponse(callback_, true, false, result);
ReadResponse(callback_, false, false, result);
}
// Send a special payload command ("SEND", "DATA", or "DONE").
......@@ -523,179 +531,135 @@ void AdbClientSocket::Connect(const net::CompletionCallback& callback) {
}
void AdbClientSocket::SendCommand(const std::string& command,
bool is_void,
bool has_output,
bool has_length,
const CommandCallback& callback) {
const CommandCallback& response_callback) {
scoped_refptr<net::StringIOBuffer> request_buffer =
new net::StringIOBuffer(EncodeMessage(command));
int result = socket_->Write(
request_buffer.get(), request_buffer->size(),
base::Bind(&AdbClientSocket::ReadResponse, base::Unretained(this),
callback, is_void, has_length),
response_callback, has_output, has_length),
TRAFFIC_ANNOTATION_FOR_TESTS);
if (result != net::ERR_IO_PENDING)
ReadResponse(callback, is_void, has_length, result);
ReadResponse(response_callback, has_output, has_length, result);
}
void AdbClientSocket::ReadResponse(const CommandCallback& callback,
bool is_void,
void AdbClientSocket::ReadResponse(const CommandCallback& response_callback,
bool has_output,
bool has_length,
int result) {
if (result < 0) {
callback.Run(result, "IO error");
response_callback.Run(result, "IO error");
return;
}
scoped_refptr<net::IOBuffer> response_buffer =
new net::IOBuffer(kBufferSize);
result = socket_->Read(response_buffer.get(),
kBufferSize,
base::Bind(&AdbClientSocket::OnResponseStatus,
base::Unretained(this),
callback,
is_void,
has_length,
response_buffer));
if (result != net::ERR_IO_PENDING)
OnResponseStatus(callback, is_void, has_length, response_buffer, result);
}
void AdbClientSocket::OnResponseStatus(
const CommandCallback& callback,
bool is_void,
bool has_length,
scoped_refptr<net::IOBuffer> response_buffer,
int result) {
if (result <= 0) {
callback.Run(result == 0 ? net::ERR_CONNECTION_CLOSED : result,
"IO error");
return;
scoped_refptr<net::GrowableIOBuffer> socket_buffer =
new net::GrowableIOBuffer;
socket_buffer->SetCapacity(kBufferSize);
if (has_output) {
const ParserCallback& parse_output_callback = base::Bind(
&AdbClientSocket::ParseOutput, has_length, response_callback);
int socket_result = socket_->Read(
socket_buffer.get(), kBufferSize,
base::Bind(&AdbClientSocket::ReadUntilEOF, base::Unretained(this),
parse_output_callback, response_callback, socket_buffer));
if (socket_result != net::ERR_IO_PENDING) {
ReadUntilEOF(parse_output_callback, response_callback, socket_buffer,
socket_result);
}
std::string data = std::string(response_buffer->data(), result);
if (result < 4) {
callback.Run(net::ERR_FAILED, "Response is too short: " + data);
return;
}
std::string status = data.substr(0, 4);
if (status != kOkayResponse) {
callback.Run(net::ERR_FAILED, data);
return;
}
data = data.substr(4);
if (!is_void) {
if (!has_length) {
// Payload doesn't include length, so skip straight to reading in data.
OnResponseData(callback, data, response_buffer, -1, 0);
} else if (data.length() >= 4) {
// We've already read the length out of the socket, so we don't need to
// read more yet.
OnResponseLength(callback, data, response_buffer, 0);
} else {
// Part or all of the length is still in the socket, so we need to read it
// out of the socket before parsing the length.
result = socket_->Read(response_buffer.get(),
kBufferSize,
base::Bind(&AdbClientSocket::OnResponseLength,
base::Unretained(this),
callback,
data,
response_buffer));
if (result != net::ERR_IO_PENDING)
OnResponseLength(callback, data, response_buffer, result);
int socket_result =
socket_->Read(socket_buffer.get(), kBufferSize,
base::Bind(&AdbClientSocket::ReadStatusOutput,
response_callback, socket_buffer));
if (socket_result != net::ERR_IO_PENDING) {
ReadStatusOutput(response_callback, socket_buffer, socket_result);
}
} else {
callback.Run(net::OK, data);
}
}
void AdbClientSocket::OnResponseLength(
const CommandCallback& callback,
const std::string& response,
scoped_refptr<net::IOBuffer> response_buffer,
int result) {
if (result < 0) {
callback.Run(result, "IO error");
void AdbClientSocket::ReadStatusOutput(
const CommandCallback& response_callback,
scoped_refptr<net::IOBuffer> socket_buffer,
int socket_result) {
// Sometimes adb-server responds with the 8 char string "OKAY\0\0\0\0" instead
// of the expected "OKAY".
if (socket_result >= 4 &&
std::string(socket_buffer->data(), 4) == kOkayResponse) {
response_callback.Run(kAdbSuccess, kOkayResponse);
return;
}
response_callback.Run(kAdbFailure, kFailResponse);
}
std::string new_response =
response + std::string(response_buffer->data(), result);
// Sometimes ADB server will respond like "OKAYOKAY<payload_length><payload>"
// instead of the expected "OKAY<payload_length><payload>".
// For the former case, the first OKAY is cropped off in the OnResponseStatus
// but we still need to crop the second OKAY.
if (new_response.substr(0, 4) == "OKAY") {
VLOG(3) << "cutting new_response down to size";
new_response = new_response.substr(4);
}
if (new_response.length() < 4) {
if (new_response.length() == 0 && result == net::OK) {
// The socket is shut down and all data has been read.
// Note that this is a hack because is_void is false,
// but we are not returning any data. The upstream logic
// to determine is_void is not in a good state.
// However, this is a better solution than trusting is_void anyway
// because otherwise this can become an infinite loop.
callback.Run(net::OK, new_response);
return;
}
result = socket_->Read(response_buffer.get(),
kBufferSize,
base::Bind(&AdbClientSocket::OnResponseLength,
base::Unretained(this),
callback,
new_response,
response_buffer));
if (result != net::ERR_IO_PENDING)
OnResponseLength(callback, new_response, response_buffer, result);
} else {
int payload_length = 0;
if (!base::HexStringToInt(new_response.substr(0, 4), &payload_length)) {
VLOG(1) << "net error since payload length wasn't readable.";
callback.Run(net::ERR_FAILED, "response <" + new_response +
"> from adb server was unexpected");
void AdbClientSocket::ReadUntilEOF(
const ParserCallback& parse_output_callback,
const CommandCallback& response_callback,
scoped_refptr<net::GrowableIOBuffer> socket_buffer,
int socket_result) {
if (socket_result < 0) {
VLOG(3) << "IO error";
response_callback.Run(socket_result, "IO error");
return;
}
new_response = new_response.substr(4);
int bytes_left = payload_length - new_response.length();
OnResponseData(callback, new_response, response_buffer, bytes_left, 0);
} else if (socket_result > 0) {
// We read in data. Let's try to read in more.
socket_buffer->set_offset(socket_buffer->offset() + socket_result);
if (socket_buffer->RemainingCapacity() == 0) {
socket_buffer->SetCapacity(socket_buffer->capacity() + kBufferGrowthRate);
}
int new_socket_result = socket_->Read(
socket_buffer.get(), socket_buffer->RemainingCapacity(),
base::Bind(&AdbClientSocket::ReadUntilEOF, base::Unretained(this),
parse_output_callback, response_callback, socket_buffer));
if (new_socket_result != net::ERR_IO_PENDING) {
ReadUntilEOF(parse_output_callback, response_callback, socket_buffer,
new_socket_result);
}
} else if (socket_result == 0) {
// We hit EOF. The socket is closed on the other side.
std::string adb_output(socket_buffer->StartOfBuffer(),
socket_buffer->offset());
parse_output_callback.Run(adb_output);
}
}
void AdbClientSocket::OnResponseData(
const CommandCallback& callback,
const std::string& response,
scoped_refptr<net::IOBuffer> response_buffer,
int bytes_left,
int result) {
if (result < 0) {
callback.Run(result, "IO error");
return;
void AdbClientSocket::ParseOutput(bool has_length,
const CommandCallback& response_callback,
const std::string& adb_output) {
int result = kAdbFailure;
// Expected data format is
// "OKAY<payload_length><payload>" if has_length
// or "OKAY<payload>" if not has_length.
// or "OKAY" if there is no output (regardless of has_length).
// FAIL is returned instead of OKAY if there was an error.
std::string output(adb_output);
if (output.substr(0, 4) == kOkayResponse) {
output = output.substr(4);
result = kAdbSuccess;
}
if (output.substr(0, 4) == kFailResponse) {
output = output.substr(4);
result = kAdbFailure;
}
if (output.substr(0, 4) == kOkayResponse) {
VLOG(3) << "ADB server responded with \"OKAYOKAY\" instead of \"OKAY\".";
output = output.substr(4);
// Note: It's unclear whether we should set result = kAdbSuccess here or
// not. I've never seen "FAILOKAY" in the wild.
}
// Note that has_length=true implies that the payload length will be prepended
// to the payload in the case that there is a payload. If there is no payload,
// then there may not be a payload length.
if (has_length && output.size() != 0) {
if (output.size() >= 4) {
// Just skip the hex string length. It is unnecessary since
// EOF is sent after the message is complete.
output = output.substr(4);
} else {
VLOG(3) << "Error: ADB server responded without the expected hexstring"
<< " length";
result = kAdbFailure;
}
bytes_left -= result;
std::string new_response =
response + std::string(response_buffer->data(), result);
if (bytes_left == 0) {
callback.Run(net::OK, new_response);
return;
}
// Read tail
result = socket_->Read(response_buffer.get(),
kBufferSize,
base::Bind(&AdbClientSocket::OnResponseData,
base::Unretained(this),
callback,
new_response,
response_buffer,
bytes_left));
if (result > 0)
OnResponseData(callback, new_response, response_buffer, bytes_left, result);
else if (result != net::ERR_IO_PENDING)
callback.Run(net::OK, new_response);
response_callback.Run(result, output);
}
......@@ -16,6 +16,7 @@ class AdbClientSocket {
typedef base::Callback<void(int, const std::string&)> CommandCallback;
typedef base::Callback<void(int result,
net::StreamSocket*)> SocketCallback;
typedef base::Callback<void(const std::string&)> ParserCallback;
static void AdbQuery(int port,
const std::string& query,
......@@ -51,38 +52,34 @@ class AdbClientSocket {
void Connect(const net::CompletionCallback& callback);
void SendCommand(const std::string& command,
bool is_void,
bool has_output,
bool has_length,
const CommandCallback& callback);
const CommandCallback& response_callback);
std::unique_ptr<net::StreamSocket> socket_;
void ReadResponse(const CommandCallback& callback,
bool is_void,
bool has_output,
bool has_length,
int result);
private:
void OnResponseStatus(const CommandCallback& callback,
bool is_void,
bool has_length,
scoped_refptr<net::IOBuffer> response_buffer,
int result);
static void ReadStatusOutput(const CommandCallback& response_callback,
scoped_refptr<net::IOBuffer> socket_buffer,
int socket_result);
void OnResponseLength(const CommandCallback& callback,
const std::string& response,
scoped_refptr<net::IOBuffer> response_buffer,
int result);
void ReadUntilEOF(const ParserCallback& parse_output_callback,
const CommandCallback& response_callback,
scoped_refptr<net::GrowableIOBuffer> socket_buffer,
int socket_result);
void OnResponseData(const CommandCallback& callback,
const std::string& response,
scoped_refptr<net::IOBuffer> response_buffer,
int bytes_left,
int result);
static void ParseOutput(bool has_length,
const CommandCallback& response_callback,
const std::string& adb_output);
int port_;
friend class AdbClientSocketTest;
DISALLOW_COPY_AND_ASSIGN(AdbClientSocket);
};
#endif // CHROME_TEST_CHROMEDRIVER_NET_ADB_CLIENT_SOCKET_H_
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/chromedriver/net/adb_client_socket.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/test/gtest_util.h"
#include "base/test/mock_callback.h"
#include "net/socket/socket_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
class MockSocket : public net::MockClientSocket {
public:
int return_values_length;
std::string* return_values_array;
MockSocket(std::string* return_values_array, int return_values_length)
: MockClientSocket(net::NetLogWithSource()),
return_values_length(return_values_length),
return_values_array(return_values_array) {}
MockSocket() : MockClientSocket(net::NetLogWithSource()) {}
int Read(net::IOBuffer* buf,
int buf_len,
net::CompletionOnceCallback callback) override {
int result = ReadHelper(buf, buf_len);
if (result == net::ERR_IO_PENDING) {
// Note this really should be posted as a task, but that is a pain to
// figure out.
std::move(callback).Run(ReadLoop(buf, buf_len));
}
return result;
}
int ReadLoop(net::IOBuffer* buf, int buf_len) {
int result;
do {
result = ReadHelper(buf, buf_len);
} while (result == net::ERR_IO_PENDING);
return result;
}
int ReadHelper(net::IOBuffer* buf, int buf_len) {
if (return_values_length) {
int chunk_length = return_values_array[0].length();
if (chunk_length > buf_len) {
strncpy(buf->data(), return_values_array[0].data(), buf_len);
return_values_array[0] = return_values_array[0].substr(buf_len);
return buf_len;
}
strncpy(buf->data(), return_values_array[0].data(), chunk_length);
return_values_length--;
return_values_array++;
if (chunk_length == 0) {
return net::ERR_IO_PENDING;
}
return chunk_length;
}
return 0;
}
int Write(
net::IOBuffer* buf,
int buf_len,
const net::CompletionOnceCallback callback,
const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
return 0;
}
// The following functions are not expected to be used.
int Connect(const net::CompletionOnceCallback callback) override {
return net::ERR_UNEXPECTED;
}
bool GetSSLInfo(net::SSLInfo* ssl_info) override { return false; }
bool WasEverUsed() const override { return false; }
};
class AdbClientSocketTest : public testing::Test {
public:
void TestParsing(const char* adb_output,
bool has_length,
int expected_result_code,
const char* expected_response) {
base::MockCallback<AdbClientSocket::CommandCallback> callback;
EXPECT_CALL(callback, Run(expected_result_code, expected_response));
AdbClientSocket::ParseOutput(has_length, callback.Get(),
std::string(adb_output));
}
void TestReadUntilEOF_EOF(const char* data_on_buffer) {
std::unique_ptr<MockSocket> socket = std::make_unique<MockSocket>();
AdbClientSocket adb_socket(3);
base::MockCallback<AdbClientSocket::ParserCallback> parse_callback;
EXPECT_CALL(parse_callback, Run(data_on_buffer));
base::MockCallback<AdbClientSocket::CommandCallback> response_callback;
// The following means "expect not to be called."
EXPECT_CALL(response_callback, Run(0, "")).Times(0);
scoped_refptr<net::GrowableIOBuffer> buffer = new net::GrowableIOBuffer;
buffer->SetCapacity(100);
strcpy(buffer->data(), data_on_buffer);
buffer->set_offset(strlen(data_on_buffer));
adb_socket.ReadUntilEOF(parse_callback.Get(), response_callback.Get(),
buffer, 0);
}
void TestReadUntilEOF_Error() {
int error_code = -1;
std::unique_ptr<MockSocket> socket = std::make_unique<MockSocket>();
// 3 is an arbitrary meaningless number in the following call.
AdbClientSocket adb_socket(3);
base::MockCallback<AdbClientSocket::ParserCallback> parse_callback;
// The following means "expect not to be called."
EXPECT_CALL(parse_callback, Run("")).Times(0);
base::MockCallback<AdbClientSocket::CommandCallback> response_callback;
EXPECT_CALL(response_callback, Run(error_code, "IO error")).Times(1);
scoped_refptr<net::GrowableIOBuffer> buffer = new net::GrowableIOBuffer;
buffer->SetCapacity(100);
adb_socket.ReadUntilEOF(parse_callback.Get(), response_callback.Get(),
buffer, error_code);
}
void TestReadUntilEOF_Recurse(std::string* chunks,
int number_chunks,
std::string expected_result) {
// 3 is an arbitrary meaningless number in the following call.
AdbClientSocket adb_socket(3);
adb_socket.socket_.reset(new MockSocket(chunks, number_chunks));
base::MockCallback<AdbClientSocket::ParserCallback> parse_callback;
EXPECT_CALL(parse_callback, Run(expected_result.c_str())).Times(1);
base::MockCallback<AdbClientSocket::CommandCallback> response_callback;
// The following means "expect not to be called."
EXPECT_CALL(response_callback, Run(0, "")).Times(0);
scoped_refptr<net::GrowableIOBuffer> buffer = new net::GrowableIOBuffer;
int initial_capacity = 4;
buffer->SetCapacity(initial_capacity);
int result = adb_socket.socket_->Read(
buffer.get(), initial_capacity,
base::Bind(&AdbClientSocket::ReadUntilEOF,
base::Unretained(&adb_socket), parse_callback.Get(),
response_callback.Get(), buffer));
if (result != net::ERR_IO_PENDING) {
adb_socket.ReadUntilEOF(parse_callback.Get(), response_callback.Get(),
buffer, result);
}
}
void TestReadStatus(const char* buffer_data,
int result,
const char* expected_result_string,
int expected_result_code) {
base::MockCallback<AdbClientSocket::ParserCallback> parse_callback;
// The following means "expect not to be called."
EXPECT_CALL(parse_callback, Run("")).Times(0);
base::MockCallback<AdbClientSocket::CommandCallback> response_callback;
EXPECT_CALL(response_callback,
Run(expected_result_code, expected_result_string))
.Times(1);
scoped_refptr<net::GrowableIOBuffer> buffer = new net::GrowableIOBuffer;
int initial_capacity = 100;
buffer->SetCapacity(initial_capacity);
if (result > 0) {
strncpy(buffer->data(), buffer_data, result);
}
AdbClientSocket::ReadStatusOutput(response_callback.Get(), buffer, result);
}
};
TEST_F(AdbClientSocketTest, ParseOutput) {
TestParsing("OKAY000512345", true, 0, "12345");
TestParsing("FAIL000512345", true, 1, "12345");
TestParsing("OKAY12345", false, 0, "12345");
TestParsing("FAIL12345", false, 1, "12345");
TestParsing("ABC", false, 1, "ABC");
TestParsing("ABC", true, 1, "ABC");
TestParsing("OKAYAB", false, 0, "AB");
TestParsing("OKAYAB", true, 1, "AB");
TestParsing("OKAYOKAYOKAY", false, 0, "OKAY");
TestParsing("", false, 1, "");
TestParsing("", true, 1, "");
TestParsing("OKAYOKAY", true, 0, "");
TestParsing("OKAYOKAY", false, 0, "");
}
TEST_F(AdbClientSocketTest, ReadUntilEOF_EOFEmptyString) {
TestReadUntilEOF_EOF("");
}
TEST_F(AdbClientSocketTest, ReadUntilEOF_EOFNonEmptyString1) {
TestReadUntilEOF_EOF("blah");
}
TEST_F(AdbClientSocketTest, ReadUntilEOF_EOFNonEmptyString2) {
TestReadUntilEOF_EOF("blahbla");
}
TEST_F(AdbClientSocketTest, ReadUntilEOF_Error) {
TestReadUntilEOF_Error();
}
TEST_F(AdbClientSocketTest, ReadUntilEOF_GrowBuffer) {
std::string chunks[7] = {"This", "", " data", " should",
"", " be ", "read in."};
TestReadUntilEOF_Recurse(chunks, 7, "This data should be read in.");
}
TEST_F(AdbClientSocketTest, ReadUntilEOF_EmptyChunks) {
std::string chunks[5] = {"", "", "", "", ""};
TestReadUntilEOF_Recurse(chunks, 5, "");
}
TEST_F(AdbClientSocketTest, ReadUntilEOF_Empty) {
std::string chunks[0] = {};
TestReadUntilEOF_Recurse(chunks, 0, "");
}
TEST_F(AdbClientSocketTest, ReadUntilEOF_EmptyEndingChunk) {
std::string chunks[2] = {"yeah", ""};
TestReadUntilEOF_Recurse(chunks, 2, "yeah");
}
TEST_F(AdbClientSocketTest, ReadStatusOutput_Okay) {
TestReadStatus("OKAY", 4, "OKAY", 0);
}
TEST_F(AdbClientSocketTest, ReadStatusOutput_OkayNulls) {
TestReadStatus("OKAY\0\0\0\0", 8, "OKAY", 0);
}
TEST_F(AdbClientSocketTest, ReadStatusOutput_Fail) {
TestReadStatus("FAIL", 4, "FAIL", 1);
}
TEST_F(AdbClientSocketTest, ReadStatusOutput_FailEmpty) {
TestReadStatus("", 0, "FAIL", 1);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment