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 = 3;
49 int max_address_resolution_attempts = 2;
50 std::string cache_file = DnsCache::DoNotUseCacheFile;
52 // rely on boost that there will only be one instance
54 GlobalFixture *global_fixture;
65 BOOST_TEST_MESSAGE("Create global fixture");
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::Info );
70 I2n::Logger::GlobalLogger.info() << "Logging enabled for DnsTest";
73 IoServiceItem io_service_temp( new boost::asio::io_service() );
74 io_service_temp.swap( IoService );
75 io_service_temp.reset();
78 DnsCacheItem cache_temp = DnsCacheItem(
79 new DnsCache(IoService, cache_file) );
80 cache_temp.swap( Cache );
85 DnsMaster::create_master(IoService,
87 resolved_ip_ttl_threshold,
88 max_address_resolution_attempts,
90 Master = DnsMaster::get_instance();
92 // remember this instance, so we can later access all these variables
93 if (global_fixture == 0)
94 global_fixture = this;
99 BOOST_TEST_MESSAGE("Destructing global fixture");
107 BOOST_TEST_MESSAGE( "Filling cache..." );
109 HostAddress ip(address::from_string("192.168.42.1"), 61);
112 Cache->update("host1.test", ips);
116 HostAddress ip1(address::from_string("192.168.42.2"), 92);
117 HostAddress ip2(address::from_string("192.168.42.3"), 93);
121 Cache->update("host2_3.test", ips);
125 // cname.test --> host1.test
126 Cache->update("cname.test", Cname("host1.test", 35) );
128 // cname2.test --> cname.test --> host1.test
129 Cache->update("cname2.test", Cname("cname.test", 33) );
131 // cname3.test --> cname2.test --> cname.test --> host1.test
132 Cache->update("cname3.test", Cname("cname2.test", 37) );
137 ips.push_back( HostAddress( address::from_string("192.168.42.4"),
139 ips.push_back( HostAddress( address::from_string("192.168.42.5"),
140 resolved_ip_ttl_threshold-1 ) );
141 ips.push_back( HostAddress( address::from_string("192.168.42.6"),
142 resolved_ip_ttl_threshold ) );
143 ips.push_back( HostAddress( address::from_string("192.168.42.7"),
144 resolved_ip_ttl_threshold+1 ) );
145 Cache->update("host_outdated.test", ips);
147 Cache->update( "cname_outdated.test",
148 Cname("host_outdated.test", resolved_ip_ttl_threshold) );
149 Cache->update( "cname_up_to_date.test",
150 Cname("host_outdated.test", resolved_ip_ttl_threshold+1));
153 BOOST_TEST_MESSAGE( "Done filling cache." );
156 // these variables will not be available in test cases:
157 IoServiceItem IoService;
159 DnsMasterItem Master;
162 // this causes above fixture to be created only once before tests start and
163 // destructed after tests end; however, variables are not accessible in test
165 BOOST_GLOBAL_FIXTURE( GlobalFixture )
168 // using this as suite-level fixture makes variable Master accessible in all
172 IoServiceItem IoService;
174 DnsMasterItem Master;
181 BOOST_TEST_MESSAGE("Create test-level fixture");
182 GlobalFixture *global = global_fixture;
183 IoService = global->IoService;
184 Cache = global->Cache;
185 Master = global->Master;
188 virtual ~TestFixture() {}
191 //------------------------------------------------------------------------------
193 //------------------------------------------------------------------------------
195 BOOST_FIXTURE_TEST_SUITE( TestDns, TestFixture )
197 BOOST_AUTO_TEST_CASE( create_master )
200 BOOST_CHECK_EQUAL( Master->get_resolved_ip_ttl_threshold(),
201 resolved_ip_ttl_threshold );
202 BOOST_CHECK_EQUAL( Master->get_max_address_resolution_attempts(),
203 max_address_resolution_attempts );
206 //------------------------------------------------------------------------------
208 //------------------------------------------------------------------------------
209 BOOST_FIXTURE_TEST_SUITE( TestDnsCache, TestFixture )
211 BOOST_AUTO_TEST_CASE( cache_retrieve_ip1 )
213 HostAddressVec ips = Cache->get_ips("host1.test");
214 BOOST_CHECK_EQUAL( ips.size(), 1 );
215 HostAddress ip = ips.front();
216 BOOST_CHECK( ip.is_valid() );
217 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
218 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 61 );
222 BOOST_AUTO_TEST_CASE( cache_retrieve_ip2 )
224 HostAddressVec ips = Cache->get_ips("host2_3.test");
225 BOOST_CHECK_EQUAL( ips.size(), 2 );
226 HostAddress ip = ips[0];
227 BOOST_CHECK( ip.is_valid() );
228 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.2" );
229 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 92 );
231 BOOST_CHECK( ip.is_valid() );
232 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.3" );
233 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 93 );
236 BOOST_AUTO_TEST_CASE( cache_retrieve_cname )
238 HostAddressVec ips = Cache->get_ips("cname.test");
239 BOOST_CHECK( ips.empty() );
241 Cname cname = Cache->get_cname("cname.test");
242 BOOST_CHECK_EQUAL( cname.Host, "host1.test" );
243 BOOST_CHECK_EQUAL( cname.Ttl.get_value(), 35 );
246 BOOST_AUTO_TEST_CASE( cache_retrieve_recursive1 )
248 // should get IP from host1 but ttl from cname since is smaller
249 HostAddressVec ips = Cache->get_ips_recursive("cname.test");
250 BOOST_CHECK_EQUAL( ips.size(), 1 );
251 HostAddress ip = ips.front();
252 BOOST_CHECK( ip.is_valid() );
253 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
254 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 35 );
257 BOOST_AUTO_TEST_CASE( cache_retrieve_recursive2 )
259 // should get IP from host1 but ttl from cname2 since is smaller
260 HostAddressVec ips = Cache->get_ips_recursive("cname3.test");
261 BOOST_CHECK_EQUAL( ips.size(), 1 );
262 HostAddress ip = ips.front();
263 BOOST_CHECK( ip.is_valid() );
264 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
265 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 33 );
268 void cname_skip_test(const uint32_t ttl1, const uint32_t ttl2,
269 const uint32_t ttl3, const uint32_t ttl4,
270 const DnsCacheItem &cache,
271 const std::string &correct_host_after_skip)
273 { // create cname chain:
274 // skip_chain_first -(ttl1)-> skip_chain_second -(ttl2)->
275 // skip_chain_third -(ttl3)-> skip_chain_fourth -(ttl4)-> IPs
276 cache->update( "skip_chain_first.test",
277 Cname("skip_chain_second.test", ttl1) );
278 cache->update( "skip_chain_second.test",
279 Cname("skip_chain_third.test", ttl2) );
280 cache->update( "skip_chain_third.test",
281 Cname("skip_chain_fourth.test", ttl3) );
283 ips.push_back( HostAddress( address::from_string("192.168.42.100"),
285 cache->update("skip_chain_fourth.test", ips);
288 // normal recursive call should give nothing since one cname is outdated
289 bool check_up_to_date = true;
290 HostAddressVec ips = cache->get_ips_recursive("skip_chain_first.test",
292 bool one_is_out_of_date = (ttl1 < 5) || (ttl2 < 5)
293 || (ttl3 < 5) || (ttl4 < 5);
294 BOOST_CHECK_EQUAL( ips.empty(), one_is_out_of_date );
296 // now find host to resolve after the outdated one
297 std::string first_outdated = cache->get_first_outdated_cname(
298 "skip_chain_first.test", 5);
299 BOOST_CHECK_EQUAL( first_outdated, correct_host_after_skip );
302 BOOST_AUTO_TEST_CASE( cache_skip_tests )
304 // build a cname chain where first one is out of date
305 cname_skip_test(0, 120, 120, 60, Cache, "skip_chain_second.test");
307 // build a cname chain where second one is out of date
308 cname_skip_test(120, 0, 120, 60, Cache, "skip_chain_third.test");
310 // build a cname chain where third one is out of date
311 cname_skip_test(120, 120, 0, 120, Cache, "skip_chain_fourth.test");
313 // build a cname chain where just IPs are out of date
314 cname_skip_test(120, 120, 120, 0, Cache, "");
316 // build a cname chain where all are out of date
317 cname_skip_test(0, 0, 0, 0, Cache, "skip_chain_second.test");
319 // build a cname chain where all is up to date
320 cname_skip_test(120, 120, 120, 120, Cache, "");
322 // test case with very short cname list that is up-to-date
323 BOOST_CHECK_EQUAL( Cache->get_first_outdated_cname("cname.test", 5), "" );
325 // test case where there is no cname at all
326 BOOST_CHECK_EQUAL( Cache->get_first_outdated_cname("host1.test", 5), "" );
329 BOOST_AUTO_TEST_CASE( cache_load_test )
331 std::stringstream file_name;
332 file_name << DATA_DIR_STRING << "/" << "dns_cache_example.xml";
333 BOOST_TEST_MESSAGE( "loading cache from file " << file_name.str() );
334 DnsCache loaded_cache( IoService, file_name.str() );
335 HostAddressVec ips = loaded_cache.get_ips("abc.xyz");
336 BOOST_CHECK_EQUAL( ips.size(), 1 );
337 HostAddress ip = ips.front();
338 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "11.22.33.44" );
339 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 567 );
340 BOOST_CHECK_EQUAL( ip.get_ttl().get_updated_value(), 0 );
342 Cname cname = loaded_cache.get_cname("cname1.xyz");
343 BOOST_CHECK_EQUAL( cname.Host, "abc.xyz" );
344 BOOST_CHECK_EQUAL( cname.Ttl.get_value(), 27 );
345 BOOST_CHECK_EQUAL( cname.Ttl.get_updated_value(), 0 );
347 // not testing Ttl set time since is private
350 BOOST_AUTO_TEST_CASE( cache_outdated_test )
352 bool check_up_to_date = false;
353 HostAddressVec ips = Cache->get_ips("host_outdated.test", check_up_to_date);
354 BOOST_CHECK_EQUAL( ips.size(), 4 );
355 ips = Cache->get_ips_recursive("host_outdated.test", check_up_to_date);
356 BOOST_CHECK_EQUAL( ips.size(), 4 );
357 Cname cname = Cache->get_cname("cname_outdated.test", check_up_to_date);
358 BOOST_CHECK( !cname.Host.empty() );
359 ips = Cache->get_ips_recursive("cname_outdated.test", check_up_to_date);
360 BOOST_CHECK_EQUAL( ips.size(), 4 );
361 ips = Cache->get_ips_recursive("cname_up_to_date.test", check_up_to_date);
362 BOOST_CHECK_EQUAL( ips.size(), 4 );
364 check_up_to_date = true;
365 ips = Cache->get_ips( "host_outdated.test", check_up_to_date );
366 BOOST_CHECK_EQUAL( ips.size(), 1 );
367 ips = Cache->get_ips_recursive("host_outdated.test", check_up_to_date);
368 BOOST_CHECK_EQUAL( ips.size(), 1 );
369 cname = Cache->get_cname("cname_outdated.test", check_up_to_date);
370 BOOST_CHECK( cname.Host.empty() );
371 ips = Cache->get_ips_recursive("cname_outdated.test", check_up_to_date);
372 BOOST_CHECK_EQUAL( ips.size(), 0 );
373 ips = Cache->get_ips_recursive("cname_up_to_date.test", check_up_to_date);
374 BOOST_CHECK_EQUAL( ips.size(), 1 );
379 BOOST_AUTO_TEST_SUITE_END() // of TestDnsCache
382 // -----------------------------------------------------------------------------
384 // -----------------------------------------------------------------------------
386 BOOST_FIXTURE_TEST_SUITE( TestDnsResolver, TestFixture )
388 BOOST_AUTO_TEST_CASE( create_resolver_v4 )
391 std::string hostname = "www.intra2net.com";
392 ResolverItem resolver = Master->get_resolver_for(hostname,
394 BOOST_CHECK_EQUAL( resolver->get_hostname(), hostname );
395 BOOST_CHECK( !resolver->is_resolving() );
396 BOOST_CHECK( !resolver->is_waiting_to_resolve() );
398 // cancel should have no effect
399 resolver->cancel_resolve();
400 BOOST_CHECK( !resolver->is_resolving() );
401 BOOST_CHECK( !resolver->is_waiting_to_resolve() );
403 // should not have any ips since cache did not load anything
404 BOOST_CHECK_EQUAL( resolver->get_resolved_ip_count(), 0 );
405 BOOST_CHECK( !resolver->have_up_to_date_ip() );
406 std::string no_ip = "0.0.0.0";
407 BOOST_CHECK_EQUAL( resolver->get_next_ip().get_ip().to_string(), no_ip );
411 void resolve_callback(IoServiceItem io_serv, ResolverItem resolver,
412 const bool was_success, const int cname_count)
414 resolver->cancel_resolve();
416 BOOST_TEST_MESSAGE( "Stopped io_service" );
417 BOOST_CHECK( was_success );
418 BOOST_CHECK_EQUAL( cname_count, 0 );
422 BOOST_AUTO_TEST_CASE( do_resolve )
425 std::string hostname = "www.intra2net.com";
426 ResolverItem resolver = Master->get_resolver_for(hostname,
428 BOOST_CHECK( !resolver->is_resolving() );
429 BOOST_CHECK( !resolver->is_waiting_to_resolve() );
432 callback_type callback = boost::bind( resolve_callback, IoService, resolver,
435 resolver->async_resolve(callback);
436 BOOST_CHECK( resolver->is_resolving() );
438 // this will block until io service is stopped in resolve_callback
441 BOOST_CHECK( resolver->have_up_to_date_ip() );
444 BOOST_AUTO_TEST_SUITE_END() // of TestDnsResolver
446 BOOST_AUTO_TEST_SUITE_END()