Skip to content

Commit

Permalink
fix: remove implicit intent when unregistering a capability
Browse files Browse the repository at this point in the history
fixes: #200
  • Loading branch information
mofogasy committed Nov 8, 2019
1 parent 97ab6bb commit 14ae08c
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Injectable } from '@angular/core';
import { Capability, Intent, Qualifier } from '@scion/workbench-application-platform.api';
import { Defined } from './defined.util';
import { sha256 } from 'js-sha256';
import { matchesCapabilityQualifier, matchesIntentQualifier } from './qualifier-tester';
import { matchesCapabilityQualifier, matchesIntentQualifier, qualifiersEqual } from './qualifier-tester';

/**
* Registry with all registered application capabilities and intents.
Expand Down Expand Up @@ -157,6 +157,9 @@ export class ManifestRegistry {
const registeredCapabilities = this._capabilitiesByType.get(capabilityToUnregister.type);
this._capabilitiesById.delete(capabilityId);
this._capabilitiesByType.set(capabilityToUnregister.type, registeredCapabilities.filter(capability => capability.metadata.id !== capabilityId));

// Unregister implicit intent.
this.unregisterImplicitIntent(symbolicName, {type: capabilityToUnregister.type, qualifier: capabilityToUnregister.qualifier});
}

/**
Expand Down Expand Up @@ -187,6 +190,25 @@ export class ManifestRegistry {
});
}

/**
* Unregisters the implicit intent of the given type and qualifier for the given application.
*
* Used to remove implicit intents when unregistering capabilities.
*/
private unregisterImplicitIntent(symbolicName: string, intent: Intent): void {
const intentsToUnregister = this.getIntentsByApplication(symbolicName)
.filter(it => it.metadata.implicit && it.type === intent.type && qualifiersEqual(it.qualifier, intent.qualifier));

if (!intentsToUnregister.length) {
throw Error(`[IntentUnregistrationError] No implicit intents exist [appName=${symbolicName}, type=${intent.type}, qualifier=${intent.qualifier}]`);
}

intentsToUnregister.forEach(intentToUnregister => {
this._intentsById.delete(intentToUnregister.metadata.id);
this._intentsByApplication.set(symbolicName, this._intentsByApplication.get(symbolicName).filter(it => it.metadata.id !== intentToUnregister.metadata.id));
});
}

