1034 lines
36 KiB
Lua
1034 lines
36 KiB
Lua
local helpers = require "spec.helpers"
|
|
local cjson = require "cjson"
|
|
local escape = require("socket.url").escape
|
|
local Errors = require "kong.db.errors"
|
|
local uuid = require "kong.tools.uuid"
|
|
|
|
|
|
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
|
|
|
|
|
|
local gensym
|
|
do
|
|
local i = 0
|
|
gensym = function()
|
|
i = i + 1
|
|
return "abc def " .. i -- containing space for urlencoded test
|
|
end
|
|
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, {
|
|
"consumers",
|
|
"plugins",
|
|
}, {
|
|
"rewriter",
|
|
})
|
|
assert(helpers.start_kong({
|
|
database = strategy,
|
|
plugins = "bundled,rewriter",
|
|
}))
|
|
end)
|
|
|
|
lazy_teardown(function()
|
|
helpers.stop_kong()
|
|
end)
|
|
|
|
before_each(function()
|
|
client = helpers.admin_client()
|
|
end)
|
|
|
|
after_each(function()
|
|
if client then client:close() end
|
|
end)
|
|
|
|
describe("/consumers", function()
|
|
describe("POST", function()
|
|
it_content_types("creates a Consumer", function(content_type)
|
|
return function()
|
|
local username = gensym()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
body = {
|
|
username = username,
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(201, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(username, json.username)
|
|
assert.is_number(json.created_at)
|
|
assert.is_string(json.id)
|
|
end
|
|
end)
|
|
describe("errors", function()
|
|
it_content_types("handles invalid input", function(content_type)
|
|
return function()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
body = {},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("schema violation", json.name)
|
|
assert.same(
|
|
{ "at least one of these fields must be non-empty: 'custom_id', 'username'" },
|
|
json.fields["@entity"]
|
|
)
|
|
end
|
|
end)
|
|
it_content_types("returns 409 on conflicting username", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
body = {
|
|
username = consumer.username,
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(409, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("unique constraint violation", json.name)
|
|
assert.equal("UNIQUE violation detected on '{username=\"" ..
|
|
consumer.username .. "\"}'", json.message)
|
|
end
|
|
end)
|
|
it_content_types("returns 400 on conflicting custom_id", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
body = {
|
|
username = "tom",
|
|
custom_id = consumer.custom_id,
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(409, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("unique constraint violation", json.name)
|
|
assert.equal("UNIQUE violation detected on '{custom_id=\"" ..
|
|
consumer.custom_id .. "\"}'", json.message)
|
|
end
|
|
end)
|
|
it("returns 415 on invalid content-type", function()
|
|
local res = assert(client:request {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
body = '{"hello": "world"}',
|
|
headers = {["Content-Type"] = "invalid"}
|
|
})
|
|
assert.res_status(415, res)
|
|
end)
|
|
it("returns 415 on missing content-type with body ", function()
|
|
local res = assert(client:request {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
body = "invalid"
|
|
})
|
|
assert.res_status(415, res)
|
|
end)
|
|
it("returns 400 on missing body with application/json", function()
|
|
local res = assert(client:request {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
headers = {["Content-Type"] = "application/json"}
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
assert.same({ message = "Cannot parse JSON body" }, json)
|
|
end)
|
|
it("returns 400 on missing body with multipart/form-data", function()
|
|
local res = assert(client:request {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
headers = {["Content-Type"] = "multipart/form-data"}
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
assert.equals("schema violation", json.name)
|
|
assert.same(
|
|
{ "at least one of these fields must be non-empty: 'custom_id', 'username'" },
|
|
json.fields["@entity"])
|
|
end)
|
|
it("returns 400 on missing body with multipart/x-www-form-urlencoded", function()
|
|
local res = assert(client:request {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
headers = {["Content-Type"] = "application/x-www-form-urlencoded"}
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
assert.equals("schema violation", json.name)
|
|
assert.same(
|
|
{ "at least one of these fields must be non-empty: 'custom_id', 'username'" },
|
|
json.fields["@entity"])
|
|
end)
|
|
it("returns 400 on missing body with no content-type header", function()
|
|
local res = assert(client:request {
|
|
method = "POST",
|
|
path = "/consumers",
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
assert.equals("schema violation", json.name)
|
|
assert.same(
|
|
{ "at least one of these fields must be non-empty: 'custom_id', 'username'" },
|
|
json.fields["@entity"])
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("GET", function()
|
|
before_each(function()
|
|
assert(db:truncate("consumers"))
|
|
bp.consumers:insert_n(10)
|
|
end)
|
|
lazy_teardown(function()
|
|
assert(db:truncate("consumers"))
|
|
db:truncate("plugins")
|
|
end)
|
|
|
|
it("retrieves the first page", function()
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers"
|
|
})
|
|
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 = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers",
|
|
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("not crashed by empty custom_id #KAG-867", function()
|
|
local res = client:get("/consumers?custom_id=")
|
|
local body = assert.res_status(400, res)
|
|
assert(cjson.decode(body))
|
|
res = client:get("/consumers?custom_id")
|
|
body = assert.res_status(400, res)
|
|
assert(cjson.decode(body))
|
|
end)
|
|
it("allows filtering by custom_id", function()
|
|
local custom_id = gensym()
|
|
local c = bp.consumers:insert({ custom_id = custom_id }, { nulls = true })
|
|
|
|
local res = client:get("/consumers?custom_id=" .. escape(custom_id))
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
|
|
assert.equal(1, #json.data)
|
|
assert.same(c, json.data[1])
|
|
end)
|
|
it("allows filtering by uuid-like custom_id", function()
|
|
local custom_id = uuid.uuid()
|
|
local c = bp.consumers:insert({ custom_id = custom_id }, { nulls = true })
|
|
|
|
local res = client:get("/consumers?custom_id=" .. custom_id)
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
|
|
assert.equal(1, #json.data)
|
|
assert.same(c, json.data[1])
|
|
end)
|
|
it("returns empty json array when consumer does not exist", function()
|
|
local res = client:get("/consumers?custom_id=does-not-exist")
|
|
local body = assert.response(res).has.status(200)
|
|
assert.match('"data":%[%]', body)
|
|
end)
|
|
it("returns bad request for empty tags", function()
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers",
|
|
query = { tags = ngx.null}
|
|
})
|
|
res = assert.res_status(400, res)
|
|
local json = cjson.decode(res)
|
|
assert.same("invalid option (tags: cannot be null)", json.message)
|
|
end)
|
|
end)
|
|
it("returns 405 on invalid method", function()
|
|
local methods = {"DELETE", "PATCH"}
|
|
for i = 1, #methods do
|
|
local res = assert(client:send {
|
|
method = methods[i],
|
|
path = "/consumers",
|
|
body = {}, -- tmp: body to allow POST/PUT to work
|
|
headers = {["Content-Type"] = "application/json"}
|
|
})
|
|
local body = assert.response(res).has.status(405)
|
|
local json = cjson.decode(body)
|
|
assert.same({ message = "Method not allowed" }, json)
|
|
end
|
|
end)
|
|
|
|
describe("/consumers/{consumer}", function()
|
|
describe("GET", function()
|
|
it("retrieves by id", function()
|
|
local consumer = bp.consumers:insert(nil, { nulls = true })
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/" .. consumer.id
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.same(consumer, json)
|
|
end)
|
|
it("retrieves by username", function()
|
|
local consumer = bp.consumers:insert(nil, { nulls = true })
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/" .. consumer.username
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.same(consumer, json)
|
|
end)
|
|
it("retrieves by urlencoded username", function()
|
|
local consumer = bp.consumers:insert(nil, { nulls = true })
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/" .. escape(consumer.username)
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.same(consumer, json)
|
|
end)
|
|
it("retrieves by utf-8 name and encoded utf-8 name", function()
|
|
local consumer = bp.consumers:insert({ username = "円" }, { nulls = true })
|
|
local res = client:get("/consumers/" .. consumer.username)
|
|
local body = assert.res_status(200, res)
|
|
|
|
local json = cjson.decode(body)
|
|
assert.same(consumer, json)
|
|
|
|
res = client:get("/consumers/" .. escape(consumer.username))
|
|
body = assert.res_status(200, res)
|
|
|
|
json = cjson.decode(body)
|
|
assert.same(consumer, json)
|
|
end)
|
|
it("returns 404 if not found", function()
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/_inexistent_"
|
|
})
|
|
assert.res_status(404, res)
|
|
end)
|
|
end)
|
|
|
|
describe("PATCH", function()
|
|
it_content_types("updates by id", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local new_username = gensym()
|
|
ngx.sleep(1)
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.id,
|
|
body = {
|
|
username = new_username,
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(new_username, json.username)
|
|
assert.equal(consumer.id, json.id)
|
|
assert.truthy(consumer.updated_at < json.updated_at)
|
|
|
|
local in_db = assert(db.consumers:select(consumer, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end
|
|
end)
|
|
it_content_types("updates by username", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local new_username = gensym()
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.username,
|
|
body = {
|
|
username = new_username,
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(new_username, json.username)
|
|
assert.equal(consumer.id, json.id)
|
|
|
|
local in_db = assert(db.consumers:select(consumer, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end
|
|
end)
|
|
it_content_types("updates by username and custom_id with previous values", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.username,
|
|
body = {
|
|
username = consumer.username,
|
|
custom_id = consumer.custom_id,
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(consumer.username, json.username)
|
|
assert.equal(consumer.custom_id, json.custom_id)
|
|
assert.equal(consumer.id, json.id)
|
|
|
|
local in_db = assert(db.consumers:select(consumer, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end
|
|
end)
|
|
|
|
describe("errors", function()
|
|
it_content_types("returns 404 if not found", function(content_type)
|
|
return function()
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/consumers/_inexistent_",
|
|
body = {
|
|
username = gensym(),
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
assert.res_status(404, res)
|
|
end
|
|
end)
|
|
it("returns 415 on invalid content-type", function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:request {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.id,
|
|
body = '{"hello": "world"}',
|
|
headers = {["Content-Type"] = "invalid"}
|
|
})
|
|
assert.res_status(415, res)
|
|
end)
|
|
it("returns 415 on missing content-type with body ", function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:request {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.id,
|
|
body = "invalid"
|
|
})
|
|
assert.res_status(415, res)
|
|
end)
|
|
it("returns 400 on missing body with application/json", function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:request {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.id,
|
|
headers = {["Content-Type"] = "application/json"}
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
assert.same({ message = "Cannot parse JSON body" }, json)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("PUT", function()
|
|
it_content_types("creates if not exists", function(content_type)
|
|
return function()
|
|
local custom_id = gensym()
|
|
local id = uuid.uuid()
|
|
local res = client:put("/consumers/" .. id, {
|
|
body = { custom_id = custom_id },
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.same(custom_id, json.custom_id)
|
|
assert.same(id, json.id)
|
|
end
|
|
end)
|
|
|
|
it_content_types("creates if not exists by username", function(content_type)
|
|
return function()
|
|
local name = gensym()
|
|
local res = client:put("/consumers/" .. escape(name), {
|
|
body = {},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(name, json.username)
|
|
assert.equal(cjson.null, json.custom_id)
|
|
end
|
|
end)
|
|
|
|
it_content_types("replaces if found", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local new_username = gensym()
|
|
local res = client:put("/consumers/" .. consumer.id, {
|
|
body = { username = new_username },
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(new_username, json.username)
|
|
|
|
local in_db = assert(db.consumers:select(consumer, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end
|
|
end)
|
|
|
|
it_content_types("replaces if found by username", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local new_custom_id = gensym()
|
|
local res = client:put("/consumers/" .. consumer.username, {
|
|
body = { custom_id = new_custom_id },
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal(consumer.username, json.username)
|
|
assert.equal(new_custom_id, json.custom_id)
|
|
|
|
local id = json.id
|
|
res = client:put("/consumers/" .. consumer.username, {
|
|
body = {},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
body = assert.res_status(200, res)
|
|
json = cjson.decode(body)
|
|
assert.equal(id, json.id)
|
|
assert.equal(consumer.username, json.username)
|
|
assert.equal(cjson.null, json.custom_id)
|
|
end
|
|
end)
|
|
|
|
describe("errors", function()
|
|
it("handles malformed JSON body", function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = client:put("/consumers/" .. consumer.id, {
|
|
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:put("/consumers/" .. uuid.uuid(), {
|
|
body = {},
|
|
headers = { ["Content-Type"] = content_type }
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
assert.same({
|
|
code = Errors.codes.SCHEMA_VIOLATION,
|
|
name = "schema violation",
|
|
fields = {
|
|
["@entity"] = {
|
|
"at least one of these fields must be non-empty: 'custom_id', 'username'"
|
|
}
|
|
},
|
|
message = "schema violation (at least one of these fields must be non-empty: 'custom_id', 'username')"
|
|
}, cjson.decode(body))
|
|
end
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("DELETE", function()
|
|
it("deletes by id", function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:send {
|
|
method = "DELETE",
|
|
path = "/consumers/" .. consumer.id
|
|
})
|
|
local body = assert.res_status(204, res)
|
|
assert.equal("", body)
|
|
end)
|
|
it("deletes by username", function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:send {
|
|
method = "DELETE",
|
|
path = "/consumers/" .. consumer.username
|
|
})
|
|
local body = assert.res_status(204, res)
|
|
assert.equal("", body)
|
|
end)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("/consumers/{username_or_id}/plugins", function()
|
|
before_each(function()
|
|
db.plugins:truncate()
|
|
end)
|
|
describe("POST", function()
|
|
local inputs = {
|
|
["application/x-www-form-urlencoded"] = {
|
|
name = "rewriter",
|
|
["config.value"] = "potato",
|
|
},
|
|
["application/json"] = {
|
|
name = "rewriter",
|
|
config = {
|
|
value = "potato",
|
|
}
|
|
}
|
|
}
|
|
|
|
for content_type, input in pairs(inputs) do
|
|
it("creates a plugin config using a consumer id with " .. content_type, function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/consumers/" .. consumer.id .. "/plugins",
|
|
body = input,
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(201, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("rewriter", json.name)
|
|
assert.same("potato", json.config.value)
|
|
end)
|
|
it("creates a plugin config using a consumer username with " .. content_type, function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/consumers/" .. consumer.username .. "/plugins",
|
|
body = input,
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(201, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("rewriter", json.name)
|
|
assert.same("potato", json.config.value)
|
|
end)
|
|
end
|
|
|
|
describe("errors", function()
|
|
it_content_types("handles invalid input", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/consumers/" .. consumer.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",
|
|
fields = {
|
|
name = "required field missing"
|
|
},
|
|
message = "schema violation (name: required field missing)",
|
|
}, json)
|
|
end
|
|
end)
|
|
it_content_types("returns 409 on conflict", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
-- insert initial plugin
|
|
local res = assert(client:send {
|
|
method = "POST",
|
|
path = "/consumers/" .. consumer.id .. "/plugins",
|
|
body = {
|
|
name = "rewriter",
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
assert.response(res).has.status(201)
|
|
assert.response(res).has.jsonbody()
|
|
|
|
-- do it again, to provoke the error
|
|
res = assert(client:send {
|
|
method = "POST",
|
|
path = "/consumers/" .. consumer.id .. "/plugins",
|
|
body = {
|
|
name = "rewriter",
|
|
},
|
|
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",
|
|
message = [[UNIQUE violation detected on '{consumer={id="]] .. consumer.id ..
|
|
[["},name="rewriter",route=null,service=null}']],
|
|
fields = {
|
|
name = "rewriter",
|
|
consumer = {
|
|
id = consumer.id,
|
|
},
|
|
route = ngx.null,
|
|
service = ngx.null,
|
|
},
|
|
}, json)
|
|
end
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("GET", function()
|
|
it("retrieves the first page", function()
|
|
local consumer = bp.consumers:insert()
|
|
bp.rewriter_plugins:insert({ consumer = { id = consumer.id }})
|
|
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/" .. consumer.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 consumer = bp.consumers:insert()
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/" .. consumer.id .. "/plugins",
|
|
body = "this fails if decoded as json",
|
|
headers = {
|
|
["Content-Type"] = "application/json",
|
|
}
|
|
})
|
|
assert.res_status(200, res)
|
|
end)
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
describe("/consumers/{username_or_id}/plugins/{plugin}", function()
|
|
|
|
describe("GET", function()
|
|
|
|
it("retrieves by id", function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }}, { nulls = true })
|
|
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin.id
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.same(plugin, json)
|
|
end)
|
|
it("retrieves by consumer id when it has spaces", function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }}, { nulls = true })
|
|
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin.id
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.same(plugin, json)
|
|
end)
|
|
it("only retrieves if associated to the correct consumer", function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }})
|
|
|
|
-- Create an consumer and try to query our plugin through it
|
|
local w_consumer = bp.consumers:insert {
|
|
custom_id = "wc",
|
|
username = "wrong-consumer"
|
|
}
|
|
|
|
-- Try to request the plugin through it (belongs to the fixture consumer instead)
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/" .. w_consumer.id .. "/plugins/" .. plugin.id
|
|
})
|
|
assert.res_status(404, res)
|
|
end)
|
|
it("ignores an invalid body", function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }})
|
|
|
|
local res = assert(client:send {
|
|
method = "GET",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin.id,
|
|
body = "this fails if decoded as json",
|
|
headers = {
|
|
["Content-Type"] = "application/json",
|
|
}
|
|
})
|
|
assert.res_status(200, res)
|
|
end)
|
|
end)
|
|
|
|
describe("PATCH", function()
|
|
|
|
local inputs = {
|
|
["application/x-www-form-urlencoded"] = {
|
|
["config.value"] = "updated",
|
|
},
|
|
["application/json"] = {
|
|
config = {
|
|
value = "updated",
|
|
}
|
|
}
|
|
}
|
|
|
|
for content_type, input in pairs(inputs) do
|
|
|
|
it("updates if found with " .. content_type, function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }})
|
|
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin.id,
|
|
body = input,
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("updated", json.config.value)
|
|
assert.equal(plugin.id, json.id)
|
|
|
|
local in_db = assert(db.plugins:select(plugin, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end)
|
|
|
|
it("doesn't override a plugin config if partial with " .. content_type, function()
|
|
-- This is delicate since a plugin config is a text field in a DB like Cassandra
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }})
|
|
|
|
local err
|
|
plugin, err = db.plugins:update(plugin,
|
|
{
|
|
name = "rewriter",
|
|
route = plugin.route,
|
|
service = plugin.service,
|
|
consumer = plugin.consumer,
|
|
config = {
|
|
value = "potato",
|
|
extra = "extra1",
|
|
}
|
|
}
|
|
)
|
|
assert.is_nil(err)
|
|
assert.equal("potato", plugin.config.value)
|
|
assert.equal("extra1", plugin.config.extra )
|
|
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin.id,
|
|
body = input,
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("updated", json.config.value)
|
|
assert.equal("extra1", json.config.extra)
|
|
|
|
plugin = assert(db.plugins:select { id = plugin.id })
|
|
assert.equal("updated", plugin.config.value)
|
|
assert.equal("extra1", plugin.config.extra)
|
|
end)
|
|
end
|
|
|
|
it_content_types("updates the enabled property", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }})
|
|
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin.id,
|
|
body = {
|
|
name = "rewriter",
|
|
enabled = false
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.False(json.enabled)
|
|
|
|
plugin = assert(db.plugins:select(plugin))
|
|
assert.False(plugin.enabled)
|
|
end
|
|
end)
|
|
describe("errors", function()
|
|
it_content_types("returns 404 if not found", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
|
|
local res = assert(client:send {
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/b6cca0aa-4537-11e5-af97-23a06d98af51",
|
|
body = {},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
assert.res_status(404, res)
|
|
end
|
|
end)
|
|
it_content_types("handles invalid input", function(content_type)
|
|
return function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }})
|
|
|
|
local res = assert(client:send {
|
|
|
|
method = "PATCH",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin.id,
|
|
body = {
|
|
name = "foo"
|
|
},
|
|
headers = {["Content-Type"] = content_type}
|
|
})
|
|
local body = assert.res_status(400, res)
|
|
local json = cjson.decode(body)
|
|
|
|
assert.equals("schema violation", json.name)
|
|
assert.equals("plugin 'foo' not enabled; add it to the 'plugins' configuration property", json.fields.name)
|
|
end
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
describe("PUT", function()
|
|
local inputs = {
|
|
["application/x-www-form-urlencoded"] = {
|
|
name = "rewriter",
|
|
["config.value"] = "updated",
|
|
},
|
|
["application/json"] = {
|
|
name = "rewriter",
|
|
config = {
|
|
value = "updated",
|
|
}
|
|
}
|
|
}
|
|
|
|
for content_type, input in pairs(inputs) do
|
|
it("creates if not found with " .. content_type, function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin_id = uuid.uuid()
|
|
|
|
local res = assert(client:send {
|
|
method = "PUT",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin_id,
|
|
body = input,
|
|
headers = { ["Content-Type"] = content_type },
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("updated", json.config.value)
|
|
assert.equal(plugin_id, json.id)
|
|
|
|
local in_db = assert(db.plugins:select({
|
|
id = plugin_id,
|
|
}, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end)
|
|
|
|
it("updates if found with " .. content_type, function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }})
|
|
|
|
local res = assert(client:send {
|
|
method = "PUT",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin.id,
|
|
body = input,
|
|
headers = { ["Content-Type"] = content_type },
|
|
})
|
|
local body = assert.res_status(200, res)
|
|
local json = cjson.decode(body)
|
|
assert.equal("updated", json.config.value)
|
|
assert.equal(plugin.id, json.id)
|
|
|
|
local in_db = assert(db.plugins:select(plugin, { nulls = true }))
|
|
assert.same(json, in_db)
|
|
end)
|
|
end
|
|
end)
|
|
|
|
describe("DELETE", function()
|
|
it("deletes a plugin configuration", function()
|
|
local consumer = bp.consumers:insert()
|
|
local plugin = bp.rewriter_plugins:insert({ consumer = { id = consumer.id }})
|
|
|
|
local res = assert(client:send {
|
|
method = "DELETE",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/" .. plugin.id
|
|
})
|
|
assert.res_status(204, res)
|
|
end)
|
|
describe("errors", function()
|
|
it("returns 404 if not found", function()
|
|
local consumer = bp.consumers:insert()
|
|
|
|
local res = assert(client:send {
|
|
method = "DELETE",
|
|
path = "/consumers/" .. consumer.id .. "/plugins/fafafafa-1234-baba-5678-cececececece"
|
|
})
|
|
assert.res_status(404, res)
|
|
end)
|
|
end)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
end
|