Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests(helpers): separate dns_mock module #13617

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 213 additions & 0 deletions spec/details/dns.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
local cjson = require("cjson.safe")


----------------
-- DNS-record mocking.
-- These function allow to create mock dns records that the test Kong instance
-- will use to resolve names. The created mocks are injected by the `start_kong`
-- function.
-- @usage
-- -- Create a new DNS mock and add some DNS records
-- local fixtures = {
-- dns_mock = helpers.dns_mock.new { mocks_only = true }
-- }
--
-- fixtures.dns_mock:SRV {
-- name = "my.srv.test.com",
-- target = "a.my.srv.test.com",
-- port = 80,
-- }
-- fixtures.dns_mock:SRV {
-- name = "my.srv.test.com", -- adding same name again: record gets 2 entries!
-- target = "b.my.srv.test.com", -- a.my.srv.test.com and b.my.srv.test.com
-- port = 8080,
-- }
-- fixtures.dns_mock:A {
-- name = "a.my.srv.test.com",
-- address = "127.0.0.1",
-- }
-- fixtures.dns_mock:A {
-- name = "b.my.srv.test.com",
-- address = "127.0.0.1",
-- }
-- @section DNS-mocks


local dns_mock = {}


dns_mock.__index = dns_mock
dns_mock.__tostring = function(self)
-- fill array to prevent json encoding errors
local out = {
mocks_only = self.mocks_only,
records = {}
}
for i = 1, 33 do
out.records[i] = self[i] or {}
end
local json = assert(cjson.encode(out))
return json
end


local TYPE_A, TYPE_AAAA, TYPE_CNAME, TYPE_SRV = 1, 28, 5, 33


--- Creates a new DNS mock.
-- The options table supports the following fields:
--
-- - `mocks_only`: boolean, if set to `true` then only mock records will be
-- returned. If `falsy` it will fall through to an actual DNS lookup.
-- @function dns_mock.new
-- @param options table with mock options
-- @return dns_mock object
-- @usage
-- local mock = helpers.dns_mock.new { mocks_only = true }
function dns_mock.new(options)
return setmetatable(options or {}, dns_mock)
end


--- Adds an SRV record to the DNS mock.
-- Fields `name`, `target`, and `port` are required. Other fields get defaults:
--
-- * `weight`; 20
-- * `ttl`; 600
-- * `priority`; 20
-- @param rec the mock DNS record to insert
-- @return true
function dns_mock:SRV(rec)
if self == dns_mock then
error("can't operate on the class, you must create an instance", 2)
end
if getmetatable(self or {}) ~= dns_mock then
error("SRV method must be called using the colon notation", 2)
end
assert(rec, "Missing record parameter")
local name = assert(rec.name, "No name field in SRV record")

self[TYPE_SRV] = self[TYPE_SRV] or {}
local query_answer = self[TYPE_SRV][name]
if not query_answer then
query_answer = {}
self[TYPE_SRV][name] = query_answer
end

table.insert(query_answer, {
type = TYPE_SRV,
name = name,
target = assert(rec.target, "No target field in SRV record"),
port = assert(rec.port, "No port field in SRV record"),
weight = rec.weight or 10,
ttl = rec.ttl or 600,
priority = rec.priority or 20,
class = rec.class or 1
})
return true
end


--- Adds an A record to the DNS mock.
-- Fields `name` and `address` are required. Other fields get defaults:
--
-- * `ttl`; 600
-- @param rec the mock DNS record to insert
-- @return true
function dns_mock:A(rec)
if self == dns_mock then
error("can't operate on the class, you must create an instance", 2)
end
if getmetatable(self or {}) ~= dns_mock then
error("A method must be called using the colon notation", 2)
end
assert(rec, "Missing record parameter")
local name = assert(rec.name, "No name field in A record")

self[TYPE_A] = self[TYPE_A] or {}
local query_answer = self[TYPE_A][name]
if not query_answer then
query_answer = {}
self[TYPE_A][name] = query_answer
end

table.insert(query_answer, {
type = TYPE_A,
name = name,
address = assert(rec.address, "No address field in A record"),
ttl = rec.ttl or 600,
class = rec.class or 1
})
return true
end


--- Adds an AAAA record to the DNS mock.
-- Fields `name` and `address` are required. Other fields get defaults:
--
-- * `ttl`; 600
-- @param rec the mock DNS record to insert
-- @return true
function dns_mock:AAAA(rec)
if self == dns_mock then
error("can't operate on the class, you must create an instance", 2)
end
if getmetatable(self or {}) ~= dns_mock then
error("AAAA method must be called using the colon notation", 2)
end
assert(rec, "Missing record parameter")
local name = assert(rec.name, "No name field in AAAA record")

self[TYPE_AAAA] = self[TYPE_AAAA] or {}
local query_answer = self[TYPE_AAAA][name]
if not query_answer then
query_answer = {}
self[TYPE_AAAA][name] = query_answer
end

table.insert(query_answer, {
type = TYPE_AAAA,
name = name,
address = assert(rec.address, "No address field in AAAA record"),
ttl = rec.ttl or 600,
class = rec.class or 1
})
return true
end


--- Adds a CNAME record to the DNS mock.
-- Fields `name` and `cname` are required. Other fields get defaults:
--
-- * `ttl`; 600
-- @param rec the mock DNS record to insert
-- @return true
function dns_mock:CNAME(rec)
if self == dns_mock then
error("can't operate on the class, you must create an instance", 2)
end
if getmetatable(self or {}) ~= dns_mock then
error("CNAME method must be called using the colon notation", 2)
end
assert(rec, "Missing record parameter")
local name = assert(rec.name, "No name field in CNAME record")

self[TYPE_CNAME] = self[TYPE_CNAME] or {}
local query_answer = self[TYPE_CNAME][name]
if not query_answer then
query_answer = {}
self[TYPE_CNAME][name] = query_answer
end

table.insert(query_answer, {
type = TYPE_CNAME,
name = name,
cname = assert(rec.cname, "No cname field in CNAME record"),
ttl = rec.ttl or 600,
class = rec.class or 1
})
return true
end


return dns_mock
Loading
Loading