quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ares-test.h (29337B)


      1 /* MIT License
      2  *
      3  * Copyright (c) The c-ares project and its contributors
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a copy
      6  * of this software and associated documentation files (the "Software"), to deal
      7  * in the Software without restriction, including without limitation the rights
      8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9  * copies of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  *
     24  * SPDX-License-Identifier: MIT
     25  */
     26 // -*- mode: c++ -*-
     27 #ifndef ARES_TEST_H
     28 #define ARES_TEST_H
     29 
     30 #include "ares_setup.h"
     31 #include "dns-proto.h"
     32 // Include ares internal file for DNS protocol constants
     33 #include "ares_nameser.h"
     34 
     35 #include "gtest/gtest.h"
     36 #include "gmock/gmock.h"
     37 
     38 #if defined(HAVE_USER_NAMESPACE) && defined(HAVE_UTS_NAMESPACE)
     39 #  define HAVE_CONTAINER
     40 #endif
     41 
     42 #include <functional>
     43 #include <list>
     44 #include <map>
     45 #include <memory>
     46 #include <set>
     47 #include <string>
     48 #include <mutex>
     49 #include <thread>
     50 #include <utility>
     51 #include <vector>
     52 #include <chrono>
     53 
     54 #if defined(HAVE_CLOSESOCKET)
     55 #  define sclose(x) closesocket(x)
     56 #elif defined(HAVE_CLOSESOCKET_CAMEL)
     57 #  define sclose(x) CloseSocket(x)
     58 #elif defined(HAVE_CLOSE_S)
     59 #  define sclose(x) close_s(x)
     60 #else
     61 #  define sclose(x) close(x)
     62 #endif
     63 
     64 #ifndef HAVE_WRITEV
     65 extern "C" {
     66 /* Structure for scatter/gather I/O. */
     67 struct iovec {
     68   void  *iov_base; /* Pointer to data. */
     69   size_t iov_len;  /* Length of data.  */
     70 };
     71 };
     72 #endif
     73 
     74 namespace ares {
     75 
     76 typedef unsigned char byte;
     77 
     78 namespace test {
     79 
     80 extern bool                                    verbose;
     81 extern unsigned short                          mock_port;
     82 extern const std::vector<int>                  both_families;
     83 extern const std::vector<int>                  ipv4_family;
     84 extern const std::vector<int>                  ipv6_family;
     85 
     86 extern const std::vector<std::pair<int, bool>> both_families_both_modes;
     87 extern const std::vector<std::pair<int, bool>> ipv4_family_both_modes;
     88 extern const std::vector<std::pair<int, bool>> ipv6_family_both_modes;
     89 
     90 extern const std::vector<std::tuple<ares_evsys_t, int, bool>>
     91   all_evsys_ipv4_family_both_modes;
     92 extern const std::vector<std::tuple<ares_evsys_t, int, bool>>
     93   all_evsys_ipv6_family_both_modes;
     94 extern const std::vector<std::tuple<ares_evsys_t, int, bool>>
     95   all_evsys_both_families_both_modes;
     96 
     97 extern const std::vector<std::tuple<ares_evsys_t, int>> all_evsys_ipv4_family;
     98 extern const std::vector<std::tuple<ares_evsys_t, int>> all_evsys_ipv6_family;
     99 extern const std::vector<std::tuple<ares_evsys_t, int>> all_evsys_both_families;
    100 
    101 // Which parameters to use in tests
    102 extern std::vector<int>                                 families;
    103 extern std::vector<std::tuple<ares_evsys_t, int>>       evsys_families;
    104 extern std::vector<std::pair<int, bool>>                families_modes;
    105 extern std::vector<std::tuple<ares_evsys_t, int, bool>> evsys_families_modes;
    106 
    107 // Hopefully a more accurate sleep than sleep_for()
    108 void                    ares_sleep_time(unsigned int ms);
    109 
    110 // Process all pending work on ares-owned file descriptors, plus
    111 // optionally the given set-of-FDs + work function.
    112 void                    ProcessWork(ares_channel_t                          *channel,
    113                                     std::function<std::set<ares_socket_t>()> get_extrafds,
    114                                     std::function<void(ares_socket_t)>       process_extra,
    115                                     unsigned int                             cancel_ms = 0);
    116 std::set<ares_socket_t> NoExtraFDs();
    117 
    118 const char             *af_tostr(int af);
    119 const char             *mode_tostr(bool mode);
    120 std::string
    121   PrintFamilyMode(const testing::TestParamInfo<std::pair<int, bool>> &info);
    122 std::string PrintFamily(const testing::TestParamInfo<int> &info);
    123 
    124 // Test fixture that ensures library initialization, and allows
    125 // memory allocations to be failed.
    126 class LibraryTest : public ::testing::Test {
    127 public:
    128   LibraryTest()
    129   {
    130     EXPECT_EQ(ARES_SUCCESS, ares_library_init_mem(
    131                               ARES_LIB_INIT_ALL, &LibraryTest::amalloc,
    132                               &LibraryTest::afree, &LibraryTest::arealloc));
    133   }
    134 
    135   ~LibraryTest()
    136   {
    137     ares_library_cleanup();
    138     ClearFails();
    139   }
    140 
    141   // Set the n-th malloc call (of any size) from the library to fail.
    142   // (nth == 1 means the next call)
    143   static void  SetAllocFail(int nth);
    144   // Set the next malloc call for the given size to fail.
    145   static void  SetAllocSizeFail(size_t size);
    146   // Remove any pending alloc failures.
    147   static void  ClearFails();
    148 
    149   static void *amalloc(size_t size);
    150   static void *arealloc(void *ptr, size_t size);
    151   static void  afree(void *ptr);
    152 
    153   static void SetFailSend(void);
    154   static ares_ssize_t ares_sendv_fail(ares_socket_t socket, const struct iovec *vec, int len,
    155                                       void *user_data);
    156 
    157 
    158 private:
    159   static bool                  ShouldAllocFail(size_t size);
    160   static unsigned long long    fails_;
    161   static std::map<size_t, int> size_fails_;
    162   static std::mutex            lock_;
    163   static bool                  failsend_;
    164 };
    165 
    166 // Test fixture that uses a default channel.
    167 class DefaultChannelTest : public LibraryTest {
    168 public:
    169   DefaultChannelTest() : channel_(nullptr)
    170   {
    171     /* Enable query cache for live tests */
    172     struct ares_options opts;
    173     memset(&opts, 0, sizeof(opts));
    174     opts.qcache_max_ttl = 300;
    175     int optmask         = ARES_OPT_QUERY_CACHE;
    176     EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask));
    177     EXPECT_NE(nullptr, channel_);
    178   }
    179 
    180   ~DefaultChannelTest()
    181   {
    182     ares_destroy(channel_);
    183     channel_ = nullptr;
    184   }
    185 
    186   // Process all pending work on ares-owned file descriptors.
    187   void Process(unsigned int cancel_ms = 0);
    188 
    189 protected:
    190   ares_channel_t *channel_;
    191 };
    192 
    193 // Test fixture that uses a file-only channel.
    194 class FileChannelTest : public LibraryTest {
    195 public:
    196   FileChannelTest() : channel_(nullptr)
    197   {
    198     struct ares_options opts;
    199     memset(&opts, 0, sizeof(opts));
    200     opts.lookups = strdup("f");
    201     int optmask  = ARES_OPT_LOOKUPS;
    202     EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask));
    203     EXPECT_NE(nullptr, channel_);
    204     free(opts.lookups);
    205   }
    206 
    207   ~FileChannelTest()
    208   {
    209     ares_destroy(channel_);
    210     channel_ = nullptr;
    211   }
    212 
    213   // Process all pending work on ares-owned file descriptors.
    214   void Process(unsigned int cancel_ms = 0);
    215 
    216 protected:
    217   ares_channel_t *channel_;
    218 };
    219 
    220 // Test fixture that uses a default channel with the specified lookup mode.
    221 class DefaultChannelModeTest
    222   : public LibraryTest,
    223     public ::testing::WithParamInterface<std::string> {
    224 public:
    225   DefaultChannelModeTest() : channel_(nullptr)
    226   {
    227     struct ares_options opts;
    228     memset(&opts, 0, sizeof(opts));
    229     opts.lookups = strdup(GetParam().c_str());
    230     int optmask  = ARES_OPT_LOOKUPS;
    231     EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask));
    232     EXPECT_NE(nullptr, channel_);
    233     free(opts.lookups);
    234   }
    235 
    236   ~DefaultChannelModeTest()
    237   {
    238     ares_destroy(channel_);
    239     channel_ = nullptr;
    240   }
    241 
    242   // Process all pending work on ares-owned file descriptors.
    243   void Process(unsigned int cancel_ms = 0);
    244 
    245 protected:
    246   ares_channel_t *channel_;
    247 };
    248 
    249 // Mock DNS server to allow responses to be scripted by tests.
    250 class MockServer {
    251 public:
    252   MockServer(int family, unsigned short port);
    253   ~MockServer();
    254 
    255   // Mock method indicating the processing of a particular <name, RRtype>
    256   // request.
    257   MOCK_METHOD2(OnRequest, void(const std::string &name, int rrtype));
    258 
    259   // Set the reply to be sent next; the query ID field will be overwritten
    260   // with the value from the request.
    261   void SetReplyData(const std::vector<byte> &reply)
    262   {
    263     exact_reply_ = reply;
    264     reply_       = nullptr;
    265   }
    266 
    267   void SetReply(const DNSPacket *reply)
    268   {
    269     reply_ = reply;
    270     exact_reply_.clear();
    271   }
    272 
    273   // Set the reply to be sent next as well as the request (in string form) that
    274   // the server should expect to receive; the query ID field in the reply will
    275   // be overwritten with the value from the request.
    276   void SetReplyExpRequest(const DNSPacket *reply, const std::string &request)
    277   {
    278     expected_request_ = request;
    279     reply_            = reply;
    280   }
    281 
    282   void SetReplyQID(int qid)
    283   {
    284     qid_ = qid;
    285   }
    286 
    287   void Disconnect()
    288   {
    289     reply_ = nullptr;
    290     exact_reply_.clear();
    291     for (ares_socket_t fd : connfds_) {
    292       sclose(fd);
    293     }
    294     connfds_.clear();
    295     free(tcp_data_);
    296     tcp_data_     = NULL;
    297     tcp_data_len_ = 0;
    298   }
    299 
    300   // The set of file descriptors that the server handles.
    301   std::set<ares_socket_t> fds() const;
    302 
    303   // Process activity on a file descriptor.
    304   void                    ProcessFD(ares_socket_t fd);
    305 
    306   // Ports the server is responding to
    307   unsigned short          udpport() const
    308   {
    309     return udpport_;
    310   }
    311 
    312   unsigned short tcpport() const
    313   {
    314     return tcpport_;
    315   }
    316 
    317 private:
    318   void           ProcessRequest(ares_socket_t fd, struct sockaddr_storage *addr,
    319                                 ares_socklen_t addrlen, const std::vector<byte> &req,
    320                                 const std::string &reqstr, int qid, const char *name,
    321                                 int rrtype);
    322   void           ProcessPacket(ares_socket_t fd, struct sockaddr_storage *addr,
    323                                ares_socklen_t addrlen, byte *data, int len);
    324   unsigned short udpport_;
    325   unsigned short tcpport_;
    326   ares_socket_t  udpfd_;
    327   ares_socket_t  tcpfd_;
    328   std::set<ares_socket_t> connfds_;
    329   std::vector<byte>       exact_reply_;
    330   const DNSPacket        *reply_;
    331   std::string             expected_request_;
    332   int                     qid_;
    333   unsigned char          *tcp_data_;
    334   size_t                  tcp_data_len_;
    335 };
    336 
    337 // Test fixture that uses a mock DNS server.
    338 class MockChannelOptsTest : public LibraryTest {
    339 public:
    340   MockChannelOptsTest(int count, int family, bool force_tcp,
    341                       bool honor_sysconfig, struct ares_options *givenopts,
    342                       int optmask);
    343   ~MockChannelOptsTest();
    344 
    345   // Process all pending work on ares-owned and mock-server-owned file
    346   // descriptors.
    347   void ProcessAltChannel(ares_channel_t *chan, unsigned int cancel_ms = 0);
    348   void Process(unsigned int cancel_ms = 0);
    349 
    350 protected:
    351   // NiceMockServer doesn't complain about uninteresting calls.
    352   typedef testing::NiceMock<MockServer>                NiceMockServer;
    353   typedef std::vector<std::unique_ptr<NiceMockServer>> NiceMockServers;
    354 
    355   std::set<ares_socket_t>                              fds() const;
    356   void                   ProcessFD(ares_socket_t fd);
    357 
    358   static NiceMockServers BuildServers(int count, int family,
    359                                       unsigned short base_port);
    360 
    361   NiceMockServers        servers_;
    362   // Convenience reference to first server.
    363   NiceMockServer        &server_;
    364   ares_channel_t        *channel_;
    365 };
    366 
    367 class MockChannelTest
    368   : public MockChannelOptsTest,
    369     public ::testing::WithParamInterface<std::pair<int, bool>> {
    370 public:
    371   MockChannelTest()
    372     : MockChannelOptsTest(1, GetParam().first, GetParam().second, false,
    373                           nullptr, 0)
    374   {
    375   }
    376 };
    377 
    378 class MockUDPChannelTest : public MockChannelOptsTest,
    379                            public ::testing::WithParamInterface<int> {
    380 public:
    381   MockUDPChannelTest()
    382     : MockChannelOptsTest(1, GetParam(), false, false, nullptr, 0)
    383   {
    384   }
    385 };
    386 
    387 class MockTCPChannelTest : public MockChannelOptsTest,
    388                            public ::testing::WithParamInterface<int> {
    389 public:
    390   MockTCPChannelTest()
    391     : MockChannelOptsTest(1, GetParam(), true, false, nullptr, 0)
    392   {
    393   }
    394 };
    395 
    396 class MockEventThreadOptsTest : public MockChannelOptsTest {
    397 public:
    398   MockEventThreadOptsTest(int count, ares_evsys_t evsys, int family,
    399                           bool force_tcp, struct ares_options *givenopts,
    400                           int optmask)
    401     : MockChannelOptsTest(count, family, force_tcp, false,
    402                           FillOptionsET(&evopts_, givenopts, evsys),
    403                           optmask | ARES_OPT_EVENT_THREAD)
    404   {
    405   }
    406 
    407   ~MockEventThreadOptsTest()
    408   {
    409   }
    410 
    411   static struct ares_options *FillOptionsET(struct ares_options *opts,
    412                                             struct ares_options *givenopts,
    413                                             ares_evsys_t         evsys)
    414   {
    415     if (givenopts) {
    416       memcpy(opts, givenopts, sizeof(*opts));
    417     } else {
    418       memset(opts, 0, sizeof(*opts));
    419     }
    420     opts->evsys = evsys;
    421     return opts;
    422   }
    423 
    424   void Process(unsigned int cancel_ms = 0);
    425 
    426 private:
    427   struct ares_options evopts_;
    428 };
    429 
    430 class MockEventThreadTest
    431   : public MockEventThreadOptsTest,
    432     public ::testing::WithParamInterface<std::tuple<ares_evsys_t, int, bool>> {
    433 public:
    434   MockEventThreadTest()
    435     : MockEventThreadOptsTest(1, std::get<0>(GetParam()),
    436                               std::get<1>(GetParam()), std::get<2>(GetParam()),
    437                               nullptr, 0)
    438   {
    439   }
    440 };
    441 
    442 class MockUDPEventThreadTest
    443   : public MockEventThreadOptsTest,
    444     public ::testing::WithParamInterface<std::tuple<ares_evsys_t, int>> {
    445 public:
    446   MockUDPEventThreadTest()
    447     : MockEventThreadOptsTest(1, std::get<0>(GetParam()),
    448                               std::get<1>(GetParam()), false, nullptr, 0)
    449   {
    450   }
    451 };
    452 
    453 class MockTCPEventThreadTest
    454   : public MockEventThreadOptsTest,
    455     public ::testing::WithParamInterface<std::tuple<ares_evsys_t, int>> {
    456 public:
    457   MockTCPEventThreadTest()
    458     : MockEventThreadOptsTest(1, std::get<0>(GetParam()),
    459                               std::get<1>(GetParam()), true, nullptr, 0)
    460   {
    461   }
    462 };
    463 
    464 // gMock action to set the reply for a mock server.
    465 ACTION_P2(SetReplyData, mockserver, data)
    466 {
    467   mockserver->SetReplyData(data);
    468 }
    469 
    470 ACTION_P2(SetReplyAndFailSend, mockserver, reply)
    471 {
    472   mockserver->SetReply(reply);
    473   LibraryTest::SetFailSend();
    474 }
    475 
    476 ACTION_P2(SetReply, mockserver, reply)
    477 {
    478   mockserver->SetReply(reply);
    479 }
    480 
    481 // gMock action to set the reply for a mock server, as well as the request (in
    482 // string form) that the server should expect to receive.
    483 ACTION_P3(SetReplyExpRequest, mockserver, reply, request)
    484 {
    485   mockserver->SetReplyExpRequest(reply, request);
    486 }
    487 
    488 ACTION_P2(SetReplyQID, mockserver, qid)
    489 {
    490   mockserver->SetReplyQID(qid);
    491 }
    492 
    493 // gMock action to cancel a channel.
    494 ACTION_P2(CancelChannel, mockserver, channel)
    495 {
    496   ares_cancel(channel);
    497 }
    498 
    499 // gMock action to disconnect all connections.
    500 ACTION_P(Disconnect, mockserver)
    501 {
    502   mockserver->Disconnect();
    503 }
    504 
    505 // C++ wrapper for struct hostent.
    506 struct HostEnt {
    507   HostEnt() : addrtype_(-1)
    508   {
    509   }
    510 
    511   HostEnt(const struct hostent *hostent);
    512   std::string              name_;
    513   std::vector<std::string> aliases_;
    514   int                      addrtype_;  // AF_INET or AF_INET6
    515   std::vector<std::string> addrs_;
    516 };
    517 
    518 std::ostream &operator<<(std::ostream &os, const HostEnt &result);
    519 
    520 // Structure that describes the result of an ares_host_callback invocation.
    521 struct HostResult {
    522   HostResult() : done_(false), status_(0), timeouts_(0)
    523   {
    524   }
    525 
    526   // Whether the callback has been invoked.
    527   bool    done_;
    528   // Explicitly provided result information.
    529   int     status_;
    530   int     timeouts_;
    531   // Contents of the hostent structure, if provided.
    532   HostEnt host_;
    533 };
    534 
    535 std::ostream &operator<<(std::ostream &os, const HostResult &result);
    536 
    537 // C++ wrapper for ares_dns_record_t.
    538 struct AresDnsRecord {
    539   ~AresDnsRecord()
    540   {
    541     ares_dns_record_destroy(dnsrec_);
    542     dnsrec_ = NULL;
    543   }
    544 
    545   AresDnsRecord() : dnsrec_(NULL)
    546   {
    547   }
    548 
    549   void SetDnsRecord(const ares_dns_record_t *dnsrec)
    550   {
    551     if (dnsrec_ != NULL) {
    552       ares_dns_record_destroy(dnsrec_);
    553     }
    554     if (dnsrec == NULL) {
    555       return;
    556     }
    557     dnsrec_ = ares_dns_record_duplicate(dnsrec);
    558   }
    559 
    560   ares_dns_record_t *dnsrec_ = NULL;
    561 };
    562 
    563 std::ostream &operator<<(std::ostream &os, const AresDnsRecord &result);
    564 
    565 // Structure that describes the result of an ares_host_callback invocation.
    566 struct QueryResult {
    567   QueryResult() : done_(false), status_(ARES_SUCCESS), timeouts_(0)
    568   {
    569   }
    570 
    571   // Whether the callback has been invoked.
    572   bool          done_;
    573   // Explicitly provided result information.
    574   ares_status_t status_;
    575   size_t        timeouts_;
    576   // Contents of the ares_dns_record_t structure if provided
    577   AresDnsRecord dnsrec_;
    578 };
    579 
    580 std::ostream &operator<<(std::ostream &os, const QueryResult &result);
    581 
    582 // Structure that describes the result of an ares_callback invocation.
    583 struct SearchResult {
    584   // Whether the callback has been invoked.
    585   bool              done_;
    586   // Explicitly provided result information.
    587   int               status_;
    588   int               timeouts_;
    589   std::vector<byte> data_;
    590 };
    591 
    592 std::ostream &operator<<(std::ostream &os, const SearchResult &result);
    593 
    594 // Structure that describes the result of an ares_nameinfo_callback invocation.
    595 struct NameInfoResult {
    596   // Whether the callback has been invoked.
    597   bool        done_;
    598   // Explicitly provided result information.
    599   int         status_;
    600   int         timeouts_;
    601   std::string node_;
    602   std::string service_;
    603 };
    604 
    605 std::ostream &operator<<(std::ostream &os, const NameInfoResult &result);
    606 
    607 struct AddrInfoDeleter {
    608   void operator()(ares_addrinfo *ptr)
    609   {
    610     if (ptr) {
    611       ares_freeaddrinfo(ptr);
    612     }
    613   }
    614 };
    615 
    616 // C++ wrapper for struct ares_addrinfo.
    617 using AddrInfo = std::unique_ptr<ares_addrinfo, AddrInfoDeleter>;
    618 
    619 std::ostream &operator<<(std::ostream &os, const AddrInfo &result);
    620 
    621 // Structure that describes the result of an ares_addrinfo_callback invocation.
    622 struct AddrInfoResult {
    623   AddrInfoResult() : done_(false), status_(-1), timeouts_(0)
    624   {
    625   }
    626 
    627   // Whether the callback has been invoked.
    628   bool     done_;
    629   // Explicitly provided result information.
    630   int      status_;
    631   int      timeouts_;
    632   // Contents of the ares_addrinfo structure, if provided.
    633   AddrInfo ai_;
    634 };
    635 
    636 std::ostream &operator<<(std::ostream &os, const AddrInfoResult &result);
    637 
    638 // Standard implementation of ares callbacks that fill out the corresponding
    639 // structures.
    640 void          HostCallback(void *data, int status, int timeouts,
    641                            struct hostent *hostent);
    642 void          QueryCallback(void *data, ares_status_t status, size_t timeouts,
    643                             const ares_dns_record_t *dnsrec);
    644 void SearchCallback(void *data, int status, int timeouts, unsigned char *abuf,
    645                     int alen);
    646 void SearchCallbackDnsRec(void *data, ares_status_t status, size_t timeouts,
    647                           const ares_dns_record_t *dnsrec);
    648 void NameInfoCallback(void *data, int status, int timeouts, char *node,
    649                       char *service);
    650 void AddrInfoCallback(void *data, int status, int timeouts,
    651                       struct ares_addrinfo *res);
    652 
    653 // Retrieve the name servers used by a channel.
    654 std::string GetNameServers(ares_channel_t *channel);
    655 
    656 // RAII class to temporarily create a directory of a given name.
    657 class TransientDir {
    658 public:
    659   TransientDir(const std::string &dirname);
    660   ~TransientDir();
    661 
    662 private:
    663   std::string dirname_;
    664 };
    665 
    666 // C++ wrapper around tempnam()
    667 std::string TempNam(const char *dir, const char *prefix);
    668 
    669 // RAII class to temporarily create file of a given name and contents.
    670 class TransientFile {
    671 public:
    672   TransientFile(const std::string &filename, const std::string &contents);
    673   ~TransientFile();
    674 
    675 protected:
    676   std::string filename_;
    677 };
    678 
    679 // RAII class for a temporary file with the given contents.
    680 class TempFile : public TransientFile {
    681 public:
    682   TempFile(const std::string &contents);
    683 
    684   const char *filename() const
    685   {
    686     return filename_.c_str();
    687   }
    688 };
    689 
    690 #ifdef _WIN32
    691 extern "C" {
    692 
    693 static int setenv(const char *name, const char *value, int overwrite)
    694 {
    695   char  *buffer;
    696   size_t buf_size;
    697 
    698   if (name == NULL) {
    699     return -1;
    700   }
    701 
    702   if (value == NULL) {
    703     value = ""; /* For unset */
    704   }
    705 
    706   if (!overwrite && getenv(name) != NULL) {
    707     return -1;
    708   }
    709 
    710   buf_size = strlen(name) + strlen(value) + 1 /* = */ + 1 /* NULL */;
    711   buffer   = (char *)malloc(buf_size);
    712   _snprintf(buffer, buf_size, "%s=%s", name, value);
    713   _putenv(buffer);
    714   free(buffer);
    715   return 0;
    716 }
    717 
    718 static int unsetenv(const char *name)
    719 {
    720   return setenv(name, NULL, 1);
    721 }
    722 
    723 } /* extern "C" */
    724 #endif
    725 
    726 // RAII class for a temporary environment variable value.
    727 class EnvValue {
    728 public:
    729   EnvValue(const char *name, const char *value) : name_(name), restore_(false)
    730   {
    731     char *original = getenv(name);
    732     if (original) {
    733       restore_  = true;
    734       original_ = original;
    735     }
    736     setenv(name_.c_str(), value, 1);
    737   }
    738 
    739   ~EnvValue()
    740   {
    741     if (restore_) {
    742       setenv(name_.c_str(), original_.c_str(), 1);
    743     } else {
    744       unsetenv(name_.c_str());
    745     }
    746   }
    747 
    748 private:
    749   std::string name_;
    750   bool        restore_;
    751   std::string original_;
    752 };
    753 
    754 
    755 #ifdef HAVE_CONTAINER
    756 // Linux-specific functionality for running code in a container, implemented
    757 // in ares-test-ns.cc
    758 typedef std::function<int(void)>                         VoidToIntFn;
    759 typedef std::vector<std::pair<std::string, std::string>> NameContentList;
    760 
    761 class ContainerFilesystem {
    762 public:
    763   ContainerFilesystem(NameContentList files, const std::string &mountpt);
    764   ~ContainerFilesystem();
    765 
    766   std::string root() const
    767   {
    768     return rootdir_;
    769   }
    770 
    771   std::string mountpt() const
    772   {
    773     return mountpt_;
    774   }
    775 
    776 private:
    777   void                   EnsureDirExists(const std::string &dir);
    778   std::string            rootdir_;
    779   std::string            mountpt_;
    780   std::list<std::string> dirs_;
    781   std::vector<std::unique_ptr<TransientFile>> files_;
    782 };
    783 
    784 int RunInContainer(ContainerFilesystem *fs, const std::string &hostname,
    785                    const std::string &domainname, VoidToIntFn fn);
    786 
    787 #  define ICLASS_NAME(casename, testname) Contained##casename##_##testname
    788 #  define CONTAINED_TEST_F(casename, testname, hostname, domainname, files)   \
    789     class ICLASS_NAME(casename, testname) : public casename {                 \
    790     public:                                                                   \
    791       ICLASS_NAME(casename, testname)()                                       \
    792       {                                                                       \
    793       }                                                                       \
    794       static int InnerTestBody();                                             \
    795     };                                                                        \
    796     TEST_F(ICLASS_NAME(casename, testname), _)                                \
    797     {                                                                         \
    798       ContainerFilesystem chroot(files, "..");                                \
    799       VoidToIntFn         fn(ICLASS_NAME(casename, testname)::InnerTestBody); \
    800       EXPECT_EQ(0, RunInContainer(&chroot, hostname, domainname, fn));        \
    801     }                                                                         \
    802     int ICLASS_NAME(casename, testname)::InnerTestBody()
    803 
    804 
    805 /* Derived from googletest/include/gtest/gtest-param-test.h, specifically the
    806  * TEST_P() macro, and some fixes to try to be compatible with different
    807  * versions. */
    808 #  ifndef GTEST_ATTRIBUTE_UNUSED_
    809 #    define GTEST_ATTRIBUTE_UNUSED_
    810 #  endif
    811 #  ifndef GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED
    812 #    define GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED
    813 #  endif
    814 #  define CONTAINED_TEST_P(test_suite_name, test_name, hostname, domainname, \
    815                            files)                                            \
    816     class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)                 \
    817       : public test_suite_name {                                             \
    818     public:                                                                  \
    819       GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)()                   \
    820       {                                                                      \
    821       }                                                                      \
    822       int  InnerTestBody();                                                  \
    823       void TestBody()                                                        \
    824       {                                                                      \
    825         ContainerFilesystem chroot(files, "..");                             \
    826         VoidToIntFn         fn = [this](void) -> int {                       \
    827           ares_reinit(this->channel_);                               \
    828           ares_sleep_time(100);                                      \
    829           return this->InnerTestBody();                              \
    830         };                                                                   \
    831         EXPECT_EQ(0, RunInContainer(&chroot, hostname, domainname, fn));     \
    832       }                                                                      \
    833                                                                              \
    834     private:                                                                 \
    835       static int AddToRegistry()                                             \
    836       {                                                                      \
    837         ::testing::UnitTest::GetInstance()                                   \
    838           ->parameterized_test_registry()                                    \
    839           .GetTestSuitePatternHolder<test_suite_name>(                       \
    840             GTEST_STRINGIFY_(test_suite_name),                               \
    841             ::testing::internal::CodeLocation(__FILE__, __LINE__))           \
    842           ->AddTestPattern(                                                  \
    843             GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name),  \
    844             new ::testing::internal::TestMetaFactory<GTEST_TEST_CLASS_NAME_( \
    845               test_suite_name, test_name)>(),                                \
    846             ::testing::internal::CodeLocation(__FILE__, __LINE__));          \
    847         return 0;                                                            \
    848       }                                                                      \
    849       GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static int                       \
    850         gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_;                    \
    851     };                                                                       \
    852     int GTEST_TEST_CLASS_NAME_(test_suite_name,                              \
    853                                test_name)::gtest_registering_dummy_ =        \
    854       GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry();   \
    855     int GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::InnerTestBody()
    856 
    857 #endif
    858 
    859 /* Assigns virtual IO functions to a channel. These functions simply call
    860  * the actual system functions.
    861  */
    862 class VirtualizeIO {
    863 public:
    864   VirtualizeIO(ares_channel);
    865   ~VirtualizeIO();
    866 
    867   static const ares_socket_functions default_functions;
    868 
    869 private:
    870   ares_channel_t *channel_;
    871 };
    872 
    873 /*
    874  * Slightly white-box macro to generate two runs for a given test case:
    875  * One with no modifications, and one with all IO functions set to use
    876  * the virtual io structure.
    877  * Since no magic socket setup or anything is done in the latter case
    878  * this should probably only be used for test with very vanilla IO
    879  * requirements.
    880  */
    881 #define VCLASS_NAME(casename, testname) Virt##casename##_##testname
    882 #define VIRT_NONVIRT_TEST_F(casename, testname)                    \
    883   class VCLASS_NAME(casename, testname) : public casename {        \
    884   public:                                                          \
    885     VCLASS_NAME(casename, testname)()                              \
    886     {                                                              \
    887     }                                                              \
    888     void InnerTestBody();                                          \
    889   };                                                               \
    890   GTEST_TEST_(casename, testname, VCLASS_NAME(casename, testname), \
    891               ::testing::internal::GetTypeId<casename>())          \
    892   {                                                                \
    893     InnerTestBody();                                               \
    894   }                                                                \
    895   GTEST_TEST_(casename, testname##_virtualized,                    \
    896               VCLASS_NAME(casename, testname),                     \
    897               ::testing::internal::GetTypeId<casename>())          \
    898   {                                                                \
    899     VirtualizeIO vio(channel_);                                    \
    900     InnerTestBody();                                               \
    901   }                                                                \
    902   void VCLASS_NAME(casename, testname)::InnerTestBody()
    903 
    904 }  // namespace test
    905 }  // namespace ares
    906 
    907 #endif