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);
124 // cname.test --> host1.test
125 Cache->update("cname.test", Cname("host1.test", 35) );
127 // cname2.test --> cname.test --> host1.test
128 Cache->update("cname2.test", Cname("cname.test", 33) );
130 // cname3.test --> cname2.test --> cname.test --> host1.test
131 Cache->update("cname3.test", Cname("cname2.test", 37) );
133 BOOST_TEST_MESSAGE( "Done filling cache." );
136 // these variables will not be available in test cases:
137 IoServiceItem IoService;
139 DnsMasterItem Master;
142 // this causes above fixture to be created only once before tests start and
143 // destructed after tests end; however, variables are not accessible in test
145 BOOST_GLOBAL_FIXTURE( GlobalFixture )
148 // using this as suite-level fixture makes variable Master accessible in all
152 IoServiceItem IoService;
154 DnsMasterItem Master;
161 BOOST_TEST_MESSAGE("Create test-level fixture");
162 GlobalFixture *global = global_fixture;
163 IoService = global->IoService;
164 Cache = global->Cache;
165 Master = global->Master;
168 virtual ~TestFixture() {}
171 //------------------------------------------------------------------------------
173 //------------------------------------------------------------------------------
175 BOOST_FIXTURE_TEST_SUITE( TestDns, TestFixture )
177 BOOST_AUTO_TEST_CASE( create_master )
180 BOOST_CHECK_EQUAL( Master->get_resolved_ip_ttl_threshold(),
181 resolved_ip_ttl_threshold );
182 BOOST_CHECK_EQUAL( Master->get_max_address_resolution_attempts(),
183 max_address_resolution_attempts );
186 //------------------------------------------------------------------------------
188 //------------------------------------------------------------------------------
189 BOOST_FIXTURE_TEST_SUITE( TestDnsCache, TestFixture )
191 BOOST_AUTO_TEST_CASE( cache_retrieve_ip1 )
193 HostAddressVec ips = Cache->get_ips("host1.test");
194 BOOST_CHECK_EQUAL( ips.size(), 1 );
195 HostAddress ip = ips.front();
196 BOOST_CHECK( ip.is_valid() );
197 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
198 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 61 );
202 BOOST_AUTO_TEST_CASE( cache_retrieve_ip2 )
204 HostAddressVec ips = Cache->get_ips("host2_3.test");
205 BOOST_CHECK_EQUAL( ips.size(), 2 );
206 HostAddress ip = ips[0];
207 BOOST_CHECK( ip.is_valid() );
208 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.2" );
209 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 92 );
211 BOOST_CHECK( ip.is_valid() );
212 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.3" );
213 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 93 );
216 BOOST_AUTO_TEST_CASE( cache_retrieve_cname )
218 HostAddressVec ips = Cache->get_ips("cname.test");
219 BOOST_CHECK( ips.empty() );
221 Cname cname = Cache->get_cname("cname.test");
222 BOOST_CHECK_EQUAL( cname.Host, "host1.test" );
223 BOOST_CHECK_EQUAL( cname.Ttl.get_value(), 35 );
226 BOOST_AUTO_TEST_CASE( cache_retrieve_recursive1 )
228 // should get IP from host1 but ttl from cname since is smaller
229 HostAddressVec ips = Cache->get_ips_recursive("cname.test");
230 BOOST_CHECK_EQUAL( ips.size(), 1 );
231 HostAddress ip = ips.front();
232 BOOST_CHECK( ip.is_valid() );
233 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
234 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 35 );
237 BOOST_AUTO_TEST_CASE( cache_retrieve_recursive2 )
239 // should get IP from host1 but ttl from cname2 since is smaller
240 HostAddressVec ips = Cache->get_ips_recursive("cname3.test");
241 BOOST_CHECK_EQUAL( ips.size(), 1 );
242 HostAddress ip = ips.front();
243 BOOST_CHECK( ip.is_valid() );
244 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
245 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 33 );
248 void cname_skip_test(const uint32_t ttl1, const uint32_t ttl2,
249 const uint32_t ttl3, const uint32_t ttl4,
250 const DnsCacheItem &cache,
251 const std::string &correct_host_after_skip)
253 { // create cname chain:
254 // skip_chain_first -(ttl1)-> skip_chain_second -(ttl2)->
255 // skip_chain_third -(ttl3)-> skip_chain_fourth -(ttl4)-> IPs
256 cache->update( "skip_chain_first.test",
257 Cname("skip_chain_second.test", ttl1) );
258 cache->update( "skip_chain_second.test",
259 Cname("skip_chain_third.test", ttl2) );
260 cache->update( "skip_chain_third.test",
261 Cname("skip_chain_fourth.test", ttl3) );
263 ips.push_back( HostAddress( address::from_string("192.168.42.4"), ttl4) );
264 cache->update("skip_chain_fourth.test", ips);
267 // normal recursive call should give nothing since one cname is outdated
268 bool check_up_to_date = true;
269 HostAddressVec ips = cache->get_ips_recursive("skip_chain_first.test",
271 bool one_is_out_of_date = (ttl1 < 5) || (ttl2 < 5)
272 || (ttl3 < 5) || (ttl4 < 5);
273 BOOST_CHECK_EQUAL( ips.empty(), one_is_out_of_date );
275 // now find host to resolve after the outdated one
276 std::string first_outdated = cache->get_first_outdated_cname(
277 "skip_chain_first.test", 5);
278 BOOST_CHECK_EQUAL( first_outdated, correct_host_after_skip );
281 BOOST_AUTO_TEST_CASE( cache_skip_tests )
283 // build a cname chain where first one is out of date
284 cname_skip_test(0, 120, 120, 60, Cache, "skip_chain_second.test");
286 // build a cname chain where second one is out of date
287 cname_skip_test(120, 0, 120, 60, Cache, "skip_chain_third.test");
289 // build a cname chain where third one is out of date
290 cname_skip_test(120, 120, 0, 120, Cache, "skip_chain_fourth.test");
292 // build a cname chain where just IPs are out of date
293 cname_skip_test(120, 120, 120, 0, Cache, "");
295 // build a cname chain where all are out of date
296 cname_skip_test(0, 0, 0, 0, Cache, "skip_chain_second.test");
298 // build a cname chain where all is up to date
299 cname_skip_test(120, 120, 120, 120, Cache, "");
301 // test case with very short cname list that is up-to-date
302 BOOST_CHECK_EQUAL( Cache->get_first_outdated_cname("cname.test", 5), "" );
304 // test case where there is no cname at all
305 BOOST_CHECK_EQUAL( Cache->get_first_outdated_cname("host1.test", 5), "" );
308 BOOST_AUTO_TEST_CASE( cache_load_test )
310 std::stringstream file_name;
311 file_name << DATA_DIR_STRING << "/" << "dns_cache_example.xml";
312 BOOST_TEST_MESSAGE( "loading cache from file " << file_name.str() );
313 DnsCache loaded_cache( IoService, file_name.str() );
314 HostAddressVec ips = loaded_cache.get_ips("abc.xyz");
315 BOOST_CHECK_EQUAL( ips.size(), 1 );
316 HostAddress ip = ips.front();
317 BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "11.22.33.44" );
318 BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 567 );
319 BOOST_CHECK_EQUAL( ip.get_ttl().get_updated_value(), 0 );
321 Cname cname = loaded_cache.get_cname("cname1.xyz");
322 BOOST_CHECK_EQUAL( cname.Host, "abc.xyz" );
323 BOOST_CHECK_EQUAL( cname.Ttl.get_value(), 27 );
324 BOOST_CHECK_EQUAL( cname.Ttl.get_updated_value(), 0 );
326 // not testing Ttl set time since is private
330 BOOST_AUTO_TEST_SUITE_END() // of TestDnsCache
333 // -----------------------------------------------------------------------------
335 // -----------------------------------------------------------------------------
337 BOOST_FIXTURE_TEST_SUITE( TestDnsResolver, TestFixture )
339 BOOST_AUTO_TEST_CASE( create_resolver_v4 )
342 std::string hostname = "www.intra2net.com";
343 ResolverItem resolver = Master->get_resolver_for(hostname,
345 BOOST_CHECK_EQUAL( resolver->get_hostname(), hostname );
346 BOOST_CHECK( !resolver->is_resolving() );
347 BOOST_CHECK( !resolver->is_waiting_to_resolve() );
349 // cancel should have no effect
350 resolver->cancel_resolve();
351 BOOST_CHECK( !resolver->is_resolving() );
352 BOOST_CHECK( !resolver->is_waiting_to_resolve() );
354 // should not have any ips since cache did not load anything
355 BOOST_CHECK_EQUAL( resolver->get_resolved_ip_count(), 0 );
356 BOOST_CHECK( !resolver->have_up_to_date_ip() );
357 std::string no_ip = "0.0.0.0";
358 BOOST_CHECK_EQUAL( resolver->get_next_ip().get_ip().to_string(), no_ip );
362 void resolve_callback(IoServiceItem io_serv, ResolverItem resolver,
363 const bool was_success, const int cname_count)
365 resolver->cancel_resolve();
367 BOOST_TEST_MESSAGE( "Stopped io_service" );
371 BOOST_AUTO_TEST_CASE( do_resolve )
374 std::string hostname = "www.intra2net.com";
375 ResolverItem resolver = Master->get_resolver_for(hostname,
377 BOOST_CHECK( !resolver->is_resolving() );
378 BOOST_CHECK( !resolver->is_waiting_to_resolve() );
381 callback_type callback = boost::bind( resolve_callback, IoService, resolver,
384 resolver->async_resolve(callback);
385 BOOST_CHECK( resolver->is_resolving() );
387 // this will block until io service is stopped in resolve_callback
390 BOOST_CHECK( resolver->have_up_to_date_ip() );
393 BOOST_AUTO_TEST_SUITE_END() // of TestDnsResolver
395 BOOST_AUTO_TEST_SUITE_END()