Added unit tests to bugreportz.

BUG: 28609499

Change-Id: I5b846eeeaa7c05c3e3f66f36d31ef42c472a3099
This commit is contained in:
Felipe Leme 2016-07-21 20:10:57 -07:00
parent 0a21df7838
commit 59f5af0465
6 changed files with 276 additions and 83 deletions

View 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

View file

@ -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)

View file

@ -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;
}

View 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

View 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
View 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);
}