/* SSSD Async resolver tests Authors: Martin Nagy Jakub Hrozek Copyright (C) Red Hat, Inc 2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include "tests/common.h" #include "util/util.h" #include "tests/common_check.h" /* Interface under test */ #include "resolv/async_resolv.h" #define RESOLV_DEFAULT_TIMEOUT 6 static int use_net_test; static char *txt_host; static char *srv_host; struct resolv_test_ctx { struct tevent_context *ev; struct resolv_ctx *resolv; enum { TESTING_HOSTNAME, TESTING_TXT, TESTING_SRV, } tested_function; int error; bool done; }; static int setup_resolv_test(int timeout, struct resolv_test_ctx **ctx) { struct resolv_test_ctx *test_ctx; int ret; test_ctx = talloc_zero(global_talloc_context, struct resolv_test_ctx); if (test_ctx == NULL) { fail("Could not allocate memory for test context"); return ENOMEM; } test_ctx->ev = tevent_context_init(test_ctx); if (test_ctx->ev == NULL) { fail("Could not init tevent context"); talloc_free(test_ctx); return EFAULT; } ret = resolv_init(test_ctx, test_ctx->ev, timeout, &test_ctx->resolv); if (ret != EOK) { fail("Could not init resolv context"); talloc_free(test_ctx); return ret; } *ctx = test_ctx; return EOK; } static int test_loop(struct resolv_test_ctx *data) { while (!data->done) tevent_loop_once(data->ev); return data->error; } struct resolv_hostent * test_create_rhostent(TALLOC_CTX *mem_ctx, const char *hostname, const char *address) { struct resolv_hostent *rhostent; int ret; int family; rhostent = talloc_zero(mem_ctx, struct resolv_hostent); if (!rhostent) { return NULL; } rhostent->name = talloc_strdup(rhostent, hostname); rhostent->addr_list = talloc_array(rhostent, struct resolv_addr *, 2); if (!rhostent->name || !rhostent->addr_list) { goto fail; } rhostent->addr_list[0] = talloc_zero(rhostent->addr_list, struct resolv_addr); if (!rhostent->addr_list[0]) { goto fail; } rhostent->addr_list[0]->ipaddr = talloc_array(rhostent->addr_list[0], uint8_t, sizeof(struct in6_addr)); if (!rhostent->addr_list[0]->ipaddr) { goto fail; } family = AF_INET; ret = inet_pton(family, address, rhostent->addr_list[0]->ipaddr); if (ret != 1) { family = AF_INET6; ret = inet_pton(family, address, rhostent->addr_list[0]->ipaddr); if (ret != 1) { goto fail; } } rhostent->addr_list[0]->ttl = RESOLV_DEFAULT_TTL; rhostent->addr_list[1] = NULL; rhostent->family = family; rhostent->aliases = NULL; return rhostent; fail: talloc_free(rhostent); return NULL; } START_TEST(test_copy_hostent) { void *ctx; struct resolv_hostent *rhe; char name[] = "foo.example.com"; char alias_1[] = "bar.example.com"; char alias_2[] = "baz.example.com"; char *aliases[] = { alias_1, alias_2, NULL }; struct in_addr addr_1 = { 1234 }; struct in_addr addr_2 = { 5678 }; int ttl_1 = 12; int ttl_2 = 34; char *addr_list[] = { (char *) &addr_2, (char *) &addr_1, NULL }; struct hostent he = { name, aliases, AF_INET, sizeof(addr_1), addr_list }; struct ares_addrttl attl[] = { { addr_1, ttl_1 }, { addr_2, ttl_2 } }; ctx = talloc_new(global_talloc_context); fail_if(ctx == NULL); ck_leaks_push(ctx); rhe = resolv_copy_hostent_ares(ctx, &he, AF_INET, &attl, 2); fail_if(rhe == NULL); fail_if(strcmp(rhe->name, name)); fail_if(strcmp(rhe->aliases[0], alias_1)); fail_if(strcmp(rhe->aliases[1], alias_2)); fail_if(rhe->aliases[2] != NULL); fail_if(rhe->family != AF_INET); fail_if(memcmp(rhe->addr_list[0]->ipaddr, &addr_1, sizeof(addr_1))); fail_if(rhe->addr_list[0]->ttl != ttl_1); fail_if(memcmp(rhe->addr_list[1]->ipaddr, &addr_2, sizeof(addr_2))); fail_if(rhe->addr_list[1]->ttl != ttl_2); fail_if(rhe->addr_list[2] != NULL); talloc_zfree(rhe); rhe = resolv_copy_hostent(ctx, &he); fail_if(rhe == NULL); fail_if(strcmp(rhe->name, name)); fail_if(strcmp(rhe->aliases[0], alias_1)); fail_if(strcmp(rhe->aliases[1], alias_2)); fail_if(rhe->aliases[2] != NULL); fail_if(rhe->family != AF_INET); fail_if(memcmp(rhe->addr_list[0]->ipaddr, &addr_2, sizeof(addr_1))); fail_if(rhe->addr_list[0]->ttl != RESOLV_DEFAULT_TTL); fail_if(memcmp(rhe->addr_list[1]->ipaddr, &addr_1, sizeof(addr_2))); fail_if(rhe->addr_list[1]->ttl != RESOLV_DEFAULT_TTL); fail_if(rhe->addr_list[2] != NULL); talloc_free(rhe); ck_leaks_pop(ctx); } END_TEST START_TEST(test_address_to_string) { void *ctx; struct resolv_hostent *rhe; char *str_addr; char *ptr_addr; ctx = talloc_new(global_talloc_context); fail_if(ctx == NULL); ck_leaks_push(ctx); rhe = test_create_rhostent(ctx, "www.example.com", "1.2.3.4"); fail_if(rhe == NULL); str_addr = resolv_get_string_address_index(ctx, rhe, 0); fail_if(str_addr == NULL); fail_unless(strcmp(str_addr, "1.2.3.4") == 0, "Unexpected address\n"); talloc_free(str_addr); ptr_addr = resolv_get_string_ptr_address(ctx, rhe->family, rhe->addr_list[0]->ipaddr); fail_if(ptr_addr == NULL); fail_unless(strcmp(ptr_addr, "4.3.2.1.in-addr.arpa.") == 0, "Unexpected PTR address\n"); talloc_free(ptr_addr); talloc_free(rhe); rhe = test_create_rhostent(ctx, "www6.example.com", "2607:f8b0:400c:c03::6a"); fail_if(rhe == NULL); str_addr = resolv_get_string_address_index(ctx, rhe, 0); fail_if(str_addr == NULL); fail_unless(strcmp(str_addr, "2607:f8b0:400c:c03::6a") == 0, "Unexpected address\n"); talloc_free(str_addr); ptr_addr = resolv_get_string_ptr_address(ctx, rhe->family, rhe->addr_list[0]->ipaddr); fail_if(ptr_addr == NULL); fail_unless(strcmp(ptr_addr, "a.6.0.0.0.0.0.0.0.0.0.0.0.0.0.0.3.0.c.0.c.0.0.4.0.b.8.f.7.0.6.2.ip6.arpa.") == 0, "Unexpected PTR address\n"); talloc_free(ptr_addr); talloc_free(rhe); ck_leaks_pop(ctx); } END_TEST static void test_ip_addr(struct tevent_req *req) { int recv_status; int status; struct resolv_hostent *rhostent; int i; struct resolv_test_ctx *test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx); test_ctx->done = true; recv_status = resolv_gethostbyname_recv(req, test_ctx, &status, NULL, &rhostent); talloc_zfree(req); if (recv_status != EOK) { DEBUG(SSSDBG_OP_FAILURE, "resolv_gethostbyname_recv failed: %d\n", recv_status); test_ctx->error = recv_status; return; } DEBUG(SSSDBG_TRACE_LIBS, "resolv_gethostbyname_recv status: %d\n", status); test_ctx->error = ENOENT; for (i = 0; rhostent->addr_list[i]; i++) { char addr_buf[256]; inet_ntop(rhostent->family, rhostent->addr_list[i]->ipaddr, addr_buf, sizeof(addr_buf)); if (strcmp(addr_buf, "127.0.0.1") == 0) { test_ctx->error = EOK; } } talloc_free(rhostent); } START_TEST(test_resolv_ip_addr) { struct resolv_test_ctx *test_ctx; int ret = EOK; struct tevent_req *req; const char *hostname = "127.0.0.1"; ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx); if (ret != EOK) { fail("Could not set up test"); return; } ck_leaks_push(test_ctx); req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname, IPV4_ONLY, default_host_dbs); DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n"); if (req == NULL) { ret = ENOMEM; } if (ret == EOK) { tevent_req_set_callback(req, test_ip_addr, test_ctx); ret = test_loop(test_ctx); } ck_leaks_pop(test_ctx); fail_unless(ret == EOK); talloc_zfree(test_ctx); } END_TEST static void test_localhost(struct tevent_req *req) { int recv_status; int status; struct resolv_hostent *rhostent; int i; struct resolv_test_ctx *test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx); test_ctx->done = true; recv_status = resolv_gethostbyname_recv(req, test_ctx, &status, NULL, &rhostent); talloc_zfree(req); if (recv_status != EOK) { DEBUG(SSSDBG_OP_FAILURE, "resolv_gethostbyname_recv failed: %d\n", recv_status); test_ctx->error = recv_status; return; } DEBUG(SSSDBG_TRACE_LIBS, "resolv_gethostbyname_recv status: %d\n", status); test_ctx->error = ENOENT; for (i = 0; rhostent->addr_list[i]; i++) { char addr_buf[256]; inet_ntop(rhostent->family, rhostent->addr_list[i]->ipaddr, addr_buf, sizeof(addr_buf)); /* test that localhost resolves to 127.0.0.1 or ::1 */ if (strcmp(addr_buf, "127.0.0.1") == 0 || strcmp(addr_buf, "::1") == 0) { test_ctx->error = EOK; } } talloc_free(rhostent); } START_TEST(test_resolv_localhost) { struct resolv_test_ctx *test_ctx; int ret = EOK; struct tevent_req *req; const char *hostname = "localhost.localdomain"; ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx); if (ret != EOK) { fail("Could not set up test"); return; } ck_leaks_push(test_ctx); req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname, IPV4_FIRST, default_host_dbs); DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n"); if (req == NULL) { ret = ENOMEM; } if (ret == EOK) { tevent_req_set_callback(req, test_localhost, test_ctx); ret = test_loop(test_ctx); } ck_leaks_pop(test_ctx); fail_unless(ret == EOK); talloc_zfree(test_ctx); } END_TEST static void test_negative(struct tevent_req *req) { int recv_status; int status; struct resolv_hostent *hostent; struct resolv_test_ctx *test_ctx; test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx); test_ctx->done = true; recv_status = resolv_gethostbyname_recv(req, test_ctx, &status, NULL, &hostent); talloc_zfree(req); if (recv_status == EOK) { DEBUG(SSSDBG_TRACE_LIBS, "resolv_gethostbyname_recv succeeded in a negative test\n"); return; } test_ctx->error = status; DEBUG(SSSDBG_OP_FAILURE, "resolv_gethostbyname_recv status: %d: %s\n", status, resolv_strerror(status)); } START_TEST(test_resolv_negative) { int ret = EOK; struct tevent_req *req; const char *hostname = "sssd.foo"; struct resolv_test_ctx *test_ctx; ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx); if (ret != EOK) { fail("Could not set up test"); return; } ck_leaks_push(test_ctx); req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname, IPV4_FIRST, default_host_dbs); DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n"); if (req == NULL) { ret = ENOMEM; } if (ret == EOK) { tevent_req_set_callback(req, test_negative, test_ctx); ret = test_loop(test_ctx); } ck_leaks_pop(test_ctx); fail_unless(ret != EOK); fail_unless(test_ctx->error == ARES_ENOTFOUND); talloc_zfree(test_ctx); } END_TEST static void test_internet(struct tevent_req *req) { int recv_status; int status; struct resolv_test_ctx *test_ctx; void *tmp_ctx; struct resolv_hostent *rhostent = NULL; struct ares_txt_reply *txt_replies = NULL, *txtptr; struct ares_srv_reply *srv_replies = NULL, *require 'test/unit' require 'tmpdir' require 'tempfile' require_relative 'envutil' class TestRubyOptions < Test::Unit::TestCase def test_source_file assert_in_out_err([], "", [], []) end def test_usage assert_in_out_err(%w(-h)) do |r, e| assert_operator(r.size, :<=, 24) assert_equal([], e) end assert_in_out_err(%w(--help)) do |r, e| assert_operator(r.size, :<=, 24) assert_equal([], e) end end def test_option_variables assert_in_out_err(["-e", 'p [$-p, $-l, $-a]']) do |r, e| assert_equal(["[false, false, false]"], r) assert_equal([], e) end assert_in_out_err(%w(-p -l -a -e) + ['p [$-p, $-l, $-a]'], "foo\nbar\nbaz\n") do |r, e| assert_equal( [ '[true, true, true]', 'foo', '[true, true, true]', 'bar', '[true, true, true]', 'baz' ], r) assert_equal([], e) end end def test_warning assert_in_out_err(%w(-W0 -e) + ['p $-W'], "", %w(0), []) assert_in_out_err(%w(-W1 -e) + ['p $-W'], "", %w(1), []) assert_in_out_err(%w(-Wx -e) + ['p $-W'], "", %w(1), []) assert_in_out_err(%w(-W -e) + ['p $-W'], "", %w(2), []) end def test_safe_level assert_in_out_err(%w(-T -e) + [""], "", [], /no -e allowed in tainted mode \(SecurityError\)/) assert_in_out_err(%w(-T4 -S foo.rb), "", [], /no -S allowed in tainted mode \(SecurityError\)/) end def test_debug assert_in_out_err(%w(-de) + ["p $DEBUG"], "", %w(true), []) assert_in_out_err(%w(--debug -e) + ["p $DEBUG"], "", %w(true), []) end def test_verbose assert_in_out_err(%w(-vve) + [""]) do |r, e| assert_match(/^ruby #{RUBY_VERSION}(?:[p ]|dev).*? \[#{RUBY_PLATFORM}\]$/, r.join) assert_equal RUBY_DESCRIPTION, r.join.chomp assert_equal([], e) end assert_in_out_err(%w(--verbose -e) + ["p $VERBOSE"], "", %w(true), []) assert_in_out_err(%w(--verbose), "", [], []) end def test_copyright assert_in_out_err(%w(--copyright), "", /^ruby - Copyright \(C\) 1993-\d+ Yukihiro Matsumoto$/, []) assert_in_out_err(%w(--verbose -e) + ["p $VERBOSE"], "", %w(true), []) end def test_enable assert_in_out_err(%w(--enable all -e) + [""], "", [], []) assert_in_out_err(%w(--enable-all -e) + [""], "", [], []) assert_in_out_err(%w(--enable=all -e) + [""], "", [], []) assert_in_out_err(%w(--enable foobarbazqux -e) + [""], "", [], /unknown argument for --enable: `foobarbazqux'/) assert_in_out_err(%w(--enable), "", [], /missing argument for --enable/) end def test_disable assert_in_out_err(%w(--disable all -e) + [""], "", [], []) assert_in_out_err(%w(--disable-all -e) + [""], "", [], []) assert_in_out_err(%w(--disable=all -e) + [""], "", [], []) assert_in_out_err(%w(--disable foobarbazqux -e) + [""], "", [], /unknown argument for --disable: `foobarbazqux'/) assert_in_out_err(%w(--disable), "", [], /missing argument for --disable/) end def test_kanji assert_in_out_err(%w(-KU), "p '\u3042'") do |r, e| assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8)) end assert_in_out_err(%w(-KE -e) + [""], "", [], []) assert_in_out_err(%w(-KS -e) + [""], "", [], []) assert_in_out_err(%w(-KN -e) + [""], "", [], []) end def test_version assert_in_out_err(%w(--version)) do |r, e| assert_match(/^ruby #{RUBY_VERSION}(?:[p ]|dev).*? \[#{RUBY_PLATFORM}\]$/, r.join) assert_equal RUBY_DESCRIPTION, r.join.chomp assert_equal([], e) end end def test_eval assert_in_out_err(%w(-e), "", [], /no code specified for -e \(RuntimeError\)/) end def test_require require "pp" assert_in_out_err(%w(-r pp -e) + ["pp 1"], "", %w(1), []) assert_in_out_err(%w(-rpp -e) + ["pp 1"], "", %w(1), []) rescue LoadError end def test_include d = Dir.tmpdir assert_in_out_err(["-I" + d, "-e", ""], "", [], []) assert_in_out_err(["-I", d, "-e", ""], "", [], []) end def test_separator assert_in_out_err(%w(-000 -e) + ["print gets"], "foo\nbar\0baz", %W(foo bar\0baz), []) assert_in_out_err(%w(-0141 -e) + ["print gets"], "foo\nbar\0baz", %w(foo ba), []) assert_in_out_err(%w(-0e) + ["print gets"], "foo\nbar\0baz", %W(foo bar\0), []) end def test_autosplit assert_in_out_err(%w(-an -F: -e) + ["p $F"], "foo:bar:baz\nqux:quux:quuux\n", ['["foo", "bar", "baz\n"]', '["qux", "quux", "quuux\n"]'], []) end def test_chdir assert_in_out_err(%w(-C), "", [], /Can't chdir/) assert_in_out_err(%w(-C test_ruby_test_rubyoptions_foobarbazqux), "", [], /Can't chdir/) d = Dir.tmpdir assert_in_out_err(["-C", d, "-e", "puts Dir.pwd"]) do |r, e| assert(File.identical?(r.join, d)) assert_equal([], e) end end def test_yydebug assert_in_out_err(["-ye", ""]) do |r, e| assert_equal([], r) assert_not_equal([], e) end assert_in_out_err(%w(--yydebug -e) + [""]) do |r, e| assert_equal([], r) assert_not_equal([], e) end end def test_encoding assert_in_out_err(%w(-Eutf-8), "p '\u3042'", [], /invalid multibyte char/) assert_in_out_err(%w(--encoding), "", [], /missing argument for --encoding/) assert_in_out_err(%w(--encoding test_ruby_test_rubyoptions_foobarbazqux), "", [], /unknown encoding name - test_ruby_test_rubyoptions_foobarbazqux \(RuntimeError\)/) assert_in_out_err(%w(--encoding utf-8), "p '\u3042'", [], /invalid multibyte char/) end def test_syntax_check assert_in_out_err(%w(-c -e 1+1), "", ["Syntax OK"], []) end def test_invalid_option assert_in_out_err(%w(--foobarbazqux), "", [], /invalid option --foobarbazqux/) assert_in_out_err(%W(-\r -e) + [""], "", [], []) assert_in_out_err(%W(-\rx), "", [], /invalid option -\\x0D \(-h will show valid options\) \(RuntimeError\)/) assert_in_out_err(%W(-\x01), "", [], /invalid option -\\x01 \(-h will show valid options\) \(RuntimeError\)/) assert_in_out_err(%w(-Z), "", [], /invalid option -Z \(-h will show valid options\) \(RuntimeError\)/) end def test_rubyopt rubyopt_orig = ENV['RUBYOPT'] ENV['RUBYOPT'] = ' - -' assert_in_out_err([], "", [], []) assert_in_out_err(['-e', 'p $:.include?(".")'], "", ["true"], []) ENV['RUBYOPT'] = '-e "p 1"' assert_in_out_err([], "", [], /invalid switch in RUBYOPT: -e \(RuntimeError\)/) ENV['RUBYOPT'] = '-T1' assert_in_out_err([], "", [], /no program input from stdin allowed in tainted mode \(SecurityError\)/) assert_in_out_err(['-e', 'p $:.include?(".")'], "", ["false"], []) ENV['RUBYOPT'] = '-T4' assert_in_out_err([], "", [], /no program input from stdin allowed in tainted mode \(SecurityError\)/) ENV['RUBYOPT'] = '-Eus-ascii -KN' assert_in_out_err(%w(-Eutf-8 -KU), "p '\u3042'") do |r, e| assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8)) assert_equal([], e) end ensure if rubyopt_orig ENV['RUBYOPT'] = rubyopt_orig else ENV.delete('RUBYOPT') end end def test_search rubypath_orig = ENV['RUBYPATH'] path_orig = ENV['PATH'] t = Tempfile.new(["test_ruby_test_rubyoption", ".rb"]) t.puts "p 1" t.close @verbose = $VERBOSE $VERBOSE = nil ENV['PATH'] = File.dirname(t.path) assert_in_out_err(%w(-S) + [File.basename(t.path)], "", %w(1), []) ENV['RUBYPATH'] = File.dirname(t.path) assert_in_out_err(%w(-S) + [File.basename(t.path)], "", %w(1), []) ensure if rubypath_orig ENV['RUBYPATH'] = rubypath_orig else ENV.delete('RUBYPATH') end if path_orig ENV['PATH'] = path_orig else ENV.delete('PATH') end t.close(true) if t $VERBOSE = @verbose end def test_shebang assert_in_out_err([], "#! /test_r_u_b_y_test_r_u_b_y_options_foobarbazqux\r\np 1\r\n", [], /Can't exec [\/\\]test_r_u_b_y_test_r_u_b_y_options_foobarbazqux \(fatal\)/) assert_in_out_err([], "#! /test_r_u_b_y_test_r_u_b_y_options_foobarbazqux -foo -bar\r\np 1\r\n", [], /Can't exec [\/\\]test_r_u_b_y_test_r_u_b_y_options_foobarbazqux \(fatal\)/) assert_in_out_err([], "#!ruby -KU -Eutf-8\r\np \"\u3042\"\r\n") do |r, e| assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8)) assert_equal([], e) end end def test_sflag assert_in_out_err(%w(- -abc -def=foo -ghi-jkl -- -xyz), "#!ruby -s\np [$abc, $def, $ghi_jkl, $xyz]\n", ['[true, "foo", true, nil]'], []) assert_in_out_err(%w(- -#), "#!ruby -s\n", [], /invalid name for global variable - -# \(NameError\)/) assert_in_out_err(%w(- -#=foo), "#!ruby -s\n", [], /invalid name for global variable - -# \(NameError\)/) end end