stitch-ui
Version:
521 lines (497 loc) • 14.1 kB
JavaScript
/* 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);
});
});