-- SPDX-FileCopyrightText: © 2022—2026 Vladimir Zorin -- SPDX-License-Identifier: LicenseRef-OWL-1.0-or-later -- Licensed under OWL v1.0+. See LICENSE. local testimony = require("testimony") local client = require("dns.client") local cache = require("dns.cache") local testify = testimony.new("== dns.client ==") -- ========================================================================= -- Constructor -- ========================================================================= testify:that("new: returns resolver with default config", function() local r, err = client.new({ servers = { "1.1.1.1" } }) testimony.assert_not_nil(r, "expected resolver, got error: " .. (err or "nil")) testimony.assert_equal(5, r.cfg.timeout) testimony.assert_equal(2, r.cfg.retries) testimony.assert_equal(1, r.cfg.ndots) testimony.assert_equal(false, r.cfg.use_tcp) testimony.assert_equal(false, r.cfg.use_tls) testimony.assert_equal(false, r.cfg.use_0x20) testimony.assert_equal(4096, r.cfg.edns_buffer_size) r:close() end) testify:that("new: accepts all config options", function() local c = cache.new() local r, err = client.new({ servers = { "8.8.8.8", "8.8.4.4" }, timeout = 3, retries = 1, ndots = 2, search = { "corp.internal." }, edns_buffer_size = 1232, use_0x20 = true, cache = c, }) testimony.assert_not_nil(r, "expected resolver, got error: " .. (err or "nil")) testimony.assert_equal(3, r.cfg.timeout) testimony.assert_equal(1, r.cfg.retries) testimony.assert_equal(2, r.cfg.ndots) testimony.assert_equal(1232, r.cfg.edns_buffer_size) testimony.assert_equal(true, r.cfg.use_0x20) testimony.assert_equal(2, #r.cfg.servers) testimony.assert_equal(1, #r.cfg.search) r:close() end) testify:that("new: returns nil when servers missing", function() local r, err = client.new({}) testimony.assert_nil(r) testimony.assert_match("servers", err) end) testify:that("new: returns nil when servers empty", function() local r, err = client.new({ servers = {} }) testimony.assert_nil(r) testimony.assert_match("servers", err) end) -- ========================================================================= -- resolve() — Validation -- ========================================================================= testify:that("resolve: rejects unknown string qtype", function() local r, err = client.new({ servers = { "1.1.1.1" } }) testimony.assert_not_nil(r, "expected resolver, got error: " .. (err or "nil")) local answers, qerr = r:resolve("example.com", "BOGUS") testimony.assert_nil(answers) testimony.assert_match("unknown query type", qerr) r:close() end) -- ========================================================================= -- close() -- ========================================================================= testify:that("close: is callable without error", function() local r, err = client.new({ servers = { "1.1.1.1" } }) testimony.assert_not_nil(r, "expected resolver, got error: " .. (err or "nil")) r:close() -- Should not raise end) -- ========================================================================= -- parse_resolv_conf() -- ========================================================================= testify:that("parse_resolv_conf: parses system resolv.conf", function() local result, err = client.parse_resolv_conf() testimony.assert_not_nil(result, "expected result, got error: " .. (err or "nil")) testimony.assert_not_nil(result.servers) testimony.assert_true(#result.servers > 0, "expected at least one nameserver") for _, s in ipairs(result.servers) do testimony.assert_not_nil(s.host, "expected host field in server entry") end end) testify:that("parse_resolv_conf: returns nil for nonexistent file", function() local result, err = client.parse_resolv_conf("/nonexistent/resolv.conf") testimony.assert_nil(result) testimony.assert_not_nil(err) end) testify:that("parse_resolv_conf: output accepted by new()", function() local sys, err = client.parse_resolv_conf() if not sys or #sys.servers == 0 then return end local r, rerr = client.new(sys) testimony.assert_not_nil(r, "expected resolver from resolv.conf, got error: " .. (rerr or "nil")) r:close() end) -- ========================================================================= -- Server normalization -- ========================================================================= testify:that("new: normalizes string servers to tables", function() local r, err = client.new({ servers = { "1.1.1.1", "8.8.8.8" } }) testimony.assert_not_nil(r, "expected resolver, got error: " .. (err or "nil")) testimony.assert_equal("1.1.1.1", r.cfg.servers[1].host) testimony.assert_equal("8.8.8.8", r.cfg.servers[2].host) testimony.assert_nil(r.cfg.servers[1].port) r:close() end) testify:that("new: accepts table servers with host and port", function() local r, err = client.new({ servers = { { host = "1.1.1.1", port = 5353 } } }) testimony.assert_not_nil(r, "expected resolver, got error: " .. (err or "nil")) testimony.assert_equal("1.1.1.1", r.cfg.servers[1].host) testimony.assert_equal(5353, r.cfg.servers[1].port) r:close() end) testify:that("new: accepts mixed string and table servers", function() local r, err = client.new({ servers = { "1.1.1.1", { host = "8.8.8.8", port = 5353 } } }) testimony.assert_not_nil(r, "expected resolver, got error: " .. (err or "nil")) testimony.assert_equal("1.1.1.1", r.cfg.servers[1].host) testimony.assert_nil(r.cfg.servers[1].port) testimony.assert_equal("8.8.8.8", r.cfg.servers[2].host) testimony.assert_equal(5353, r.cfg.servers[2].port) r:close() end) testify:that("new: rejects table server without host", function() local r, err = client.new({ servers = { { port = 5353 } } }) testimony.assert_nil(r) testimony.assert_match("host", err) end) -- ========================================================================= -- Conclude -- ========================================================================= testify:conclude()