1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
-- SPDX-License-Identifier: GPL-3.0-or-later
-- check prerequisites
local has_http = pcall(require, 'kres_modules.http') and pcall(require, 'http.request')
if not has_http then
-- skipping daf module test because http its not installed
os.exit(77)
else
local path = worker.cwd..'/control/'..worker.pid
same(true, net.listen(path, nil, {kind = 'control'}),
'new control sockets were created so map() can work')
local request = require('http.request')
modules.load('http')
modules.load('daf')
local bound
for _ = 1,1000 do
bound, _err = pcall(net.listen, '127.0.0.1', math.random(40000, 49999), { kind = 'webmgmt'})
if bound then
break
end
end
assert(bound, 'unable to bind a port for HTTP module (1000 attempts)')
-- globals for this module
local _, host, port, baseuri
local function start_server()
local server_fd = next(http.servers)
assert(server_fd)
local server = http.servers[server_fd].server
ok(server ~= nil, 'creates server instance')
_, host, port = server:localname()
ok(host and port, 'binds to an interface')
baseuri = string.format('http://%s:%d/daf', host, port)
end
-- helper for returning useful values to test on
-- local function http_get(uri)
-- local headers, stream = assert(request.new_from_uri(uri):go(16))
-- local body = assert(stream:get_body_as_string())
-- return tonumber(headers:get(':status')), body, headers:get('content-type')
-- end
local function http_req(uri, method, reqbody)
local req = assert(request.new_from_uri(baseuri .. uri))
req.headers:upsert(':method', method)
req:set_body(reqbody)
local headers, stream = assert(req:go(16))
local ansbody = assert(stream:get_body_as_string())
return tonumber(headers:get(':status')), ansbody, headers:get('content-type')
end
local function http_get(uri)
return http_req(uri, 'GET')
end
-- compare two tables, expected value is specified as JSON
-- comparison relies on table_print which sorts table keys
local function compare_tables(expectedjson, gotjson, desc)
same(
table_print(fromjson(expectedjson)),
table_print(fromjson(gotjson)),
desc)
end
-- test whether http interface responds and binds
local function test_daf_api()
local code, body, mime
-- rule listing /daf
code, body, mime = http_get('/')
same(code, 200, 'rule listing return 200 OK')
same(body, '{}', 'daf rule list is empty after start')
same(mime, 'application/json', 'daf rule list has application/json content type')
-- get non-existing rule
code, body = http_req('/0', 'GET')
same(code, 404, 'non-existing rule retrieval returns 404')
same(body, '"No such rule"', 'explanatory message is present')
-- delete non-existing rule
code, body = http_req('/0', 'DELETE')
same(code, 404, 'non-existing rule deletion returns 404')
same(body, '"No such rule"', 'explanatory message is present')
-- bad PATCH
code = http_req('/0', 'PATCH')
same(code, 400, 'PATCH detects missing parameters')
-- bad POST
code = http_req('/', 'POST')
same(code, 500, 'POST without parameters is detected')
-- POST first new rule
code, body, mime = http_req('/', 'POST', 'src = 192.0.2.0 pass')
same(code, 200, 'first POST succeeds')
compare_tables(body,
'{"count":0,"active":true,"id":0,"info":"src = 192.0.2.0 pass"}',
'POST returns new rule in JSON')
same(mime, 'application/json', 'rule has application/json content type')
-- GET first rule
code, body, mime = http_req('/0', 'GET')
same(code, 200, 'GET for first rule succeeds')
compare_tables(body,
'{"count":0,"active":true,"id":0,"info":"src = 192.0.2.0 pass"}',
'POST returns new rule in JSON')
same(mime, 'application/json', 'rule has application/json content type')
-- POST second new rule
code, body, mime = http_req('/', 'POST', 'src = 192.0.2.1 pass')
same(code, 200, 'second POST succeeds')
compare_tables(body,
'{"count":0,"active":true,"id":1,"info":"src = 192.0.2.1 pass"}',
'POST returns new rule in JSON')
same(mime, 'application/json', 'rule has application/json content type')
-- GET second rule
code, body, mime = http_req('/1', 'GET')
same(code, 200, 'GET for second rule succeeds')
compare_tables(body,
'{"count":0,"active":true,"id":1,"info":"src = 192.0.2.1 pass"}',
'POST returns new rule in JSON')
same(mime, 'application/json', 'rule has application/json content type')
-- PATCH first rule
code, body, mime = http_req('/0/active/false', 'PATCH')
same(code, 200, 'PATCH for first rule succeeds')
same(body, 'true', 'PATCH returns success in body')
same(mime, 'application/json', 'PATCH return value has application/json content type')
-- GET modified first rule
code, body, mime = http_req('/0', 'GET')
same(code, 200, 'GET for first rule succeeds')
compare_tables(body,
'{"count":0,"active":false,"id":0,"info":"src = 192.0.2.0 pass"}',
'GET returns modified rule in JSON')
same(mime, 'application/json', 'rule has application/json content type')
-- GET both rules
code, body, mime = http_req('/', 'GET')
same(code, 200, 'GET for both rule succeeds')
compare_tables(body, [[
[
{"count":0,"active":false,"info":"src = 192.0.2.0 pass","id":0},
{"count":0,"active":true,"info":"src = 192.0.2.1 pass","id":1}]
]],
'GET returns both rules in JSON including modifications')
same(mime, 'application/json', 'rule list has application/json content type')
-- PATCH first rule back to original state
code, body, mime = http_req('/0/active/true', 'PATCH')
same(code, 200, 'PATCH for first rule succeeds')
same(body, 'true', 'PATCH returns success in body')
same(mime, 'application/json', 'PATCH return value has application/json content type')
-- GET modified (reversed) first rule
code, body, mime = http_req('/0', 'GET')
same(code, 200, 'GET for first rule succeeds')
compare_tables(body,
'{"count":0,"active":true,"id":0,"info":"src = 192.0.2.0 pass"}',
'GET returns modified rule in JSON')
same(mime, 'application/json', 'rule has application/json content type')
-- DELETE first rule
code, body, mime = http_req('/0', 'DELETE')
same(code, 200, 'DELETE for first rule succeeds')
same(body, 'true', 'DELETE returns success in body')
same(mime, 'application/json', 'DELETE return value has application/json content type')
-- GET deleted (first) rule
code, body = http_req('/0', 'GET')
same(code, 404, 'GET for deleted fails with 404')
same(body, '"No such rule"', 'failed GET contains explanatory message')
-- GET second rule
code, body, mime = http_req('/1', 'GET')
same(code, 200, 'GET for second rule still succeeds')
compare_tables(body,
'{"count":0,"active":true,"id":1,"info":"src = 192.0.2.1 pass"}',
'POST returns new rule in JSON')
same(mime, 'application/json', 'rule has application/json content type')
-- GET list of all rules
code, body, mime = http_req('/', 'GET')
same(code, 200, 'GET returns list with the remaining rule')
compare_tables(body,
'[{"count":0,"active":true,"id":1,"info":"src = 192.0.2.1 pass"}]',
'rule list contains only the remaining rule in JSON')
same(mime, 'application/json', 'rule has application/json content type')
-- try to DELETE first rule again
code, body = http_req('/0', 'DELETE')
same(code, 404, 'DELETE for already deleted rule fails with 404')
same(body, '"No such rule"', 'DELETE explains failure')
-- DELETE second rule
code, body, mime = http_req('/1', 'DELETE')
same(code, 200, 'DELETE for second rule succeeds')
same(body, 'true', 'DELETE returns success in body')
same(mime, 'application/json', 'DELETE return value has application/json content type')
-- GET (supposedly empty) list of all rules
code, body, mime = http_req('/', 'GET')
same(code, 200, 'GET returns list with the remaining rule')
compare_tables(body, '[]', 'rule list is now empty JSON list')
same(mime, 'application/json', 'rule has application/json content type')
end
-- plan tests
local tests = {
start_server,
test_daf_api,
}
return tests
end
|