kong/spec/01-unit/01-db/01-schema/02-metaschema_spec.lua (1,270 lines of code) (raw):

local Schema = require "kong.db.schema" local helpers = require "spec.helpers" local MetaSchema = require "kong.db.schema.metaschema" describe("metaschema", function() it("rejects a bad schema", function() local s = { name = "bad", fields = { { foo = "bar", }, }, primary_key = { "foo" }, } assert.falsy(MetaSchema:validate(s)) end) it("requires an array schema to have `elements`", function() local s = { name = "bad", primary_key = { "f" }, fields = { { f = { type = "array" } } } } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("field of type 'array' must declare 'elements'", err.f) end) it("requires an set schema to have `elements`", function() local s = { name = "bad", primary_key = { "f" }, fields = { { f = { type = "set" } } } } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("field of type 'set' must declare 'elements'", err.f) end) it("requires a map schema to have `keys`", function() local s = { name = "bad", primary_key = { "f" }, fields = { { f = { type = "map", values = { type = "string" } } } } } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("field of type 'map' must declare 'keys'", err.f) end) it("requires a map schema to have `values`", function() local s = { name = "bad", primary_key = { "f" }, fields = { { f = { type = "map", keys = { type = "string" } } } } } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("field of type 'map' must declare 'values'", err.f) end) it("requires a record schema to have `fields`", function() local s = { name = "bad", primary_key = { "f" }, fields = { { f = { type = "record" } } } } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("field of type 'record' must declare 'fields'", err.f) end) it("fields cannot be empty", function() local s = { name = "bad", fields = { {} }, primary_key = { "foo" }, } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("field entry table is empty", err.fields) end) it("rejects an invalid entity check", function() local s = { name = "bad", fields = { { foo = { type = "number" }, }, }, primary_key = { "foo" }, entity_checks = { foo = { "bar" }, } } assert.falsy(MetaSchema:validate(s)) end) it("validates a schema with nested records", function() local s = { name = "hello", primary_key = { "foo" }, fields = { { foo = { type = "number" } }, { f = { type = "record", fields = { { r = { type = "record", fields = { { a = { type = "string" }, }, { b = { type = "number" }, } }}}}}}}} assert.truthy(MetaSchema:validate(s)) end) it("a schema cannot be marked as legacy", function() local s = { name = "hello", primary_key = { "foo" }, legacy = true, fields = { { foo = { type = "number" } } } } assert.falsy(MetaSchema:validate(s)) s = { name = "hello", primary_key = { "foo" }, legacy = 2, fields = { { foo = { type = "number" } } } } assert.falsy(MetaSchema:validate(s)) end) it("a schema can declare a cache_key", function() local s = { name = "hello", primary_key = { "foo" }, cache_key = { "foo" }, fields = { { foo = { type = "number", unique = true } } } } assert.truthy(MetaSchema:validate(s)) end) it("cache_key elements must be fields", function() local s = { name = "hello", primary_key = { "foo" }, cache_key = { "foo", "bar" }, fields = { { foo = { type = "number" } } } } assert.falsy(MetaSchema:validate(s)) end) it("a field in a single-field cache_key must be unique", function() local s = { name = "hello", primary_key = { "foo" }, cache_key = { "foo" }, fields = { { foo = { type = "number" } } } } assert.falsy(MetaSchema:validate(s)) end) it("fields in a composite cache_key don't need to be unique", function() local s = { name = "hello", primary_key = { "foo" }, cache_key = { "foo", "bar" }, fields = { { foo = { type = "number" } }, { bar = { type = "number" } } } } assert.truthy(MetaSchema:validate(s)) end) it("allows only one entity check per array field", function() local s = { name = "bad", fields = { { a = { type = "number" } }, { b = { type = "number" } }, { c = { type = "number" } }, { d = { type = "number" } }, }, primary_key = { "foo" }, entity_checks = { { only_one_of = { "a", "b" }, at_least_one_of = { "c", "d" }, }, } } local ok, errs = MetaSchema:validate(s) assert.falsy(ok) assert.truthy(errs) end) it("accepts a function in an entity check", function() local s = { name = "bad", fields = { { a = { type = "number" } }, { b = { type = "number" } }, }, primary_key = { "a" }, entity_checks = { { custom_entity_check = { field_sources = { "a" }, fn = function() return true end, } }, } } local ok = MetaSchema:validate(s) assert.truthy(ok) end) it("demands a primary key", function() local s = { name = "bad", fields = { { foo = "bar", }, }, } local ok, errs = MetaSchema:validate(s) assert.falsy(ok) assert.truthy(errs["primary_key"]) end) it("rejects a bad schema checking nested error", function() local s = { name = "bad", fields = { { foo = { type = "array", elements = { { foo = "bar", }, } } } }, primary_key = { "foo" }, } assert.falsy(MetaSchema:validate(s)) end) it("rejects a bad schema matching validators and types", function() local s = { name = "bad", fields = { { foo = { type = "array", -- will cause error because `uuid` must be used with `strings` elements = { type = "number", uuid = true, }, } } }, primary_key = { "foo" }, } local ret, errs = MetaSchema:validate(s) assert.falsy(ret) assert.truthy(errs and errs["foo"]) end) it("supports all Schema validators", function() local set = MetaSchema.get_supported_validator_set() for name, _ in pairs(Schema.validators) do assert.truthy(set[name], "'" .. name .. "' is missing from MetaSchema") end for name, _ in pairs(set) do local err = "'" .. name .. "' in MetaSchema is not a declared validator" assert.truthy(Schema.validators[name], err) end end) it("allows specifying an endpoint key with endpoint_key", function() local s = { name = "test", endpoint_key = "str", fields = { { str = { type = "string", unique = true } }, { num = { type = "number" } }, }, primary_key = { "str" }, } assert.truthy(MetaSchema:validate(s)) end) it("endpoint_key must be a field", function() local s = { name = "test", endpoint_key = "bla", fields = { { str = { type = "string", unique = true } }, { num = { type = "number" } }, }, primary_key = { "str" }, } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("value must be a field name", err.endpoint_key) end) it("ttl support can be enabled with ttl = true", function() local s = { name = "test", ttl = true, fields = { { str = { type = "string", unique = true } }, { created_at = { type = "number", timestamp = true, auto = true } }, }, primary_key = { "str" }, } assert.truthy(MetaSchema:validate(s)) end) it("ttl support can be disabled with ttl = false", function() local s = { name = "test", ttl = false, fields = { { str = { type = "string", unique = true } }, }, primary_key = { "str" }, } assert.truthy(MetaSchema:validate(s)) end) it("ttl support can be disabled with ttl = nil", function() local s = { name = "test", fields = { { str = { type = "string", unique = true } }, { ttl = { type = "integer" } }, }, primary_key = { "str" }, } assert.truthy(MetaSchema:validate(s)) end) it("ttl must be a boolean (true)", function() local s = { name = "test", ttl = "true", fields = { { str = { type = "string", unique = true } }, { created_at = { type = "integer", timestamp = true, auto = true } }, }, primary_key = { "str" }, } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("expected a boolean", err.ttl) end) it("ttl reserves ttl as a field name", function() local s = { name = "test", ttl = "true", fields = { { str = { type = "string", unique = true } }, { ttl = { type = "integer" } }, { created_at = { type = "integer", timestamp = true, auto = true } }, }, primary_key = { "str" }, } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("ttl is a reserved field name when ttl is enabled", err.ttl) end) it("supports the unique attribute in base types", function() local s = { name = "test", fields = { { str = { type = "string", unique = true } }, { num = { type = "number", unique = true } }, { int = { type = "integer", unique = true } }, }, primary_key = { "str" }, } assert.truthy(MetaSchema:validate(s)) end) it("rejects the unique attribute in composite types", function() local s = { name = "test", fields = { { id = { type = "string" } }, { arr = { type = "array", unique = true } }, { map = { type = "map", unique = true } }, { rec = { type = "record", unique = true } }, { set = { type = "set", unique = true } }, }, primary_key = { "id" }, } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("'array' cannot have attribute 'unique'", err.arr) assert.match("'map' cannot have attribute 'unique'", err.map) assert.match("'record' cannot have attribute 'unique'", err.rec) assert.match("'set' cannot have attribute 'unique'", err.set) end) it("a schema cannot have a field of type 'any'", function() local s = { name = "hello", primary_key = { "foo" }, fields = { { foo = { type = "any" } } } } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("expected one of", err.fields[1].type) end) it("accepts an 'err' field", function() local s = { name = "hello", primary_key = { "foo" }, fields = { { foo = { type = "array", elements = {type = "string"}, eq = ngx.null, err = "cannot set value" } } } } assert.truthy(MetaSchema:validate(s)) end) it("populates the 'table_name' field from 'name' if not supplied", function() local s = { name = "testing", primary_key = { "id" }, fields = { { id = { type = "string", }, }, { foo = { type = "string" }, }, }, } assert.truthy(MetaSchema:validate(s)) local schema = Schema.new(s) assert.not_nil(schema.table_name) assert.equals("testing", schema.name) assert.equals("testing", schema.table_name) s.table_name = "explicit_table_name" assert.truthy(MetaSchema:validate(s)) schema = Schema.new(s) assert.not_nil(schema.table_name) assert.equals("testing", schema.name) assert.equals("explicit_table_name", schema.table_name) end) describe("subschemas", function() it("supports declaring subschemas", function() local s = { name = "test", subschema_key = "str", fields = { { str = { type = "string", unique = true } }, }, primary_key = { "str" }, } assert.truthy(MetaSchema:validate(s)) end) it("subschema_key must be an existing field name", function() local s = { name = "test", subschema_key = "str", fields = { { str = { type = "string", unique = true } }, }, primary_key = { "str" }, } local ok = MetaSchema:validate(s) assert.truthy(ok) local err s.subschema_key = "foo" ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("value must be a field name", err.subschema_key) end) it("subschema_key must be a string field", function() local s = { name = "test", subschema_key = "num", fields = { { str = { type = "string", unique = true } }, { num = { type = "number", unique = true } }, }, primary_key = { "str" }, } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.match("must be a string", err.subschema_key) end) it("schema can define abstract fields", function() local s = { name = "test", subschema_key = "str", fields = { { str = { type = "string", unique = true } }, { num = { type = "number", abstract = true } }, }, primary_key = { "str" }, } local ok = MetaSchema:validate(s) assert.truthy(ok) end) it("abstract composite types can be abstract within their limitations", function() local s = { name = "test", subschema_key = "str", fields = { { str = { type = "string", unique = true } }, -- abstract arrays, sets and maps need their types -- so that strategies (postgres in particular) -- can build the proper types { arr = { type = "array", abstract = true } }, { set = { type = "set", abstract = true } }, { map = { type = "map", abstract = true } }, -- abstract records don't need their fields -- to be declared because strategies store them as JSON -- (we need this property for the `config` field of Plugins) { rec = { type = "record", abstract = true } }, }, primary_key = { "str" }, } local ok, err = MetaSchema:validate(s) assert.falsy(ok) assert.same({ arr = "field of type 'array' must declare 'elements'", set = "field of type 'set' must declare 'elements'", map = "field of type 'map' must declare 'values'", }, err) s = { name = "test", subschema_key = "str", fields = { { str = { type = "string", unique = true } }, { arr = { type = "array", elements = { type = "string" }, abstract = true } }, { set = { type = "set", elements = { type = "string" }, abstract = true } }, { rec = { type = "record", abstract = true } }, }, primary_key = { "str" }, } ok = MetaSchema:validate(s) assert.truthy(ok) end) end) it("validates a value with 'eq'", function() assert.truthy(MetaSchema:validate({ name = "test", primary_key = { "pk" }, fields = { { pk = { type = "boolean", default = true, eq = true } }, }, })) end) it("validates the routes schema", function() local Routes = require("kong.db.schema.entities.routes") assert.truthy(MetaSchema:validate(Routes)) Schema.new(Routes) -- do it a second time to show that Schema.new does not corrupt the table assert.truthy(MetaSchema:validate(Routes)) end) it("validates the services schema", function() local Services = require("kong.db.schema.entities.services") assert.truthy(MetaSchema:validate(Services)) end) pending("validates itself", function() -- This goes into an endless loop because the schema validator -- does not account for cyclic schemas at this point. assert.truthy(MetaSchema:validate(MetaSchema)) end) it("validates transformation has transformation function specified (positive)", function() assert.truthy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, on_write = function() return true end, }, }, })) assert.truthy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, on_read = function() return true end, }, }, })) assert.truthy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, on_read = function() return true end, on_write = function() return true end, }, }, })) end) it("validates transformation has transformation function specified (negative)", function() assert.falsy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, }, }, })) end) it("validates transformation input fields exists (positive)", function() assert.truthy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, on_write = function() return true end, }, }, })) end) it("validates transformation input fields exists (negative)", function() assert.falsy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "string" } }, }, transformations = { { input = { "nonexisting" }, on_write = function() return true end, }, }, })) end) it("validates nested transformation input fields exists (positive)", function() assert.truthy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "record", fields = { { field = { type = "string" } }, } } }, }, transformations = { { input = { "test.field" }, on_write = function() return true end, }, }, })) end) it("validates nested transformation input fields exists (negative)", function() assert.falsy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "record", fields = { { field = { type = "string" }, }, }, }, }, }, transformations = { { input = { "test.nonexisting" }, on_write = function() return true end, }, }, })) assert.falsy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "record", fields = { { field = { type = "string" }, }, }, }, }, }, transformations = { { input = { "nonexisting.field" }, on_write = function() return true end, }, }, })) end) it("validates transformation needs fields exists (positive)", function() assert.truthy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, needs = { "test" }, on_write = function() return true end, }, }, })) end) it("validates transformation needs fields exists (negative)", function() assert.falsy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, needs = { "nonexisting" }, on_write = function() return true end, }, }, })) end) it("validates nested transformation needs fields exists (positive)", function() assert.truthy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "record", fields = { { field = { type = "string" } }, } } }, }, transformations = { { input = { "test.field" }, needs = { "test.field" }, on_write = function() return true end, }, }, })) end) it("validates nested transformation needs fields exists (negative)", function() assert.falsy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "record", fields = { { field = { type = "string" }, }, }, }, }, }, transformations = { { input = { "test.field" }, needs = { "test.nonexisting" }, on_write = function() return true end, }, }, })) assert.falsy(MetaSchema:validate({ name = "test", primary_key = { "test" }, fields = { { test = { type = "record", fields = { { field = { type = "string" }, }, }, }, }, }, transformations = { { input = { "test.field" }, needs = { "nonexisting.field" }, on_write = function() return true end, }, }, })) end) end) describe("metasubschema", function() it("rejects a bad schema", function() local s = { name = "bad", fields = { { foo = "bar", }, }, primary_key = { "foo" }, } local ok, err = MetaSchema.MetaSubSchema:validate(s) assert.falsy(ok) assert.same({ fields = { "expected a record", }, foo = "'foo' must be a table", primary_key = "unknown field" }, err) end) it("fields cannot be empty", function() local s = { name = "bad", fields = { {} }, } local ok, err = MetaSchema.MetaSubSchema:validate(s) assert.falsy(ok) assert.match("field entry table is empty", err.fields) end) it("rejects an invalid entity check", function() local s = { name = "bad", fields = { { foo = { type = "number" }, }, }, entity_checks = { foo = { "bar" }, } } local ok, err = MetaSchema.MetaSubSchema:validate(s) assert.falsy(ok) assert.same({ entity_checks = "expected an array", }, err) end) it("validates a schema with nested records", function() local s = { name = "hello", fields = { { foo = { type = "number" } }, { f = { type = "record", fields = { { r = { type = "record", fields = { { a = { type = "string" }, }, { b = { type = "number" }, } }}}}}}}} assert.truthy(MetaSchema.MetaSubSchema:validate(s)) end) it("allows only one entity check per array field", function() local s = { name = "bad", fields = { { a = { type = "number" } }, { b = { type = "number" } }, { c = { type = "number" } }, { d = { type = "number" } }, }, entity_checks = { { only_one_of = { "a", "b" }, at_least_one_of = { "c", "d" }, }, } } local ok, err = MetaSchema.MetaSubSchema:validate(s) assert.falsy(ok) assert.match("exactly one of these fields must be non-empty", err.entity_checks[1]["@entity"][1], 1, true) end) it("accepts a function in an entity check", function() local s = { name = "bad", fields = { { a = { type = "number" } }, { b = { type = "number" } }, }, entity_checks = { { custom_entity_check = { field_sources = { "a" }, fn = function() return true end, } }, } } local ok = MetaSchema.MetaSubSchema:validate(s) assert.truthy(ok) end) it("rejects a bad schema checking nested error", function() local s = { name = "bad", fields = { { foo = { type = "array", elements = { { foo = "bar", }, } } } }, } local ok, err = MetaSchema.MetaSubSchema:validate(s) assert.falsy(ok) assert.same({ fields = { { elements = { "unknown field", type = "required field missing", } } }, foo = "missing type declaration", }, err) end) it("rejects a bad schema matching validators and types", function() local s = { name = "bad", fields = { { foo = { type = "array", -- will cause error because `uuid` must be used with `strings` elements = { type = "number", uuid = true, }, } } }, primary_key = { "foo" }, } local ret, err = MetaSchema.MetaSubSchema:validate(s) assert.falsy(ret) assert.same({ foo = "field of type 'number' cannot have attribute 'uuid'", primary_key = "unknown field" }, err) end) it("supports all Schema validators", function() local set = MetaSchema.get_supported_validator_set() for name, _ in pairs(Schema.validators) do assert.truthy(set[name], "'" .. name .. "' is missing from MetaSchema") end for name, _ in pairs(set) do local err = "'" .. name .. "' in MetaSchema is not a declared validator" assert.truthy(Schema.validators[name], err) end end) it("allows specifying an endpoint key with endpoint_key", function() local s = { name = "test", fields = { { str = { type = "string", unique = true } }, { num = { type = "number" } }, }, } assert.truthy(MetaSchema.MetaSubSchema:validate(s)) end) it("supports the unique attribute in base types", function() local s = { name = "test", fields = { { str = { type = "string", unique = true } }, { num = { type = "number", unique = true } }, { int = { type = "integer", unique = true } }, }, } assert.truthy(MetaSchema.MetaSubSchema:validate(s)) end) it("rejects the unique attribute in composite types", function() local s = { name = "test", fields = { { id = { type = "string" } }, { arr = { type = "array", unique = true } }, { map = { type = "map", unique = true } }, { rec = { type = "record", unique = true } }, { set = { type = "set", unique = true } }, }, } local ok, err = MetaSchema.MetaSubSchema:validate(s) assert.falsy(ok) assert.match("'array' cannot have attribute 'unique'", err.arr) assert.match("'map' cannot have attribute 'unique'", err.map) assert.match("'record' cannot have attribute 'unique'", err.rec) assert.match("'set' cannot have attribute 'unique'", err.set) end) it("a schema cannot have a field of type 'any'", function() local s = { name = "hello", primary_key = { "foo" }, fields = { { foo = { type = "any" } } } } local ok, err = MetaSchema.MetaSubSchema:validate(s) assert.falsy(ok) assert.match("expected one of", err.fields[1].type) end) it("validates a value with 'eq'", function() assert.truthy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { pk = { type = "boolean", default = true, eq = true } }, }, })) end) for plugin, _ in pairs(helpers.test_conf.loaded_plugins) do it("validates plugin subschema for " .. plugin, function() local schema = require("kong.plugins." .. plugin .. ".schema") assert.truthy(MetaSchema.MetaSubSchema:validate(schema)) end) end it("validates transformation has transformation function specified (positive)", function() assert.truthy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, on_write = function() return true end, }, }, })) assert.truthy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, on_read = function() return true end, }, }, })) assert.truthy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, on_read = function() return true end, on_write = function() return true end, }, }, })) end) it("validates transformation has transformation function specified (negative)", function() assert.falsy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, }, }, })) end) it("validates transformation input fields exists (positive)", function() assert.truthy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, on_write = function() return true end, }, }, })) end) it("validates transformation input fields exists (negative)", function() assert.falsy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "string" } }, }, transformations = { { input = { "nonexisting" }, on_write = function() return true end, }, }, })) end) it("validates nested transformation input fields exists (positive)", function() assert.truthy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "record", fields = { { field = { type = "string" } }, } } }, }, transformations = { { input = { "test.field" }, on_write = function() return true end, }, }, })) end) it("validates nested transformation input fields exists (negative)", function() assert.falsy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "record", fields = { { field = { type = "string" }, }, }, }, }, }, transformations = { { input = { "test.nonexisting" }, on_write = function() return true end, }, }, })) assert.falsy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "record", fields = { { field = { type = "string" }, }, }, }, }, }, transformations = { { input = { "nonexisting.field" }, on_write = function() return true end, }, }, })) end) it("validates transformation needs fields exists (positive)", function() assert.truthy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, needs = { "test" }, on_write = function() return true end, }, }, })) end) it("validates transformation needs fields exists (negative)", function() assert.falsy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "string" } }, }, transformations = { { input = { "test" }, needs = { "nonexisting" }, on_write = function() return true end, }, }, })) end) it("validates nested transformation needs fields exists (positive)", function() assert.truthy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "record", fields = { { field = { type = "string" } }, } } }, }, transformations = { { input = { "test.field" }, needs = { "test.field" }, on_write = function() return true end, }, }, })) end) it("validates nested transformation needs fields exists (negative)", function() assert.falsy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "record", fields = { { field = { type = "string" }, }, }, }, }, }, transformations = { { input = { "test.field" }, needs = { "test.nonexisting" }, on_write = function() return true end, }, }, })) assert.falsy(MetaSchema.MetaSubSchema:validate({ name = "test", fields = { { test = { type = "record", fields = { { field = { type = "string" }, }, }, }, }, }, transformations = { { input = { "test.field" }, needs = { "nonexisting.field" }, on_write = function() return true end, }, }, })) end) end)