Imported Upstream version 1.18.1
[platform/upstream/c-ares.git] / test / ares-test.h
1 // -*- mode: c++ -*-
2 #ifndef ARES_TEST_H
3 #define ARES_TEST_H
4
5 #include "ares_setup.h"
6 #include "ares.h"
7
8 #include "dns-proto.h"
9 // Include ares internal file for DNS protocol constants
10 #include "ares_nameser.h"
11
12 #include "gtest/gtest.h"
13 #include "gmock/gmock.h"
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18 #if defined(HAVE_USER_NAMESPACE) && defined(HAVE_UTS_NAMESPACE)
19 #define HAVE_CONTAINER
20 #endif
21
22 #include <functional>
23 #include <list>
24 #include <map>
25 #include <memory>
26 #include <set>
27 #include <string>
28 #include <utility>
29 #include <vector>
30
31 namespace ares {
32
33 typedef unsigned char byte;
34
35 namespace test {
36
37 extern bool verbose;
38 extern int mock_port;
39 extern const std::vector<int> both_families;
40 extern const std::vector<int> ipv4_family;
41 extern const std::vector<int> ipv6_family;
42
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;
46
47 // Which parameters to use in tests
48 extern std::vector<int> families;
49 extern std::vector<std::pair<int, bool>> families_modes;
50
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();
57
58 // Test fixture that ensures library initialization, and allows
59 // memory allocations to be failed.
60 class LibraryTest : public ::testing::Test {
61  public:
62   LibraryTest() {
63     EXPECT_EQ(ARES_SUCCESS,
64               ares_library_init_mem(ARES_LIB_INIT_ALL,
65                                     &LibraryTest::amalloc,
66                                     &LibraryTest::afree,
67                                     &LibraryTest::arealloc));
68   }
69   ~LibraryTest() {
70     ares_library_cleanup();
71     ClearFails();
72   }
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();
80
81   static void *amalloc(size_t size);
82   static void* arealloc(void *ptr, size_t size);
83   static void afree(void *ptr);
84  private:
85   static bool ShouldAllocFail(size_t size);
86   static unsigned long long fails_;
87   static std::map<size_t, int> size_fails_;
88 };
89
90 // Test fixture that uses a default channel.
91 class DefaultChannelTest : public LibraryTest {
92  public:
93   DefaultChannelTest() : channel_(nullptr) {
94     EXPECT_EQ(ARES_SUCCESS, ares_init(&channel_));
95     EXPECT_NE(nullptr, channel_);
96   }
97
98   ~DefaultChannelTest() {
99     ares_destroy(channel_);
100     channel_ = nullptr;
101   }
102
103   // Process all pending work on ares-owned file descriptors.
104   void Process();
105
106  protected:
107   ares_channel channel_;
108 };
109
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> {
114  public:
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_);
121     free(opts.lookups);
122   }
123
124   ~DefaultChannelModeTest() {
125     ares_destroy(channel_);
126     channel_ = nullptr;
127   }
128
129   // Process all pending work on ares-owned file descriptors.
130   void Process();
131
132  protected:
133   ares_channel channel_;
134 };
135
136 // Mock DNS server to allow responses to be scripted by tests.
137 class MockServer {
138  public:
139   MockServer(int family, int port);
140   ~MockServer();
141
142   // Mock method indicating the processing of a particular <name, RRtype>
143   // request.
144   MOCK_METHOD2(OnRequest, void(const std::string& name, int rrtype));
145
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; }
151
152   // The set of file descriptors that the server handles.
153   std::set<int> fds() const;
154
155   // Process activity on a file descriptor.
156   void ProcessFD(int fd);
157
158   // Ports the server is responding to
159   int udpport() const { return udpport_; }
160   int tcpport() const { return tcpport_; }
161
162  private:
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);
167   int udpport_;
168   int tcpport_;
169   int udpfd_;
170   int tcpfd_;
171   std::set<int> connfds_;
172   std::vector<byte> reply_;
173   int qid_;
174 };
175
176 // Test fixture that uses a mock DNS server.
177 class MockChannelOptsTest : public LibraryTest {
178  public:
179   MockChannelOptsTest(int count, int family, bool force_tcp, struct ares_options* givenopts, int optmask);
180   ~MockChannelOptsTest();
181
182   // Process all pending work on ares-owned and mock-server-owned file descriptors.
183   void Process();
184
185  protected:
186   // NiceMockServer doesn't complain about uninteresting calls.
187   typedef testing::NiceMock<MockServer> NiceMockServer;
188   typedef std::vector< std::unique_ptr<NiceMockServer> > NiceMockServers;
189
190   std::set<int> fds() const;
191   void ProcessFD(int fd);
192
193   static NiceMockServers BuildServers(int count, int family, int base_port);
194
195   NiceMockServers servers_;
196   // Convenience reference to first server.
197   NiceMockServer& server_;
198   ares_channel channel_;
199 };
200
201 class MockChannelTest
202     : public MockChannelOptsTest,
203       public ::testing::WithParamInterface< std::pair<int, bool> > {
204  public:
205   MockChannelTest() : MockChannelOptsTest(1, GetParam().first, GetParam().second, nullptr, 0) {}
206 };
207
208 class MockUDPChannelTest
209     : public MockChannelOptsTest,
210       public ::testing::WithParamInterface<int> {
211  public:
212   MockUDPChannelTest() : MockChannelOptsTest(1, GetParam(), false, nullptr, 0) {}
213 };
214
215 class MockTCPChannelTest
216     : public MockChannelOptsTest,
217       public ::testing::WithParamInterface<int> {
218  public:
219   MockTCPChannelTest() : MockChannelOptsTest(1, GetParam(), true, nullptr, 0) {}
220 };
221
222 // gMock action to set the reply for a mock server.
223 ACTION_P2(SetReplyData, mockserver, data) {
224   mockserver->SetReplyData(data);
225 }
226 ACTION_P2(SetReply, mockserver, reply) {
227   mockserver->SetReply(reply);
228 }
229 ACTION_P2(SetReplyQID, mockserver, qid) {
230   mockserver->SetReplyQID(qid);
231 }
232 // gMock action to cancel a channel.
233 ACTION_P2(CancelChannel, mockserver, channel) {
234   ares_cancel(channel);
235 }
236
237 // C++ wrapper for struct hostent.
238 struct HostEnt {
239   HostEnt() : addrtype_(-1) {}
240   HostEnt(const struct hostent* hostent);
241   std::string name_;
242   std::vector<std::string> aliases_;
243   int addrtype_;  // AF_INET or AF_INET6
244   std::vector<std::string> addrs_;
245 };
246 std::ostream& operator<<(std::ostream& os, const HostEnt& result);
247
248 // Structure that describes the result of an ares_host_callback invocation.
249 struct HostResult {
250   HostResult() : done_(false), status_(0), timeouts_(0) {}
251   // Whether the callback has been invoked.
252   bool done_;
253   // Explicitly provided result information.
254   int status_;
255   int timeouts_;
256   // Contents of the hostent structure, if provided.
257   HostEnt host_;
258 };
259 std::ostream& operator<<(std::ostream& os, const HostResult& result);
260
261 // Structure that describes the result of an ares_callback invocation.
262 struct SearchResult {
263   // Whether the callback has been invoked.
264   bool done_;
265   // Explicitly provided result information.
266   int status_;
267   int timeouts_;
268   std::vector<byte> data_;
269 };
270 std::ostream& operator<<(std::ostream& os, const SearchResult& result);
271
272 // Structure that describes the result of an ares_nameinfo_callback invocation.
273 struct NameInfoResult {
274   // Whether the callback has been invoked.
275   bool done_;
276   // Explicitly provided result information.
277   int status_;
278   int timeouts_;
279   std::string node_;
280   std::string service_;
281 };
282 std::ostream& operator<<(std::ostream& os, const NameInfoResult& result);
283
284 struct AddrInfoDeleter {
285   void operator() (ares_addrinfo *ptr) {
286     if (ptr) ares_freeaddrinfo(ptr);
287   }
288 };
289
290 // C++ wrapper for struct ares_addrinfo.
291 using AddrInfo = std::unique_ptr<ares_addrinfo, AddrInfoDeleter>;
292
293 std::ostream& operator<<(std::ostream& os, const AddrInfo& result);
294
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.
299   bool done_;
300   // Explicitly provided result information.
301   int status_;
302   int timeouts_;
303   // Contents of the ares_addrinfo structure, if provided.
304   AddrInfo ai_;
305 };
306 std::ostream& operator<<(std::ostream& os, const AddrInfoResult& result);
307
308 // Standard implementation of ares callbacks that fill out the corresponding
309 // structures.
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);
318
319 // Retrieve the name servers used by a channel.
320 std::vector<std::string> GetNameServers(ares_channel channel);
321
322
323 // RAII class to temporarily create a directory of a given name.
324 class TransientDir {
325  public:
326   TransientDir(const std::string& dirname);
327   ~TransientDir();
328
329  private:
330   std::string dirname_;
331 };
332
333 // C++ wrapper around tempnam()
334 std::string TempNam(const char *dir, const char *prefix);
335
336 // RAII class to temporarily create file of a given name and contents.
337 class TransientFile {
338  public:
339   TransientFile(const std::string &filename, const std::string &contents);
340   ~TransientFile();
341
342  protected:
343   std::string filename_;
344 };
345
346 // RAII class for a temporary file with the given contents.
347 class TempFile : public TransientFile {
348  public:
349   TempFile(const std::string& contents);
350   const char* filename() const { return filename_.c_str(); }
351 };
352
353 #ifdef _WIN32
354 extern "C" {
355
356 static int setenv(const char *name, const char *value, int overwrite)
357 {
358   char  *buffer;
359   size_t buf_size;
360
361   if (name == NULL)
362     return -1;
363
364   if (value == NULL)
365     value = ""; /* For unset */
366
367   if (!overwrite && getenv(name) != NULL) {
368     return -1;
369   }
370
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);
374   _putenv(buffer);
375   free(buffer);
376   return 0;
377 }
378
379 static int unsetenv(const char *name)
380 {
381   return setenv(name, NULL, 1);
382 }
383
384 } /* extern "C" */
385 #endif
386
387 // RAII class for a temporary environment variable value.
388 class EnvValue {
389  public:
390   EnvValue(const char *name, const char *value) : name_(name), restore_(false) {
391     char *original = getenv(name);
392     if (original) {
393       restore_ = true;
394       original_ = original;
395     }
396     setenv(name_.c_str(), value, 1);
397   }
398   ~EnvValue() {
399     if (restore_) {
400       setenv(name_.c_str(), original_.c_str(), 1);
401     } else {
402       unsetenv(name_.c_str());
403     }
404   }
405  private:
406   std::string name_;
407   bool restore_;
408   std::string original_;
409 };
410
411
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;
417
418 class ContainerFilesystem {
419  public:
420   ContainerFilesystem(NameContentList files, const std::string& mountpt);
421   ~ContainerFilesystem();
422   std::string root() const { return rootdir_; };
423   std::string mountpt() const { return mountpt_; };
424  private:
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_;
430 };
431
432 int RunInContainer(ContainerFilesystem* fs, const std::string& hostname,
433                    const std::string& domainname, VoidToIntFn fn);
434
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 {                     \
438    public:                                                                      \
439     ICLASS_NAME(casename, testname)() {}                                        \
440     static int InnerTestBody();                                                 \
441   };                                                                            \
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));            \
446   }                                                                             \
447   int ICLASS_NAME(casename, testname)::InnerTestBody()
448
449 #endif
450
451 /* Assigns virtual IO functions to a channel. These functions simply call
452  * the actual system functions.
453  */
454 class VirtualizeIO {
455 public:
456   VirtualizeIO(ares_channel);
457   ~VirtualizeIO();
458
459   static const ares_socket_functions default_functions;
460 private:
461   ares_channel channel_;
462 };
463
464 /*
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
470  * requirements.
471  */
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 {                     \
475   public:                                                                       \
476     VCLASS_NAME(casename, testname)() {}                                        \
477     void InnerTestBody();                                                       \
478   };                                                                            \
479   GTEST_TEST_(casename, testname, VCLASS_NAME(casename, testname),              \
480               ::testing::internal::GetTypeId<casename>()) {                     \
481     InnerTestBody();                                                            \
482   }                                                                             \
483   GTEST_TEST_(casename, testname##_virtualized,                                 \
484               VCLASS_NAME(casename, testname),                                  \
485               ::testing::internal::GetTypeId<casename>()) {                     \
486     VirtualizeIO vio(channel_);                                                 \
487     InnerTestBody();                                                            \
488   }                                                                             \
489   void VCLASS_NAME(casename, testname)::InnerTestBody()
490
491 }  // namespace test
492 }  // namespace ares
493
494 #endif