aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Yu <yumike@google.com>2019-10-31 16:12:23 +0800
committerMike Yu <yumike@google.com>2019-12-11 22:31:45 +0800
commit39df0b13bb000abfbc9fbb01edacd54f4fc421c9 (patch)
tree5c46857705be0841cc4b895cfa8e3994a2cae8f8
parent939e3690aeb0142679678313a74bf024cfba7129 (diff)
downloadDnsResolver-39df0b13bb000abfbc9fbb01edacd54f4fc421c9.tar.gz
Add unit tests for DnsQueryLog
Ensure the basic functions of DnsQueryLog work as expected. Bug: 139040977 Test: cd packages/modules/DnsResolver && atest Change-Id: I6b318beeed7ff5942e8d08474c354e48ebdac936
-rw-r--r--Android.bp1
-rw-r--r--DnsQueryLog.cpp6
-rw-r--r--DnsQueryLog.h13
-rw-r--r--DnsQueryLogTest.cpp164
4 files changed, 178 insertions, 6 deletions
diff --git a/Android.bp b/Android.bp
index 50d5dabe..fd868f77 100644
--- a/Android.bp
+++ b/Android.bp
@@ -171,6 +171,7 @@ cc_test {
"resolv_tls_unit_test.cpp",
"resolv_unit_test.cpp",
"DnsStatsTest.cpp",
+ "DnsQueryLogTest.cpp",
],
shared_libs: [
"libbase",
diff --git a/DnsQueryLog.cpp b/DnsQueryLog.cpp
index 82ed581d..6f0e1795 100644
--- a/DnsQueryLog.cpp
+++ b/DnsQueryLog.cpp
@@ -61,19 +61,19 @@ std::string timestampToString(const std::chrono::system_clock::time_point& ts) {
void DnsQueryLog::push(Record&& record) {
std::lock_guard guard(mLock);
mQueue.push_back(std::move(record));
- if (mQueue.size() > kLogSize) {
+ if (mQueue.size() > mCapacity) {
mQueue.pop_front();
}
}
void DnsQueryLog::dump(netdutils::DumpWriter& dw) const {
- dw.println("DNS query log (last %ld minutes):", kValidityMinutes.count());
+ dw.println("DNS query log (last %lld minutes):", (mValidityTimeMs / 60000).count());
netdutils::ScopedIndent indentStats(dw);
const auto now = std::chrono::system_clock::now();
std::lock_guard guard(mLock);
for (const auto& record : mQueue) {
- if (now - record.timestamp > kValidityMinutes) continue;
+ if (now - record.timestamp > mValidityTimeMs) continue;
const std::string maskedHostname = maskHostname(record.hostname);
const std::string maskedIpsStr = maskIps(record.addrs);
diff --git a/DnsQueryLog.h b/DnsQueryLog.h
index a3190471..c19f8db3 100644
--- a/DnsQueryLog.h
+++ b/DnsQueryLog.h
@@ -49,18 +49,25 @@ class DnsQueryLog {
const int timeTaken;
};
+ // Allow the tests to set the capacity and the validaty time in milliseconds.
+ DnsQueryLog(size_t size = kDefaultLogSize,
+ std::chrono::milliseconds time = kDefaultValidityMinutes)
+ : mCapacity(size), mValidityTimeMs(time) {}
+
void push(Record&& record) EXCLUDES(mLock);
void dump(netdutils::DumpWriter& dw) const EXCLUDES(mLock);
private:
mutable std::mutex mLock;
std::deque<Record> mQueue GUARDED_BY(mLock);
+ const size_t mCapacity;
+ const std::chrono::milliseconds mValidityTimeMs;
// The capacity of the circular buffer.
- static constexpr size_t kLogSize = 200;
+ static constexpr size_t kDefaultLogSize = 200;
- // Limit to dump the queries within last |kValidityMinutes| minutes.
- static constexpr std::chrono::minutes kValidityMinutes{60};
+ // Limit to dump the queries within last |kDefaultValidityMinutes| minutes.
+ static constexpr std::chrono::minutes kDefaultValidityMinutes{60};
};
} // namespace android::net
diff --git a/DnsQueryLogTest.cpp b/DnsQueryLogTest.cpp
new file mode 100644
index 00000000..b652412a
--- /dev/null
+++ b/DnsQueryLogTest.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2019 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 <regex>
+#include <thread>
+
+#include <android-base/strings.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include "DnsQueryLog.h"
+
+using namespace std::chrono_literals;
+
+namespace android::net {
+
+namespace {
+
+// Dump the log to STDOUT and capture it.
+std::string captureDumpOutput(const DnsQueryLog& queryLog) {
+ netdutils::DumpWriter dw(STDOUT_FILENO);
+ CapturedStdout captured;
+ queryLog.dump(dw);
+ return captured.str();
+}
+
+// A simple check for the dump result by checking the netIds one by one.
+void verifyDumpOutput(const std::string& dumpLog, const std::vector<int>& expectedNetIds) {
+ // Capture three matches: netId, hostname, and answer (empty allowed).
+ static const std::regex pattern(
+ R"(netId=(\d+).* hostname=([\w\*]+) answer=\[([\w:,\.\*\s]*)\])");
+
+ std::string str(dumpLog);
+ std::smatch sm;
+ for (const auto& netId : expectedNetIds) {
+ SCOPED_TRACE(netId);
+ EXPECT_TRUE(std::regex_search(str, sm, pattern));
+ EXPECT_EQ(sm[1], std::to_string(netId));
+ str = sm.suffix();
+ }
+
+ // Ensure the dumpLog is exactly as expected.
+ EXPECT_FALSE(std::regex_search(str, sm, pattern));
+}
+
+} // namespace
+
+class DnsQueryLogTest : public ::testing::Test {
+ protected:
+ const std::vector<std::string> serversV4 = {"127.0.0.1", "1.2.3.4"};
+ const std::vector<std::string> serversV4V6 = {"127.0.0.1", "1.2.3.4", "2001:db8::1",
+ "fe80:1::2%testnet"};
+};
+
+TEST_F(DnsQueryLogTest, Push) {
+ std::vector<DnsQueryLog::Record> records = {
+ DnsQueryLog::Record(30, 1000, 1000, "example.com", serversV4, 10),
+ DnsQueryLog::Record(31, 1000, 1000, "", serversV4, 10), // Empty hostname.
+ DnsQueryLog::Record(32, 1000, 1000, "example.com", {}, 10), // No answer.
+ DnsQueryLog::Record(33, 1000, 1000, "example.com", serversV4V6, 10),
+ };
+ DnsQueryLog queryLog;
+ for (auto& r : records) {
+ queryLog.push(std::move(r));
+ }
+
+ std::string output = captureDumpOutput(queryLog);
+ verifyDumpOutput(output, {30, 31, 32, 33});
+}
+
+TEST_F(DnsQueryLogTest, PushStressTest) {
+ const int threadNum = 100;
+ const int pushNum = 1000;
+ const size_t size = 500;
+ DnsQueryLog queryLog(size);
+ std::vector<std::thread> threads(threadNum);
+
+ // Launch 'threadNum' threads to push the same queryLog 'pushNum' times.
+ for (auto& thread : threads) {
+ thread = std::thread([&]() {
+ for (int i = 0; i < pushNum; i++) {
+ DnsQueryLog::Record record(30, 1000, 1000, "www.example.com", serversV4, 10);
+ queryLog.push(std::move(record));
+ }
+ });
+ }
+ for (auto& thread : threads) {
+ thread.join();
+ }
+
+ // Verify there are exact 'size' records in queryLog.
+ std::string output = captureDumpOutput(queryLog);
+ verifyDumpOutput(output, std::vector(size, 30));
+}
+
+TEST_F(DnsQueryLogTest, ZeroSize) {
+ const size_t size = 0;
+ DnsQueryLog::Record r1(30, 1000, 1000, "www.example1.com", serversV4V6, 10);
+ DnsQueryLog::Record r2(31, 1000, 1000, "www.example2.com", serversV4V6, 10);
+ DnsQueryLog::Record r3(32, 1000, 1000, "www.example3.com", serversV4V6, 10);
+
+ DnsQueryLog queryLog(size);
+ queryLog.push(std::move(r1));
+ queryLog.push(std::move(r2));
+ queryLog.push(std::move(r3));
+
+ std::string output = captureDumpOutput(queryLog);
+ verifyDumpOutput(output, {});
+}
+
+TEST_F(DnsQueryLogTest, CapacityFull) {
+ const size_t size = 3;
+ DnsQueryLog::Record r1(30, 1000, 1000, "www.example1.com", serversV4V6, 10);
+ DnsQueryLog::Record r2(31, 1000, 1000, "www.example2.com", serversV4V6, 10);
+ DnsQueryLog::Record r3(32, 1000, 1000, "www.example3.com", serversV4V6, 10);
+ DnsQueryLog::Record r4(33, 1000, 1000, "www.example4.com", serversV4V6, 10);
+ const std::vector<int> expectedNetIds = {31, 32, 33};
+
+ DnsQueryLog queryLog(size);
+ queryLog.push(std::move(r1));
+ queryLog.push(std::move(r2));
+ queryLog.push(std::move(r3));
+ queryLog.push(std::move(r4));
+
+ std::string output = captureDumpOutput(queryLog);
+ verifyDumpOutput(output, expectedNetIds);
+}
+
+TEST_F(DnsQueryLogTest, ValidityTime) {
+ DnsQueryLog::Record r1(30, 1000, 1000, "www.example.com", serversV4, 10);
+ DnsQueryLog queryLog(3, 100ms);
+ queryLog.push(std::move(r1));
+
+ // Dump the output and verify the correctness by checking netId.
+ std::string output = captureDumpOutput(queryLog);
+ verifyDumpOutput(output, {30});
+
+ std::this_thread::sleep_for(150ms);
+
+ // The record is expired thus not shown in the output.
+ output = captureDumpOutput(queryLog);
+ verifyDumpOutput(output, {});
+
+ // Push another record to ensure it still works.
+ DnsQueryLog::Record r2(31, 1000, 1000, "example.com", serversV4V6, 10);
+ queryLog.push(std::move(r2));
+ output = captureDumpOutput(queryLog);
+ verifyDumpOutput(output, {31});
+}
+
+} // namespace android::net