Merge "onDnsEvent check in resolv_integration_test"
diff --git a/tests/dns_metrics_listener/dns_metrics_listener.cpp b/tests/dns_metrics_listener/dns_metrics_listener.cpp
index c3a15ed..1715118 100644
--- a/tests/dns_metrics_listener/dns_metrics_listener.cpp
+++ b/tests/dns_metrics_listener/dns_metrics_listener.cpp
@@ -16,9 +16,11 @@
#include "dns_metrics_listener.h"
-#include <android-base/chrono_utils.h>
#include <thread>
+#include <android-base/chrono_utils.h>
+#include <android-base/format.h>
+
namespace android {
namespace net {
namespace metrics {
@@ -29,6 +31,18 @@
constexpr milliseconds kRetryIntervalMs{20};
constexpr milliseconds kEventTimeoutMs{5000};
+bool DnsMetricsListener::DnsEvent::operator==(const DnsMetricsListener::DnsEvent& o) const {
+ return std::tie(netId, eventType, returnCode, hostname, ipAddresses, ipAddressesCount) ==
+ std::tie(o.netId, o.eventType, o.returnCode, o.hostname, o.ipAddresses,
+ o.ipAddressesCount);
+}
+
+std::ostream& operator<<(std::ostream& os, const DnsMetricsListener::DnsEvent& data) {
+ return os << fmt::format("[{}, {}, {}, {}, [{}], {}]", data.netId, data.eventType,
+ data.returnCode, data.hostname, fmt::join(data.ipAddresses, ", "),
+ data.ipAddressesCount);
+}
+
::ndk::ScopedAStatus DnsMetricsListener::onNat64PrefixEvent(int32_t netId, bool added,
const std::string& prefixString,
int32_t /*prefixLength*/) {
@@ -50,6 +64,19 @@
return ::ndk::ScopedAStatus::ok();
}
+::ndk::ScopedAStatus DnsMetricsListener::onDnsEvent(int32_t netId, int32_t eventType,
+ int32_t returnCode, int32_t /*latencyMs*/,
+ const std::string& hostname,
+ const std::vector<std::string>& ipAddresses,
+ int32_t ipAddressesCount, int32_t /*uid*/) {
+ std::lock_guard lock(mMutex);
+ if (netId == mNetId) {
+ mDnsEventRecords.push(
+ {netId, eventType, returnCode, hostname, ipAddresses, ipAddressesCount});
+ }
+ return ::ndk::ScopedAStatus::ok();
+}
+
bool DnsMetricsListener::waitForNat64Prefix(ExpectNat64PrefixStatus status, milliseconds timeout) {
android::base::Timer t;
while (t.duration() < timeout) {
@@ -91,6 +118,25 @@
return false;
}
+std::optional<DnsMetricsListener::DnsEvent> DnsMetricsListener::popDnsEvent() {
+ // Wait until the queue is not empty or timeout.
+ android::base::Timer t;
+ while (t.duration() < milliseconds{1000}) {
+ {
+ std::lock_guard lock(mMutex);
+ if (!mDnsEventRecords.empty()) break;
+ }
+ std::this_thread::sleep_for(kRetryIntervalMs);
+ }
+
+ std::lock_guard lock(mMutex);
+ if (mDnsEventRecords.empty()) return std::nullopt;
+
+ auto ret = mDnsEventRecords.front();
+ mDnsEventRecords.pop();
+ return ret;
+}
+
} // namespace metrics
} // namespace net
} // namespace android
diff --git a/tests/dns_metrics_listener/dns_metrics_listener.h b/tests/dns_metrics_listener/dns_metrics_listener.h
index 0b36462..ff71466 100644
--- a/tests/dns_metrics_listener/dns_metrics_listener.h
+++ b/tests/dns_metrics_listener/dns_metrics_listener.h
@@ -18,6 +18,7 @@
#include <condition_variable>
#include <map>
+#include <queue>
#include <utility>
#include <android-base/thread_annotations.h>
@@ -38,6 +39,20 @@
// verify the event count, the event change order, and so on.
class DnsMetricsListener : public BaseMetricsListener {
public:
+ struct DnsEvent {
+ int32_t netId;
+ int32_t eventType;
+ int32_t returnCode;
+ std::string hostname;
+ std::vector<std::string> ipAddresses;
+ int32_t ipAddressesCount;
+
+ bool operator==(const DnsEvent& o) const;
+
+ // Informative for debugging.
+ friend std::ostream& operator<<(std::ostream& os, const DnsEvent& data);
+ };
+
DnsMetricsListener() = delete;
DnsMetricsListener(int32_t netId) : mNetId(netId){};
@@ -50,6 +65,11 @@
const std::string& /*hostname*/,
bool validated) override;
+ ::ndk::ScopedAStatus onDnsEvent(int32_t netId, int32_t eventType, int32_t returnCode,
+ int32_t /*latencyMs*/, const std::string& hostname,
+ const std::vector<std::string>& ipAddresses,
+ int32_t ipAddressesCount, int32_t /*uid*/) override;
+
// Wait for expected NAT64 prefix status until timeout.
bool waitForNat64Prefix(ExpectNat64PrefixStatus status, std::chrono::milliseconds timeout)
EXCLUDES(mMutex);
@@ -70,10 +90,15 @@
return mValidationRecords.find({mNetId, serverAddr}) != mValidationRecords.end();
}
+ std::optional<DnsEvent> popDnsEvent() EXCLUDES(mMutex);
+
void reset() EXCLUDES(mMutex) {
std::lock_guard lock(mMutex);
mUnexpectedNat64PrefixUpdates = 0;
mValidationRecords.clear();
+
+ std::queue<DnsEvent> emptyQueue;
+ std::swap(mDnsEventRecords, emptyQueue);
}
private:
@@ -99,6 +124,9 @@
// Used to store the data from onPrivateDnsValidationEvent.
std::map<ServerKey, bool> mValidationRecords GUARDED_BY(mMutex);
+ // Used to store the data from onDnsEvent.
+ std::queue<DnsEvent> mDnsEventRecords GUARDED_BY(mMutex);
+
mutable std::mutex mMutex;
std::condition_variable mCv;
};
diff --git a/tests/resolv_integration_test.cpp b/tests/resolv_integration_test.cpp
index 236b031..fddb96e 100644
--- a/tests/resolv_integration_test.cpp
+++ b/tests/resolv_integration_test.cpp
@@ -61,6 +61,7 @@
#include "ResolverStats.h"
#include "netid_client.h" // NETID_UNSET
#include "params.h" // MAXNS
+#include "stats.h" // RCODE_TIMEOUT
#include "test_utils.h"
#include "tests/dns_metrics_listener/dns_metrics_listener.h"
#include "tests/dns_responder/dns_responder.h"
@@ -84,6 +85,7 @@
using aidl::android::net::IDnsResolver;
using aidl::android::net::INetd;
using aidl::android::net::ResolverParamsParcel;
+using aidl::android::net::metrics::INetdEventListener;
using android::base::ParseInt;
using android::base::StringPrintf;
using android::base::unique_fd;
@@ -230,6 +232,16 @@
return sDnsMetricsListener->findValidationRecord(serverAddr);
}
+ void ExpectDnsEvent(int32_t eventType, int32_t returnCode, const std::string& hostname,
+ const std::vector<std::string>& ipAddresses) {
+ const DnsMetricsListener::DnsEvent expect = {
+ TEST_NETID, eventType, returnCode,
+ hostname, ipAddresses, static_cast<int32_t>(ipAddresses.size())};
+ const auto dnsEvent = sDnsMetricsListener->popDnsEvent();
+ ASSERT_TRUE(dnsEvent.has_value());
+ EXPECT_EQ(dnsEvent.value(), expect);
+ }
+
bool expectStatsFromGetResolverInfo(const std::vector<NameserverStats>& nameserversStats) {
std::vector<std::string> res_servers;
std::vector<std::string> res_domains;
@@ -953,6 +965,7 @@
EXPECT_TRUE(result != nullptr);
EXPECT_EQ(1U, GetNumQueries(dns0, host_name1));
EXPECT_EQ(1U, GetNumQueries(dns1, host_name1));
+ ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, 0, host_name1, {"2001:db8::6"});
// Now make dns1 also ignore 100% requests... The resolve should alternate
// queries between the nameservers and fail
@@ -962,6 +975,7 @@
EXPECT_EQ(nullptr, result2);
EXPECT_EQ(1U, GetNumQueries(dns0, host_name2));
EXPECT_EQ(1U, GetNumQueries(dns1, host_name2));
+ ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, RCODE_TIMEOUT, host_name2, {});
}
TEST_F(ResolverTest, GetAddrInfoV6_concurrent) {
@@ -2170,6 +2184,12 @@
res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
EXPECT_GT(res, 0);
EXPECT_EQ("::1.2.3.4", toString(buf, res, AF_INET6));
+
+ // Trailing dot is removed. Is it intended?
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, 0, "howdy.example.com", {"::1.2.3.4"});
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, 0, "howdy.example.com", {"1.2.3.4"});
}
TEST_F(ResolverTest, Async_MalformedQuery) {
@@ -2452,6 +2472,8 @@
// expect no response
expectAnswersNotValid(fd1, -ETIMEDOUT);
expectAnswersNotValid(fd2, -ETIMEDOUT);
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
// No retry case, expect total 2 queries. The server is selected randomly.
EXPECT_EQ(2U, GetNumQueries(dns0, host_name) + GetNumQueries(dns1, host_name));
@@ -2468,6 +2490,8 @@
// expect no response
expectAnswersNotValid(fd1, -ETIMEDOUT);
expectAnswersNotValid(fd2, -ETIMEDOUT);
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
// Retry case, expect 4 queries
EXPECT_EQ(4U, GetNumQueries(dns0, host_name));
@@ -2707,10 +2731,13 @@
ASSERT_FALSE(h_result->h_addr_list[0] == nullptr);
EXPECT_EQ(ADDR4, ToString(h_result));
EXPECT_TRUE(h_result->h_addr_list[1] == nullptr);
+ ExpectDnsEvent(INetdEventListener::EVENT_GETHOSTBYNAME, 0, host_name, {ADDR4});
} else {
EXPECT_EQ(0U, GetNumQueriesForType(dns, ns_type::ns_t_a, host_name));
ASSERT_TRUE(h_result == nullptr);
ASSERT_EQ(HOST_NOT_FOUND, h_errno);
+ int returnCode = (config.edns == Edns::DROP) ? RCODE_TIMEOUT : EAI_FAIL;
+ ExpectDnsEvent(INetdEventListener::EVENT_GETHOSTBYNAME, returnCode, host_name, {});
}
} else if (config.method == GETADDRINFO) {
ScopedAddrinfo ai_result;
@@ -2721,9 +2748,12 @@
EXPECT_EQ(1U, GetNumQueries(dns, host_name));
const std::string result_str = ToString(ai_result);
EXPECT_EQ(ADDR4, result_str);
+ ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, 0, host_name, {ADDR4});
} else {
EXPECT_TRUE(ai_result == nullptr);
EXPECT_EQ(0U, GetNumQueries(dns, host_name));
+ int returnCode = (config.edns == Edns::DROP) ? RCODE_TIMEOUT : EAI_FAIL;
+ ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, returnCode, host_name, {});
}
} else {
FAIL() << "Unsupported query method: " << config.method;
@@ -4016,6 +4046,9 @@
memset(buf, 0, MAXPACKET);
res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
EXPECT_EQ(-ECONNREFUSED, res);
+
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, EAI_SYSTEM, "howdy.example.com", {});
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, EAI_SYSTEM, "howdy.example.com", {});
}
namespace {
@@ -4932,6 +4965,7 @@
EXPECT_NEAR(DNS_TIMEOUT_MS, timeTakenMs, TIMING_TOLERANCE_MS)
<< "took time should approximate equal timeout";
EXPECT_EQ(2U, GetNumQueries(neverRespondDns, host_name));
+ ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, RCODE_TIMEOUT, host_name, {});
}
TEST_F(ResolverTest, GetAddrInfoParallelLookupSleepTime) {