Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 21c0f836 authored by Hungming Chen's avatar Hungming Chen
Browse files

resolv_gold_test: Use proto text file to store test data

Wrap DNS query API arguments and its corresponding DNS packets
from real life network into proto text file. The proto text
file is used to be gold test data.

Test: cd packages/modules/DnsResolver && atest
Change-Id: If3e73fee093c6e2228950c61ec11050f90f9b770
parent f9cd4ebc
Loading
Loading
Loading
Loading
+15 −1
Original line number Original line Diff line number Diff line
@@ -19,11 +19,24 @@ cc_test_library {
    ],
    ],
}
}


cc_library_static {
    name: "golddata_proto",
    defaults: ["netd_defaults"],
    proto: {
        export_proto_headers: true,
        type: "full",
    },
    srcs: [
        "golddata.proto",
    ],
}

cc_test {
cc_test {
    name: "resolv_gold_test",
    name: "resolv_gold_test",
    test_suites: ["device-tests"],
    test_suites: ["device-tests"],
    require_root: true,
    require_root: true,
    defaults: ["netd_defaults"],
    defaults: ["netd_defaults"],
    data: ["testdata/*.pbtxt"],
    srcs: [
    srcs: [
        "resolv_gold_test.cpp",
        "resolv_gold_test.cpp",
    ],
    ],
@@ -32,11 +45,12 @@ cc_test {
    ],
    ],
    shared_libs: [
    shared_libs: [
        "libcrypto",
        "libcrypto",
        "libprotobuf-cpp-lite",
        "libprotobuf-cpp-full",
        "libssl",
        "libssl",
    ],
    ],
    static_libs: [
    static_libs: [
        "dnsresolver_aidl_interface-cpp",
        "dnsresolver_aidl_interface-cpp",
        "golddata_proto",
        "libbase",
        "libbase",
        "libgmock",
        "libgmock",
        "liblog",
        "liblog",

tests/golddata.proto

0 → 100644
+195 −0
Original line number Original line Diff line number Diff line
/*
 * 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.
 */

syntax = "proto3";
package android.net;

// Used to indicate which call is invoked to send DNS lookups.
enum CallType {
    CALL_GETADDRINFO = 0;
    CALL_GETHOSTBYNAME = 1;
    CALL_GETHOSTBYADDR = 2;
    CALL_GETNAMEINFO = 3;
    CALL_RES_NSEND = 4;
}

// Values from bionic/libc/include/sys/socket.h
enum AddressFamily {
    option allow_alias = true;  // for AF_ROUTE = AF_NETLINK

    GT_AF_UNSPEC = 0;
    GT_AF_UNIX = 1;
    GT_AF_LOCAL = 1;
    GT_AF_INET = 2;
    GT_AF_AX25 = 3;
    GT_AF_IPX = 4;
    GT_AF_APPLETALK = 5;
    GT_AF_NETROM = 6;
    GT_AF_BRIDGE = 7;
    GT_AF_ATMPVC= 8;
    GT_AF_X25 = 9;
    GT_AF_INET6 = 10;
    GT_AF_ROSE = 11;
    GT_AF_DECnet = 12;
    GT_AF_NETBEUI = 13;
    GT_AF_SECURITY = 14;
    GT_AF_KEY = 15;
    GT_AF_NETLINK = 16;
    GT_AF_ROUTE = 16;  // AF_NETLINK
    GT_AF_PACKET = 17;
    GT_AF_ASH = 18;
    GT_AF_ECONET = 19;
    GT_AF_ATMSVC = 20;
    GT_AF_RDS = 21;
    GT_AF_SNA = 22;
    GT_AF_IRDA = 23;
    GT_AF_PPPOX = 24;
    GT_AF_WANPIPE = 25;
    GT_AF_LLC = 26;
    GT_AF_CAN = 29;
    GT_AF_TIPC = 30;
    GT_AF_BLUETOOTH = 31;
    GT_AF_IUCV = 32;
    GT_AF_RXRPC = 33;
    GT_AF_ISDN = 34;
    GT_AF_PHONET = 35;
    GT_AF_IEEE802154 = 36;
    GT_AF_CAIF = 37;
    GT_AF_ALG = 38;
    GT_AF_NFC = 39;
    GT_AF_VSOCK = 40;
    GT_AF_KCM = 41;
    GT_AF_QIPCRTR = 42;
    GT_AF_MAX = 43;
}

// Values from bionic/libc/include/sys/socket.h
enum SocketType {
    GT_SOCK_ANY = 0;  // See man getaddrinfo for more detail
    GT_SOCK_STREAM = 1;
    GT_SOCK_DGRAM = 2;
    GT_SOCK_RAW = 3;
    GT_SOCK_RDM = 4;
    GT_SOCK_SEQPACKET = 5;
    GT_SOCK_DCCP = 6;
    GT_SOCK_PACKET = 10;
}

// Values from bionic/libc/kernel/uapi/linux/in.h
enum ProtocolType {
    GT_IPPROTO_IP = 0;
    GT_IPPROTO_ICMP = 1;
    GT_IPPROTO_IGMP = 2;
    GT_IPPROTO_IPIP = 4;
    GT_IPPROTO_TCP = 6;
    GT_IPPROTO_EGP = 8;
    GT_IPPROTO_PUP = 12;
    GT_IPPROTO_UDP = 17;
    GT_IPPROTO_IDP = 22;
    GT_IPPROTO_TP = 29;
    GT_IPPROTO_DCCP = 33;
    GT_IPPROTO_IPV6 = 41;
    GT_IPPROTO_RSVP = 46;
    GT_IPPROTO_GRE = 47;
    GT_IPPROTO_ESP = 50;
    GT_IPPROTO_AH = 51;
    GT_IPPROTO_MTP = 92;
    GT_IPPROTO_BEETPH = 94;
    GT_IPPROTO_ENCAP = 98;
    GT_IPPROTO_PIM = 103;
    GT_IPPROTO_COMP = 108;
    GT_IPPROTO_SCTP = 132;
    GT_IPPROTO_UDPLITE = 136;
    GT_IPPROTO_MPLS = 137;
    GT_IPPROTO_RAW = 255;
    GT_IPPROTO_MAX = 256;
}

// The return value of the DNS resolver for each DNS lookups.
// Values from bionic/libc/include/netdb.h
// Values from system/netd/resolv/include/netd_resolv/resolv.h
enum ReturnCodeType {
    GT_EAI_NO_ERROR = 0;
    GT_EAI_ADDRFAMILY = 1;
    GT_EAI_AGAIN = 2;
    GT_EAI_BADFLAGS = 3;
    GT_EAI_FAIL = 4;
    GT_EAI_FAMILY = 5;
    GT_EAI_MEMORY = 6;
    GT_EAI_NODATA = 7;
    GT_EAI_NONAME = 8;
    GT_EAI_SERVICE = 9;
    GT_EAI_SOCKTYPE = 10;
    GT_EAI_SYSTEM = 11;
    GT_EAI_BADHINTS = 12;
    GT_EAI_PROTOCOL = 13;
    GT_EAI_OVERFLOW = 14;
    GT_RESOLV_TIMEOUT = 255;
    GT_EAI_MAX = 256;
}

// Describes the test configuration and expected result for gold test.
// The unit test files a DNS query by the predefined |config|. Expect that the resolver sends the
// query packet as the predefined packet in |packet_mapping.query|. When the DNS responser receives
// the query packet, it returns the corresponding response packet from |packet_mapping.response|.
// Finally, the unit test checks the return values if they are the same as |result|. Currently,
// support getaddrinfo only.
// TODO: Support gethostbyname, gethostbyaddr, and getnameinfo.
message GoldTest {
    // The configuration of various DNS query calls.
    message Config {
        // The arguments used to send a DNS query by call type CALL_GETADDRINFO.
        message AddrInfo {
            string host = 1;
            AddressFamily family = 2;
            SocketType socktype = 3;
            ProtocolType protocol = 4;
            int32 ai_flags = 5;
        }

        // The call is used to send DNS lookups.
        CallType call = 1;

        // The arguments are used by the call.
        oneof Arg {
            // The arguments of call type CALL_GETADDRINFO.
            AddrInfo addrinfo = 2;
        }
    };

    // The result is expected in DNS lookups.
    message Result {
        ReturnCodeType return_code = 1;
        repeated string addresses = 2;
    };

    // Describes how the DNS responser handles and responses the DNS lookup packets.
    message PacketMapping {
      bytes query = 1;
      bytes response = 2;
    }

    // Configs used to send a DNS query via a DNS query API.
    Config config = 1;

    // Expected return values from DNS query API.
    Result result = 2;

    // Used to build the packet mapping (query, response) in DNS responser. See also
    // addMappingBinaryPacket() in
    // packages/modules/DnsResolver/tests/dns_responder/dns_responder.cpp.
    repeated PacketMapping packet_mapping = 3;
}
 No newline at end of file
+77 −2
Original line number Original line Diff line number Diff line
@@ -17,11 +17,14 @@


#define LOG_TAG "resolv_gold_test"
#define LOG_TAG "resolv_gold_test"


#include <android-base/file.h>
#include <gmock/gmock-matchers.h>
#include <gmock/gmock-matchers.h>
#include <google/protobuf/text_format.h>
#include <gtest/gtest.h>
#include <gtest/gtest.h>


#include "dns_responder/dns_responder.h"
#include "dns_responder/dns_responder.h"
#include "getaddrinfo.h"
#include "getaddrinfo.h"
#include "golddata.pb.h"
#include "resolv_cache.h"
#include "resolv_cache.h"
#include "resolv_test_utils.h"
#include "resolv_test_utils.h"


@@ -68,6 +71,7 @@ static const std::vector<uint8_t> kHelloExampleComResponseV4 = {
        0x01, 0x02, 0x03, 0x04  /* Address: 1.2.3.4 */
        0x01, 0x02, 0x03, 0x04  /* Address: 1.2.3.4 */
};
};


// Fixture test class definition.
class TestBase : public ::testing::Test {
class TestBase : public ::testing::Test {
  protected:
  protected:
    void SetUp() override {
    void SetUp() override {
@@ -86,6 +90,8 @@ class TestBase : public ::testing::Test {
        return resolv_set_nameservers(TEST_NETID, servers, domains, kParams);
        return resolv_set_nameservers(TEST_NETID, servers, domains, kParams);
    }
    }


    const std::string kTestPath = android::base::GetExecutableDirectory();
    const std::string kTestDataPath = kTestPath + "/testdata/";
    static constexpr res_params kParams = {
    static constexpr res_params kParams = {
            .sample_validity = 300,
            .sample_validity = 300,
            .success_threshold = 25,
            .success_threshold = 25,
@@ -94,7 +100,6 @@ class TestBase : public ::testing::Test {
            .base_timeout_msec = 1000,
            .base_timeout_msec = 1000,
            .retry_count = 2,
            .retry_count = 2,
    };
    };

    static constexpr android_net_context kNetcontext = {
    static constexpr android_net_context kNetcontext = {
            .app_netid = TEST_NETID,
            .app_netid = TEST_NETID,
            .app_mark = MARK_UNSET,
            .app_mark = MARK_UNSET,
@@ -103,9 +108,23 @@ class TestBase : public ::testing::Test {
            .uid = NET_CONTEXT_INVALID_UID,
            .uid = NET_CONTEXT_INVALID_UID,
    };
    };
};
};

class ResolvGetAddrInfo : public TestBase {};
class ResolvGetAddrInfo : public TestBase {};


// Parameterized test class definition.
class ResolvGoldTest : public TestBase, public ::testing::WithParamInterface<std::string> {};

// GetAddrInfo tests.
INSTANTIATE_TEST_SUITE_P(GetAddrInfo, ResolvGoldTest,
                         ::testing::Values(std::string("getaddrinfo.topsite.google.pbtxt")),
                         [](const ::testing::TestParamInfo<std::string>& info) {
                             std::string name = info.param;
                             std::replace_if(
                                     std::begin(name), std::end(name),
                                     [](char ch) { return !std::isalnum(ch); }, '_');
                             return name;
                         });

// Fixture tests.
TEST_F(ResolvGetAddrInfo, RemovePacketMapping) {
TEST_F(ResolvGetAddrInfo, RemovePacketMapping) {
    test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET);
    test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET);
    ASSERT_TRUE(dns.startServer());
    ASSERT_TRUE(dns.startServer());
@@ -183,5 +202,61 @@ TEST_F(ResolvGetAddrInfo, ReplacePacketMapping) {
    EXPECT_EQ("5.6.7.8", ToString(result));
    EXPECT_EQ("5.6.7.8", ToString(result));
}
}


// Parameterized tests.
TEST_P(ResolvGoldTest, GoldData) {
    const auto& testFile = GetParam();

    // Convert the testing configuration from .pbtxt file to proto.
    std::string file_content;
    ASSERT_TRUE(android::base::ReadFileToString(kTestDataPath + testFile, &file_content))
            << strerror(errno);
    android::net::GoldTest goldtest;
    ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(file_content, &goldtest));
    ASSERT_EQ(android::net::CallType::CALL_GETADDRINFO, goldtest.config().call());
    ASSERT_TRUE(goldtest.config().has_addrinfo());

    test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET);
    ASSERT_TRUE(dns.startServer());
    ASSERT_EQ(0, SetResolvers());

    // Register packet mapping (query, response) from proto.
    for (const auto& m : goldtest.packet_mapping()) {
        // Convert string to bytes because .proto type "bytes" is "string" type in C++.
        // See also the section "Scalar Value Types" in "Language Guide (proto3)".
        dns.addMappingBinaryPacket(std::vector<uint8_t>(m.query().begin(), m.query().end()),
                                   std::vector<uint8_t>(m.response().begin(), m.response().end()));
    }

    addrinfo* res = nullptr;
    const auto& args = goldtest.config().addrinfo();
    const addrinfo hints = {
            .ai_family = args.family(),
            .ai_socktype = args.socktype(),
            .ai_protocol = args.protocol(),
            // Clear the flag AI_ADDRCONFIG to avoid flaky test because AI_ADDRCONFIG looks at
            // whether connectivity is available. It makes that the resolver may send only A
            // or AAAA DNS query per connectivity even AF_UNSPEC has been assigned. See also
            // have_ipv6() and have_ipv4() in packages/modules/DnsResolver/getaddrinfo.cpp.
            // TODO: Consider keeping the configuration flag AI_ADDRCONFIG once the unit
            // test can treat the IPv4 and IPv6 connectivity.
            .ai_flags = args.ai_flags() & ~AI_ADDRCONFIG,
    };
    NetworkDnsEventReported event;
    int rv = resolv_getaddrinfo(args.host().c_str(), nullptr, &hints, &kNetcontext, &res, &event);
    ScopedAddrinfo result(res);
    ASSERT_EQ(goldtest.result().return_code(), rv);

    if (goldtest.result().return_code() != GT_EAI_NO_ERROR) {
        ASSERT_EQ(nullptr, result);
    } else {
        ASSERT_NE(nullptr, result);
        const auto& addresses = goldtest.result().addresses();
        EXPECT_THAT(ToStrings(result),
                    ::testing::UnorderedElementsAreArray(
                            std::vector<std::string>(addresses.begin(), addresses.end())));
    }
    EXPECT_EQ((hints.ai_family == AF_UNSPEC) ? 2U : 1U, GetNumQueries(dns, args.host().c_str()));
}

}  // end of namespace net
}  // end of namespace net
}  // end of namespace android
}  // end of namespace android
+86 −0
Original line number Original line Diff line number Diff line
# Location: Tokyo, Japan
# Network: IIJ Mobile
# Date: 16 AUG 2019

