diff options
Diffstat (limited to 'logcat/tests')
-rw-r--r-- | logcat/tests/Android.mk | 31 | ||||
-rw-r--r-- | logcat/tests/logcat_benchmark.cpp | 128 | ||||
-rw-r--r-- | logcat/tests/logcat_test.cpp | 428 |
3 files changed, 470 insertions, 117 deletions
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk index bdaec14..015a23d 100644 --- a/logcat/tests/Android.mk +++ b/logcat/tests/Android.mk @@ -16,11 +16,7 @@ LOCAL_PATH := $(call my-dir) -# ----------------------------------------------------------------------------- -# Unit tests. -# ----------------------------------------------------------------------------- - -test_module := logcat-unit-tests +test_module_prefix := logcat- test_tags := tests test_c_flags := \ @@ -29,6 +25,28 @@ test_c_flags := \ -Wall -Wextra \ -Werror \ -fno-builtin \ + -std=gnu++11 + +# ----------------------------------------------------------------------------- +# Benchmarks (actually a gTest where the result code does not matter) +# ---------------------------------------------------------------------------- + +benchmark_src_files := \ + logcat_benchmark.cpp + +# Build benchmarks for the device. Run with: +# adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks +include $(CLEAR_VARS) +LOCAL_MODULE := $(test_module_prefix)benchmarks +LOCAL_MODULE_TAGS := $(test_tags) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_CFLAGS += $(test_c_flags) +LOCAL_SRC_FILES := $(benchmark_src_files) +include $(BUILD_NATIVE_TEST) + +# ----------------------------------------------------------------------------- +# Unit tests. +# ----------------------------------------------------------------------------- test_src_files := \ logcat_test.cpp \ @@ -36,11 +54,10 @@ test_src_files := \ # 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 := $(test_module_prefix)unit-tests 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_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp new file mode 100644 index 0000000..be815be --- /dev/null +++ b/logcat/tests/logcat_benchmark.cpp @@ -0,0 +1,128 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gtest/gtest.h> + +static const char begin[] = "--------- beginning of "; + +TEST(logcat, sorted_order) { + FILE *fp; + + ASSERT_TRUE(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 *last_buffer = NULL; + char buffer[5120]; + + int count = 0; + int next_lt_last = 0; + + while (fgets(buffer, sizeof(buffer), fp)) { + if (!strncmp(begin, buffer, sizeof(begin) - 1)) { + continue; + } + if (!last.valid()) { + free(last_buffer); + last_buffer = strdup(buffer); + last.init(buffer); + } + timestamp next(buffer); + if (next < last) { + if (last_buffer) { + fprintf(stderr, "<%s", last_buffer); + } + fprintf(stderr, ">%s", buffer); + ++next_lt_last; + } + if (next.valid()) { + free(last_buffer); + last_buffer = strdup(buffer); + last.init(buffer); + } + ++count; + } + free(last_buffer); + + pclose(fp); + + static const int max_ok = 2; + + // Allow few fails, happens with readers active + fprintf(stderr, "%s: %d/%d out of order entries\n", + (next_lt_last) + ? ((next_lt_last <= max_ok) + ? "WARNING" + : "ERROR") + : "INFO", + next_lt_last, count); + + EXPECT_GE(max_ok, next_lt_last); + + // sample statistically too small + EXPECT_LT(100, count); +} diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp index f963a3a..9b316d1 100644 --- a/logcat/tests/logcat_test.cpp +++ b/logcat/tests/logcat_test.cpp @@ -14,8 +14,12 @@ * limitations under the License. */ +#include <ctype.h> #include <signal.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> + #include <gtest/gtest.h> #include <log/log.h> #include <log/logger.h> @@ -38,88 +42,10 @@ 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( + ASSERT_TRUE(NULL != (fp = popen( "logcat -b radio -b events -b system -b main -d 2>/dev/null", "r"))); @@ -141,15 +67,15 @@ TEST(logcat, buckets) { pclose(fp); - ASSERT_EQ(15, ids); + EXPECT_EQ(15, ids); - ASSERT_EQ(4, count); + EXPECT_EQ(4, count); } TEST(logcat, tail_3) { FILE *fp; - ASSERT_EQ(0, NULL == (fp = popen( + ASSERT_TRUE(NULL != (fp = popen( "logcat -v long -b radio -b events -b system -b main -t 3 2>/dev/null", "r"))); @@ -173,7 +99,7 @@ TEST(logcat, tail_3) { TEST(logcat, tail_10) { FILE *fp; - ASSERT_EQ(0, NULL == (fp = popen( + ASSERT_TRUE(NULL != (fp = popen( "logcat -v long -b radio -b events -b system -b main -t 10 2>/dev/null", "r"))); @@ -197,7 +123,7 @@ TEST(logcat, tail_10) { TEST(logcat, tail_100) { FILE *fp; - ASSERT_EQ(0, NULL == (fp = popen( + ASSERT_TRUE(NULL != (fp = popen( "logcat -v long -b radio -b events -b system -b main -t 100 2>/dev/null", "r"))); @@ -221,7 +147,7 @@ TEST(logcat, tail_100) { TEST(logcat, tail_1000) { FILE *fp; - ASSERT_EQ(0, NULL == (fp = popen( + ASSERT_TRUE(NULL != (fp = popen( "logcat -v long -b radio -b events -b system -b main -t 1000 2>/dev/null", "r"))); @@ -242,6 +168,72 @@ TEST(logcat, tail_1000) { ASSERT_EQ(1000, count); } +TEST(logcat, tail_time) { + FILE *fp; + + ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r"))); + + char buffer[5120]; + char *last_timestamp = NULL; + char *first_timestamp = NULL; + int count = 0; + const unsigned int time_length = 18; + const unsigned int time_offset = 2; + + while (fgets(buffer, sizeof(buffer), fp)) { + if ((buffer[0] == '[') && (buffer[1] == ' ') + && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1]) + && (buffer[time_offset + 2] == '-')) { + ++count; + buffer[time_length + time_offset] = '\0'; + if (!first_timestamp) { + first_timestamp = strdup(buffer + time_offset); + } + free(last_timestamp); + last_timestamp = strdup(buffer + time_offset); + } + } + pclose(fp); + + EXPECT_EQ(10, count); + EXPECT_TRUE(last_timestamp != NULL); + EXPECT_TRUE(first_timestamp != NULL); + + snprintf(buffer, sizeof(buffer), "logcat -v long -b all -t '%s' 2>&1", + first_timestamp); + ASSERT_TRUE(NULL != (fp = popen(buffer, "r"))); + + int second_count = 0; + int last_timestamp_count = -1; + + while (fgets(buffer, sizeof(buffer), fp)) { + if ((buffer[0] == '[') && (buffer[1] == ' ') + && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1]) + && (buffer[time_offset + 2] == '-')) { + ++second_count; + buffer[time_length + time_offset] = '\0'; + if (first_timestamp) { + // we can get a transitory *extremely* rare failure if hidden + // underneath the time is *exactly* XX-XX XX:XX:XX.XXX000000 + EXPECT_STREQ(buffer + time_offset, first_timestamp); + free(first_timestamp); + first_timestamp = NULL; + } + if (!strcmp(buffer + time_offset, last_timestamp)) { + last_timestamp_count = second_count; + } + } + } + pclose(fp); + + free(last_timestamp); + last_timestamp = NULL; + + EXPECT_TRUE(first_timestamp == NULL); + EXPECT_LE(count, second_count); + EXPECT_LE(count, last_timestamp_count); +} + TEST(logcat, End_to_End) { pid_t pid = getpid(); @@ -250,7 +242,7 @@ TEST(logcat, End_to_End) { ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts))); FILE *fp; - ASSERT_EQ(0, NULL == (fp = popen( + ASSERT_TRUE(NULL != (fp = popen( "logcat -b events -t 100 2>/dev/null", "r"))); @@ -278,10 +270,11 @@ TEST(logcat, End_to_End) { ASSERT_EQ(1, count); } -TEST(logcat, get_) { +TEST(logcat, get_size) { FILE *fp; - ASSERT_EQ(0, NULL == (fp = popen( + // NB: crash log only available in user space + ASSERT_TRUE(NULL != (fp = popen( "logcat -b radio -b events -b system -b main -g 2>/dev/null", "r"))); @@ -291,13 +284,49 @@ TEST(logcat, get_) { while (fgets(buffer, sizeof(buffer), fp)) { int size, consumed, max, payload; + char size_mult, consumed_mult; + long full_size, full_consumed; 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) + // NB: crash log can be very small, not hit a Kb of consumed space + // doubly lucky we are not including it. + if (6 != sscanf(buffer, "%*s ring buffer is %d%cb (%d%cb consumed)," + " max entry is %db, max payload is %db", + &size, &size_mult, &consumed, &consumed_mult, + &max, &payload)) { + fprintf(stderr, "WARNING: Parse error: %s", buffer); + continue; + } + full_size = size; + switch(size_mult) { + case 'G': + full_size *= 1024; + /* FALLTHRU */ + case 'M': + full_size *= 1024; + /* FALLTHRU */ + case 'K': + full_size *= 1024; + break; + } + full_consumed = consumed; + switch(consumed_mult) { + case 'G': + full_consumed *= 1024; + /* FALLTHRU */ + case 'M': + full_consumed *= 1024; + /* FALLTHRU */ + case 'K': + full_consumed *= 1024; + break; + } + EXPECT_GT((full_size * 9) / 4, full_consumed); + EXPECT_GT(full_size, max); + EXPECT_GT(max, payload); + + if ((((full_size * 9) / 4) >= full_consumed) + && (full_size > max) && (max > payload)) { ++count; } @@ -308,7 +337,7 @@ TEST(logcat, get_) { ASSERT_EQ(4, count); } -static void caught_blocking(int signum) +static void caught_blocking(int /*signum*/) { unsigned long long v = 0xDEADBEEFA55A0000ULL; @@ -319,13 +348,17 @@ static void caught_blocking(int signum) TEST(logcat, blocking) { FILE *fp; - unsigned long long v = 0xDEADBEEFA55A0000ULL; + unsigned long long v = 0xDEADBEEFA55F0000ULL; pid_t pid = getpid(); v += pid & 0xFFFF; - ASSERT_EQ(0, NULL == (fp = popen( + LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); + + v &= 0xFFFFFFFFFFFAFFFFULL; + + ASSERT_TRUE(NULL != (fp = popen( "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" " logcat -b events 2>&1", "r"))); @@ -339,14 +372,13 @@ TEST(logcat, blocking) { signal(SIGALRM, caught_blocking); alarm(2); while (fgets(buffer, sizeof(buffer), fp)) { - alarm(2); - - ++count; if (!strncmp(buffer, "DONE", 4)) { break; } + ++count; + int p; unsigned long long l; @@ -369,12 +401,12 @@ TEST(logcat, blocking) { pclose(fp); - ASSERT_LT(10, count); + EXPECT_LE(2, count); - ASSERT_EQ(1, signals); + EXPECT_EQ(1, signals); } -static void caught_blocking_tail(int signum) +static void caught_blocking_tail(int /*signum*/) { unsigned long long v = 0xA55ADEADBEEF0000ULL; @@ -385,13 +417,17 @@ static void caught_blocking_tail(int signum) TEST(logcat, blocking_tail) { FILE *fp; - unsigned long long v = 0xA55ADEADBEEF0000ULL; + unsigned long long v = 0xA55FDEADBEEF0000ULL; pid_t pid = getpid(); v += pid & 0xFFFF; - ASSERT_EQ(0, NULL == (fp = popen( + LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); + + v &= 0xFFFAFFFFFFFFFFFFULL; + + ASSERT_TRUE(NULL != (fp = popen( "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" " logcat -b events -T 5 2>&1", "r"))); @@ -405,14 +441,13 @@ TEST(logcat, blocking_tail) { signal(SIGALRM, caught_blocking_tail); alarm(2); while (fgets(buffer, sizeof(buffer), fp)) { - alarm(2); - - ++count; if (!strncmp(buffer, "DONE", 4)) { break; } + ++count; + int p; unsigned long long l; @@ -431,13 +466,186 @@ TEST(logcat, blocking_tail) { alarm(0); signal(SIGALRM, SIG_DFL); - /* Generate SIGPIPE */ + // Generate SIGPIPE fclose(fp); caught_blocking_tail(0); pclose(fp); - ASSERT_LT(5, count); + EXPECT_LE(2, count); + + EXPECT_EQ(1, signals); +} + +static void caught_blocking_clear(int /*signum*/) +{ + unsigned long long v = 0xDEADBEEFA55C0000ULL; + + v += getpid() & 0xFFFF; + + LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); +} + +TEST(logcat, blocking_clear) { + FILE *fp; + unsigned long long v = 0xDEADBEEFA55C0000ULL; + + pid_t pid = getpid(); + + v += pid & 0xFFFF; + + // This test is racey; an event occurs between clear and dump. + // We accept that we will get a false positive, but never a false negative. + ASSERT_TRUE(NULL != (fp = popen( + "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" + " logcat -b events -c 2>&1 ;" + " logcat -b events 2>&1", + "r"))); + + char buffer[5120]; + + int count = 0; + + int signals = 0; + + signal(SIGALRM, caught_blocking_clear); + alarm(2); + while (fgets(buffer, sizeof(buffer), fp)) { + + if (!strncmp(buffer, "clearLog: ", 10)) { + fprintf(stderr, "WARNING: Test lacks permission to run :-(\n"); + count = signals = 1; + break; + } + + if (!strncmp(buffer, "DONE", 4)) { + break; + } + + ++count; + + int p; + unsigned long long l; + + if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) + || (p != pid)) { + continue; + } + + if (l == v) { + if (count > 1) { + fprintf(stderr, "WARNING: Possible false positive\n"); + } + ++signals; + break; + } + } + alarm(0); + signal(SIGALRM, SIG_DFL); + + // Generate SIGPIPE + fclose(fp); + caught_blocking_clear(0); + + pclose(fp); + + EXPECT_LE(1, count); + + EXPECT_EQ(1, signals); +} + +static bool get_white_black(char **list) { + FILE *fp; + + fp = popen("logcat -p 2>/dev/null", "r"); + if (fp == NULL) { + fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n"); + return false; + } + + char buffer[5120]; + + while (fgets(buffer, sizeof(buffer), fp)) { + char *hold = *list; + char *buf = buffer; + while (isspace(*buf)) { + ++buf; + } + char *end = buf + strlen(buf); + while (isspace(*--end) && (end >= buf)) { + *end = '\0'; + } + if (end < buf) { + continue; + } + if (hold) { + asprintf(list, "%s %s", hold, buf); + free(hold); + } else { + asprintf(list, "%s", buf); + } + } + pclose(fp); + return *list != NULL; +} + +static bool set_white_black(const char *list) { + FILE *fp; + + char buffer[5120]; + + snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : ""); + fp = popen(buffer, "r"); + if (fp == NULL) { + fprintf(stderr, "ERROR: %s\n", buffer); + return false; + } + + while (fgets(buffer, sizeof(buffer), fp)) { + char *buf = buffer; + while (isspace(*buf)) { + ++buf; + } + char *end = buf + strlen(buf); + while ((end > buf) && isspace(*--end)) { + *end = '\0'; + } + if (end <= buf) { + continue; + } + fprintf(stderr, "%s\n", buf); + pclose(fp); + return false; + } + return pclose(fp) == 0; +} - ASSERT_EQ(1, signals); +TEST(logcat, white_black_adjust) { + char *list = NULL; + char *adjust = NULL; + + get_white_black(&list); + + static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30"; + ASSERT_EQ(true, set_white_black(adjustment)); + ASSERT_EQ(true, get_white_black(&adjust)); + EXPECT_STREQ(adjustment, adjust); + free(adjust); + adjust = NULL; + + static const char adjustment2[] = "300/20 300/21 2000 ~1000"; + ASSERT_EQ(true, set_white_black(adjustment2)); + ASSERT_EQ(true, get_white_black(&adjust)); + EXPECT_STREQ(adjustment2, adjust); + free(adjust); + adjust = NULL; + + ASSERT_EQ(true, set_white_black(list)); + get_white_black(&adjust); + EXPECT_STREQ(list ? list : "", adjust ? adjust : ""); + free(adjust); + adjust = NULL; + + free(list); + list = NULL; } |