/**
* Disables capability scope check for given application.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,31 @@ export function matchesIntentQualifier(intentQualifier: Qualifier, testee: Quali
return _intentQualifier[key] === _testee[key];
});
}

/**
* Tests if the two qualifies are equal.
*/
export function qualifiersEqual(first: Qualifier, second: Qualifier): boolean {
// Test if same instance
if (first === second) {
return true;
}

// Test if one of the qualifiers is undefined
if (!first || !second) {
return false;
}

// Test if second has all required entries
if (!Object.keys(first).every(key => second.hasOwnProperty(key))) {
return false;
}

// Test if second has no additional entries
if (!Object.keys(second).every(key => first.hasOwnProperty(key))) {
return false;
}

// Test if values match
return Object.keys(first).every(key => first[key] === second[key]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ describe('ManifestRegistry', () => {

describe('function \'unregisterCapability(...)\'', () => {

it('should unregister capability of given id', fakeAsync(inject([ManifestRegistry], (manifestRegistry: ManifestRegistry) => {
it('should unregister capability of given id and its implicit intent', fakeAsync(inject([ManifestRegistry], (manifestRegistry: ManifestRegistry) => {
const type = PlatformCapabilityTypes.View;
const qualifier1: Qualifier = {entity: 'entity', qualifier: 1};
const qualifier2: Qualifier = {entity: 'entity', qualifier: 2};
Expand All @@ -293,6 +293,39 @@ describe('ManifestRegistry', () => {
expect(manifestRegistry.getCapabilities(type, qualifier1).length).toBe(1);
expect(manifestRegistry.getCapabilities(type, qualifier2).length).toBe(0);
expect(manifestRegistry.getCapabilities(type, qualifier3).length).toBe(1);
expect(manifestRegistry.hasIntent('app-1', type, qualifier1)).toBeTruthy();
expect(manifestRegistry.hasIntent('app-1', type, qualifier2)).toBeFalsy();
expect(manifestRegistry.hasIntent('app-1', type, qualifier3)).toBeTruthy();
})));

it('should unregister capability of given id and its implicit intent, but not the implicit intents of wildcard (*) capabilities', fakeAsync(inject([ManifestRegistry], (manifestRegistry: ManifestRegistry) => {
const type = PlatformCapabilityTypes.View;
const qualifier1: Qualifier = {entity: 'entity', qualifier: 1};
const qualifier2: Qualifier = {entity: '*', qualifier: '*'}; // implicit intent of this capability should not be unregistered
manifestRegistry.registerCapability('app-1', [{type, qualifier: qualifier1, private: false}]);
manifestRegistry.registerCapability('app-1', [{type, qualifier: qualifier2, private: false}]);
const capability = manifestRegistry.getCapabilities(type, qualifier1)[0];

manifestRegistry.unregisterCapability('app-1', capability.metadata.id);
expect(manifestRegistry.getCapabilitiesByApplication('app-1').length).toBe(1);
expect(manifestRegistry.getCapabilitiesByType(type).length).toBe(1);
expect(manifestRegistry.getIntentsByApplication('app-1').length).toBe(1);
expect(manifestRegistry.getIntentsByApplication('app-1')[0].qualifier).toEqual(qualifier2);
})));

it('should unregister capability of given id and its implicit intent, but not the implicit intents of wildcard (?) capabilities', fakeAsync(inject([ManifestRegistry], (manifestRegistry: ManifestRegistry) => {
const type = PlatformCapabilityTypes.View;
const qualifier1: Qualifier = {entity: 'entity', qualifier: 1};
const qualifier2: Qualifier = {entity: '?', qualifier: '?'}; // implicit intent of this capability should not be unregistered
manifestRegistry.registerCapability('app-1', [{type, qualifier: qualifier1, private: false}]);
manifestRegistry.registerCapability('app-1', [{type, qualifier: qualifier2, private: false}]);
const capability = manifestRegistry.getCapabilities(type, qualifier1)[0];

manifestRegistry.unregisterCapability('app-1', capability.metadata.id);
expect(manifestRegistry.getCapabilitiesByApplication('app-1').length).toBe(1);
expect(manifestRegistry.getCapabilitiesByType(type).length).toBe(1);
expect(manifestRegistry.getIntentsByApplication('app-1').length).toBe(1);
expect(manifestRegistry.getIntentsByApplication('app-1')[0].qualifier).toEqual(qualifier2);
})));

it('should throw exception for nonexistent capability', fakeAsync(inject([ManifestRegistry], (manifestRegistry: ManifestRegistry) => {
Expand All @@ -304,6 +337,7 @@ describe('ManifestRegistry', () => {
expect(manifestRegistry.getCapabilitiesByApplication('app-1').length).toBe(1);
expect(manifestRegistry.getCapabilitiesByType(type).length).toBe(1);
expect(manifestRegistry.getCapabilities(type, qualifier).length).toBe(1);
expect(manifestRegistry.hasIntent('app-1', type, qualifier)).toBeTruthy();
})));

it('should throw exception for capability of other application', fakeAsync(inject([ManifestRegistry], (manifestRegistry: ManifestRegistry) => {
Expand All @@ -316,6 +350,7 @@ describe('ManifestRegistry', () => {
expect(manifestRegistry.getCapabilitiesByApplication('app-1').length).toBe(1);
expect(manifestRegistry.getCapabilitiesByType(type).length).toBe(1);
expect(manifestRegistry.getCapabilities(type, qualifier).length).toBe(1);
expect(manifestRegistry.hasIntent('app-1', type, qualifier)).toBeTruthy();
})));
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* SPDX-License-Identifier: EPL-2.0
*/

import { matchesCapabilityQualifier, matchesIntentQualifier } from '../core/qualifier-tester';
import { qualifiersEqual, matchesCapabilityQualifier, matchesIntentQualifier } from '../core/qualifier-tester';
import { patchQualifier } from '../core/qualifier-patcher';

describe('Qualifier', () => {
Expand Down Expand Up @@ -253,4 +253,50 @@ describe('Qualifier', () => {
expect(patchQualifier({'*': '*'}, {entity: 'user', id: '?'})).toEqual({entity: 'user', id: '?'});
});
});

describe('function \'qualifiersEqual(...)\'', () => {

it('equal for same qualifier instance', () => {
const qualifier = {entity: 'person', id: 42};
expect(qualifiersEqual(qualifier, qualifier)).toBeTruthy();
});

it('equal when all keys and values match', () => {
expect(qualifiersEqual(null, null)).toBeTruthy();
expect(qualifiersEqual(undefined, undefined)).toBeTruthy();
expect(qualifiersEqual({}, {})).toBeTruthy();
expect(qualifiersEqual({entity: 'person', id: 42}, {entity: 'person', id: 42})).toBeTruthy();
expect(qualifiersEqual({entity: '*', id: 42}, {entity: '*', id: 42})).toBeTruthy();
expect(qualifiersEqual({entity: '?', id: 42}, {entity: '?', id: 42})).toBeTruthy();
expect(qualifiersEqual({'*': '*'}, {'*': '*'})).toBeTruthy();
});

it('not equal when qualifier key missing', () => {
expect(qualifiersEqual({entity: 'person'}, {entity: 'person', id: 42})).toBeFalsy();
expect(qualifiersEqual({entity: 'person', id: 42}, {entity: 'person'})).toBeFalsy();
});

it('not equal when qualifier value different', () => {
expect(qualifiersEqual({entity: 'person', id: 42}, {entity: 'person', id: 43})).toBeFalsy();
expect(qualifiersEqual({entity: 'person', id: 43}, {entity: 'person', id: 42})).toBeFalsy();
});

it('not equal when comparing wildcard qualifier with specific qualifier', () => {
expect(qualifiersEqual({'*': '*'}, {entity: 'person'})).toBeFalsy();
expect(qualifiersEqual({entity: '*'}, {entity: 'person'})).toBeFalsy();
expect(qualifiersEqual({entity: '?'}, {entity: 'person'})).toBeFalsy();
expect(qualifiersEqual({entity: 'person'}, {'*': '*'})).toBeFalsy();
expect(qualifiersEqual({entity: 'person'}, {entity: '*'})).toBeFalsy();
expect(qualifiersEqual({entity: 'person'}, {entity: '?'})).toBeFalsy();
});

it('not equal when comparing empty qualifier with non-empty qualifier', () => {
expect(qualifiersEqual(null, {entity: 'person'})).toBeFalsy();
expect(qualifiersEqual(undefined, {entity: 'person'})).toBeFalsy();
expect(qualifiersEqual({}, {entity: 'person'})).toBeFalsy();
expect(qualifiersEqual({entity: 'person'}, null)).toBeFalsy();
expect(qualifiersEqual({entity: 'person'}, undefined)).toBeFalsy();
expect(qualifiersEqual({entity: 'person'}, {})).toBeFalsy();
});
});
});

0 comments on commit 14ae08c

Please sign in to comment.