5 #include "ares_setup.h"
9 // Include ares internal file for DNS protocol constants
10 #include "ares_nameser.h"
12 #include "gtest/gtest.h"
13 #include "gmock/gmock.h"
18 #if defined(HAVE_USER_NAMESPACE) && defined(HAVE_UTS_NAMESPACE)
19 #define HAVE_CONTAINER
33 typedef unsigned char byte;
39 extern const std::vector<int> both_families;
40 extern const std::vector<int> ipv4_family;
41 extern const std::vector<int> ipv6_family;
43 extern const std::vector<std::pair<int, bool>> both_families_both_modes;
44 extern const std::vector<std::pair<int, bool>> ipv4_family_both_modes;
45 extern const std::vector<std::pair<int, bool>> ipv6_family_both_modes;
47 // Which parameters to use in tests
48 extern std::vector<int> families;
49 extern std::vector<std::pair<int, bool>> families_modes;
51 // Process all pending work on ares-owned file descriptors, plus
52 // optionally the given set-of-FDs + work function.
53 void ProcessWork(ares_channel channel,
54 std::function<std::set<int>()> get_extrafds,
55 std::function<void(int)> process_extra);
56 std::set<int> NoExtraFDs();
58 // Test fixture that ensures library initialization, and allows
59 // memory allocations to be failed.
60 class LibraryTest : public ::testing::Test {
63 EXPECT_EQ(ARES_SUCCESS,
64 ares_library_init_mem(ARES_LIB_INIT_ALL,
65 &LibraryTest::amalloc,
67 &LibraryTest::arealloc));
70 ares_library_cleanup();
73 // Set the n-th malloc call (of any size) from the library to fail.
74 // (nth == 1 means the next call)
75 static void SetAllocFail(int nth);
76 // Set the next malloc call for the given size to fail.
77 static void SetAllocSizeFail(size_t size);
78 // Remove any pending alloc failures.
79 static void ClearFails();
81 static void *amalloc(size_t size);
82 static void* arealloc(void *ptr, size_t size);
83 static void afree(void *ptr);
85 static bool ShouldAllocFail(size_t size);
86 static unsigned long long fails_;
87 static std::map<size_t, int> size_fails_;
90 // Test fixture that uses a default channel.
91 class DefaultChannelTest : public LibraryTest {
93 DefaultChannelTest() : channel_(nullptr) {
94 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel_));
95 EXPECT_NE(nullptr, channel_);
98 ~DefaultChannelTest() {
99 ares_destroy(channel_);
103 // Process all pending work on ares-owned file descriptors.
107 ares_channel channel_;
110 // Test fixture that uses a default channel with the specified lookup mode.
111 class DefaultChannelModeTest
112 : public LibraryTest,
113 public ::testing::WithParamInterface<std::string> {
115 DefaultChannelModeTest() : channel_(nullptr) {
116 struct ares_options opts = {0};
117 opts.lookups = strdup(GetParam().c_str());
118 int optmask = ARES_OPT_LOOKUPS;
119 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask));
120 EXPECT_NE(nullptr, channel_);
124 ~DefaultChannelModeTest() {
125 ares_destroy(channel_);
129 // Process all pending work on ares-owned file descriptors.
133 ares_channel channel_;
136 // Mock DNS server to allow responses to be scripted by tests.
139 MockServer(int family, int port);
142 // Mock method indicating the processing of a particular <name, RRtype>
144 MOCK_METHOD2(OnRequest, void(const std::string& name, int rrtype));
146 // Set the reply to be sent next; the query ID field will be overwritten
147 // with the value from the request.
148 void SetReplyData(const std::vector<byte>& reply) { reply_ = reply; }
149 void SetReply(const DNSPacket* reply) { SetReplyData(reply->data()); }
150 void SetReplyQID(int qid) { qid_ = qid; }
152 // The set of file descriptors that the server handles.
153 std::set<int> fds() const;
155 // Process activity on a file descriptor.
156 void ProcessFD(int fd);
158 // Ports the server is responding to
159 int udpport() const { return udpport_; }
160 int tcpport() const { return tcpport_; }
163 void ProcessRequest(int fd, struct sockaddr_storage* addr, int addrlen,
164 int qid, const std::string& name, int rrtype);
165 void ProcessPacket(int fd, struct sockaddr_storage *addr, socklen_t addrlen,
166 byte *data, int len);
171 std::set<int> connfds_;
172 std::vector<byte> reply_;
176 // Test fixture that uses a mock DNS server.
177 class MockChannelOptsTest : public LibraryTest {
179 MockChannelOptsTest(int count, int family, bool force_tcp, struct ares_options* givenopts, int optmask);
180 ~MockChannelOptsTest();
182 // Process all pending work on ares-owned and mock-server-owned file descriptors.
186 // NiceMockServer doesn't complain about uninteresting calls.
187 typedef testing::NiceMock<MockServer> NiceMockServer;
188 typedef std::vector< std::unique_ptr<NiceMockServer> > NiceMockServers;
190 std::set<int> fds() const;
191 void ProcessFD(int fd);
193 static NiceMockServers BuildServers(int count, int family, int base_port);
195 NiceMockServers servers_;
196 // Convenience reference to first server.
197 NiceMockServer& server_;
198 ares_channel channel_;
201 class MockChannelTest
202 : public MockChannelOptsTest,
203 public ::testing::WithParamInterface< std::pair<int, bool> > {
205 MockChannelTest() : MockChannelOptsTest(1, GetParam().first, GetParam().second, nullptr, 0) {}
208 class MockUDPChannelTest
209 : public MockChannelOptsTest,
210 public ::testing::WithParamInterface<int> {
212 MockUDPChannelTest() : MockChannelOptsTest(1, GetParam(), false, nullptr, 0) {}
215 class MockTCPChannelTest
216 : public MockChannelOptsTest,
217 public ::testing::WithParamInterface<int> {
219 MockTCPChannelTest() : MockChannelOptsTest(1, GetParam(), true, nullptr, 0) {}
222 // gMock action to set the reply for a mock server.
223 ACTION_P2(SetReplyData, mockserver, data) {
224 mockserver->SetReplyData(data);
226 ACTION_P2(SetReply, mockserver, reply) {
227 mockserver->SetReply(reply);
229 ACTION_P2(SetReplyQID, mockserver, qid) {
230 mockserver->SetReplyQID(qid);
232 // gMock action to cancel a channel.
233 ACTION_P2(CancelChannel, mockserver, channel) {
234 ares_cancel(channel);
237 // C++ wrapper for struct hostent.
239 HostEnt() : addrtype_(-1) {}
240 HostEnt(const struct hostent* hostent);
242 std::vector<std::string> aliases_;
243 int addrtype_; // AF_INET or AF_INET6
244 std::vector<std::string> addrs_;
246 std::ostream& operator<<(std::ostream& os, const HostEnt& result);
248 // Structure that describes the result of an ares_host_callback invocation.
250 HostResult() : done_(false), status_(0), timeouts_(0) {}
251 // Whether the callback has been invoked.
253 // Explicitly provided result information.
256 // Contents of the hostent structure, if provided.
259 std::ostream& operator<<(std::ostream& os, const HostResult& result);
261 // Structure that describes the result of an ares_callback invocation.
262 struct SearchResult {
263 // Whether the callback has been invoked.
265 // Explicitly provided result information.
268 std::vector<byte> data_;
270 std::ostream& operator<<(std::ostream& os, const SearchResult& result);
272 // Structure that describes the result of an ares_nameinfo_callback invocation.
273 struct NameInfoResult {
274 // Whether the callback has been invoked.
276 // Explicitly provided result information.
280 std::string service_;
282 std::ostream& operator<<(std::ostream& os, const NameInfoResult& result);
284 struct AddrInfoDeleter {
285 void operator() (ares_addrinfo *ptr) {
286 if (ptr) ares_freeaddrinfo(ptr);
290 // C++ wrapper for struct ares_addrinfo.
291 using AddrInfo = std::unique_ptr<ares_addrinfo, AddrInfoDeleter>;
293 std::ostream& operator<<(std::ostream& os, const AddrInfo& result);
295 // Structure that describes the result of an ares_addrinfo_callback invocation.
296 struct AddrInfoResult {
297 AddrInfoResult() : done_(false), status_(-1), timeouts_(0) {}
298 // Whether the callback has been invoked.
300 // Explicitly provided result information.
303 // Contents of the ares_addrinfo structure, if provided.
306 std::ostream& operator<<(std::ostream& os, const AddrInfoResult& result);
308 // Standard implementation of ares callbacks that fill out the corresponding
310 void HostCallback(void *data, int status, int timeouts,
311 struct hostent *hostent);
312 void SearchCallback(void *data, int status, int timeouts,
313 unsigned char *abuf, int alen);
314 void NameInfoCallback(void *data, int status, int timeouts,
315 char *node, char *service);
316 void AddrInfoCallback(void *data, int status, int timeouts,
317 struct ares_addrinfo *res);
319 // Retrieve the name servers used by a channel.
320 std::vector<std::string> GetNameServers(ares_channel channel);
323 // RAII class to temporarily create a directory of a given name.
326 TransientDir(const std::string& dirname);
330 std::string dirname_;
333 // C++ wrapper around tempnam()
334 std::string TempNam(const char *dir, const char *prefix);
336 // RAII class to temporarily create file of a given name and contents.
337 class TransientFile {
339 TransientFile(const std::string &filename, const std::string &contents);
343 std::string filename_;
346 // RAII class for a temporary file with the given contents.
347 class TempFile : public TransientFile {
349 TempFile(const std::string& contents);
350 const char* filename() const { return filename_.c_str(); }
356 static int setenv(const char *name, const char *value, int overwrite)
365 value = ""; /* For unset */
367 if (!overwrite && getenv(name) != NULL) {
371 buf_size = strlen(name) + strlen(value) + 1 /* = */ + 1 /* NULL */;
372 buffer = (char *)malloc(buf_size);
373 _snprintf(buffer, buf_size, "%s=%s", name, value);
379 static int unsetenv(const char *name)
381 return setenv(name, NULL, 1);
387 // RAII class for a temporary environment variable value.
390 EnvValue(const char *name, const char *value) : name_(name), restore_(false) {
391 char *original = getenv(name);
394 original_ = original;
396 setenv(name_.c_str(), value, 1);
400 setenv(name_.c_str(), original_.c_str(), 1);
402 unsetenv(name_.c_str());
408 std::string original_;
412 #ifdef HAVE_CONTAINER
413 // Linux-specific functionality for running code in a container, implemented
414 // in ares-test-ns.cc
415 typedef std::function<int(void)> VoidToIntFn;
416 typedef std::vector<std::pair<std::string, std::string>> NameContentList;
418 class ContainerFilesystem {
420 ContainerFilesystem(NameContentList files, const std::string& mountpt);
421 ~ContainerFilesystem();
422 std::string root() const { return rootdir_; };
423 std::string mountpt() const { return mountpt_; };
425 void EnsureDirExists(const std::string& dir);
426 std::string rootdir_;
427 std::string mountpt_;
428 std::list<std::string> dirs_;
429 std::vector<std::unique_ptr<TransientFile>> files_;
432 int RunInContainer(ContainerFilesystem* fs, const std::string& hostname,
433 const std::string& domainname, VoidToIntFn fn);
435 #define ICLASS_NAME(casename, testname) Contained##casename##_##testname
436 #define CONTAINED_TEST_F(casename, testname, hostname, domainname, files) \
437 class ICLASS_NAME(casename, testname) : public casename { \
439 ICLASS_NAME(casename, testname)() {} \
440 static int InnerTestBody(); \
442 TEST_F(ICLASS_NAME(casename, testname), _) { \
443 ContainerFilesystem chroot(files, ".."); \
444 VoidToIntFn fn(ICLASS_NAME(casename, testname)::InnerTestBody); \
445 EXPECT_EQ(0, RunInContainer(&chroot, hostname, domainname, fn)); \
447 int ICLASS_NAME(casename, testname)::InnerTestBody()
451 /* Assigns virtual IO functions to a channel. These functions simply call
452 * the actual system functions.
456 VirtualizeIO(ares_channel);
459 static const ares_socket_functions default_functions;
461 ares_channel channel_;
465 * Slightly white-box macro to generate two runs for a given test case:
466 * One with no modifications, and one with all IO functions set to use
467 * the virtual io structure.
468 * Since no magic socket setup or anything is done in the latter case
469 * this should probably only be used for test with very vanilla IO
472 #define VCLASS_NAME(casename, testname) Virt##casename##_##testname
473 #define VIRT_NONVIRT_TEST_F(casename, testname) \
474 class VCLASS_NAME(casename, testname) : public casename { \
476 VCLASS_NAME(casename, testname)() {} \
477 void InnerTestBody(); \
479 GTEST_TEST_(casename, testname, VCLASS_NAME(casename, testname), \
480 ::testing::internal::GetTypeId<casename>()) { \
483 GTEST_TEST_(casename, testname##_virtualized, \
484 VCLASS_NAME(casename, testname), \
485 ::testing::internal::GetTypeId<casename>()) { \
486 VirtualizeIO vio(channel_); \
489 void VCLASS_NAME(casename, testname)::InnerTestBody()