Split bugreport() into its own file and added unit tests.
am: 78e0963e4b
Change-Id: I0ae6ba38b62f714895e8d9abb5b36c5d8a82c6f2
This commit is contained in:
commit
5c01124f37
9 changed files with 324 additions and 54 deletions
|
@ -181,6 +181,9 @@ LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
|
|||
LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
|
||||
LOCAL_SRC_FILES := \
|
||||
$(LIBADB_TEST_SRCS) \
|
||||
adb_client.cpp \
|
||||
bugreport.cpp \
|
||||
bugreport_test.cpp \
|
||||
services.cpp \
|
||||
shell_service_protocol.cpp \
|
||||
shell_service_protocol_test.cpp \
|
||||
|
@ -196,6 +199,7 @@ LOCAL_STATIC_LIBRARIES := \
|
|||
libcrypto_static \
|
||||
libcutils \
|
||||
libdiagnose_usb \
|
||||
libgmock_host \
|
||||
|
||||
# Set entrypoint to wmain from sysdeps_win32.cpp instead of main
|
||||
LOCAL_LDFLAGS_windows := -municode
|
||||
|
@ -224,6 +228,7 @@ LOCAL_REQUIRED_MODULES_windows := AdbWinApi AdbWinUsbApi
|
|||
|
||||
LOCAL_SRC_FILES := \
|
||||
adb_client.cpp \
|
||||
bugreport.cpp \
|
||||
client/main.cpp \
|
||||
console.cpp \
|
||||
commandline.cpp \
|
||||
|
|
|
@ -203,8 +203,6 @@ void usb_kick(usb_handle *h);
|
|||
int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
|
||||
#endif
|
||||
|
||||
int adb_commandline(int argc, const char **argv);
|
||||
|
||||
ConnectionState connection_state(atransport *t);
|
||||
|
||||
extern const char* adb_device_banner;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define _ADB_CLIENT_H_
|
||||
|
||||
#include "adb.h"
|
||||
#include "sysdeps.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include <string>
|
||||
|
|
80
adb/bugreport.cpp
Normal file
80
adb/bugreport.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include "bugreport.h"
|
||||
#include "commandline.h"
|
||||
#include "file_sync_service.h"
|
||||
|
||||
static constexpr char BUGZ_OK_PREFIX[] = "OK:";
|
||||
static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:";
|
||||
|
||||
int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, const char** argv) {
|
||||
if (argc == 1) return SendShellCommand(transport_type, serial, "bugreport", false);
|
||||
if (argc != 2) return usage();
|
||||
|
||||
// Zipped bugreport option - will call 'bugreportz', which prints the location
|
||||
// of the generated
|
||||
// file, then pull it to the destination file provided by the user.
|
||||
std::string dest_file = argv[1];
|
||||
if (!android::base::EndsWith(argv[1], ".zip")) {
|
||||
// TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
|
||||
dest_file += ".zip";
|
||||
}
|
||||
std::string output;
|
||||
|
||||
fprintf(stderr,
|
||||
"Bugreport is in progress and it could take minutes to complete.\n"
|
||||
"Please be patient and do not cancel or disconnect your device until "
|
||||
"it completes.\n");
|
||||
int status = SendShellCommand(transport_type, serial, "bugreportz", false, &output, nullptr);
|
||||
if (status != 0 || output.empty()) return status;
|
||||
output = android::base::Trim(output);
|
||||
|
||||
if (android::base::StartsWith(output, BUGZ_OK_PREFIX)) {
|
||||
const char* zip_file = &output[strlen(BUGZ_OK_PREFIX)];
|
||||
std::vector<const char*> srcs{zip_file};
|
||||
status = DoSyncPull(srcs, dest_file.c_str(), true, dest_file.c_str()) ? 0 : 1;
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "Could not copy file '%s' to '%s'\n", zip_file, dest_file.c_str());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
if (android::base::StartsWith(output, BUGZ_FAIL_PREFIX)) {
|
||||
const char* error_message = &output[strlen(BUGZ_FAIL_PREFIX)];
|
||||
fprintf(stderr, "Device failed to take a zipped bugreport: %s\n", error_message);
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr,
|
||||
"Unexpected string (%s) returned by bugreportz, "
|
||||
"device probably does not support it\n",
|
||||
output.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Bugreport::SendShellCommand(TransportType transport_type, const char* serial,
|
||||
const std::string& command, bool disable_shell_protocol,
|
||||
std::string* output, std::string* err) {
|
||||
return send_shell_command(transport_type, serial, command, disable_shell_protocol, output, err);
|
||||
}
|
||||
|
||||
bool Bugreport::DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
|
||||
const char* name) {
|
||||
return do_sync_pull(srcs, dst, copy_attrs, name);
|
||||
}
|
44
adb/bugreport.h
Normal file
44
adb/bugreport.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BUGREPORT_H
|
||||
#define BUGREPORT_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "adb.h"
|
||||
|
||||
class Bugreport {
|
||||
public:
|
||||
Bugreport() {
|
||||
}
|
||||
int DoIt(TransportType transport_type, const char* serial, int argc, const char** argv);
|
||||
|
||||
protected:
|
||||
// Functions below are abstractions of external functions so they can be
|
||||
// mocked on tests.
|
||||
virtual int SendShellCommand(TransportType transport_type, const char* serial,
|
||||
const std::string& command, bool disable_shell_protocol,
|
||||
std::string* output = nullptr, std::string* err = nullptr);
|
||||
|
||||
virtual bool DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
|
||||
const char* name);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(Bugreport);
|
||||
};
|
||||
|
||||
#endif // BUGREPORT_H
|
155
adb/bugreport_test.cpp
Normal file
155
adb/bugreport_test.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "bugreport.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::DoAll;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Return;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::StrEq;
|
||||
using ::testing::internal::CaptureStderr;
|
||||
using ::testing::internal::GetCapturedStderr;
|
||||
|
||||
// Empty function so tests don't need to be linked against
|
||||
// file_sync_service.cpp, which requires
|
||||
// SELinux and its transitive dependencies...
|
||||
bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
|
||||
const char* name) {
|
||||
ADD_FAILURE() << "do_sync_pull() should have been mocked";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Implemented in commandline.cpp
|
||||
int usage() {
|
||||
return -42;
|
||||
}
|
||||
|
||||
// Implemented in commandline.cpp
|
||||
int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
|
||||
bool disable_shell_protocol, std::string* output, std::string* err) {
|
||||
ADD_FAILURE() << "send_shell_command() should have been mocked";
|
||||
return -42;
|
||||
}
|
||||
|
||||
class BugreportMock : public Bugreport {
|
||||
public:
|
||||
MOCK_METHOD6(SendShellCommand,
|
||||
int(TransportType transport_type, const char* serial, const std::string& command,
|
||||
bool disable_shell_protocol, std::string* output, std::string* err));
|
||||
MOCK_METHOD4(DoSyncPull, bool(const std::vector<const char*>& srcs, const char* dst,
|
||||
bool copy_attrs, const char* name));
|
||||
};
|
||||
|
||||
class BugreportTest : public ::testing::Test {
|
||||
public:
|
||||
BugreportMock br_;
|
||||
};
|
||||
|
||||
// Tests when called with invalid number of argumnts
|
||||
TEST_F(BugreportTest, InvalidNumberArgs) {
|
||||
const char* args[1024] = {"bugreport", "to", "principal"};
|
||||
ASSERT_EQ(-42, br_.DoIt(kTransportLocal, "HannibalLecter", 3, args));
|
||||
}
|
||||
|
||||
// Tests the legacy 'adb bugreport' option
|
||||
TEST_F(BugreportTest, FlatFileFormat) {
|
||||
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreport", false,
|
||||
nullptr, nullptr))
|
||||
.WillOnce(Return(0));
|
||||
|
||||
const char* args[1024] = {"bugreport"};
|
||||
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
|
||||
}
|
||||
|
||||
// Tests 'adb bugreport file.zip' when it succeeds
|
||||
TEST_F(BugreportTest, Ok) {
|
||||
EXPECT_CALL(
|
||||
br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _, nullptr))
|
||||
.WillOnce(DoAll(SetArgPointee<4>("OK:/device/bugreport.zip"), Return(0)));
|
||||
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
|
||||
true, StrEq("file.zip")))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
const char* args[1024] = {"bugreport", "file.zip"};
|
||||
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
|
||||
}
|
||||
|
||||
// Tests 'adb bugreport file' when it succeeds
|
||||
TEST_F(BugreportTest, OkNoExtension) {
|
||||
EXPECT_CALL(
|
||||
br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _, nullptr))
|
||||
.WillOnce(DoAll(SetArgPointee<4>("OK:/device/bugreport.zip"), Return(0)));
|
||||
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
|
||||
true, StrEq("file.zip")))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
const char* args[1024] = {"bugreport", "file"};
|
||||
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
|
||||
}
|
||||
|
||||
// Tests 'adb bugreport file.zip' when the bugreport itself failed
|
||||
TEST_F(BugreportTest, BugreportzReturnedFail) {
|
||||
EXPECT_CALL(
|
||||
br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _, nullptr))
|
||||
.WillOnce(DoAll(SetArgPointee<4>("FAIL:D'OH!"), Return(0)));
|
||||
|
||||
CaptureStderr();
|
||||
const char* args[1024] = {"bugreport", "file.zip"};
|
||||
ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
|
||||
ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH"));
|
||||
}
|
||||
|
||||
// Tests 'adb bugreport file.zip' when the bugreportz returned an unsupported
|
||||
// response.
|
||||
TEST_F(BugreportTest, BugreportzReturnedUnsupported) {
|
||||
EXPECT_CALL(
|
||||
br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _, nullptr))
|
||||
.WillOnce(DoAll(SetArgPointee<4>("bugreportz? What am I, a zombie?"), Return(0)));
|
||||
|
||||
CaptureStderr();
|
||||
const char* args[1024] = {"bugreport", "file.zip"};
|
||||
ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
|
||||
ASSERT_THAT(GetCapturedStderr(), HasSubstr("bugreportz? What am I, a zombie?"));
|
||||
}
|
||||
|
||||
// Tests 'adb bugreport file.zip' when the bugreportz command fails
|
||||
TEST_F(BugreportTest, BugreportzFailed) {
|
||||
EXPECT_CALL(
|
||||
br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _, nullptr))
|
||||
.WillOnce(Return(666));
|
||||
|
||||
const char* args[1024] = {"bugreport", "file.zip"};
|
||||
ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
|
||||
}
|
||||
|
||||
// Tests 'adb bugreport file.zip' when the bugreport could not be pulled
|
||||
TEST_F(BugreportTest, PullFails) {
|
||||
EXPECT_CALL(
|
||||
br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _, nullptr))
|
||||
.WillOnce(DoAll(SetArgPointee<4>("OK:/device/bugreport.zip"), Return(0)));
|
||||
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
|
||||
true, StrEq("file.zip")))
|
||||
.WillOnce(Return(false));
|
||||
|
||||
const char* args[1024] = {"bugreport", "file.zip"};
|
||||
ASSERT_EQ(1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
|
||||
}
|
|
@ -32,6 +32,7 @@
|
|||
#include "adb_auth.h"
|
||||
#include "adb_listeners.h"
|
||||
#include "adb_utils.h"
|
||||
#include "commandline.h"
|
||||
#include "transport.h"
|
||||
|
||||
static std::string GetLogFilePath() {
|
||||
|
|
|
@ -52,10 +52,11 @@
|
|||
#include "adb_client.h"
|
||||
#include "adb_io.h"
|
||||
#include "adb_utils.h"
|
||||
#include "bugreport.h"
|
||||
#include "commandline.h"
|
||||
#include "file_sync_service.h"
|
||||
#include "services.h"
|
||||
#include "shell_service.h"
|
||||
#include "transport.h"
|
||||
|
||||
static int install_app(TransportType t, const char* serial, int argc, const char** argv);
|
||||
static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv);
|
||||
|
@ -66,9 +67,6 @@ static int uninstall_app_legacy(TransportType t, const char* serial, int argc, c
|
|||
static auto& gProductOutPath = *new std::string();
|
||||
extern int gListenAll;
|
||||
|
||||
static constexpr char BUGZ_OK_PREFIX[] = "OK:";
|
||||
static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:";
|
||||
|
||||
static std::string product_file(const char *extra) {
|
||||
if (gProductOutPath.empty()) {
|
||||
fprintf(stderr, "adb: Product directory not specified; "
|
||||
|
@ -254,7 +252,7 @@ static void help() {
|
|||
);
|
||||
}
|
||||
|
||||
static int usage() {
|
||||
int usage() {
|
||||
help();
|
||||
return 1;
|
||||
}
|
||||
|
@ -1119,13 +1117,8 @@ static bool adb_root(const char* command) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Connects to the device "shell" service with |command| and prints the
|
||||
// resulting output.
|
||||
static int send_shell_command(TransportType transport_type, const char* serial,
|
||||
const std::string& command,
|
||||
bool disable_shell_protocol,
|
||||
std::string* output=nullptr,
|
||||
std::string* err=nullptr) {
|
||||
int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
|
||||
bool disable_shell_protocol, std::string* output, std::string* err) {
|
||||
int fd;
|
||||
bool use_shell_protocol = false;
|
||||
|
||||
|
@ -1169,45 +1162,6 @@ static int send_shell_command(TransportType transport_type, const char* serial,
|
|||
return exit_code;
|
||||
}
|
||||
|
||||
static int bugreport(TransportType transport_type, const char* serial, int argc,
|
||||
const char** argv) {
|
||||
if (argc == 1) return send_shell_command(transport_type, serial, "bugreport", false);
|
||||
if (argc != 2) return usage();
|
||||
|
||||
// Zipped bugreport option - will call 'bugreportz', which prints the location of the generated
|
||||
// file, then pull it to the destination file provided by the user.
|
||||
std::string dest_file = argv[1];
|
||||
if (!android::base::EndsWith(argv[1], ".zip")) {
|
||||
// TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
|
||||
dest_file += ".zip";
|
||||
}
|
||||
std::string output;
|
||||
|
||||
fprintf(stderr, "Bugreport is in progress and it could take minutes to complete.\n"
|
||||
"Please be patient and do not cancel or disconnect your device until it completes.\n");
|
||||
int status = send_shell_command(transport_type, serial, "bugreportz", false, &output, nullptr);
|
||||
if (status != 0 || output.empty()) return status;
|
||||
output = android::base::Trim(output);
|
||||
|
||||
if (android::base::StartsWith(output, BUGZ_OK_PREFIX)) {
|
||||
const char* zip_file = &output[strlen(BUGZ_OK_PREFIX)];
|
||||
std::vector<const char*> srcs{zip_file};
|
||||
status = do_sync_pull(srcs, dest_file.c_str(), true, dest_file.c_str()) ? 0 : 1;
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "Could not copy file '%s' to '%s'\n", zip_file, dest_file.c_str());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
if (android::base::StartsWith(output, BUGZ_FAIL_PREFIX)) {
|
||||
const char* error_message = &output[strlen(BUGZ_FAIL_PREFIX)];
|
||||
fprintf(stderr, "Device failed to take a zipped bugreport: %s\n", error_message);
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "Unexpected string (%s) returned by bugreportz, "
|
||||
"device probably does not support -z option\n", output.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int logcat(TransportType transport, const char* serial, int argc, const char** argv) {
|
||||
char* log_tags = getenv("ANDROID_LOG_TAGS");
|
||||
std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
|
||||
|
@ -1778,7 +1732,8 @@ int adb_commandline(int argc, const char **argv) {
|
|||
} else if (!strcmp(argv[0], "root") || !strcmp(argv[0], "unroot")) {
|
||||
return adb_root(argv[0]) ? 0 : 1;
|
||||
} else if (!strcmp(argv[0], "bugreport")) {
|
||||
return bugreport(transport_type, serial, argc, argv);
|
||||
Bugreport bugreport;
|
||||
return bugreport.DoIt(transport_type, serial, argc, argv);
|
||||
} else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
|
||||
bool reverse = !strcmp(argv[0], "reverse");
|
||||
++argv;
|
||||
|
|
31
adb/commandline.h
Normal file
31
adb/commandline.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef COMMANDLINE_H
|
||||
#define COMMANDLINE_H
|
||||
|
||||
#include "adb.h"
|
||||
|
||||
int adb_commandline(int argc, const char** argv);
|
||||
int usage();
|
||||
|
||||
// Connects to the device "shell" service with |command| and prints the
|
||||
// resulting output.
|
||||
int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
|
||||
bool disable_shell_protocol, std::string* output = nullptr,
|
||||
std::string* err = nullptr);
|
||||
|
||||
#endif // COMMANDLINE_H
|
Loading…
Reference in a new issue