kong/spec/02-integration/03-db/10-db_unique_foreign_spec.lua (301 lines of code) (raw):

local Errors = require "kong.db.errors" local helpers = require "spec.helpers" local utils = require "kong.tools.utils" local fmt = string.format for _, strategy in helpers.each_strategy() do describe("kong.db [#" .. strategy .. "]", function() local _, db local unique_foreigns local unique_references lazy_setup(function() _, db = helpers.get_db_utils(strategy, { "unique_foreigns", "unique_references", }, { "unique-foreign" }) local env = {} env.database = strategy env.plugins = env.plugins or "unique-foreign" local lua_path = [[ KONG_LUA_PATH_OVERRIDE="./spec/fixtures/migrations/?.lua;]] .. [[./spec/fixtures/migrations/?/init.lua;]].. [[./spec/fixtures/custom_plugins/?.lua;]].. [[./spec/fixtures/custom_plugins/?/init.lua;" ]] local cmdline = "migrations up -c " .. helpers.test_conf_path local _, code, _, stderr = helpers.kong_exec(cmdline, env, true, lua_path) assert.same(0, code) assert.equal("", stderr) unique_foreigns = {} unique_references = {} for i = 1, 5 do local unique_foreign = assert(db.unique_foreigns:insert({ name = "unique_" .. i, })) local unique_reference = assert(db.unique_references:insert({ note = "note_" .. i, unique_foreign = { id = unique_foreign.id } })) unique_foreigns[i] = unique_foreign unique_references[i] = unique_reference end end) describe("Unique Reference", function() describe(":select_by_unique_foreign()", function() -- no I/O it("errors on invalid arg", function() assert.has_error(function() db.unique_references:select_by_unique_foreign(123) end, "unique_foreign must be a table") end) -- I/O it("returns existing Unique Foreign", function() for i = 1, 5 do local unique_reference, err, err_t = db.unique_references:select_by_unique_foreign({ id = unique_foreigns[i].id, }) assert.is_nil(err) assert.is_nil(err_t) assert.same(unique_references[i], unique_reference) end end) it("returns nothing on non-existing Unique Foreign", function() for i = 1, 5 do local unique_reference, err, err_t = db.unique_references:select_by_unique_foreign({ id = utils.uuid() }) assert.is_nil(err) assert.is_nil(err_t) assert.is_nil(unique_reference) end end) end) describe(":update_by_unique_foreign()", function() -- no I/O it("errors on invalid arg", function() assert.has_error(function() db.unique_references:update_by_unique_foreign(123) end, "unique_foreign must be a table") end) it("errors on invalid values", function() local unique_reference, err, err_t = db.unique_references:update_by_unique_foreign({ id = unique_foreigns[1].id, }, { note = 123, }) assert.is_nil(unique_reference) local message = "schema violation (note: expected a string)" assert.equal(fmt("[%s] %s", strategy, message), err) assert.same({ code = Errors.codes.SCHEMA_VIOLATION, name = "schema violation", message = message, strategy = strategy, fields = { note = "expected a string", } }, err_t) end) -- I/O it("returns not found error", function() local uuid = utils.uuid() local unique_reference, err, err_t = db.unique_references:update_by_unique_foreign({ id = uuid, }, { note = "hello", }) assert.is_nil(unique_reference) local message = fmt( [[[%s] could not find the entity with '{unique_foreign={id="%s"}}']], strategy, uuid) assert.equal(message, err) assert.equal(Errors.codes.NOT_FOUND, err_t.code) end) it("updates an existing Unique Reference", function() local unique_reference, err, err_t = db.unique_references:update_by_unique_foreign({ id = unique_foreigns[1].id, }, { note = "note updated", }) assert.is_nil(err_t) assert.is_nil(err) assert.equal("note updated", unique_reference.note) local unique_reference_in_db, err, err_t = db.unique_references:select({ id = unique_reference.id }) assert.is_nil(err_t) assert.is_nil(err) assert.equal("note updated", unique_reference_in_db.note) end) it("cannot update a Unique Reference to be an already existing Unique Foreign", function() local updated_service, _, err_t = db.unique_references:update_by_unique_foreign({ id = unique_foreigns[1].id, }, { unique_foreign = { id = unique_foreigns[2].id, } }) assert.is_nil(updated_service) assert.same({ code = Errors.codes.UNIQUE_VIOLATION, name = "unique constraint violation", message = fmt([[UNIQUE violation detected on '{unique_foreign={id="%s"}}']], unique_foreigns[2].id), strategy = strategy, fields = { unique_foreign = { id = unique_foreigns[2].id, } } }, err_t) end) end) describe(":upsert_by_unique_foreign()", function() -- no I/O it("errors on invalid arg", function() assert.has_error(function() db.unique_references:upsert_by_unique_foreign(123) end, "unique_foreign must be a table") end) it("errors on invalid values", function() local unique_reference, err, err_t = db.unique_references:upsert_by_unique_foreign({ id = unique_foreigns[1].id, }, { note = 123, }) assert.is_nil(unique_reference) local message = "schema violation (note: expected a string)" assert.equal(fmt("[%s] %s", strategy, message), err) assert.same({ code = Errors.codes.SCHEMA_VIOLATION, name = "schema violation", message = message, strategy = strategy, fields = { note = "expected a string", } }, err_t) end) -- I/O it("returns not found error", function() local uuid = utils.uuid() local unique_reference, err, err_t = db.unique_references:upsert_by_unique_foreign({ id = uuid, }, { note = "hello", }) assert.is_nil(unique_reference) local message = fmt( [[[%s] the foreign key '{id="%s"}' does not reference an existing 'unique_foreigns' entity.]], strategy, uuid) assert.equal(message, err) assert.equal(Errors.codes.FOREIGN_KEY_VIOLATION, err_t.code) end) it("upserts an existing Unique Reference", function() local unique_reference, err, err_t = db.unique_references:upsert_by_unique_foreign({ id = unique_foreigns[1].id, }, { note = "note updated", }) assert.is_nil(err_t) assert.is_nil(err) assert.equal("note updated", unique_reference.note) local unique_reference_in_db, err, err_t = db.unique_references:select({ id = unique_reference.id }) assert.is_nil(err_t) assert.is_nil(err) assert.equal("note updated", unique_reference_in_db.note) end) it("unique foreign given with entity is ignored when upserting by unique foreign", function() -- TODO: this is slightly unexpected, but it has its uses when thinking about idempotency -- of `PUT`. This has been like that with other DAO methods do, but perhaps we want -- to revisit this later. local unique_reference, err, err_t = db.unique_references:upsert_by_unique_foreign({ id = unique_foreigns[1].id, }, { unique_foreign = { id = unique_foreigns[2].id, } }) assert.is_nil(err_t) assert.is_nil(err) assert.equal(unique_foreigns[1].id, unique_reference.unique_foreign.id) end) end) describe(":update()", function() it("cannot update a Unique Reference to be an already existing Unique Foreign", function() local updated_unique_reference, _, err_t = db.unique_references:update({ id = unique_references[1].id, }, { unique_foreign = { id = unique_foreigns[2].id, } }) assert.is_nil(updated_unique_reference) assert.same({ code = Errors.codes.UNIQUE_VIOLATION, name = "unique constraint violation", message = fmt([[UNIQUE violation detected on '{unique_foreign={id="%s"}}']], unique_foreigns[2].id), strategy = strategy, fields = { unique_foreign = { id = unique_foreigns[2].id, } } }, err_t) end) it("changes a Unique Reference to point to a new Unique Foreign", function() local unique_foreign = assert(db.unique_foreigns:insert({ name = "new unique foreign", })) local updated_unique_reference, err, err_t = db.unique_references:update({ id = unique_references[1].id, }, { note = "updated note", unique_foreign = { id = unique_foreign.id, }, }) assert.is_nil(err_t) assert.is_nil(err) assert.equal("updated note", updated_unique_reference.note) assert.equal(unique_foreign.id, updated_unique_reference.unique_foreign.id) end) end) describe(":delete_by_unique_foreign()", function() local unique_foreign local unique_reference lazy_setup(function() unique_foreign = assert(db.unique_foreigns:insert({ name = "test", })) unique_reference = assert(db.unique_references:insert({ note = "test", unique_foreign = { id = unique_foreign.id } })) end) -- no I/O it("errors on invalid arg", function() assert.has_error(function() db.unique_references:delete_by_unique_foreign(123) end, "unique_foreign must be a table") end) -- I/O it("returns nothing if the Unique Foreign does not exist", function() local ok, err, err_t = db.unique_references:delete_by_unique_foreign({ id = utils.uuid() }) assert.is_true(ok) assert.is_nil(err_t) assert.is_nil(err) end) it("deletes an existing Unique Reference", function() local ok, err, err_t = db.unique_references:delete_by_unique_foreign({ id = unique_foreign.id, }) assert.is_nil(err_t) assert.is_nil(err) assert.is_true(ok) local unique_reference, err, err_t = db.unique_references:select({ id = unique_reference.id }) assert.is_nil(err_t) assert.is_nil(err) assert.is_nil(unique_reference) end) end) end) end) -- kong.db [strategy] end