config {
    call: CALL_GETADDRINFO
    addrinfo {
        host: "www.google.com."
        family: GT_AF_UNSPEC
        socktype: GT_SOCK_DGRAM
        protocol: GT_IPPROTO_IP
        ai_flags: 1024
    };
}
result {
    return_code: GT_EAI_NO_ERROR
    addresses: "2404:6800:4004:80f::2004"
    addresses: "172.217.26.4"
}
packet_mapping {
    query:    # Header
              "\x00\x00"         # Transaction ID: 0x0000
              "\x01\x00"         # Flags: rd
              "\x00\x01"         # Questions: 1
              "\x00\x00"         # Answer RRs: 0
              "\x00\x00"         # Authority RRs: 0
              "\x00\x00"         # Additional RRs: 0
              # Queries
              "\x03\x77\x77\x77\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00"
                                 # Name: www.google.com
              "\x00\x1c"         # Type: AAAA
              "\x00\x01"         # Class: IN
    response: # Header
              "\x00\x00"         # Transaction ID: 0x0000
              "\x81\x80"         # Flags: qr rd ra
              "\x00\x01"         # Questions: 1
              "\x00\x01"         # Answer RRs: 1
              "\x00\x00"         # Authority RRs: 0
              "\x00\x00"         # Additional RRs: 0
              # Queries
              "\x03\x77\x77\x77\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00"
                                 # Name: www.google.com
              "\x00\x1c"         # Type: AAAA
              "\x00\x01"         # Class: IN
              # Answers
              "\xc0\x0c"         # Name: www.google.com
              "\x00\x1c"         # Type: AAAA
              "\x00\x01"         # Class: IN
              "\x00\x00\x00\xee" # Time to live: 238
              "\x00\x10"         # Data length: 16
              "\x24\x04\x68\x00\x40\x04\x08\x0f\x00\x00\x00\x00\x00\x00\x20\x04"
                                 # Address: 2404:6800:4004:80f::2004
}
packet_mapping {
    query:    # Header
              "\x00\x00"         # Transaction ID: 0x0000
              "\x01\x00"         # Flags: rd
              "\x00\x01"         # Questions: 1
              "\x00\x00"         # Answer RRs: 0
              "\x00\x00"         # Authority RRs: 0
              "\x00\x00"         # Additional RRs: 0
              # Queries
              "\x03\x77\x77\x77\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00"
                                 # Name: www.google.com
              "\x00\x01"         # Type: A
              "\x00\x01"         # Class: IN
    response: # Header
              "\x00\x00"         # Transaction ID: 0x0000
              "\x81\x80"         # Flags: qr rd ra
              "\x00\x01"         # Questions: 1
              "\x00\x01"         # Answer RRs: 1
              "\x00\x00"         # Authority RRs: 0
              "\x00\x00"         # Additional RRs: 0
              # Queries
              "\x03\x77\x77\x77\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00"
                                 # Name: www.google.com
              "\x00\x01"         # Type: A
              "\x00\x01"         # Class: IN
              # Answers
              "\xc0\x0c"         # Name: www.google.com
              "\x00\x01"         # Type: A
              "\x00\x01"         # Class: IN
              "\x00\x00\x00\x03" # Time to live: 3
              "\x00\x04"         # Data length: 4
              "\xac\xd9\x1a\x04" # Address: 172.217.26.4
}
 No newline at end of file