2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
21 #define BOOST_TEST_MAIN
22 #define BOOST_TEST_DYN_LINK
26 #include <boost/test/unit_test.hpp>
27 #include <boost/asio/io_service.hpp>
28 #include <boost/asio/ip/address.hpp>
29 #include <boost/bind.hpp>
31 #include <logfunc.hpp>
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"
38 #include "dns/cname.h"
40 using boost::asio::ip::address;
42 //------------------------------------------------------------------------------
43 // Global Test fixture (created once for test suite)
44 //------------------------------------------------------------------------------
46 // constants for master
47 address name_server = address::from_string("127.0.0.1");
48 int resolved_ip_ttl_threshold = 5;
49 uint32_t min_time_between_resolves = 3; // should be < resolved_ip_ttl_threshold
50 int max_address_resolution_attempts = 2;
51 std::string cache_file = DnsCache::DoNotUseCacheFile;
53 // rely on boost that there will only be one instance
55 GlobalFixture *global_fixture;
66 BOOST_TEST_MESSAGE("Create global fixture");
68 // setup logging so we can see output from out code
69 I2n::Logger::enable_stderr_log( true );
70 I2n::Logger::set_log_level( I2n::Logger::LogLevel::Info );
71 I2n::Logger::GlobalLogger.info() << "Logging enabled for DnsTest";
74 IoServiceItem io_service_temp( new boost::asio::io_service() );
75 io_service_temp.swap( IoService );
76 io_service_temp.reset();
79 DnsCacheItem cache_temp = DnsCacheItem(
80 new DnsCache(IoService, cache_file, min_time_between_resolves) );
81 cache_temp.swap( Cache );
86 DnsMaster::create_master(IoService,
88 resolved_ip_ttl_threshold,
89 max_address_resolution_attempts,
91 Master = DnsMaster::get_instance();
93 // remember this instance, so we can later access all these variables
94 if (global_fixture == 0)
95 global_fixture = this;
100 BOOST_TEST_MESSAGE("Destructing global fixture");
108 BOOST_TEST_MESSAGE( "Filling cache..." );
110 HostAddress ip(address::from_string("192.168.42.1"), 61);
113 Cache->update("host1.test", ips);
117 HostAddress ip1(address::from_string("192.168.42.2"), 92);
118 HostAddress ip2(address::from_string("192.168.42.3"), 93);
122 Cache->update("host2_3.test", ips);
126 // cname.test --> host1.test
127 Cache->update("cname.test", Cname("host1.test", 35) );
129 // cname2.test --> cname.test --> host1.test
130 Cache->update("cname2.test", Cname("cname.test", 33) );
132 // cname3.test --> cname2.test --> cname.test --> host1.test
133 Cache->update("cname3.test", Cname("cname2.test", 37) );
136 { // for cache_outdated_test
138 ips.push_back( HostAddress( address::from_string("192.168.42.4"),
140 ips.push_back( HostAddress( address::from_string("192.168.42.5"),
141 resolved_ip_ttl_threshold-1 ) );
142 ips.push_back( HostAddress( address::from_string("192.168.42.6"),
143 resolved_ip_ttl_threshold ) );
144 ips.push_back( HostAddress( address::from_string("192.168.42.7"),
145 resolved_ip_ttl_threshold+1 ) );
146 Cache->update("host_outdated.test", ips);
148 Cache->update( "cname_outdated.test",
149 Cname("host_outdated.test", resolved_ip_ttl_threshold) );
150 Cache->update( "cname_up_to_date.test",
151 Cname("host_outdated.test", resolved_ip_ttl_threshold+1));
154 { // for cache_ttl_below_thresh_test
155 // TTLs < min_time_between_resolves should be corrected
157 ips.push_back( HostAddress( address::from_string("192.128.42.8"),
159 Cache->update("host_ttl_below_thresh.test", ips);
161 Cache->update( "cname_ttl_below_thresh.test",
162 Cname("host_ttl_below_thresh.test", 2) );
165 BOOST_TEST_MESSAGE( "Done filling cache." );
168 // these variables will not be available in test cases:
169 IoServiceItem IoService;
171 DnsMasterItem Master;
174 // this causes above fixture to be created only once before tests start and
175 // destructed after tests end; however, variables are not accessible in test
177 BOOST_GLOBAL_FIXTURE( GlobalFixture )
180 // using this as suite-level fixture makes variable Master accessible in all
184 IoServiceItem IoService;
186 DnsMasterItem Master;
193 BOOST_TEST_MESSAGE("Create test-level fixture");
194 GlobalFixture *global = global_fixture;
195 IoService = global->IoService;
196 Cache = global->Cache;
197 Master = global->Master;
200 virtual ~TestFixture() {}
203 //------------------------------------------------------------------------------
205 //------------------------------------------------------------------------------
207 BOOST_FIXTURE_TEST_SUITE( TestDns, TestFixture )
209 BOOST_AUTO_TEST_CASE( create_master )
212 BOOST_CHECK_EQUAL( Master->get_resolved_ip_ttl_threshold(),
213 resolved_ip_ttl_threshold );
214 BOOST_CHECK_EQUAL( Master->get_max_address_resolution_attempts(),
215 max_address_resolution_attempts );
218 //------------------------------------------------------------------------------
220 //------------------------------------------------------------------------------
221 BOOST_FIXTURE_TEST_SUITE( TestDnsCache, TestFixture )
223 BOOST_AUTO_TEST_CASE( cache_retrieve_ip1 )
225 HostAddressVec ips = Cache->get_ips("host1.test");
226 BOOST_REQUIRE_EQUAL( ips.size(), 1 );
227 HostAddress ip = ips.front();
228 BOOST_CHECK( ip.is_valid() );
229 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
230 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 61 );
234 BOOST_AUTO_TEST_CASE( cache_retrieve_ip2 )
236 HostAddressVec ips = Cache->get_ips("host2_3.test");
237 BOOST_CHECK_EQUAL( ips.size(), 2 );
238 HostAddress ip = ips[0];
239 BOOST_CHECK( ip.is_valid() );
240 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.2" );
241 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 92 );
243 BOOST_CHECK( ip.is_valid() );
244 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.3" );
245 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 93 );
248 BOOST_AUTO_TEST_CASE( cache_retrieve_cname )
250 HostAddressVec ips = Cache->get_ips("cname.test");
251 BOOST_CHECK( ips.empty() );
253 Cname cname = Cache->get_cname("cname.test");
254 BOOST_CHECK_EQUAL( cname.Host, "host1.test" );
255 BOOST_CHECK_EQUAL( cname.Ttl.get_value(), 35 );
258 BOOST_AUTO_TEST_CASE( cache_retrieve_recursive1 )
260 // should get IP from host1 but ttl from cname since is smaller
261 HostAddressVec ips = Cache->get_ips_recursive("cname.test");
262 BOOST_REQUIRE_EQUAL( ips.size(), 1 );
263 HostAddress ip = ips.front();
264 BOOST_CHECK( ip.is_valid() );
265 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
266 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 35 );
269 BOOST_AUTO_TEST_CASE( cache_retrieve_recursive2 )
271 // should get IP from host1 but ttl from cname2 since is smaller
272 HostAddressVec ips = Cache->get_ips_recursive("cname3.test");
273 BOOST_REQUIRE_EQUAL( ips.size(), 1 );
274 HostAddress ip = ips.front();
275 BOOST_CHECK( ip.is_valid() );
276 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
277 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 33 );
280 void cname_skip_test(const uint32_t ttl1, const uint32_t ttl2,
281 const uint32_t ttl3, const uint32_t ttl4,
282 const DnsCacheItem &cache,
283 const std::string &correct_host_after_skip)
285 { // create cname chain:
286 // skip_chain_first -(ttl1)-> skip_chain_second -(ttl2)->
287 // skip_chain_third -(ttl3)-> skip_chain_fourth -(ttl4)-> IPs
288 cache->update( "skip_chain_first.test",
289 Cname("skip_chain_second.test", ttl1) );
290 cache->update( "skip_chain_second.test",
291 Cname("skip_chain_third.test", ttl2) );
292 cache->update( "skip_chain_third.test",
293 Cname("skip_chain_fourth.test", ttl3) );
295 ips.push_back( HostAddress( address::from_string("192.168.42.100"),
297 cache->update("skip_chain_fourth.test", ips);
300 // normal recursive call should give nothing since one cname is outdated
301 bool check_up_to_date = true;
302 HostAddressVec ips = cache->get_ips_recursive("skip_chain_first.test",
304 bool one_is_out_of_date = (ttl1 < 5) || (ttl2 < 5)
305 || (ttl3 < 5) || (ttl4 < 5);
306 BOOST_CHECK_EQUAL( ips.empty(), one_is_out_of_date );
308 // now find host to resolve after the outdated one
309 std::string first_outdated = cache->get_first_outdated_cname(
310 "skip_chain_first.test", 5);
311 BOOST_CHECK_EQUAL( first_outdated, correct_host_after_skip );
314 BOOST_AUTO_TEST_CASE( cache_skip_tests )
316 // build a cname chain where first one is out of date
317 cname_skip_test(0, 120, 120, 60, Cache, "skip_chain_second.test");
319 // build a cname chain where second one is out of date
320 cname_skip_test(120, 0, 120, 60, Cache, "skip_chain_third.test");
322 // build a cname chain where third one is out of date
323 cname_skip_test(120, 120, 0, 120, Cache, "skip_chain_fourth.test");
325 // build a cname chain where just IPs are out of date
326 cname_skip_test(120, 120, 120, 0, Cache, "");
328 // build a cname chain where all are out of date
329 cname_skip_test(0, 0, 0, 0, Cache, "skip_chain_second.test");
331 // build a cname chain where all is up to date
332 cname_skip_test(120, 120, 120, 120, Cache, "");
334 // test case with very short cname list that is up-to-date
335 BOOST_CHECK_EQUAL( Cache->get_first_outdated_cname("cname.test", 5), "" );
337 // test case where there is no cname at all
338 BOOST_CHECK_EQUAL( Cache->get_first_outdated_cname("host1.test", 5), "" );
341 BOOST_AUTO_TEST_CASE( cache_load_test )
343 std::stringstream file_name;
344 file_name << DATA_DIR_STRING << "/" << "dns_cache_example.xml";
345 BOOST_TEST_MESSAGE( "loading cache from file " << file_name.str() );
346 DnsCache loaded_cache( IoService,
348 min_time_between_resolves );
349 HostAddressVec ips = loaded_cache.get_ips("abc.xyz");
350 BOOST_REQUIRE_EQUAL( ips.size(), 1 );
351 HostAddress ip = ips.front();
352 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "11.22.33.44" );
353 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 567 );
354 BOOST_CHECK_EQUAL( ip.get_ttl().get_updated_value(), 0 );
356 Cname cname = loaded_cache.get_cname("cname1.xyz");
357 BOOST_CHECK_EQUAL( cname.Host, "abc.xyz" );
358 BOOST_CHECK_EQUAL( cname.Ttl.get_value(), 27 );
359 BOOST_CHECK_EQUAL( cname.Ttl.get_updated_value(), 0 );
361 // not testing Ttl set time since is private
364 BOOST_AUTO_TEST_CASE( cache_outdated_test )
366 bool check_up_to_date = false;
367 HostAddressVec ips = Cache->get_ips("host_outdated.test", check_up_to_date);
368 BOOST_CHECK_EQUAL( ips.size(), 4 );
369 ips = Cache->get_ips_recursive("host_outdated.test", check_up_to_date);
370 BOOST_CHECK_EQUAL( ips.size(), 4 );
371 Cname cname = Cache->get_cname("cname_outdated.test", check_up_to_date);
372 BOOST_CHECK( !cname.Host.empty() );
373 ips = Cache->get_ips_recursive("cname_outdated.test", check_up_to_date);
374 BOOST_CHECK_EQUAL( ips.size(), 4 );
375 ips = Cache->get_ips_recursive("cname_up_to_date.test", check_up_to_date);
376 BOOST_CHECK_EQUAL( ips.size(), 4 );
378 check_up_to_date = true;
379 ips = Cache->get_ips( "host_outdated.test", check_up_to_date );
380 BOOST_CHECK_EQUAL( ips.size(), 1 );
381 ips = Cache->get_ips_recursive("host_outdated.test", check_up_to_date);
382 BOOST_CHECK_EQUAL( ips.size(), 1 );
383 cname = Cache->get_cname("cname_outdated.test", check_up_to_date);
384 BOOST_CHECK( cname.Host.empty() );
385 ips = Cache->get_ips_recursive("cname_outdated.test", check_up_to_date);
386 BOOST_CHECK_EQUAL( ips.size(), 0 );
387 ips = Cache->get_ips_recursive("cname_up_to_date.test", check_up_to_date);
388 BOOST_CHECK_EQUAL( ips.size(), 1 );
391 BOOST_AUTO_TEST_CASE( cache_ttl_below_thresh_test )
394 HostAddressVec ips = Cache->get_ips("host_ttl_below_thresh.test", false);
395 BOOST_REQUIRE_EQUAL( ips.size(), 1 );
396 HostAddress ip = ips.front();
397 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), min_time_between_resolves );
399 Cname cname = Cache->get_cname("cname_ttl_below_thresh.test", false);
400 BOOST_CHECK_EQUAL( cname.Ttl.get_value(), min_time_between_resolves );
403 BOOST_AUTO_TEST_SUITE_END() // of TestDnsCache
406 // -----------------------------------------------------------------------------
408 // -----------------------------------------------------------------------------
410 BOOST_FIXTURE_TEST_SUITE( TestDnsResolver, TestFixture )
412 BOOST_AUTO_TEST_CASE( create_resolver_v4 )
415 std::string hostname = "www.intra2net.com";
416 ResolverItem resolver = Master->get_resolver_for(hostname,
418 BOOST_CHECK_EQUAL( resolver->get_hostname(), hostname );
419 BOOST_CHECK( !resolver->is_resolving() );
420 BOOST_CHECK( !resolver->is_waiting_to_resolve() );
422 // cancel should have no effect
423 resolver->cancel_resolve();
424 BOOST_CHECK( !resolver->is_resolving() );
425 BOOST_CHECK( !resolver->is_waiting_to_resolve() );
427 // should not have any ips since cache did not load anything
428 BOOST_CHECK_EQUAL( resolver->get_resolved_ip_count(), 0 );
429 BOOST_CHECK( !resolver->have_up_to_date_ip() );
430 std::string no_ip = "0.0.0.0";
431 BOOST_CHECK_EQUAL( resolver->get_next_ip().get_ip().to_string(), no_ip );
435 void resolve_callback(IoServiceItem io_serv, ResolverItem resolver,
436 const bool was_success, const int cname_count)
438 resolver->cancel_resolve();
440 BOOST_TEST_MESSAGE( "Stopped io_service" );
441 BOOST_CHECK( was_success );
442 BOOST_CHECK_EQUAL( cname_count, 0 );
446 BOOST_AUTO_TEST_CASE( do_resolve )
449 std::string hostname = "www.intra2net.com";
450 ResolverItem resolver = Master->get_resolver_for(hostname,
452 BOOST_CHECK( !resolver->is_resolving() );
453 BOOST_CHECK( !resolver->is_waiting_to_resolve() );
456 callback_type callback = boost::bind( resolve_callback, IoService, resolver,
459 resolver->async_resolve(callback);
460 BOOST_CHECK( resolver->is_resolving() );
462 // this will block until io service is stopped in resolve_callback
465 BOOST_CHECK( resolver->have_up_to_date_ip() );
468 BOOST_AUTO_TEST_SUITE_END() // of TestDnsResolver
470 BOOST_AUTO_TEST_SUITE_END()