created and passed first unit tests for DNS; finished recovery from PingScheduler...
[pingcheck] / test / test_dns.cpp
CommitLineData
26b0f687
CH
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
20
21#define BOOST_TEST_MAIN
22#define BOOST_TEST_DYN_LINK
23
24#include <algorithm>
25
26#include <boost/test/unit_test.hpp>
27#include <boost/asio/io_service.hpp>
28#include <boost/asio/ip/address.hpp>
8d26221d
CH
29#include <boost/bind.hpp>
30
31#include <logfunc.hpp>
26b0f687
CH
32
33#include "host/pingprotocol.h"
34#include "dns/hostaddress.h"
35#include "dns/dnsmaster.h"
36#include "dns/dnscache.h"
37#include "dns/resolverbase.h"
8d26221d
CH
38#include "dns/cname.h"
39
40using boost::asio::ip::address;
26b0f687
CH
41
42//------------------------------------------------------------------------------
8d26221d 43// Global Test fixture (created once for test suite)
26b0f687
CH
44//------------------------------------------------------------------------------
45
8d26221d
CH
46// constants for master
47address name_server = address::from_string("127.0.0.1");
48int resolved_ip_ttl_threshold = 3;
49int max_address_resolution_attempts = 2;
50std::string cache_file = DnsCache::DoNotUseCacheFile;
51
52// rely on boost that there will only be one instance
53struct GlobalFixture;
54GlobalFixture *global_fixture;
26b0f687 55
8d26221d
CH
56
57struct GlobalFixture
26b0f687 58{
8d26221d
CH
59
60 GlobalFixture()
61 : IoService()
62 , Cache()
63 , Master()
26b0f687 64 {
8d26221d
CH
65 BOOST_TEST_MESSAGE("Create global fixture");
66
67 // setup logging so we can see output from out code
68 I2n::Logger::enable_stderr_log( true );
69 I2n::Logger::set_log_level( I2n::Logger::LogLevel::Debug );
70 I2n::Logger::GlobalLogger.info() << "Logging enabled for DnsTest";
71
72 // IoService
73 IoServiceItem io_service_temp( new boost::asio::io_service() );
74 io_service_temp.swap( IoService );
75 io_service_temp.reset();
76
77 // DNS Cache
78 DnsCacheItem cache_temp = DnsCacheItem(
79 new DnsCache(IoService, cache_file) );
80 cache_temp.swap( Cache );
81 cache_temp.reset();
82 fill_cache();
83
84 // create master
85 DnsMaster::create_master(IoService,
26b0f687
CH
86 name_server,
87 resolved_ip_ttl_threshold,
88 max_address_resolution_attempts,
8d26221d
CH
89 Cache);
90 Master = DnsMaster::get_instance();
91
92 // remember this instance, so we can later access all these variables
93 if (global_fixture == 0)
94 global_fixture = this;
26b0f687 95 }
8d26221d
CH
96
97 ~GlobalFixture()
98 {
99 BOOST_TEST_MESSAGE("Destructing global fixture");
100 IoService->stop();
101 IoService.reset();
102 Master.reset();
103 }
104
105 void fill_cache()
106 {
107 BOOST_TEST_MESSAGE( "Filling cache..." );
108 {
109 HostAddress ip(address::from_string("192.168.42.1"), 61);
110 HostAddressVec ips;
111 ips.push_back(ip);
112 Cache->update("host1.test", ips);
113 }
114
115 {
116 HostAddress ip1(address::from_string("192.168.42.2"), 92);
117 HostAddress ip2(address::from_string("192.168.42.3"), 93);
118 HostAddressVec ips;
119 ips.push_back(ip1);
120 ips.push_back(ip2);
121 Cache->update("host2_3.test", ips);
122 }
123
124 { // cname.test --> host1.test
125 Cname cname("host1.test", 35);
126 Cache->update("cname.test", cname);
127 }
128
129 { // cname2.test --> cname.test --> host1.test
130 Cname cname("cname.test", 33);
131 Cache->update("cname2.test", cname);
132 }
133
134 { // cname3.test --> cname2.test --> cname.test --> host1.test
135 Cname cname("cname2.test", 37);
136 Cache->update("cname3.test", cname);
137 }
138 BOOST_TEST_MESSAGE( "Done filling cache." );
139 }
140
141 // these variables will not be available in test cases:
142 IoServiceItem IoService;
143 DnsCacheItem Cache;
144 DnsMasterItem Master;
145};
146
147// this causes above fixture to be created only once before tests start and
148// destructed after tests end; however, variables are not accessible in test
149// cases
150BOOST_GLOBAL_FIXTURE( GlobalFixture )
151
152
153// using this as suite-level fixture makes variable Master accessible in all
154// test cases
155struct TestFixture
156{
157 IoServiceItem IoService;
158 DnsCacheItem Cache;
159 DnsMasterItem Master;
160
161 TestFixture()
162 : IoService()
163 , Cache()
164 , Master()
165 {
166 BOOST_TEST_MESSAGE("Create test-level fixture");
167 GlobalFixture *global = global_fixture;
168 IoService = global->IoService;
169 Cache = global->Cache;
170 Master = global->Master;
171 }
172
173 virtual ~TestFixture() {}
174};
26b0f687
CH
175
176//------------------------------------------------------------------------------
177// test suite
178//------------------------------------------------------------------------------
179
8d26221d 180BOOST_FIXTURE_TEST_SUITE( TestDns, TestFixture )
26b0f687
CH
181
182BOOST_AUTO_TEST_CASE( create_master )
183{
8d26221d
CH
184 // simple checks
185 BOOST_CHECK_EQUAL( Master->get_resolved_ip_ttl_threshold(),
186 resolved_ip_ttl_threshold );
187 BOOST_CHECK_EQUAL( Master->get_max_address_resolution_attempts(),
188 max_address_resolution_attempts );
26b0f687
CH
189}
190
8d26221d
CH
191//------------------------------------------------------------------------------
192// test Cache
193//------------------------------------------------------------------------------
194BOOST_FIXTURE_TEST_SUITE( TestDnsCache, TestFixture )
195
196BOOST_AUTO_TEST_CASE( cache_retrieve_ip1 )
26b0f687 197{
8d26221d
CH
198 HostAddressVec ips = Cache->get_ips("host1.test");
199 BOOST_CHECK_EQUAL( ips.size(), 1 );
200 HostAddress ip = ips.front();
201 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
202 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 61 );
203}
204
205
206BOOST_AUTO_TEST_CASE( cache_retrieve_ip2 )
207{
208 HostAddressVec ips = Cache->get_ips("host2_3.test");
209 BOOST_CHECK_EQUAL( ips.size(), 2 );
210 HostAddress ip = ips[0];
211 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.2" );
212 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 92 );
213 ip = ips[1];
214 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.3" );
215 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 93 );
216}
26b0f687 217
8d26221d
CH
218BOOST_AUTO_TEST_CASE( cache_retrieve_cname )
219{
220 HostAddressVec ips = Cache->get_ips("cname.test");
221 BOOST_CHECK( ips.empty() );
222
223 Cname cname = Cache->get_cname("cname.test");
224 BOOST_CHECK_EQUAL( cname.Host, "host1.test" );
225 BOOST_CHECK_EQUAL( cname.Ttl.get_value(), 35 );
226}
227
228BOOST_AUTO_TEST_CASE( cache_retrieve_recursive1 )
229{
230 // should get IP from host1 but ttl from cname since is smaller
231 HostAddressVec ips = Cache->get_ips_recursive("cname.test");
232 BOOST_CHECK_EQUAL( ips.size(), 1 );
233 HostAddress ip = ips.front();
234 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
235 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 35 );
236}
237
238BOOST_AUTO_TEST_CASE( cache_retrieve_recursive2 )
239{
240 // should get IP from host1 but ttl from cname2 since is smaller
241 HostAddressVec ips = Cache->get_ips_recursive("cname3.test");
242 BOOST_CHECK_EQUAL( ips.size(), 1 );
243 HostAddress ip = ips.front();
244 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
245 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 33 );
246}
247
248BOOST_AUTO_TEST_CASE( cache_skip_test1 )
249{
250 // build a cname chain where first one is out of date
251 { // skip_chain_first -(120)-> skip_chain_second -(0)-> skip_chain_third
252 // -(120)-> skip_chain_fourth -(60)-> IPs
253 Cname first("skip_chain_second.test", 120);
254 Cache->update("skip_chain_first.test", first);
255 Cname second("skip_chain_third.test", 0);
256 Cache->update("skip_chain_second.test", second);
257 Cname third("skip_chain_fourth.test", 120);
258 Cache->update("skip_chain_third.test", third);
259 HostAddressVec ips;
260 ips.push_back( HostAddress( address::from_string("192.168.42.4"), 60) );
261 Cache->update("skip_chain_fourth.test", ips);
262 }
263
264 // normal recursive call should give nothing since all are outdated
265 bool check_up_to_date = true;
266 HostAddressVec ips = Cache->get_ips_recursive("skip_chain_first.test",
267 check_up_to_date);
268 BOOST_CHECK( ips.empty() );
269
270 // now try to skip
271 std::string first_outdated = Cache->get_first_outdated_cname(
272 "skip_chain_first.test", 5);
273 BOOST_CHECK_EQUAL( first_outdated, "skip_chain_third.test" );
274}
275
276
277BOOST_AUTO_TEST_SUITE_END() // of TestDnsCache
278
279
280// -----------------------------------------------------------------------------
281// test resolver
282// -----------------------------------------------------------------------------
283
284BOOST_FIXTURE_TEST_SUITE( TestDnsResolver, TestFixture )
285
286void resolve_callback(IoServiceItem io_serv, ResolverItem resolver,
287 const bool was_success, const int cname_count);
288
289BOOST_AUTO_TEST_CASE( create_resolver_v4 )
290{
26b0f687
CH
291 // create resolver
292 std::string hostname = "www.intra2net.com";
8d26221d
CH
293 ResolverItem resolver = Master->get_resolver_for(hostname,
294 PingProtocol_ICMP);
26b0f687
CH
295 BOOST_CHECK_EQUAL( resolver->get_hostname(), hostname );
296 BOOST_CHECK( !resolver->is_resolving() );
297
298 // cancel should have no effect
299 resolver->cancel_resolve();
300 BOOST_CHECK( !resolver->is_resolving() );
301
302 // should not have any ips since cache did not load anything
303 BOOST_CHECK_EQUAL( resolver->get_resolved_ip_count(), 0 );
304 BOOST_CHECK( !resolver->have_up_to_date_ip() );
305 std::string no_ip = "0.0.0.0";
306 BOOST_CHECK_EQUAL( resolver->get_next_ip().get_ip().to_string(), no_ip );
307}
308
8d26221d
CH
309
310void resolve_callback(IoServiceItem io_serv, ResolverItem resolver,
311 const bool was_success, const int cname_count)
312{
313 resolver->cancel_resolve();
314 io_serv->stop();
315 BOOST_TEST_MESSAGE( "Stopped io_service" );
316}
317
318
319BOOST_AUTO_TEST_CASE( do_resolve )
320{
321 // create resolver
322 std::string hostname = "www.intra2net.com";
323 ResolverItem resolver = Master->get_resolver_for(hostname,
324 PingProtocol_ICMP);
325
326 // set callback
327 callback_type callback = boost::bind( resolve_callback, IoService, resolver,
328 _1, _2 );
329 // start resolving
330 resolver->async_resolve(callback);
331 IoService->run();
332 // this will block until io service is stopped in resolve_callback
333
334 // check for result
335 BOOST_CHECK( resolver->have_up_to_date_ip() );
336}
337
338BOOST_AUTO_TEST_SUITE_END() // of TestDnsResolver
339
26b0f687 340BOOST_AUTO_TEST_SUITE_END()