mirror of
https://github.com/nasa/openmct.git
synced 2025-05-06 18:48:27 +00:00
Update specs to match composition policies
This commit is contained in:
parent
65325b90fd
commit
2a10a2cae2
@ -54,8 +54,7 @@ define(
|
|||||||
AddActionProvider.prototype.getActions = function (actionContext) {
|
AddActionProvider.prototype.getActions = function (actionContext) {
|
||||||
var context = actionContext || {},
|
var context = actionContext || {},
|
||||||
key = context.key,
|
key = context.key,
|
||||||
destination = context.domainObject,
|
destination = context.domainObject;
|
||||||
self = this;
|
|
||||||
|
|
||||||
// We only provide Add actions, and we need a
|
// We only provide Add actions, and we need a
|
||||||
// domain object to serve as the container for the
|
// domain object to serve as the container for the
|
||||||
@ -66,16 +65,16 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Introduce one create action per type
|
// Introduce one create action per type
|
||||||
['timeline', 'activity'].map(function (type) {
|
return ['timeline', 'activity'].map(function (type) {
|
||||||
return new AddAction(
|
return new AddAction(
|
||||||
type,
|
this.typeService.getType(type),
|
||||||
destination,
|
destination,
|
||||||
context,
|
context,
|
||||||
self.$q,
|
this.$q,
|
||||||
self.dialogService,
|
this.dialogService,
|
||||||
self.policyService
|
this.policyService
|
||||||
);
|
);
|
||||||
});
|
}, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
return AddActionProvider;
|
return AddActionProvider;
|
||||||
|
@ -31,9 +31,7 @@ define(
|
|||||||
var mockTypeService,
|
var mockTypeService,
|
||||||
mockDialogService,
|
mockDialogService,
|
||||||
mockPolicyService,
|
mockPolicyService,
|
||||||
mockCreationPolicy,
|
mockTypeMap,
|
||||||
mockCompositionPolicy,
|
|
||||||
mockPolicyMap = {},
|
|
||||||
mockTypes,
|
mockTypes,
|
||||||
mockDomainObject,
|
mockDomainObject,
|
||||||
mockQ,
|
mockQ,
|
||||||
@ -55,49 +53,33 @@ define(
|
|||||||
);
|
);
|
||||||
mockType.hasFeature.andReturn(true);
|
mockType.hasFeature.andReturn(true);
|
||||||
mockType.getName.andReturn(name);
|
mockType.getName.andReturn(name);
|
||||||
|
mockType.getKey.andReturn(name);
|
||||||
return mockType;
|
return mockType;
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mockTypeService = jasmine.createSpyObj(
|
mockTypeService = jasmine.createSpyObj(
|
||||||
"typeService",
|
"typeService",
|
||||||
["listTypes"]
|
["getType"]
|
||||||
);
|
|
||||||
mockDialogService = jasmine.createSpyObj(
|
|
||||||
"dialogService",
|
|
||||||
["getUserInput"]
|
|
||||||
);
|
|
||||||
mockPolicyService = jasmine.createSpyObj(
|
|
||||||
"policyService",
|
|
||||||
["allow"]
|
|
||||||
);
|
);
|
||||||
|
mockDialogService = {};
|
||||||
|
mockPolicyService = {};
|
||||||
|
mockDomainObject = {};
|
||||||
|
|
||||||
mockDomainObject = jasmine.createSpyObj(
|
mockTypes = [
|
||||||
"domainObject",
|
"timeline",
|
||||||
["getCapability"]
|
"activity",
|
||||||
);
|
"other"
|
||||||
|
].map(createMockType);
|
||||||
//Mocking getCapability because AddActionProvider uses the
|
mockTypeMap = {};
|
||||||
// type capability of the destination object.
|
|
||||||
mockDomainObject.getCapability.andReturn({});
|
|
||||||
|
|
||||||
mockTypes = ["A", "B", "C"].map(createMockType);
|
|
||||||
|
|
||||||
mockTypes.forEach(function (type) {
|
mockTypes.forEach(function (type) {
|
||||||
mockPolicyMap[type.getName()] = true;
|
mockTypeMap[type.getKey()] = type;
|
||||||
});
|
});
|
||||||
|
|
||||||
mockCreationPolicy = function (type) {
|
mockTypeService.getType.andCallFake(function (key) {
|
||||||
return mockPolicyMap[type.getName()];
|
return mockTypeMap[key];
|
||||||
};
|
});
|
||||||
|
|
||||||
mockCompositionPolicy = function () {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
mockPolicyService.allow.andReturn(true);
|
|
||||||
|
|
||||||
mockTypeService.listTypes.andReturn(mockTypes);
|
|
||||||
|
|
||||||
provider = new AddActionProvider(
|
provider = new AddActionProvider(
|
||||||
mockQ,
|
mockQ,
|
||||||
@ -107,29 +89,16 @@ define(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("checks for creatability", function () {
|
it("provides actions for timeline and activity", function () {
|
||||||
provider.getActions({
|
var actions = provider.getActions({
|
||||||
key: "add",
|
key: "add",
|
||||||
domainObject: mockDomainObject
|
domainObject: mockDomainObject
|
||||||
});
|
});
|
||||||
|
expect(actions.length).toBe(2);
|
||||||
|
expect(actions[0].metadata.type).toBe('timeline');
|
||||||
|
expect(actions[1].metadata.type).toBe('activity');
|
||||||
|
|
||||||
// Make sure it was creation which was used to check
|
// Make sure it was creation which was used to check
|
||||||
expect(mockPolicyService.allow)
|
|
||||||
.toHaveBeenCalledWith("creation", mockTypes[0]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("checks for composability of type", function () {
|
|
||||||
provider.getActions({
|
|
||||||
key: "add",
|
|
||||||
domainObject: mockDomainObject
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockPolicyService.allow).toHaveBeenCalledWith(
|
|
||||||
"composition",
|
|
||||||
jasmine.any(Object),
|
|
||||||
jasmine.any(Object)
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(mockDomainObject.getCapability).toHaveBeenCalledWith('type');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ define(
|
|||||||
expect(mockPolicyService.allow).toHaveBeenCalledWith(
|
expect(mockPolicyService.allow).toHaveBeenCalledWith(
|
||||||
'composition',
|
'composition',
|
||||||
mockOtherType,
|
mockOtherType,
|
||||||
mockType
|
mockDomainObject
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,9 +39,7 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CompositionPolicy.prototype.allow = function (parentType, child) {
|
CompositionPolicy.prototype.allow = function (parentType, child) {
|
||||||
var childType = child.getCapability('type');
|
var parentDef = parentType.getDefinition();
|
||||||
var childTypeKey = childType.getKey();
|
|
||||||
var parentDef = parent.getDefinition();
|
|
||||||
|
|
||||||
// A parent without containment rules can contain anything.
|
// A parent without containment rules can contain anything.
|
||||||
if (!parentDef.contains) {
|
if (!parentDef.contains) {
|
||||||
@ -53,7 +51,7 @@ define(
|
|||||||
return parentDef.contains.some(function (c) {
|
return parentDef.contains.some(function (c) {
|
||||||
// Simple containment rules are supported typeKeys.
|
// Simple containment rules are supported typeKeys.
|
||||||
if (typeof c === 'string') {
|
if (typeof c === 'string') {
|
||||||
return c === childTypeKey;
|
return c === child.getCapability('type').getKey();
|
||||||
}
|
}
|
||||||
// More complicated rules require context to have all specified
|
// More complicated rules require context to have all specified
|
||||||
// capabilities.
|
// capabilities.
|
||||||
|
@ -79,7 +79,7 @@ define(
|
|||||||
expect(mockPolicyService.allow).toHaveBeenCalledWith(
|
expect(mockPolicyService.allow).toHaveBeenCalledWith(
|
||||||
'composition',
|
'composition',
|
||||||
mockTypes[0],
|
mockTypes[0],
|
||||||
mockTypes[1]
|
mockDomainObjects[1]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -24,62 +24,96 @@ define(
|
|||||||
["../src/CompositionPolicy"],
|
["../src/CompositionPolicy"],
|
||||||
function (CompositionPolicy) {
|
function (CompositionPolicy) {
|
||||||
describe("Composition policy", function () {
|
describe("Composition policy", function () {
|
||||||
var mockInjector,
|
var typeA,
|
||||||
mockTypeService,
|
typeB,
|
||||||
mockCapabilityService,
|
typeC,
|
||||||
mockTypes,
|
mockChildObject,
|
||||||
policy;
|
policy;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mockInjector = jasmine.createSpyObj('$injector', ['get']);
|
typeA = jasmine.createSpyObj(
|
||||||
mockTypeService = jasmine.createSpyObj(
|
'type A-- the particular kind',
|
||||||
'typeService',
|
['getKey', 'getDefinition']
|
||||||
['listTypes']
|
|
||||||
);
|
);
|
||||||
mockCapabilityService = jasmine.createSpyObj(
|
typeA.getKey.andReturn('a');
|
||||||
'capabilityService',
|
typeA.getDefinition.andReturn({
|
||||||
['getCapabilities']
|
contains: ['a']
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
typeB = jasmine.createSpyObj(
|
||||||
|
'type B-- anything goes',
|
||||||
|
['getKey', 'getDefinition']
|
||||||
);
|
);
|
||||||
// Both types can only contain b, let's say
|
typeB.getKey.andReturn('b');
|
||||||
mockTypes = ['a', 'b'].map(function (type) {
|
typeB.getDefinition.andReturn({
|
||||||
var mockType = jasmine.createSpyObj(
|
contains: ['a', 'b']
|
||||||
'type-' + type,
|
});
|
||||||
['getKey', 'getDefinition', 'getInitialModel']
|
|
||||||
|
typeC = jasmine.createSpyObj(
|
||||||
|
'type C-- distinguishing and interested in telemetry',
|
||||||
|
['getKey', 'getDefinition']
|
||||||
);
|
);
|
||||||
mockType.getKey.andReturn(type);
|
typeC.getKey.andReturn('c');
|
||||||
mockType.getDefinition.andReturn({
|
typeC.getDefinition.andReturn({
|
||||||
contains: ['b']
|
contains: [{has: 'telemetry'}]
|
||||||
});
|
|
||||||
mockType.getInitialModel.andReturn({});
|
|
||||||
return mockType;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
mockInjector.get.andCallFake(function (name) {
|
mockChildObject = jasmine.createSpyObj(
|
||||||
return {
|
'childObject',
|
||||||
typeService: mockTypeService,
|
['getCapability', 'hasCapability']
|
||||||
capabilityService: mockCapabilityService
|
);
|
||||||
}[name];
|
|
||||||
|
policy = new CompositionPolicy();
|
||||||
});
|
});
|
||||||
|
|
||||||
mockTypeService.listTypes.andReturn(mockTypes);
|
describe('enforces simple containment rules', function () {
|
||||||
mockCapabilityService.getCapabilities.andReturn({});
|
|
||||||
|
|
||||||
policy = new CompositionPolicy(mockInjector);
|
it('allows when type matches', function () {
|
||||||
});
|
mockChildObject.getCapability.andReturn(typeA);
|
||||||
|
expect(policy.allow(typeA, mockChildObject))
|
||||||
// Test basic composition policy here; test more closely at
|
|
||||||
// the unit level in ContainmentTable for 'has' support, et al
|
|
||||||
it("enforces containment rules defined by types", function () {
|
|
||||||
expect(policy.allow(mockTypes[0], mockTypes[1]))
|
|
||||||
.toBeTruthy();
|
.toBeTruthy();
|
||||||
expect(policy.allow(mockTypes[1], mockTypes[1]))
|
|
||||||
|
expect(policy.allow(typeB, mockChildObject))
|
||||||
.toBeTruthy();
|
.toBeTruthy();
|
||||||
expect(policy.allow(mockTypes[1], mockTypes[0]))
|
|
||||||
|
mockChildObject.getCapability.andReturn(typeB);
|
||||||
|
expect(policy.allow(typeB, mockChildObject))
|
||||||
|
.toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('disallows when type doesn\'t match', function () {
|
||||||
|
|
||||||
|
mockChildObject.getCapability.andReturn(typeB);
|
||||||
|
expect(policy.allow(typeA, mockChildObject))
|
||||||
.toBeFalsy();
|
.toBeFalsy();
|
||||||
expect(policy.allow(mockTypes[0], mockTypes[0]))
|
|
||||||
|
mockChildObject.getCapability.andReturn(typeC);
|
||||||
|
expect(policy.allow(typeA, mockChildObject))
|
||||||
.toBeFalsy();
|
.toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('enforces capability-based containment rules', function () {
|
||||||
|
it('allows when object has capability', function () {
|
||||||
|
mockChildObject.hasCapability.andReturn(true);
|
||||||
|
expect(policy.allow(typeC, mockChildObject))
|
||||||
|
.toBeTruthy();
|
||||||
|
expect(mockChildObject.hasCapability)
|
||||||
|
.toHaveBeenCalledWith('telemetry');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skips when object doesn\'t have capability', function () {
|
||||||
|
mockChildObject.hasCapability.andReturn(false);
|
||||||
|
expect(policy.allow(typeC, mockChildObject))
|
||||||
|
.toBeFalsy();
|
||||||
|
expect(mockChildObject.hasCapability)
|
||||||
|
.toHaveBeenCalledWith('telemetry');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -104,7 +104,7 @@ define(
|
|||||||
expect(policyService.allow).toHaveBeenCalledWith(
|
expect(policyService.allow).toHaveBeenCalledWith(
|
||||||
"composition",
|
"composition",
|
||||||
parentCandidate.capabilities.type,
|
parentCandidate.capabilities.type,
|
||||||
object.capabilities.type
|
object
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ define(
|
|||||||
expect(mockPolicyService.allow).toHaveBeenCalledWith(
|
expect(mockPolicyService.allow).toHaveBeenCalledWith(
|
||||||
"composition",
|
"composition",
|
||||||
parentCandidate.capabilities.type,
|
parentCandidate.capabilities.type,
|
||||||
object.capabilities.type
|
object
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ define(
|
|||||||
expect(policyService.allow).toHaveBeenCalledWith(
|
expect(policyService.allow).toHaveBeenCalledWith(
|
||||||
"composition",
|
"composition",
|
||||||
parentCandidate.capabilities.type,
|
parentCandidate.capabilities.type,
|
||||||
object.capabilities.type
|
object
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -24,18 +24,25 @@ define(
|
|||||||
["../src/LayoutCompositionPolicy"],
|
["../src/LayoutCompositionPolicy"],
|
||||||
function (LayoutCompositionPolicy) {
|
function (LayoutCompositionPolicy) {
|
||||||
describe("Layout's composition policy", function () {
|
describe("Layout's composition policy", function () {
|
||||||
var mockCandidate,
|
var mockChild,
|
||||||
|
mockCandidate,
|
||||||
mockContext,
|
mockContext,
|
||||||
candidateType,
|
candidateType,
|
||||||
contextType,
|
contextType,
|
||||||
policy;
|
policy;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
mockChild = jasmine.createSpyObj(
|
||||||
|
'childObject',
|
||||||
|
['getCapability']
|
||||||
|
);
|
||||||
mockCandidate =
|
mockCandidate =
|
||||||
jasmine.createSpyObj('candidateType', ['instanceOf']);
|
jasmine.createSpyObj('candidateType', ['instanceOf']);
|
||||||
mockContext =
|
mockContext =
|
||||||
jasmine.createSpyObj('contextType', ['instanceOf']);
|
jasmine.createSpyObj('contextType', ['instanceOf']);
|
||||||
|
|
||||||
|
mockChild.getCapability.andReturn(mockContext);
|
||||||
|
|
||||||
mockCandidate.instanceOf.andCallFake(function (t) {
|
mockCandidate.instanceOf.andCallFake(function (t) {
|
||||||
return t === candidateType;
|
return t === candidateType;
|
||||||
});
|
});
|
||||||
@ -49,19 +56,19 @@ define(
|
|||||||
it("disallows folders in layouts", function () {
|
it("disallows folders in layouts", function () {
|
||||||
candidateType = 'layout';
|
candidateType = 'layout';
|
||||||
contextType = 'folder';
|
contextType = 'folder';
|
||||||
expect(policy.allow(mockCandidate, mockContext)).toBe(false);
|
expect(policy.allow(mockCandidate, mockChild)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not disallow folders elsewhere", function () {
|
it("does not disallow folders elsewhere", function () {
|
||||||
candidateType = 'nonlayout';
|
candidateType = 'nonlayout';
|
||||||
contextType = 'folder';
|
contextType = 'folder';
|
||||||
expect(policy.allow(mockCandidate, mockContext)).toBe(true);
|
expect(policy.allow(mockCandidate, mockChild)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows things other than folders in layouts", function () {
|
it("allows things other than folders in layouts", function () {
|
||||||
candidateType = 'layout';
|
candidateType = 'layout';
|
||||||
contextType = 'nonfolder';
|
contextType = 'nonfolder';
|
||||||
expect(policy.allow(mockCandidate, mockContext)).toBe(true);
|
expect(policy.allow(mockCandidate, mockChild)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user