summaryrefslogtreecommitdiffstats
path: root/logcat
diff options
context:
space:
mode:
authorMark Salyzyn <salyzyn@google.com>2013-12-13 11:10:11 -0800
committerMark Salyzyn <salyzyn@google.com>2014-01-27 15:18:49 -0800
commit65772ca7d7b61b111e75fb0f66f43966f0794bbd (patch)
treef4d230c1203ed617f65404e1a9a2e07eaffa4317 /logcat
parentcef098ef5df0d1e98bae269aaae2e3c3fbd1cb1f (diff)
downloadsystem_core-65772ca7d7b61b111e75fb0f66f43966f0794bbd.tar.gz
system_core-65772ca7d7b61b111e75fb0f66f43966f0794bbd.tar.bz2
system_core-65772ca7d7b61b111e75fb0f66f43966f0794bbd.zip
logcat: Add logcat test suite
(cherry picked from commit 2807db9a269baaa7b3f67c337d3312877ba90aa0) Change-Id: Ic4c84b88b8d899965c9765bdc3ee223ef73ba7d1
Diffstat (limited to 'logcat')
-rw-r--r--logcat/Android.mk4
-rw-r--r--logcat/logcat.cpp29
-rw-r--r--logcat/tests/Android.mk46
-rw-r--r--logcat/tests/logcat_test.cpp375
4 files changed, 440 insertions, 14 deletions
diff --git a/logcat/Android.mk b/logcat/Android.mk
index 7b8eb01e3..b5e27eb45 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -1,4 +1,4 @@
-# Copyright 2006 The Android Open Source Project
+# Copyright 2006-2014 The Android Open Source Project
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -10,3 +10,5 @@ LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE:= logcat
include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index b6ca17137..a54167ee5 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1,26 +1,27 @@
-// Copyright 2006-2013 The Android Open Source Project
-
-#include <log/log.h>
-#include <log/logger.h>
-#include <log/logd.h>
-#include <log/logprint.h>
-#include <log/event_tag_map.h>
-#include <cutils/sockets.h>
+// Copyright 2006-2014 The Android Open Source Project
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
+#include <signal.h>
#include <time.h>
-#include <errno.h>
-#include <assert.h>
-#include <ctype.h>
+#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
+#include <cutils/sockets.h>
+#include <log/log.h>
+#include <log/logger.h>
+#include <log/logd.h>
+#include <log/logprint.h>
+#include <log/event_tag_map.h>
+
#define DEFAULT_LOG_ROTATE_SIZE_KBYTES 16
#define DEFAULT_MAX_ROTATED_LOGS 4
@@ -284,6 +285,8 @@ int main(int argc, char **argv)
struct logger_list *logger_list;
int tail_lines = 0;
+ signal(SIGPIPE, exit);
+
g_logformat = android_log_format_new();
if (argc == 2 && 0 == strcmp(argv[1], "--test")) {
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
new file mode 100644
index 000000000..bdaec1419
--- /dev/null
+++ b/logcat/tests/Android.mk
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2013-2014 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
+
+test_module := logcat-unit-tests
+test_tags := tests
+
+test_c_flags := \
+ -fstack-protector-all \
+ -g \
+ -Wall -Wextra \
+ -Werror \
+ -fno-builtin \
+
+test_src_files := \
+ logcat_test.cpp \
+
+# Build tests for the device (with .so). Run with:
+# adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(test_module)
+LOCAL_MODULE_TAGS := $(test_tags)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_LDLIBS := -lpthread
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SRC_FILES := $(test_src_files)
+include $(BUILD_NATIVE_TEST)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
new file mode 100644
index 000000000..a4b796b6f
--- /dev/null
+++ b/logcat/tests/logcat_test.cpp
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2013-2014 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 <signal.h>
+#include <stdio.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+
+// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
+// non-syscall libs. Since we are only using this in the emergency of
+// a signal to stuff a terminating code into the logs, we will spin rather
+// than try a usleep.
+#define LOG_FAILURE_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (((_rc == -1) \
+ && ((errno == EINTR) \
+ || (errno == EAGAIN))) \
+ || (_rc == -EINTR) \
+ || (_rc == -EAGAIN)); \
+ _rc; })
+
+static const char begin[] = "--------- beginning of ";
+
+TEST(logcat, sorted_order) {
+ FILE *fp;
+
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
+ "r")));
+
+ class timestamp {
+ private:
+ int month;
+ int day;
+ int hour;
+ int minute;
+ int second;
+ int millisecond;
+ bool ok;
+
+ public:
+ void init(const char *buffer)
+ {
+ ok = false;
+ if (buffer != NULL) {
+ ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
+ &month, &day, &hour, &minute, &second, &millisecond) == 6;
+ }
+ }
+
+ timestamp(const char *buffer)
+ {
+ init(buffer);
+ }
+
+ bool operator< (timestamp &T)
+ {
+ return !ok || !T.ok
+ || (month < T.month)
+ || ((month == T.month)
+ && ((day < T.day)
+ || ((day == T.day)
+ && ((hour < T.hour)
+ || ((hour == T.hour)
+ && ((minute < T.minute)
+ || ((minute == T.minute)
+ && ((second < T.second)
+ || ((second == T.second)
+ && (millisecond < T.millisecond))))))))));
+ }
+
+ bool valid(void)
+ {
+ return ok;
+ }
+ } last(NULL);
+
+ char buffer[5120];
+
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
+ continue;
+ }
+ if (!last.valid()) {
+ last.init(buffer);
+ }
+ timestamp next(buffer);
+ ASSERT_EQ(0, next < last);
+ if (next.valid()) {
+ last.init(buffer);
+ }
+ ++count;
+ }
+
+ pclose(fp);
+
+ ASSERT_LT(100, count);
+}
+
+TEST(logcat, buckets) {
+ FILE *fp;
+
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "logcat -b radio -b events -b system -b main -d 2>/dev/null",
+ "r")));
+
+ char buffer[5120];
+
+ int ids = 0;
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
+ while (char *cp = strrchr(buffer, '\n')) {
+ *cp = '\0';
+ }
+ log_id_t id = android_name_to_log_id(buffer + sizeof(begin) - 1);
+ ids |= 1 << id;
+ ++count;
+ }
+ }
+
+ pclose(fp);
+
+ ASSERT_EQ(15, ids);
+
+ ASSERT_EQ(4, count);
+}
+
+TEST(logcat, tail_3) {
+ FILE *fp;
+
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "logcat -v long -b radio -b events -b system -b main -t 3 2>/dev/null",
+ "r")));
+
+ char buffer[5120];
+
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if ((buffer[0] == '[') && (buffer[1] == ' ')
+ && isdigit(buffer[2]) && isdigit(buffer[3])
+ && (buffer[4] == '-')) {
+ ++count;
+ }
+ }
+
+ pclose(fp);
+
+ ASSERT_EQ(3, count);
+}
+
+TEST(logcat, tail_10) {
+ FILE *fp;
+
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "logcat -v long -b radio -b events -b system -b main -t 10 2>/dev/null",
+ "r")));
+
+ char buffer[5120];
+
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if ((buffer[0] == '[') && (buffer[1] == ' ')
+ && isdigit(buffer[2]) && isdigit(buffer[3])
+ && (buffer[4] == '-')) {
+ ++count;
+ }
+ }
+
+ pclose(fp);
+
+ ASSERT_EQ(10, count);
+}
+
+TEST(logcat, tail_100) {
+ FILE *fp;
+
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "logcat -v long -b radio -b events -b system -b main -t 100 2>/dev/null",
+ "r")));
+
+ char buffer[5120];
+
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if ((buffer[0] == '[') && (buffer[1] == ' ')
+ && isdigit(buffer[2]) && isdigit(buffer[3])
+ && (buffer[4] == '-')) {
+ ++count;
+ }
+ }
+
+ pclose(fp);
+
+ ASSERT_EQ(100, count);
+}
+
+TEST(logcat, tail_1000) {
+ FILE *fp;
+
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "logcat -v long -b radio -b events -b system -b main -t 1000 2>/dev/null",
+ "r")));
+
+ char buffer[5120];
+
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if ((buffer[0] == '[') && (buffer[1] == ' ')
+ && isdigit(buffer[2]) && isdigit(buffer[3])
+ && (buffer[4] == '-')) {
+ ++count;
+ }
+ }
+
+ pclose(fp);
+
+ ASSERT_EQ(1000, count);
+}
+
+TEST(logcat, End_to_End) {
+ pid_t pid = getpid();
+
+ log_time ts(CLOCK_MONOTONIC);
+
+ ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+
+ FILE *fp;
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "logcat -b events -t 100 2>/dev/null",
+ "r")));
+
+ char buffer[5120];
+
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ int p;
+ unsigned long long t;
+
+ if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t))
+ || (p != pid)) {
+ continue;
+ }
+
+ log_time tx((const char *) &t);
+ if (ts == tx) {
+ ++count;
+ }
+ }
+
+ pclose(fp);
+
+ ASSERT_EQ(1, count);
+}
+
+TEST(logcat, get_) {
+ FILE *fp;
+
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "logcat -b radio -b events -b system -b main -g 2>/dev/null",
+ "r")));
+
+ char buffer[5120];
+
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ int size, consumed, max, payload;
+
+ size = consumed = max = payload = 0;
+ if ((4 == sscanf(buffer, "%*s ring buffer is %dKb (%dKb consumed),"
+ " max entry is %db, max payload is %db",
+ &size, &consumed, &max, &payload))
+ && ((size * 3) >= consumed)
+ && ((size * 1024) > max)
+ && (max > payload)) {
+ ++count;
+ }
+ }
+
+ pclose(fp);
+
+ ASSERT_EQ(4, count);
+}
+
+static void caught_blocking(int signum)
+{
+ unsigned long long v = 0xDEADBEEFA55A0000ULL;
+
+ v += getpid() & 0xFFFF;
+
+ LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+}
+
+TEST(logcat, blocking) {
+ FILE *fp;
+ unsigned long long v = 0xDEADBEEFA55A0000ULL;
+
+ pid_t pid = getpid();
+
+ v += pid & 0xFFFF;
+
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
+ " logcat -b events 2>&1",
+ "r")));
+
+ char buffer[5120];
+
+ int count = 0;
+
+ int signals = 0;
+
+ signal(SIGALRM, caught_blocking);
+ alarm(2);
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ alarm(2);
+
+ ++count;
+
+ if (!strncmp(buffer, "DONE", 4)) {
+ break;
+ }
+
+ int p;
+ unsigned long long l;
+
+ if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
+ || (p != pid)) {
+ continue;
+ }
+
+ if (l == v) {
+ ++signals;
+ break;
+ }
+ }
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+
+ // Generate SIGPIPE
+ fclose(fp);
+ caught_blocking(0);
+
+ pclose(fp);
+
+ ASSERT_LT(10, count);
+
+ ASSERT_EQ(1, signals);
+}