925 lines
33 KiB
Lua
925 lines
33 KiB
Lua
local cjson = require "cjson"
|
|
local uuid = require "kong.tools.uuid"
|
|
local helpers = require "spec.helpers"
|
|
local Errors = require "kong.db.errors"
|
|
|
|
|
|
local unindent = helpers.unindent
|
|
|
|
|
|
local function it_content_types(title, fn)
|
|
local test_form_encoded = fn("application/x-www-form-urlencoded")
|
|
local test_multipart = fn("multipart/form-data")
|
|
local test_json = fn("application/json")
|
|
|
|
it(title .. " with application/www-form-urlencoded", test_form_encoded)
|
|
it(title .. " with multipart/form-data", test_multipart)
|
|
it(title .. " with application/json", test_json)
|
|
end
|
|
|
|
|
|
for _, strategy in helpers.each_strategy() do
|
|
describe("Admin API #" .. strategy, function()
|
|
local bp
|
|
local db
|
|
local client
|
|
|
|
lazy_setup(function()
|
|
bp, db = helpers.get_db_utils(strategy, {
|
|
"routes",
|
|
"services",
|
|
})
|
|
assert(helpers.start_kong({
|
|
database = strategy,
|
|
}))
|
|
end)
|
|
|
|
lazy_teardown(function()
|
|
helpers.stop_kong()
|
|
end)
|
|
|
|
before_each(function()
|
|
client = assert(helpers.admin_client())
|
|
end)
|
|
|
|
after_each(function()
|
|
if client then
|
|
client:close()
|
|
end
|
|
end)
|
|
|
|
describe("/services", function()
|
|
describe("POST", function()
|
|
it_content_types("creates a service", function(content_type)
|
|
return function()
|
|
local res = client:post("/services", {
|
|
body = {
|
|
protocol = "http",
|
|
host = "service.test",
|
|
},
|
|
headers = { ["Content-Type"] = content_type },
|
|
})
|
|
local body = assert.res_status(201, res)
|
|
local json = cjson.decode(body)
|
|
|
|
assert.is_string(json.id)
|
|
assert.is_number(json.created_at)
|
|
assert.is_number(json.updated_at)
|
|
assert.equals(cjson.null, json.name)
|
|
assert.equals("http", json.protocol)
|
|
assert.equals("service.test", json.host)
|
|
assert.equals(80, json.port)
|
|
assert.equals(60000, json.connect_timeout)
|
|
assert.equals(60000, json.write_timeout)
|
|
assert.equals(60000, json.read_timeout)
|
|
end
|
|
end)
|
|
|
|
it_content_types("creates a service with url", function(content_type)
|
|
return function()
|
|
local res = client:post("/services", {
|
|
body = {
|
|
url = "http://service.test/",
|
|
},
|
|
headers = { ["Content-Type"] = content_type },
|
|
})
|
|
local body = assert.res_status(201, res)
|
|
local json = cjson.decode(body)
|
|
|
|
assert.is_string(json.id)
|
|
assert.is_number(json.created_at)
|
|
assert.is_number(json.updated_at)
|
|
assert.equals(cjson.null, json.name)
|
|
assert.equals("http", json.protocol)
|
|
assert.equals("service.test", json.host)
|
|
assert.equals("/", json.path)
|
|
assert.equals(80, json.port)
|
|
assert.equals(60000, json.connect_timeout)
|
|
assert.equals(60000, json.write_timeout)
|
|
assert.equals(60000, json.read_timeout)
|
|
end
|
|
end)
|
|
|
|
it_content_types("'port' defaults to 443 when 'url' scheme is https", function(content_type)
|
|
return function()
|
|
local res = client:post("/services", {
|
|
body = {
|
|
url = "https://service.test/",
|
|
},
|
|
headers = { ["Content-Type"] = content_type },
|
|
})
|
|
local body = assert.res_status(201, res)
|
|
local json = cjson.decode(body)
|
|
|
|
assert.is_string(json.id)
|
|
assert.is_number(json.created_at)
|
|
assert.is_number(json.updated_at)
|
|
assert.equals(cjson.null, json.name)
|
|
assert.equals("https", json.protocol)
|
|
assert.equals("service.test", json.host)
|
|
assert.equals("/", json.path)
|
|
assert.equals(443, json.port)
|
|
assert.equals(60000, json.connect_timeout)
|
|
assert.equals(60000, json.write_timeout)
|
|
assert.equals(60000, json.read_timeout)
|
|
end
|
|
end)
|
|
|
|
it_content_types("client error with with empty url", function(content_type)
|
|
return function()
|
|
local res = client:post("/services", {
|
|
body = {
|
|
url = "",
|
|
},
|
|
headers = { ["Content-Type"] = content_type },
|
|
})
|
|
assert.res_status(400, res)
|
|
end
|
|
end)
|
|
|
|
it_content_types("client error with invalid url", function(content_type)
|
|
return function()
|
|
local res = client:post("/services", {
|
|
body = {
|
|
url = " ",
|
|
},
|
|
headers = { ["Content-Type"] = content_type },
|
|
})
|
|
assert.res_status(400, res)
|
|
end
|
|
end)
|
|
end)
|
|
|
|
describe("GET", function()
|
|
describe("with data", function()
|
|
lazy_setup(function()
|
|
db:truncate("services")
|
|
for _ = 1, 10 do
|
|
assert(bp.named_services:insert())
|
|
end
|
|
end)
|
|
|
|
it("retrieves the first page", function()
|
|
local res = client:get("/services")
|
|
local res = assert.res_status(200, res)
|
|
local json = cjson.decode(res)
|
|
assert.equal(10, #json.data)
|
|
end)
|
|
|
|
it("paginates a set", function()
|
|
local pages = {}
|
|
local offset
|
|
|
|
for i = 1, 4 do
|
|
local res = client:get("/services",
|
|
{ query = { size = 3, offset = offset }})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
|
|
if i < 4 then
|
|
assert.equal(3, #json.data)
|
|
else
|
|
assert.equal(1, #json.data)
|
|
end
|
|
|
|
if i > 1 then
|
|
-- check all pages are different
|
|
assert.not_same(pages[i-1], json)
|
|
end
|
|
|
|
offset = json.offset
|
|
pages[i] = json
|
|
end
|
|
end)
|
|
|
|
it("propagate in next a page size", function()
|
|
local res = client:get("/services",
|
|
{ query = { size = 3 }})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
|
|
assert.equals("/services?offset=" .. ngx.escape_uri(json.offset) .. "&size=3", json.next)
|
|
end)
|
|
end)
|
|
|
|
describe("with no data", function()
|
|
lazy_setup(function()
|
|
db:truncate("services")
|
|
end)
|
|
it("data property is an empty array and not an empty hash", function()
|
|
local res = client:get("/services")
|
|
local body = assert.res_status(200, res)
|
|
assert.matches('"data":%[%]', body)
|
|
local json = cjson.decode(body)
|
|
assert.same({ data = {}, next = cjson.null }, json)
|
|
end)
|
|
end)
|
|
|
|
describe("errors", function()
|
|
it("handles invalid filters", function()
|
|
local res = client:get("/services", { query = { foo = "bar" } })
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.same({ data = {}, next = cjson.null }, json)
|
|
end)
|
|
|
|
it("ignores an invalid body", function()
|
|
local res = client:get("/services", {
|
|
body = "this fails if decoded as json",
|
|
headers = {
|
|
["Content-Type"] = "application/json",
|
|
}
|
|
})
|
|
assert.res_status(200, res)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("/services/{service}", function()
|
|
|
|
describe("GET", function()
|
|
it("retrieves by id", function()
|
|
local service = bp.services:insert(nil, { nulls = true })
|
|
local res = client:get("/services/" .. service.id)
|
|
local body = assert.res_status(200, res)
|
|
|
|
local json = cjson.decode(body)
|
|
assert.same(service, json)
|
|
end)
|
|
|
|
it("retrieves by name", function()
|
|
local service = bp.named_services:insert(nil, { nulls = true })
|
|
local res = client:get("/services/" .. service.name)
|
|
local body = assert.res_status(200, res)
|
|
|
|
local json = cjson.decode(body)
|
|
assert.same(service, json)
|
|
end)
|
|
|
|
it("retrieves by utf-8 name and percent-escaped utf-8 name", function()
|
|
local service = bp.services:insert({ name = "円" }, { nulls = true })
|
|
local res = client:get("/services/" .. service.name)
|
|
local body = assert.res_status(200, res)
|
|
|
|
local json = cjson.decode(body)
|
|
assert.same(service, json)
|
|
|
|
res = client:get("/services/%E5%86%86")
|
|
body = assert.res_status(200, res)
|
|
|
|
json = cjson.decode(body)
|
|
assert.same(service, json)
|
|
end)
|
|
|
|
it("returns 404 if not found", function()
|
|
local res = client:get("/services/" .. uuid.uuid())
|
|
assert.res_status(404, res)
|
|
end)
|
|
|
|
it("returns 404 if not found by name", function()
|
|
local res = client:get("/services/not-found")
|
|
assert.res_status(404, res)
|
|
end)
|
|
|
|
it("ignores an invalid body", function()
|
|
local service = bp.services:insert()
|
|
local res = client:get("/services/" .. service.id, {
|
|
headers = {
|
|
["Content-Type"] = "application/json"
|
|
},
|
|
body = "this fails if decoded as json",
|
|
})
|
|
assert.res_status(200, res)
|
|
end)
|
|
|
|
it("ignores an invalid body by name", function()
|
|
local service = bp.named_services:insert()
|
|
local res = client:get("/services/" .. service.name, {
|
|
headers = {
|
|
["Content-Type"] = "application/json"
|
|
},
|
|
body = "this fails if decoded as json",
|
|
})
|
|
assert.res_status(200, res)
|
|
end)
|
|
end)
|
|
|
|
describe("PATCH", function()
|
|
it_content_types("updates if found", function(content_type)
|
|
return function()
|
|
if content_type == "multipart/form-data" then
|
|
-- the client doesn't play well with this
|
|
return
|
|
end
|
|
|
|
local service = bp.services:insert()
|
|
local res = client:patch("/services/" .. service.id, {
|
|
headers = {
|
|
["Content-Type"] = content_type
|
|
},
|
|
body = {
|
|
name = cjson.null,
|
|
protocol = "https",
|
|
},
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(cjson.null, json.name)
|
|
assert.equal("https", json.protocol)
|
|
assert.equal(service.id, json.id)
|
|
|
|
local in_db = assert(db.services:select(service, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end
|
|
end)
|
|
|
|
it_content_types("updates if found by name", function(content_type)
|
|
return function()
|
|
local service = bp.named_services:insert()
|
|
local res = client:patch("/services/" .. service.name, {
|
|
headers = {
|
|
["Content-Type"] = content_type
|
|
},
|
|
body = {
|
|
protocol = "https",
|
|
},
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("https", json.protocol)
|
|
assert.equal(service.id, json.id)
|
|
assert.equal(service.name, json.name)
|
|
|
|
local in_db = assert(db.services:select_by_name(service.name, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end
|
|
end)
|
|
|
|
it_content_types("updates with url", function(content_type)
|
|
return function()
|
|
if content_type == "multipart/form-data" then
|
|
-- the client doesn't play well with this
|
|
return
|
|
end
|
|
|
|
local service = bp.services:insert()
|
|
|
|
local res = client:patch("/services/" .. service.id, {
|
|
headers = {
|
|
["Content-Type"] = content_type
|
|
},
|
|
body = {
|
|
url = "http://example.test:443"
|
|
},
|
|
})
|
|
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("http", json.protocol)
|
|
assert.equal("example.test", json.host)
|
|
assert.equal(443, json.port)
|
|
assert.equal(cjson.null, json.path)
|
|
assert.equal(service.id, json.id)
|
|
|
|
local in_db = assert(db.services:select(service, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
|
|
|
|
local res = client:patch("/services/" .. service.id, {
|
|
headers = {
|
|
["Content-Type"] = content_type
|
|
},
|
|
body = {
|
|
url = "https://example2.test:80/"
|
|
},
|
|
})
|
|
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("https", json.protocol)
|
|
assert.equal("example2.test", json.host)
|
|
assert.equal(80, json.port)
|
|
assert.equal("/", json.path)
|
|
assert.equal(service.id, json.id)
|
|
|
|
local in_db = assert(db.services:select(service, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
|
|
local res = client:patch("/services/" .. service.id, {
|
|
headers = {
|
|
["Content-Type"] = content_type
|
|
},
|
|
body = {
|
|
url = "http://example2.test"
|
|
},
|
|
})
|
|
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("http", json.protocol)
|
|
assert.equal("example2.test", json.host)
|
|
assert.equal(80, json.port)
|
|
assert.equal(cjson.null, json.path)
|
|
assert.equal(service.id, json.id)
|
|
|
|
local in_db = assert(db.services:select(service, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end
|
|
end)
|
|
|
|
end)
|
|
|
|
describe("DELETE", function()
|
|
it("deletes a service", function()
|
|
local service = bp.services:insert()
|
|
local res = client:delete("/services/" .. service.id)
|
|
local body = assert.res_status(204, res)
|
|
assert.equal("", body)
|
|
|
|
local in_db, err = db.services:select(service, { nulls = true })
|
|
assert.is_nil(err)
|
|
assert.is_nil(in_db)
|
|
end)
|
|
|
|
it("deletes a service by name", function()
|
|
local service = bp.named_services:insert()
|
|
local res = client:delete("/services/" .. service.name)
|
|
local body = assert.res_status(204, res)
|
|
assert.equal("", body)
|
|
|
|
local in_db, err = db.services:select_by_name(service.name)
|
|
assert.is_nil(err)
|
|
assert.is_nil(in_db)
|
|
end)
|
|
|
|
describe("errors", function()
|
|
it("returns HTTP 204 even if not found", function()
|
|
local res = client:delete("/services/" .. uuid.uuid())
|
|
assert.res_status(204, res)
|
|
end)
|
|
|
|
it("returns HTTP 204 even if not found by name", function()
|
|
local res = client:delete("/services/not-found")
|
|
assert.res_status(204, res)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
end)
|
|
|
|
describe("/services/{service}/routes", function()
|
|
it_content_types("lists all routes belonging to service", function(content_type)
|
|
return function()
|
|
local service = db.services:insert({
|
|
protocol = "http",
|
|
host = "service.test",
|
|
})
|
|
|
|
local route = db.routes:insert({
|
|
protocol = "http",
|
|
hosts = { "service.test" },
|
|
service = service,
|
|
})
|
|
|
|
local _ = db.routes:insert({
|
|
protocol = "http",
|
|
hosts = { "service.test" },
|
|
})
|
|
|
|
local res = client:get("/services/" .. service.id .. "/routes", {
|
|
headers = { ["Content-Type"] = content_type },
|
|
})
|
|
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
|
|
assert.same({ data = { route }, next = cjson.null }, json)
|
|
end
|
|
end)
|
|
end)
|
|
|
|
describe("/services/{service}/plugins", function()
|
|
|
|
--local service = bp.named_services:insert()
|
|
|
|
local inputs = {
|
|
["application/x-www-form-urlencoded"] = {
|
|
name = "key-auth",
|
|
["config.key_names[1]"] = "apikey",
|
|
["config.key_names[2]"] = "key",
|
|
},
|
|
["application/json"] = {
|
|
name = "key-auth",
|
|
config = {
|
|
key_names = {"apikey", "key"}
|
|
},
|
|
},
|
|
}
|
|
|
|
describe("POST", function()
|
|
it_content_types("creates a plugin config for a Service", function(content_type)
|
|
return function()
|
|
if content_type == "multipart/form-data" then
|
|
-- the client doesn't play well with this
|
|
return
|
|
end
|
|
|
|
local service = bp.services:insert()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/services/" .. service.id .. "/plugins",
|
|
body = inputs[content_type],
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local body = assert.res_status(201, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("key-auth", json.name)
|
|
assert.same({ "apikey", "key" }, json.config.key_names)
|
|
end
|
|
end)
|
|
|
|
it_content_types("references a Service by name", function(content_type)
|
|
return function()
|
|
if content_type == "multipart/form-data" then
|
|
-- the client doesn't play well with this
|
|
return
|
|
end
|
|
|
|
local service = bp.named_services:insert()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/services/" .. service.name .. "/plugins",
|
|
body = inputs[content_type],
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local body = assert.res_status(201, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("key-auth", json.name)
|
|
assert.same({ "apikey", "key" }, json.config.key_names)
|
|
end
|
|
end)
|
|
|
|
describe("errors", function()
|
|
it_content_types("handles invalid input", function(content_type)
|
|
return function()
|
|
local service = bp.services:insert()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/services/" .. service.id .. "/plugins",
|
|
body = {},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
assert.same({
|
|
code = Errors.codes.SCHEMA_VIOLATION,
|
|
name = "schema violation",
|
|
message = "schema violation (name: required field missing)",
|
|
fields = {
|
|
name = "required field missing",
|
|
}
|
|
}, json)
|
|
end
|
|
end)
|
|
|
|
it_content_types("returns 409 on conflict (same plugin name)", function(content_type)
|
|
return function()
|
|
local service = bp.services:insert()
|
|
-- insert initial plugin
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/services/" .. service.id .. "/plugins",
|
|
body = {
|
|
name = "basic-auth",
|
|
},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
assert.response(res).has.status(201)
|
|
assert.response(res).has.jsonbody()
|
|
|
|
-- do it again, to provoke the error
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/services/" .. service.id .. "/plugins",
|
|
body = {
|
|
name = "basic-auth",
|
|
},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
assert.response(res).has.status(409)
|
|
local json = assert.response(res).has.jsonbody()
|
|
assert.same({
|
|
code = Errors.codes.UNIQUE_VIOLATION,
|
|
name = "unique constraint violation",
|
|
fields = {
|
|
consumer = ngx.null,
|
|
name = "basic-auth",
|
|
route = ngx.null,
|
|
service = {
|
|
id = service.id,
|
|
}
|
|
},
|
|
message = [[UNIQUE violation detected on '{consumer=null,name="basic-auth",]] ..
|
|
[[route=null,service={id="]] .. service.id ..
|
|
[["}}']],
|
|
}, json)
|
|
end
|
|
end)
|
|
|
|
it("returns 409 on id conflict (same plugin id)", function(content_type)
|
|
return function()
|
|
local service = bp.services:insert()
|
|
-- insert initial plugin
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/services/" .. service.id .. "/plugins",
|
|
body = {
|
|
name = "basic-auth",
|
|
},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local body = assert.res_status(201, res)
|
|
local plugin = cjson.decode(body)
|
|
|
|
-- do it again, to provoke the error
|
|
local conflict_res = assert(client:send {
|
|
method = "POST",
|
|
path = "/services/" .. service.id .. "/plugins",
|
|
body = {
|
|
name = "key-auth",
|
|
id = plugin.id,
|
|
},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local conflict_body = assert.res_status(409, conflict_res)
|
|
local json = cjson.decode(conflict_body)
|
|
assert.same({ id = "already exists with value '" .. plugin.id .. "'"}, json)
|
|
end
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("PATCH", function()
|
|
it("updates a plugin", function()
|
|
local service = bp.services:insert()
|
|
bp.routes:insert({
|
|
service = { id = service.id },
|
|
hosts = { "example.test" },
|
|
})
|
|
local plugin = bp.key_auth_plugins:insert({ service = service })
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/services/" .. service.id .. "/plugins/" .. plugin.id,
|
|
body = {enabled = false},
|
|
headers = {["Content-Type"] = "application/json"}
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.False(json.enabled)
|
|
|
|
local in_db = assert(db.plugins:select(plugin, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end)
|
|
it("updates a plugin bis", function()
|
|
local service = bp.services:insert()
|
|
bp.routes:insert({
|
|
service = { id = service.id },
|
|
hosts = { "example.test" },
|
|
})
|
|
local plugin = bp.key_auth_plugins:insert({ service = service })
|
|
|
|
plugin.enabled = not plugin.enabled
|
|
plugin.created_at = nil
|
|
plugin.updated_at = nil
|
|
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/services/" .. service.id .. "/plugins/" .. plugin.id,
|
|
body = plugin,
|
|
headers = {["Content-Type"] = "application/json"}
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(plugin.enabled, json.enabled)
|
|
end)
|
|
it("updates a plugin (removing foreign key reference)", function()
|
|
local service = bp.services:insert()
|
|
local plugin = bp.key_auth_plugins:insert({ service = service })
|
|
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/services/" .. service.id .. "/plugins/" .. plugin.id,
|
|
body = {
|
|
service = cjson.null,
|
|
},
|
|
headers = { ["Content-Type"] = "application/json" }
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.same(ngx.null, json.service)
|
|
|
|
local in_db = assert(db.plugins:select(plugin, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end)
|
|
|
|
describe("errors", function()
|
|
it("handles invalid input", function()
|
|
local service = bp.services:insert()
|
|
bp.routes:insert({
|
|
service = { id = service.id },
|
|
hosts = { "example.test" },
|
|
})
|
|
local plugin = bp.key_auth_plugins:insert({
|
|
service = service,
|
|
config = { key_names = { "testkey" } },
|
|
})
|
|
|
|
local before = assert(db.plugins:select(plugin, { nulls = true }))
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/services/" .. service.id .. "/plugins/" .. plugin.id,
|
|
body = { foo = "bar" },
|
|
headers = {["Content-Type"] = "application/json"}
|
|
})
|
|
local body = cjson.decode(assert.res_status(400, res))
|
|
assert.same({
|
|
message = "schema violation (foo: unknown field)",
|
|
name = "schema violation",
|
|
fields = {
|
|
foo = "unknown field",
|
|
},
|
|
code = 2,
|
|
}, body)
|
|
local after = assert(db.plugins:select(plugin, { nulls = true }))
|
|
assert.same(before, after)
|
|
assert.same({"testkey"}, after.config.key_names)
|
|
end)
|
|
it("returns 404 if not found", function()
|
|
local service = bp.services:insert()
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/services/" .. service.id .. "/plugins/f4aecadc-05c7-11e6-8d41-1f3b3d5fa15c",
|
|
body = {enabled = false},
|
|
headers = {["Content-Type"] = "application/json"}
|
|
})
|
|
assert.res_status(404, res)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("GET", function()
|
|
it("retrieves the first page", function()
|
|
local service = bp.services:insert()
|
|
assert(db.plugins:insert {
|
|
name = "key-auth",
|
|
service = { id = service.id },
|
|
})
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/services/" .. service.id .. "/plugins"
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(1, #json.data)
|
|
end)
|
|
|
|
it("ignores an invalid body", function()
|
|
local service = bp.services:insert()
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/services/" .. service.id .. "/plugins",
|
|
body = "this fails if decoded as json",
|
|
headers = {
|
|
["Content-Type"] = "application/json",
|
|
}
|
|
})
|
|
assert.res_status(200, res)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("/services/{service}/plugins/{plugin}", function()
|
|
describe("GET", function()
|
|
it("retrieves a plugin by id", function()
|
|
local service = bp.services:insert()
|
|
local plugin = bp.key_auth_plugins:insert({
|
|
service = service,
|
|
})
|
|
local res = client:get("/services/" .. service.id .. "/plugins/" .. plugin.id)
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
local in_db = assert(db.plugins:select(plugin, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end)
|
|
it("retrieves a plugin by instance_name", function()
|
|
local service = bp.services:insert()
|
|
local plugin = bp.key_auth_plugins:insert({
|
|
instance_name = "name-" .. uuid.uuid(),
|
|
service = service,
|
|
})
|
|
local res = client:get("/services/" .. service.id .. "/plugins/" .. plugin.instance_name)
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
local in_db = assert(db.plugins:select(plugin, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end)
|
|
end)
|
|
|
|
describe("DELETE", function()
|
|
it("deletes a plugin by id", function()
|
|
local service = bp.services:insert()
|
|
local plugin = bp.key_auth_plugins:insert({
|
|
service = service,
|
|
})
|
|
local res = assert(client:delete("/services/" .. service.id .. "/plugins/" .. plugin.id))
|
|
assert.res_status(204, res)
|
|
|
|
local in_db, err = db.plugins:select(plugin, { nulls = true })
|
|
assert.is_nil(err)
|
|
assert.is_nil(in_db)
|
|
end)
|
|
it("deletes a plugin by instance_name", function()
|
|
local service = bp.services:insert()
|
|
local plugin = bp.key_auth_plugins:insert({
|
|
instance_name = "name-" .. uuid.uuid(),
|
|
service = service,
|
|
})
|
|
local res = assert(client:delete("/services/" .. service.id .. "/plugins/" .. plugin.instance_name))
|
|
assert.res_status(204, res)
|
|
|
|
local in_db, err = db.plugins:select(plugin, { nulls = true })
|
|
assert.is_nil(err)
|
|
assert.is_nil(in_db)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("errors", function()
|
|
it("handles malformed JSON body", function()
|
|
local res = client:post("/services", {
|
|
body = '{"hello": "world"',
|
|
headers = { ["Content-Type"] = "application/json" }
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
assert.equal('{"message":"Cannot parse JSON body"}', body)
|
|
end)
|
|
|
|
it_content_types("handles invalid input", function(content_type)
|
|
return function()
|
|
-- Missing params
|
|
local res = client:post("/services", {
|
|
body = {},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
assert.same({
|
|
host = "required field missing",
|
|
}, json.fields)
|
|
|
|
-- Invalid parameter
|
|
res = client:post("/services", {
|
|
body = {
|
|
host = "example.test",
|
|
protocol = "foo",
|
|
},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
body = assert.res_status(400, res)
|
|
json = cjson.decode(body)
|
|
assert.same({ protocol = "expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp" }, json.fields)
|
|
end
|
|
end)
|
|
|
|
it_content_types("handles invalid url ", function(content_type)
|
|
return function()
|
|
local res = client:post("/services", {
|
|
body = {
|
|
url = "invalid url",
|
|
},
|
|
headers = { ["Content-Type"] = content_type },
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
assert.same(
|
|
{
|
|
name = "schema violation",
|
|
code = Errors.codes.SCHEMA_VIOLATION,
|
|
message = unindent([[
|
|
2 schema violations
|
|
(host: required field missing;
|
|
path: should start with: /)
|
|
]], true, true),
|
|
fields = {
|
|
host = "required field missing",
|
|
path = "should start with: /",
|
|
},
|
|
}, json
|
|
)
|
|
end
|
|
end)
|
|
end)
|
|
end)
|
|
end)
|
|
end
|