UNPKG

stitch-ui

Version:

521 lines (497 loc) 14.1 kB
/* global it, describe, expect */ import { MongoDBServiceRule, FieldRule, PermissionsState } from "../mongodb_rule"; import { TYPE_OBJECT, TYPE_ARRAY, TYPE_UNTYPED } from "../constants"; describe("rule", () => { it("Can construct a rule", () => { const r = new MongoDBServiceRule({ _id: "x", namespace: "d.c" }); expect(r.dirty).toBe(false); expect(r.filters.size).toBe(0); }); it("Can add a filter", () => { const r = new MongoDBServiceRule({ _id: "x", namespace: "d.c" }); expect(r.filters.toJS()).toHaveLength(0); const r2 = r.addFilter(); expect(r2.filters.toJS()).toHaveLength(1); expect(r2.dirty).toBe(true); }); it("Can manipulate filters", () => { let r = new MongoDBServiceRule({ _id: "x", namespace: "d.c", filters: [{ when: { x: 0 }, matchExpression: { y: 1 } }] }); expect(r.filters.toJS()).toHaveLength(1); r = r.setFilterWhenInput(0, "foo"); expect(r.dirty).toBe(true); expect(r.filters.get(0).dirty).toBe(true); r = r.parseFilters(); expect(r.filtersHasError).toBe(true); r = r.setFilterWhenInput(0, "{}"); r = r.parseFilters(); expect(r.filtersHasError).toBe(false); // Test setting input + discarding expect(r.filters.get(0).when.input).toEqual("{}"); r = r.setFilterWhenInput(0, "foo"); r = r.discardFilterChanges(0); expect(r.filters.get(0).when.input).toEqual("{}"); r = r.removeFilter(0); expect(r.filters.toJS()).toHaveLength(0); }); it("can manipulate permissions", () => { let r = new MongoDBServiceRule({ _id: "x", namespace: "d.c" }); r = r.addField(null, "foo"); expect(r.dirty).toBe(true); r = r.setFieldType("foo", TYPE_OBJECT); r = r.addField("foo", "bar"); r = r.setFieldType("foo.bar", TYPE_OBJECT); r = r.addField("foo.bar", "baz"); r = r.removeField("foo.bar.baz"); // Test setting input, dirty flag, and discarding r = r.updatePermissionsInput("foo.bar", false, false, "read", "blah"); expect( r.fieldRules.getFieldRuleAtPath("foo.bar").permissions.read.input ).toEqual("blah"); expect(r.fieldRules.getFieldRuleAtPath("foo.bar").permissions.dirty).toBe( true ); r = r.discardPermissionsInput("foo.bar", false, false, "read"); expect( r.fieldRules.getFieldRuleAtPath("foo.bar").permissions.read.input ).toEqual(undefined); // Test parsing of invalid json r = r.updatePermissionsInput("foo.bar", false, false, "read", "blah"); r = r.parseFieldInputs(); expect(r.fieldRules.hasChildError).toBe(true); expect(r.fieldRules.getFieldRuleAtPath("foo.bar").hasError).toBe(true); }); it("new field inputs", () => { let r = new MongoDBServiceRule({ _id: "x", namespace: "d.c" }); r = r.addField(null, "foo"); r = r.setFieldType("foo", TYPE_OBJECT); r = r.addField("foo", "bar"); r = r.setFieldType("foo.bar", TYPE_OBJECT); r = r.addField("foo.bar", "baz"); r = r.removeField("foo.bar.baz"); r = r.changeNewFieldInput("foo.bar", "xxx"); expect(r.fieldRules.getFieldRuleAtPath("foo.bar").newFieldPath).toBe("xxx"); // top-level r = r.changeNewFieldInput(null, "yyy"); expect(r.fieldRules.getFieldRuleAtPath(null).newFieldPath).toBe("yyy"); }); it("field types", () => { let r = new MongoDBServiceRule({ _id: "x", namespace: "d.c" }); expect(r.fieldRules.getFieldRuleAtPath(null).getFieldType()).toBe( TYPE_OBJECT ); r = r.addField(null, "foo"); [TYPE_OBJECT, TYPE_ARRAY, TYPE_UNTYPED].forEach(x => { r = r.setFieldType("foo", x); expect(r.fieldRules.getFieldRuleAtPath("foo").getFieldType()).toBe(x); }); }); }); describe("permission inputs", () => { it("can update permission state in a rule", () => { let r = new MongoDBServiceRule({ _id: "foo", namespace: "test.test" }); r = r.updateIn(["fieldRules"], fr => fr.addField(null, "owner_id")); r = r.updateIn(["fieldRules"], fr => fr.updatePermissionsInput("owner_id", false, false, "read", '{"x":3}') ); r.updateIn(["fieldRules"], fr => fr.parseInputs()); }); it("can update inputs in permissionsstate", () => { let ps = PermissionsState.fromRaw({ read: { x: "y" }, write: { z: "b" }, valid: { nnn: "gsdgsdg" } }); ps = ps.setIn(["read", "input"], "poop").setIn(["read", "dirty"], true); expect(ps.read.input).toBe("poop"); expect(ps.read.dirty).toBe(true); ps = ps.parse(); expect(ps.read.error).toBe("Invalid JSON"); ps = ps.setIn(["read", "input"], "{}").setIn(["read", "dirty"], true); ps = ps.parse(); expect(ps.read.error).toBe(null); }); }); describe("field rules", () => { it("field rule should be parseable and be able to update perms", () => { const fr = FieldRule.fromRaw("", "", { _id: "5888d4c3772e2e4a41158d65", fields: { _id: {}, lcount: {}, lists: { otherFields: {} }, stuff: { fields: { x: { fields: { foo: { read: { "%%true": true } } } }, y: {}, z: {} } }, members: {}, name: { required: true, valid: { "%%this": { $ne: "" } } }, owner_id: {} }, namespace: "planner.boards", read: { $or: [ { "%%root.owner_id": "%%user.id" }, { "%%root.members": "%%user.id" } ] }, valid: { $or: [ { "%%prevRoot": { $exists: 1 } }, { "%%root.name": { $nin: "%%pipelines.myBoards.name" } } ] }, write: { $or: [ { "%%prevRoot.owner_id": "%%user.id" }, { "%%prevRoot": { $exists: false } } ] } }); const idField = fr.fields.toJS()._id; expect(idField.path).toBe("_id"); expect(idField.dottedFullPath).toBe("_id"); ["_id", "stuff.x", "stuff.y", "members", "name"].forEach(fieldPath => { expect(fr.getFieldRuleAtPath(fieldPath).dottedFullPath).toBe(fieldPath); }); fr.updatePermissionsInput("stuff.x", false, false, "read", "dsgkjsdgdsg"); }); }); describe("mongo service rule", () => { it("should correctly convert raw rule to array of field rules, and back", () => { const rawFieldRules = { field1: { read: { see: "you" }, write: { modify: "me" }, valid: { x: "1" }, fields: { a: { valid: { hey: "ya" }, write: { bbb: "xxx" }, read: { see: "ASFSAF" }, fields: { foo: { valid: { leaf: "NODE" }, fields: {} } } }, b: { elements: { read: { hi: "please" } } } } }, field2: { fields: { blah: { fields: { wee: { fields: {} } } } } } }; const extracted = new MongoDBServiceRule({ _id: "x", namespace: "test.test", fields: rawFieldRules }); const reassembled = extracted.toRawRule(); expect(reassembled.fields).toEqual(rawFieldRules); }); it("should support adding/deleting/updating field rules", () => { const rawRule = { _id: "5883c04eba186ebf69579ffd", namespace: "test.foo", read: { a: "b" }, write: { c: "d" }, valid: { e: "f" }, filters: [], fields: { f1: { read: { g: "h" }, fields: { f2: { write: { foo: "bar" }, fields: {} } } } } }; let testrule = new MongoDBServiceRule(rawRule); // update rule under an existing path. testrule = testrule.set( "fieldRules", testrule.fieldRules.updatePermissionsInput( "f1.f2", false, false, "read", "{ biz: 'baz' }" ) ); testrule = testrule.set( "fieldRules", testrule.fieldRules .updatePermissionsInput("f1.f2", false, false, "write", "{}") .parseInputs() ); expect(testrule.toRawRule()).toEqual({ _id: "5883c04eba186ebf69579ffd", namespace: "test.foo", filters: [], read: { a: "b" }, write: { c: "d" }, valid: { e: "f" }, fields: { f1: { read: { g: "h" }, fields: { f2: { read: { biz: "baz" }, write: {}, fields: {} } } } } }); }); it("can manipulate rules", () => { let testrule = new MongoDBServiceRule({ _id: "test", namespace: "foo.foo" }); testrule = testrule.set( "fieldRules", testrule.fieldRules.addField(null, "x").addField(null, "y") ); expect(testrule.fieldRules.fields.size).toBe(2); testrule = testrule.set( "fieldRules", testrule.fieldRules.setFieldType("x", TYPE_OBJECT) ); testrule = testrule.set( "fieldRules", testrule.fieldRules.addField("x", "foo") ); testrule = testrule.set( "fieldRules", testrule.fieldRules.setOtherFieldsEnabled("x", true) ); testrule = testrule.addFilter(); expect(testrule.toRawRule()).toEqual({ _id: "test", namespace: "foo.foo", fields: { x: { fields: { foo: {} }, otherFields: {} }, y: {} }, filters: [{ matchExpression: {}, when: {} }] }); testrule = testrule.setFilterWhenInput(0, "not json"); expect(testrule.filters.get(0).when.input).toEqual("not json"); testrule = testrule.parseFilters(); expect(testrule.filtersHasError).toBe(true); testrule = testrule.setFilterWhenInput(0, "{x:'xxx'}"); testrule = testrule.setFilterMatchInput(0, "{y:'yyy'}"); testrule = testrule.parseFilters(); expect(testrule.filtersHasError).toBe(false); expect(testrule.filters.get(0).when.data).toEqual({ x: "xxx" }); expect(testrule.filters.get(0).match.data).toEqual({ y: "yyy" }); testrule = testrule.removeFilter(0); expect(testrule.filters.size).toBe(0); testrule = testrule.updateIn(["fieldRules"], fr => fr.setFieldType("x.foo", TYPE_OBJECT) ); testrule = testrule.updateIn(["fieldRules"], fr => fr.addField("x.foo", "blah") ); expect(testrule.toRawRule()).toEqual({ _id: "test", namespace: "foo.foo", fields: { x: { fields: { foo: { fields: { blah: {} } } }, otherFields: {} }, y: {} }, filters: [] }); testrule = testrule.updateIn(["fieldRules"], fr => fr.removeField("x.foo")); expect(testrule.toRawRule()).toEqual({ _id: "test", namespace: "foo.foo", fields: { x: { fields: {}, otherFields: {} }, y: {} }, filters: [] }); testrule = testrule.updateIn(["fieldRules"], fr => fr.updatePermissionsInput("x", false, false, "write", "hey") ); let parsedFrs = testrule.fieldRules.parseInputs(); expect(parsedFrs.hasChildError).toBe(true); expect(parsedFrs.hasError).toBe(false); testrule = testrule.updateIn(["fieldRules"], fr => fr.updatePermissionsInput(null, false, false, "read", "yo") ); parsedFrs = testrule.fieldRules.parseInputs(); expect(parsedFrs.hasChildError).toBe(true); expect(parsedFrs.hasError).toBe(true); testrule = testrule.updateIn(["fieldRules"], fr => fr.updatePermissionsInput("x", false, false, "write", "{}") ); parsedFrs = testrule.fieldRules.parseInputs(); expect(parsedFrs.hasChildError).toBe(false); expect(parsedFrs.hasError).toBe(true); }); it("should detect shadowing correctly", () => { const testrule = new MongoDBServiceRule({ _id: "foo", namespace: "db.collection", fields: { x: { read: {}, fields: { y: { read: {}, write: {}, fields: { z: { valid: {} } } }, foo: { valid: {}, elements: { write: {} } } } } } }); const shadows = testrule.getShadows("x.y.z"); expect(shadows.valid).toBeUndefined(); expect(shadows.read.dottedFullPath).toBe("x"); expect(shadows.write.dottedFullPath).toBe("x.y"); // Get shadows on elements const shadows2 = testrule.getShadows("x.foo", true); expect(shadows2.read.dottedFullPath).toBe("x"); expect(shadows2.valid.dottedFullPath).toBe("x.foo"); const testrule2 = new MongoDBServiceRule({ _id: "foo", namespace: "db.collection", valid: {}, otherFields: { write: {} }, fields: { x: { read: {}, otherFields: { write: {} }, fields: { y: { read: {}, write: {}, fields: {}, otherFields: {} } } } } }); const shadow3 = testrule2.getShadows("x", false, true); expect(shadow3.read.dottedFullPath).toBe("x"); const shadow4 = testrule2.getShadows("x.y", false, true); expect(shadow4.write.dottedFullPath).toBe("x.y"); const shadow5 = testrule2.getShadows(null, false, true); expect(shadow5.valid.dottedFullPath).toBe(null); }); });