kong/spec/01-unit/01-db/02-db-errors_spec.lua (374 lines of code) (raw):
local helpers = require "spec.helpers"
local Errors = require "kong.db.errors"
local defaults = require "kong.db.strategies.connector".defaults
local fmt = string.format
local unindent = helpers.unindent
describe("DB Errors", function()
describe(".codes table", function()
it("is a map of unique error codes", function()
local seen = {}
for k, v in pairs(Errors.codes) do
if seen[v] then
assert.fail("duplicated error code between " ..
k .. " and " .. seen[v])
end
seen[v] = k
end
end)
it("all error codes have a name", function()
for k, v in pairs(Errors.codes) do
local ok
for kk, vv in pairs(Errors.names) do
if kk == v then
ok = true
end
end
if not ok then
assert.fail("no name for error code: " .. k)
end
end
end)
end)
describe("error types", function()
local e = Errors.new("some_strategy")
describe("INVALID_PRIMARY_KEY", function()
local pk = {
id = "missing",
id2 = "missing2",
}
local err_t = e:invalid_primary_key(pk)
it("creates", function()
assert.same({
code = Errors.codes.INVALID_PRIMARY_KEY,
name = "invalid primary key",
strategy = "some_strategy",
message = [[invalid primary key: '{id="missing",id2="missing2"}']],
fields = pk,
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("INVALID_FOREIGN_KEY", function()
local pk = {
id = "missing",
id2 = "missing2",
}
local err_t = e:invalid_foreign_key(pk)
it("creates", function()
assert.same({
code = Errors.codes.INVALID_FOREIGN_KEY,
name = "invalid foreign key",
strategy = "some_strategy",
message = [[invalid foreign key: '{id="missing",id2="missing2"}']],
fields = pk,
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("SCHEMA_VIOLATION", function()
local schema_errors = {
foo = "expected an integer",
bar = "length must be 5",
baz = "unknown field",
["@entity"] = {
"at least one of plim or plum is needed",
"the check function errored out",
"an extra error",
},
external_entity = {
id = "missing primary key",
}
}
local err_t = e:schema_violation(schema_errors)
it("creates with multiple errors", function()
assert.same({
code = Errors.codes.SCHEMA_VIOLATION,
name = "schema violation",
strategy = "some_strategy",
message = unindent([[
7 schema violations
(at least one of plim or plum is needed;
the check function errored out;
an extra error;
bar: length must be 5;
baz: unknown field;
external_entity.id: missing primary key;
foo: expected an integer)
]], true, true),
fields = schema_errors,
}, err_t)
end)
it("creates with a single error", function()
local schema_errors = {
["@entity"] = {
"the check function errored out",
},
}
local err_t = e:schema_violation(schema_errors)
assert.same({
code = Errors.codes.SCHEMA_VIOLATION,
name = "schema violation",
strategy = "some_strategy",
message = "schema violation (the check function errored out)",
fields = schema_errors,
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("PRIMARY_KEY_VIOLATION", function()
local pk = {
id = "already exists"
}
local err_t = e:primary_key_violation(pk)
it("creates", function()
assert.same({
code = Errors.codes.PRIMARY_KEY_VIOLATION,
name = "primary key violation",
strategy = "some_strategy",
message = [[primary key violation on key '{id="already exists"}']],
fields = pk,
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("FOREIGN_KEY_VIOLATION", function()
local parent_name = "services"
local child_name = "routes"
local entity = {
service = {
foreign_id = "0000-00-00-00000000"
}
}
it("creates an insert/update error message", function()
local err_t = e:foreign_key_violation_invalid_reference(entity.service,
"service",
parent_name)
assert.same({
code = Errors.codes.FOREIGN_KEY_VIOLATION,
name = "foreign key violation",
strategy = "some_strategy",
message = unindent([[
the foreign key '{foreign_id="0000-00-00-00000000"}' does not
reference an existing 'services' entity.
]], true, true),
fields = entity,
}, err_t)
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
it("creates a delete error message", function()
local err_t = e:foreign_key_violation_restricted(parent_name, child_name)
assert.same({
code = Errors.codes.FOREIGN_KEY_VIOLATION,
name = "foreign key violation",
strategy = "some_strategy",
message = "an existing 'routes' entity references this 'services' entity",
fields = {
["@referenced_by"] = child_name,
},
}, err_t)
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("NOT_FOUND", function()
local pk = { id = "0000-00-00-00-00000000" }
local err_t = e:not_found(pk)
it("creates", function()
assert.same({
code = Errors.codes.NOT_FOUND,
name = "not found",
strategy = "some_strategy",
message = unindent([[
could not find the entity with primary key
'{id="0000-00-00-00-00000000"}'
]], true, true),
fields = pk,
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("UNIQUE_VIOLATION", function()
local pk = { id = "0000-00-00-00-00000000" }
local err_t = e:unique_violation(pk)
it("creates", function()
assert.same({
code = Errors.codes.UNIQUE_VIOLATION,
name = "unique constraint violation",
strategy = "some_strategy",
message =
[[UNIQUE violation detected on '{id="0000-00-00-00-00000000"}']],
fields = pk,
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("INVALID_OFFSET", function()
local err_t = e:invalid_offset("bad offset", "decoding error")
it("creates", function()
assert.same({
code = Errors.codes.INVALID_OFFSET,
name = "invalid offset",
strategy = "some_strategy",
message = "'bad offset' is not a valid offset: decoding error",
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("DATABASE_ERROR", function()
it("creates", function()
local err_t = e:database_error()
assert.same({
code = Errors.codes.DATABASE_ERROR,
name = "database error",
strategy = "some_strategy",
message = "database error",
}, err_t)
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
it("creates with error string as message", function()
local err_t = e:database_error("timeout")
assert.same({
code = Errors.codes.DATABASE_ERROR,
name = "database error",
strategy = "some_strategy",
message = "timeout",
}, err_t)
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("TRANSFORMATION_ERROR", function()
it("creates", function()
local err_t = e:transformation_error()
assert.same({
code = Errors.codes.TRANSFORMATION_ERROR,
name = "transformation error",
strategy = "some_strategy",
message = "transformation error",
}, err_t)
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
it("creates with error string as message", function()
local err_t = e:transformation_error("timeout")
assert.same({
code = Errors.codes.TRANSFORMATION_ERROR,
name = "transformation error",
strategy = "some_strategy",
message = "timeout",
}, err_t)
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("INVALID_SIZE", function()
local err_t = e:invalid_size("size must be an integer between 1 and " .. defaults.pagination.max_page_size)
it("creates", function()
assert.same({
code = Errors.codes.INVALID_SIZE,
name = "invalid size",
strategy = "some_strategy",
message = "size must be an integer between 1 and " .. defaults.pagination.max_page_size,
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("INVALID_UNIQUE", function()
local err_t = e:invalid_unique("name", "name must be a string")
it("creates", function()
assert.same({
code = Errors.codes.INVALID_UNIQUE,
name = "invalid unique name",
strategy = "some_strategy",
message = "name must be a string",
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("INVALID_UNIQUE_GLOBAL", function()
local err_t = e:invalid_unique_global("bla")
it("creates", function()
assert.same({
code = Errors.codes.INVALID_UNIQUE_GLOBAL,
name = "invalid global query",
strategy = "some_strategy",
message = "unique key bla is invalid for global query",
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
describe("INVALID_OPTIONS", function()
local options_errors = {
ttl = "option can only be used with inserts, updates and upserts, not with 'deletes'",
bar = {
"must be a string",
"must contain 'foo'"
}
}
local err_t = e:invalid_options(options_errors)
it("creates with multiple errors", function()
assert.same({
code = Errors.codes.INVALID_OPTIONS,
name = "invalid options",
strategy = "some_strategy",
message = unindent([[
3 option violations
(bar.1: must be a string;
bar.2: must contain 'foo';
ttl: option can only be used with inserts, updates and upserts, not with 'deletes')
]], true, true),
options = options_errors,
}, err_t)
end)
it("creates with a single error", function()
local options_errors = {
ttl = "option can only be used with inserts, updates and upserts, not with 'deletes'",
}
local err_t = e:invalid_options(options_errors)
assert.same({
code = Errors.codes.INVALID_OPTIONS,
name = "invalid options",
strategy = "some_strategy",
message = "invalid option (ttl: option can only be used with inserts, updates and upserts, not with 'deletes')",
options = options_errors,
}, err_t)
end)
it("__tostring", function()
local s = fmt("[%s] %s", err_t.strategy, err_t.message)
assert.equals(s, tostring(err_t))
end)
end)
end)
end)