Added unit tests to bugreportz.
BUG: 28609499 Change-Id: I5b846eeeaa7c05c3e3f66f36d31ef42c472a3099
This commit is contained in:
parent
0a21df7838
commit
59f5af0465
6 changed files with 276 additions and 83 deletions
13
cmds/bugreportz/.clang-format
Normal file
13
cmds/bugreportz/.clang-format
Normal file
|
@ -0,0 +1,13 @@
|
|||
BasedOnStyle: Google
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
|
||||
AccessModifierOffset: -2
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: NOLINT:.*
|
||||
DerivePointerAlignment: false
|
||||
IndentWidth: 4
|
||||
PointerAlignment: Left
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
PenaltyExcessCharacter: 32
|
|
@ -1,12 +1,43 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# bugreportz
|
||||
# ==========
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= bugreportz.cpp
|
||||
LOCAL_SRC_FILES:= \
|
||||
bugreportz.cpp \
|
||||
main.cpp \
|
||||
|
||||
LOCAL_MODULE:= bugreportz
|
||||
|
||||
LOCAL_CFLAGS := -Wall
|
||||
LOCAL_CFLAGS := -Werror -Wall
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := libcutils
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libbase \
|
||||
libcutils \
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# bugreportz_test
|
||||
# ===============
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := bugreportz_test
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
LOCAL_CFLAGS := -Werror -Wall
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
bugreportz.cpp \
|
||||
bugreportz_test.cpp \
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libgmock \
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libbase \
|
||||
libutils \
|
||||
|
||||
include $(BUILD_NATIVE_TEST)
|
||||
|
|
|
@ -15,89 +15,17 @@
|
|||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
static constexpr char VERSION[] = "1.0";
|
||||
|
||||
static void show_usage() {
|
||||
fprintf(stderr,
|
||||
"usage: bugreportz [-h | -v]\n"
|
||||
" -h: to display this help message\n"
|
||||
" -v: to display the version\n"
|
||||
" or no arguments to generate a zipped bugreport\n");
|
||||
}
|
||||
|
||||
static void show_version() {
|
||||
fprintf(stderr, "%s\n", VERSION);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc > 1) {
|
||||
/* parse arguments */
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "vh")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
show_usage();
|
||||
return EXIT_SUCCESS;
|
||||
case 'v':
|
||||
show_version();
|
||||
return EXIT_SUCCESS;
|
||||
default:
|
||||
show_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
// passed an argument not starting with -
|
||||
if (optind > 1 || argv[optind] != nullptr) {
|
||||
show_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: code below was copy-and-pasted from bugreport.cpp (except by the timeout value);
|
||||
// should be reused instead.
|
||||
|
||||
// Start the dumpstatez service.
|
||||
property_set("ctl.start", "dumpstatez");
|
||||
|
||||
// Socket will not be available until service starts.
|
||||
int s;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
|
||||
if (s >= 0)
|
||||
break;
|
||||
// Try again in 1 second.
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (s == -1) {
|
||||
printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// Set a timeout so that if nothing is read in 10 minutes, we'll stop
|
||||
// reading and quit. No timeout in dumpstate is longer than 60 seconds,
|
||||
// so this gives lots of leeway in case of unforeseen time outs.
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 10 * 60;
|
||||
tv.tv_usec = 0;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
|
||||
fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno));
|
||||
}
|
||||
#include "bugreportz.h"
|
||||
|
||||
int bugreportz(int s) {
|
||||
while (1) {
|
||||
char buffer[65536];
|
||||
ssize_t bytes_read = TEMP_FAILURE_RETRY(
|
||||
read(s, buffer, sizeof(buffer)));
|
||||
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)));
|
||||
if (bytes_read == 0) {
|
||||
break;
|
||||
} else if (bytes_read == -1) {
|
||||
|
@ -113,11 +41,11 @@ int main(int argc, char *argv[]) {
|
|||
ssize_t bytes_written;
|
||||
do {
|
||||
bytes_written = TEMP_FAILURE_RETRY(
|
||||
write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send,
|
||||
bytes_to_send));
|
||||
write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send, bytes_to_send));
|
||||
if (bytes_written == -1) {
|
||||
fprintf(stderr,
|
||||
"Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",
|
||||
"Failed to write data to stdout: read %zd, trying to send %zd "
|
||||
"(%s)\n",
|
||||
bytes_read, bytes_to_send, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
|
21
cmds/bugreportz/bugreportz.h
Normal file
21
cmds/bugreportz/bugreportz.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2016 Google Inc. 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.
|
||||
|
||||
#ifndef BUGREPORTZ_H
|
||||
#define BUGREPORTZ_H
|
||||
|
||||
// Calls dumpstate using the given socket and output its result to stdout.
|
||||
int bugreportz(int s);
|
||||
|
||||
#endif // BUGREPORTZ_H
|
101
cmds/bugreportz/bugreportz_test.cpp
Normal file
101
cmds/bugreportz/bugreportz_test.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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 <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "bugreportz.h"
|
||||
|
||||
using ::testing::StrEq;
|
||||
using ::testing::internal::CaptureStdout;
|
||||
using ::testing::internal::GetCapturedStdout;
|
||||
|
||||
class BugreportzTest : public ::testing::Test {
|
||||
public:
|
||||
// Creates the pipe used to communicate with bugreportz()
|
||||
void SetUp() {
|
||||
int fds[2];
|
||||
ASSERT_EQ(0, pipe(fds));
|
||||
read_fd_ = fds[0];
|
||||
write_fd_ = fds[1];
|
||||
}
|
||||
|
||||
// Closes the pipe FDs.
|
||||
// If a FD is closed manually during a test, set it to -1 to prevent TearDown() trying to close
|
||||
// it again.
|
||||
void TearDown() {
|
||||
for (int fd : {read_fd_, write_fd_}) {
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emulates dumpstate output by writing to the socket passed to bugreportz()
|
||||
void WriteToSocket(const std::string& data) {
|
||||
if (write_fd_ < 0) {
|
||||
ADD_FAILURE() << "cannot write '" << data << "' because socket is already closed";
|
||||
return;
|
||||
}
|
||||
int expected = data.length();
|
||||
int actual = write(write_fd_, data.data(), data.length());
|
||||
ASSERT_EQ(expected, actual) << "wrong number of bytes written to socket";
|
||||
}
|
||||
|
||||
void AssertStdoutEquals(const std::string& expected) {
|
||||
ASSERT_THAT(stdout_, StrEq(expected)) << "wrong stdout output";
|
||||
}
|
||||
|
||||
// Calls bugreportz() using the internal pipe.
|
||||
//
|
||||
// Tests must call WriteToSocket() to set what's written prior to calling it, since the writing
|
||||
// end of the pipe will be closed before calling bugreportz() (otherwise that function would
|
||||
// hang).
|
||||
void Bugreportz() {
|
||||
close(write_fd_);
|
||||
write_fd_ = -1;
|
||||
|
||||
CaptureStdout();
|
||||
int status = bugreportz(read_fd_);
|
||||
|
||||
close(read_fd_);
|
||||
read_fd_ = -1;
|
||||
stdout_ = GetCapturedStdout();
|
||||
|
||||
ASSERT_EQ(0, status) << "bugrepotz() call failed (stdout: " << stdout_ << ")";
|
||||
}
|
||||
|
||||
private:
|
||||
int read_fd_;
|
||||
int write_fd_;
|
||||
std::string stdout_;
|
||||
};
|
||||
|
||||
// Tests 'bugreportz', without any argument - it will just echo dumpstate's output to stdout.
|
||||
TEST_F(BugreportzTest, NoArgument) {
|
||||
WriteToSocket("What happens on 'dumpstate',");
|
||||
WriteToSocket("stays on 'bugreportz'.\n");
|
||||
|
||||
Bugreportz();
|
||||
|
||||
AssertStdoutEquals("What happens on 'dumpstate',stays on 'bugreportz'.\n");
|
||||
}
|
99
cmds/bugreportz/main.cpp
Normal file
99
cmds/bugreportz/main.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
#include "bugreportz.h"
|
||||
|
||||
static constexpr char VERSION[] = "1.0";
|
||||
|
||||
static void show_usage() {
|
||||
fprintf(stderr,
|
||||
"usage: bugreportz [-h | -v]\n"
|
||||
" -h: to display this help message\n"
|
||||
" -v: to display the version\n"
|
||||
" or no arguments to generate a zipped bugreport\n");
|
||||
}
|
||||
|
||||
static void show_version() {
|
||||
fprintf(stderr, "%s\n", VERSION);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc > 1) {
|
||||
/* parse arguments */
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "vh")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
show_usage();
|
||||
return EXIT_SUCCESS;
|
||||
case 'v':
|
||||
show_version();
|
||||
return EXIT_SUCCESS;
|
||||
default:
|
||||
show_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
// passed an argument not starting with -
|
||||
if (optind > 1 || argv[optind] != nullptr) {
|
||||
show_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: code below was copy-and-pasted from bugreport.cpp (except by the
|
||||
// timeout value);
|
||||
// should be reused instead.
|
||||
|
||||
// Start the dumpstatez service.
|
||||
property_set("ctl.start", "dumpstatez");
|
||||
|
||||
// Socket will not be available until service starts.
|
||||
int s;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
|
||||
if (s >= 0) break;
|
||||
// Try again in 1 second.
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (s == -1) {
|
||||
printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// Set a timeout so that if nothing is read in 10 minutes, we'll stop
|
||||
// reading and quit. No timeout in dumpstate is longer than 60 seconds,
|
||||
// so this gives lots of leeway in case of unforeseen time outs.
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 10 * 60;
|
||||
tv.tv_usec = 0;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
|
||||
fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
bugreportz(s);
|
||||
}
|
Loading…
Reference in a new issue