diff options
author | 2016-07-21 20:10:57 -0700 | |
---|---|---|
committer | 2016-07-26 13:39:47 -0700 | |
commit | 59f5af0465dcbf275a3653ac23885d12ee7e395d (patch) | |
tree | c167078cf169d7fddb56ef20cfae86889916d7d7 | |
parent | 0a21df783892acc5cff0c39c79b0aa602074af7e (diff) |
Added unit tests to bugreportz.
BUG: 28609499
Change-Id: I5b846eeeaa7c05c3e3f66f36d31ef42c472a3099
-rw-r--r-- | cmds/bugreportz/.clang-format | 13 | ||||
-rw-r--r-- | cmds/bugreportz/Android.mk | 37 | ||||
-rw-r--r-- | cmds/bugreportz/bugreportz.cpp | 88 | ||||
-rw-r--r-- | cmds/bugreportz/bugreportz.h | 21 | ||||
-rw-r--r-- | cmds/bugreportz/bugreportz_test.cpp | 101 | ||||
-rw-r--r-- | cmds/bugreportz/main.cpp | 99 |
6 files changed, 276 insertions, 83 deletions
diff --git a/cmds/bugreportz/.clang-format b/cmds/bugreportz/.clang-format new file mode 100644 index 0000000000..fc4eb1bc03 --- /dev/null +++ b/cmds/bugreportz/.clang-format @@ -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 diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk index 14ba2259ec..880bc75bc3 100644 --- a/cmds/bugreportz/Android.mk +++ b/cmds/bugreportz/Android.mk @@ -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) diff --git a/cmds/bugreportz/bugreportz.cpp b/cmds/bugreportz/bugreportz.cpp index 312dcebe0d..4b81c910dc 100644 --- a/cmds/bugreportz/bugreportz.cpp +++ b/cmds/bugreportz/bugreportz.cpp @@ -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; } diff --git a/cmds/bugreportz/bugreportz.h b/cmds/bugreportz/bugreportz.h new file mode 100644 index 0000000000..d2b79b92f4 --- /dev/null +++ b/cmds/bugreportz/bugreportz.h @@ -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 diff --git a/cmds/bugreportz/bugreportz_test.cpp b/cmds/bugreportz/bugreportz_test.cpp new file mode 100644 index 0000000000..fb6cdc76e5 --- /dev/null +++ b/cmds/bugreportz/bugreportz_test.cpp @@ -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"); +} diff --git a/cmds/bugreportz/main.cpp b/cmds/bugreportz/main.cpp new file mode 100644 index 0000000000..6fa33cc5ab --- /dev/null +++ b/cmds/bugreportz/main.cpp @@ -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); +} |