From dc824d91feab12caf8f99bee7aa14c36ce58d8d0 Mon Sep 17 00:00:00 2001 From: Milena Czierlinski <146972016+Milena-Czierlinski@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:34:12 +0200 Subject: [PATCH] Add configuration for setting isDefault of LocalAttributes (#241) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add consumptionConfig * feat: use consumptionConfig * feat: adjust attributes controller tests * feat: adjust runtime tests * fix: runtime tests * refactor: (re)move comments * chore: remove todo comments * simplify (#244) * refactor: simplify * chore: make clear that Partial is a ConsumptionConfigOverride * chore: set correct default * fix: tests * chore: audit fix * chore: undo index changes * refactor: make config required * refactor: update TestRuntime constructor to use ConsumptionConfig instead of ConsumptionConfigOverride * fix: test --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Julian König <33655937+jkoenig134@users.noreply.github.com> Co-authored-by: Julian König --- package-lock.json | 103 +++++----- packages/app-runtime/src/AppRuntime.ts | 3 +- .../src/consumption/ConsumptionConfig.ts | 3 + .../src/consumption/ConsumptionController.ts | 11 +- .../consumption/src/consumption/CoreErrors.ts | 4 + packages/consumption/src/index.ts | 1 + .../attributes/AttributesController.ts | 14 +- packages/consumption/test/core/TestUtil.ts | 22 ++- .../AttributeListenersController.test.ts | 1 - .../attributes/AttributesController.test.ts | 178 +++++++++++++----- .../LocalAttributeDeletionInfo.test.ts | 1 - ...edByOwnerNotificationItemProcessor.test.ts | 1 - ...tedByPeerNotificationItemProcessor.test.ts | 1 - ...tedByPeerNotificationItemProcessor.test.ts | 1 - ...SucceededNotificationItemProcessor.test.ts | 1 - ...eleteAttributeRequestItemProcessor.test.ts | 1 - .../FreeTextRequestItemProcessor.test.ts | 1 - ...oposeAttributeRequestItemProcessor.test.ts | 1 - .../ReadAttributeRequestItemProcessor.test.ts | 1 - ...ributeListenerRequestItemProcessor.test.ts | 1 - ...ShareAttributeRequestItemProcessor.test.ts | 1 - .../validateAttributeMatchesWithQuery.test.ts | 1 - .../src/useCases/common/RuntimeErrors.ts | 4 + .../ChangeDefaultRepositoryAttribute.ts | 4 + .../test/consumption/attributes.test.ts | 125 +++++++++--- .../IdentityAttributeQueryExpanded.test.ts | 4 +- .../test/lib/RuntimeServiceProvider.ts | 5 +- packages/runtime/test/lib/TestRuntime.ts | 16 +- .../test/misc/DatabaseSchemaUpgrader.test.ts | 2 +- 29 files changed, 353 insertions(+), 159 deletions(-) create mode 100644 packages/consumption/src/consumption/ConsumptionConfig.ts diff --git a/package-lock.json b/package-lock.json index b878e71c7..614654435 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2195,16 +2195,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz", - "integrity": "sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/type-utils": "7.15.0", - "@typescript-eslint/utils": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2228,15 +2229,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4" }, "engines": { @@ -2256,13 +2258,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.15.0.tgz", - "integrity": "sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0" + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2273,13 +2276,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.15.0.tgz", - "integrity": "sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/utils": "7.15.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2300,10 +2304,11 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", - "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -2313,13 +2318,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.15.0.tgz", - "integrity": "sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2341,15 +2347,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.15.0.tgz", - "integrity": "sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0" + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2363,12 +2370,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.15.0.tgz", - "integrity": "sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", + "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3739,18 +3747,19 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "28.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.6.0.tgz", - "integrity": "sha512-YG28E1/MIKwnz+e2H7VwYPzHUYU4aMa19w0yGcwXnnmJH6EfgHahTJ2un3IyraUxNfnz/KUhJAFXNNwWPo12tg==", + "version": "28.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.0.tgz", + "integrity": "sha512-Tubj1hooFxCl52G4qQu0edzV/+EZzPUeN8p2NnW5uu4fbDs+Yo7+qDVDc4/oG3FbCqEBmu/OC3LSsyiU22oghw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^6.0.0 || ^7.0.0" + "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "engines": { "node": "^16.10.0 || ^18.12.0 || >=20.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0", + "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", "jest": "*" }, diff --git a/packages/app-runtime/src/AppRuntime.ts b/packages/app-runtime/src/AppRuntime.ts index 6ffb82e79..cb0ced7ed 100644 --- a/packages/app-runtime/src/AppRuntime.ts +++ b/packages/app-runtime/src/AppRuntime.ts @@ -170,7 +170,8 @@ export class AppRuntime extends Runtime { if (!localAccount.address) { throw AppRuntimeErrors.general.addressUnavailable().logWith(this.logger); } - const consumptionController = await new ConsumptionController(this.transport, accountController).init(); + + const consumptionController = await new ConsumptionController(this.transport, accountController, { setDefaultRepositoryAttributes: true }).init(); const services = await this.login(accountController, consumptionController); diff --git a/packages/consumption/src/consumption/ConsumptionConfig.ts b/packages/consumption/src/consumption/ConsumptionConfig.ts new file mode 100644 index 000000000..a2b8553c0 --- /dev/null +++ b/packages/consumption/src/consumption/ConsumptionConfig.ts @@ -0,0 +1,3 @@ +export interface ConsumptionConfig { + setDefaultRepositoryAttributes: boolean; +} diff --git a/packages/consumption/src/consumption/ConsumptionController.ts b/packages/consumption/src/consumption/ConsumptionController.ts index e4683208f..224bf6326 100644 --- a/packages/consumption/src/consumption/ConsumptionController.ts +++ b/packages/consumption/src/consumption/ConsumptionController.ts @@ -41,11 +41,13 @@ import { ShareAttributeRequestItemProcessor, ThirdPartyOwnedRelationshipAttributeDeletedByPeerNotificationItemProcessor } from "../modules"; +import { ConsumptionConfig } from "./ConsumptionConfig"; export class ConsumptionController { public constructor( public readonly transport: Transport, - public readonly accountController: AccountController + public readonly accountController: AccountController, + public readonly consumptionConfig: ConsumptionConfig ) {} private _attributes: AttributesController; @@ -87,7 +89,12 @@ export class ConsumptionController { requestItemProcessorOverrides = new Map(), notificationItemProcessorOverrides = new Map() ): Promise { - this._attributes = await new AttributesController(this, this.transport.eventBus, this.accountController.identity).init(); + this._attributes = await new AttributesController( + this, + this.transport.eventBus, + this.accountController.identity, + this.consumptionConfig.setDefaultRepositoryAttributes + ).init(); this._drafts = await new DraftsController(this).init(); const requestItemProcessorRegistry = new RequestItemProcessorRegistry(this, this.getDefaultRequestItemProcessors()); diff --git a/packages/consumption/src/consumption/CoreErrors.ts b/packages/consumption/src/consumption/CoreErrors.ts index d931c33a8..aa7bb8a2a 100644 --- a/packages/consumption/src/consumption/CoreErrors.ts +++ b/packages/consumption/src/consumption/CoreErrors.ts @@ -252,6 +252,10 @@ class Attributes { `The sender (id: '${senderId}') of the Notification is not the peer you shared the Attribute (id: '${attributeId}') with.` ); } + + public setDefaultRepositoryAttributesIsDisabled() { + return new CoreError("error.consumption.attributes.setDefaultRepositoryAttributesIsDisabled", "Setting default RepositoryAttributes is disabled for this Account."); + } } class Requests { diff --git a/packages/consumption/src/index.ts b/packages/consumption/src/index.ts index 9ab6e9f5b..d96d918ce 100644 --- a/packages/consumption/src/index.ts +++ b/packages/consumption/src/index.ts @@ -1,5 +1,6 @@ export * from "./buildInformation"; export * from "./consumption/ConsumptionBaseController"; +export * from "./consumption/ConsumptionConfig"; export * from "./consumption/ConsumptionController"; export * from "./consumption/ConsumptionControllerName"; export * from "./consumption/ConsumptionError"; diff --git a/packages/consumption/src/modules/attributes/AttributesController.ts b/packages/consumption/src/modules/attributes/AttributesController.ts index 2d0b15e60..5f2253110 100644 --- a/packages/consumption/src/modules/attributes/AttributesController.ts +++ b/packages/consumption/src/modules/attributes/AttributesController.ts @@ -48,7 +48,8 @@ export class AttributesController extends ConsumptionBaseController { public constructor( parent: ConsumptionController, private readonly eventBus: EventBus, - private readonly identity: { address: CoreAddress } + private readonly identity: { address: CoreAddress }, + private readonly setDefaultRepositoryAttributes: boolean ) { super(ConsumptionControllerName.AttributesController, parent); } @@ -248,7 +249,9 @@ export class AttributesController extends ConsumptionBaseController { await this.attributes.create(localAttribute); - localAttribute = await this.setAsDefaultRepositoryAttribute(localAttribute, true); + if (this.setDefaultRepositoryAttributes) { + localAttribute = await this.setAsDefaultRepositoryAttribute(localAttribute, true); + } if (localAttribute.content.value instanceof AbstractComplexValue) { await this.createLocalAttributesForChildrenOfComplexAttribute(localAttribute); @@ -280,6 +283,8 @@ export class AttributesController extends ConsumptionBaseController { } public async setAsDefaultRepositoryAttribute(newDefaultAttribute: LocalAttribute, skipOverwrite?: boolean): Promise { + if (!this.setDefaultRepositoryAttributes) throw CoreErrors.attributes.setDefaultRepositoryAttributesIsDisabled(); + if (!newDefaultAttribute.isRepositoryAttribute(this.identity.address)) { throw CoreErrors.attributes.isNotRepositoryAttribute(newDefaultAttribute.id); } @@ -1063,7 +1068,9 @@ export class AttributesController extends ConsumptionBaseController { await this.deletePredecessorsOfAttribute(attribute.id); - await this.transferDefault(attribute); + if (this.setDefaultRepositoryAttributes) { + await this.transferDefault(attribute); + } await this.deleteAttribute(attribute); } @@ -1134,6 +1141,7 @@ export class AttributesController extends ConsumptionBaseController { } private async transferDefault(attribute: LocalAttribute): Promise { + if (!this.setDefaultRepositoryAttributes) throw CoreErrors.attributes.setDefaultRepositoryAttributesIsDisabled(); if (!attribute.isDefault) return; const valueType = attribute.content.value.constructor.name; diff --git a/packages/consumption/test/core/TestUtil.ts b/packages/consumption/test/core/TestUtil.ts index 04bf225c7..20a93a6dd 100644 --- a/packages/consumption/test/core/TestUtil.ts +++ b/packages/consumption/test/core/TestUtil.ts @@ -26,7 +26,14 @@ import { TransportLoggerFactory } from "@nmshd/transport"; import { LogLevel } from "typescript-logging"; -import { ConsumptionController, NotificationItemConstructor, NotificationItemProcessorConstructor, RequestItemConstructor, RequestItemProcessorConstructor } from "../../src"; +import { + ConsumptionConfig, + ConsumptionController, + NotificationItemConstructor, + NotificationItemProcessorConstructor, + RequestItemConstructor, + RequestItemProcessorConstructor +} from "../../src"; export const loggerFactory = new NodeLoggerFactory({ appenders: { @@ -177,12 +184,13 @@ export class TestUtil { transport: Transport, count: number, requestItemProcessors = new Map(), - notificationItemProcessors = new Map() + notificationItemProcessors = new Map(), + customConsumptionConfig?: ConsumptionConfig ): Promise<{ accountController: AccountController; consumptionController: ConsumptionController }[]> { const accounts = []; for (let i = 0; i < count; i++) { - const account = await this.createAccount(transport, requestItemProcessors, notificationItemProcessors); + const account = await this.createAccount(transport, requestItemProcessors, notificationItemProcessors, customConsumptionConfig); accounts.push(account); } @@ -192,13 +200,17 @@ export class TestUtil { private static async createAccount( transport: Transport, requestItemProcessors = new Map(), - notificationItemProcessors = new Map() + notificationItemProcessors = new Map(), + customConsumptionConfig?: ConsumptionConfig ): Promise<{ accountController: AccountController; consumptionController: ConsumptionController }> { const db = await transport.createDatabase(`x${Math.random().toString(36).substring(7)}`); const accountController = new AccountController(transport, db, transport.config); await accountController.init(); - const consumptionController = await new ConsumptionController(transport, accountController).init(requestItemProcessors, notificationItemProcessors); + const consumptionController = await new ConsumptionController(transport, accountController, customConsumptionConfig ?? { setDefaultRepositoryAttributes: false }).init( + requestItemProcessors, + notificationItemProcessors + ); return { accountController, consumptionController }; } diff --git a/packages/consumption/test/modules/attributeListeners/AttributeListenersController.test.ts b/packages/consumption/test/modules/attributeListeners/AttributeListenersController.test.ts index 9f0637235..130438872 100644 --- a/packages/consumption/test/modules/attributeListeners/AttributeListenersController.test.ts +++ b/packages/consumption/test/modules/attributeListeners/AttributeListenersController.test.ts @@ -24,7 +24,6 @@ describe("AttributeListenersController", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection, mockEventBus); - await transport.init(); const account = (await TestUtil.provideAccounts(transport, 1))[0]; diff --git a/packages/consumption/test/modules/attributes/AttributesController.test.ts b/packages/consumption/test/modules/attributes/AttributesController.test.ts index ebb4041f7..4ea842cd6 100644 --- a/packages/consumption/test/modules/attributes/AttributesController.test.ts +++ b/packages/consumption/test/modules/attributes/AttributesController.test.ts @@ -45,18 +45,24 @@ describe("AttributesController", function () { let consumptionController: ConsumptionController; let testAccount: AccountController; + let appConsumptionController: ConsumptionController; + let appTestAccount: AccountController; + beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection, mockEventBus); - await transport.init(); - const account = (await TestUtil.provideAccounts(transport, 1))[0]; - ({ accountController: testAccount, consumptionController } = account); + const connectorAccount = (await TestUtil.provideAccounts(transport, 1))[0]; + ({ accountController: testAccount, consumptionController } = connectorAccount); + + const appAccount = (await TestUtil.provideAccounts(transport, 1, undefined, undefined, { setDefaultRepositoryAttributes: true }))[0]; + ({ accountController: appTestAccount, consumptionController: appConsumptionController } = appAccount); }); afterAll(async function () { await testAccount.close(); + await appTestAccount.close(); await connection.close(); }); @@ -66,10 +72,14 @@ describe("AttributesController", function () { afterEach(async function () { const attributes = await consumptionController.attributes.getLocalAttributes(); - for (const attribute of attributes) { await consumptionController.attributes.deleteAttribute(attribute); } + + const appAttributes = await appConsumptionController.attributes.getLocalAttributes(); + for (const attribute of appAttributes) { + await appConsumptionController.attributes.deleteAttribute(attribute); + } }); describe("create Attributes", function () { @@ -159,49 +169,62 @@ describe("AttributesController", function () { ); }); - test("should set an Attribute as default if it is the only of its value type", async function () { + test("should set an Attribute as default if it is the only of its value type and setDefaultRepositoryAttributes is true", async function () { const attributeParams: ICreateRepositoryAttributeParams = { content: IdentityAttribute.from({ value: EMailAddress.from({ value: "my@email.address" }), - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }; - const attribute = await consumptionController.attributes.createRepositoryAttribute(attributeParams); + const attribute = await appConsumptionController.attributes.createRepositoryAttribute(attributeParams); expect(attribute.isDefault).toBe(true); }); - test("should not set an Attribute as default if already another exists with that value type", async function () { + test("should not set an Attribute as default if already another exists with that value type and setDefaultRepositoryAttributes is true", async function () { const attributeParams: ICreateRepositoryAttributeParams = { content: IdentityAttribute.from({ value: EMailAddress.from({ value: "my@email.address" }), - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }; - const firstAttribute = await consumptionController.attributes.createRepositoryAttribute(attributeParams); + const firstAttribute = await appConsumptionController.attributes.createRepositoryAttribute(attributeParams); expect(firstAttribute.isDefault).toBe(true); - const secondAttribute = await consumptionController.attributes.createRepositoryAttribute(attributeParams); + const secondAttribute = await appConsumptionController.attributes.createRepositoryAttribute(attributeParams); expect(secondAttribute.isDefault).toBeUndefined(); }); - test("should set a child Attribute of a complex default attribute as default", async function () { - const complexBirthDate = await consumptionController.attributes.createRepositoryAttribute({ + test("should not set an Attribute as default if it is the only of its value type but setDefaultRepositoryAttributes is false", async function () { + const attributeParams: ICreateRepositoryAttributeParams = { + content: IdentityAttribute.from({ + value: EMailAddress.from({ + value: "my@email.address" + }), + owner: consumptionController.accountController.identity.address + }) + }; + const attribute = await consumptionController.attributes.createRepositoryAttribute(attributeParams); + expect(attribute.isDefault).toBeUndefined(); + }); + + test("should set a child Attribute of a complex default attribute as default if setDefaultRepositoryAttributes is true", async function () { + const complexBirthDate = await appConsumptionController.attributes.createRepositoryAttribute({ content: IdentityAttribute.from({ value: BirthDate.from({ day: 28, month: 2, year: 2000 }), - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }); expect(complexBirthDate.isDefault).toBe(true); - const childBirthYear = await consumptionController.attributes.getLocalAttributes({ + const childBirthYear = await appConsumptionController.attributes.getLocalAttributes({ parentId: complexBirthDate.id.toString(), "content.value.@type": "BirthYear" }); @@ -209,34 +232,37 @@ describe("AttributesController", function () { expect(childBirthYear[0].isDefault).toBe(true); }); - test("should set a child Attribute of a complex default attribute as default even if already another attribute with that value type exists", async function () { - const independentBirthYear = await consumptionController.attributes.createRepositoryAttribute({ + test("should set a child Attribute of a complex default attribute as default if setDefaultRepositoryAttributes is true, even if already another attribute with that value type exists", async function () { + const independentBirthYear = await appConsumptionController.attributes.createRepositoryAttribute({ content: IdentityAttribute.from({ value: BirthYear.from({ value: 2000 }), - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }); expect(independentBirthYear.isDefault).toBe(true); - const complexBirthDate = await consumptionController.attributes.createRepositoryAttribute({ + const complexBirthDate = await appConsumptionController.attributes.createRepositoryAttribute({ content: IdentityAttribute.from({ value: BirthDate.from({ day: 28, month: 2, year: 2000 }), - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }); expect(complexBirthDate.isDefault).toBe(true); - const childBirthYear = await consumptionController.attributes.getLocalAttributes({ parentId: complexBirthDate.id.toString(), "content.value.@type": "BirthYear" }); + const childBirthYear = await appConsumptionController.attributes.getLocalAttributes({ + parentId: complexBirthDate.id.toString(), + "content.value.@type": "BirthYear" + }); expect(childBirthYear).toHaveLength(1); expect(childBirthYear[0].isDefault).toBe(true); - const updatedIndependentBirthYear = await consumptionController.attributes.getLocalAttribute(independentBirthYear.id); + const updatedIndependentBirthYear = await appConsumptionController.attributes.getLocalAttribute(independentBirthYear.id); expect(updatedIndependentBirthYear!.isDefault).toBeUndefined(); }); @@ -914,39 +940,69 @@ describe("AttributesController", function () { expect(updatedPredecessorOwnSharedIdentityAttribute!.shareInfo!.sourceAttribute).toBeUndefined(); }); - test("should change default from deleted attribute to newest of the same value type if another exists", async function () { - const otherRepositoryAttribute = await consumptionController.attributes.createRepositoryAttribute({ + test("should change default from deleted attribute to newest of the same value type if another exists and setDefaultRepositoryAttributes is true", async function () { + const defaultRepositoryAttribute = await appConsumptionController.attributes.createRepositoryAttribute({ + content: IdentityAttribute.from({ + value: EMailAddress.from({ + value: "my@email.address" + }), + owner: appConsumptionController.accountController.identity.address + }) + }); + + const otherRepositoryAttribute = await appConsumptionController.attributes.createRepositoryAttribute({ content: IdentityAttribute.from({ value: EMailAddress.from({ value: "my2@email.address" }), - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }); - const otherNewerRepositoryAttribute = await consumptionController.attributes.createRepositoryAttribute({ + const otherNewerRepositoryAttribute = await appConsumptionController.attributes.createRepositoryAttribute({ content: IdentityAttribute.from({ value: EMailAddress.from({ value: "my3@email.address" }), - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }); - expect(successorRepositoryAttribute.isDefault).toBe(true); + expect(defaultRepositoryAttribute.isDefault).toBe(true); expect(otherRepositoryAttribute.isDefault).toBeUndefined(); expect(otherNewerRepositoryAttribute.isDefault).toBeUndefined(); - await consumptionController.attributes.executeFullAttributeDeletionProcess(successorRepositoryAttribute); - const updatedOtherRepositoryAttribute = await consumptionController.attributes.getLocalAttribute(otherNewerRepositoryAttribute.id); + await appConsumptionController.attributes.executeFullAttributeDeletionProcess(defaultRepositoryAttribute); + const updatedOtherRepositoryAttribute = await appConsumptionController.attributes.getLocalAttribute(otherNewerRepositoryAttribute.id); expect(updatedOtherRepositoryAttribute!.isDefault).toBe(true); }); - test("should not set a default if the deleted default attribute had predecessors but no other candidate exists", async function () { + test("should not set a default if the deleted default attribute had predecessors but no other candidate exists and setDefaultRepositoryAttributes is true", async function () { + const predecessorRepositoryAttribute = await appConsumptionController.attributes.createRepositoryAttribute({ + content: IdentityAttribute.from({ + value: EMailAddress.from({ + value: "my@email.address" + }), + owner: appConsumptionController.accountController.identity.address + }) + }); + + const repositorySuccessorParams: IAttributeSuccessorParams = { + content: IdentityAttribute.from({ + value: { + "@type": "EMailAddress", + value: "my-new@email.address" + }, + owner: appConsumptionController.accountController.identity.address + }) + }; + const successionResult = await appConsumptionController.attributes.succeedRepositoryAttribute(predecessorRepositoryAttribute.id, repositorySuccessorParams); + const { successor: successorRepositoryAttribute } = successionResult; + expect(successorRepositoryAttribute.isDefault).toBe(true); - await consumptionController.attributes.executeFullAttributeDeletionProcess(successorRepositoryAttribute); + await appConsumptionController.attributes.executeFullAttributeDeletionProcess(successorRepositoryAttribute); - const defaultAttributes = await consumptionController.attributes.getLocalAttributes({ isDefault: "true" }); + const defaultAttributes = await appConsumptionController.attributes.getLocalAttributes({ isDefault: "true" }); expect(defaultAttributes).toHaveLength(0); }); }); @@ -1640,13 +1696,13 @@ describe("AttributesController", function () { }); test("should make successor default succeeding a default repository attribute", async function () { - const predecessor = await consumptionController.attributes.createRepositoryAttribute({ + const predecessor = await appConsumptionController.attributes.createRepositoryAttribute({ content: IdentityAttribute.from({ value: { "@type": "Nationality", value: "DE" }, - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }); expect(predecessor.isDefault).toBe(true); @@ -1657,11 +1713,11 @@ describe("AttributesController", function () { "@type": "Nationality", value: "US" }, - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }; - const { predecessor: updatedPredecessor, successor } = await consumptionController.attributes.succeedRepositoryAttribute(predecessor.id, successorParams); + const { predecessor: updatedPredecessor, successor } = await appConsumptionController.attributes.succeedRepositoryAttribute(predecessor.id, successorParams); expect(successor.isDefault).toBe(true); expect(updatedPredecessor.isDefault).toBeUndefined(); }); @@ -2341,58 +2397,58 @@ describe("AttributesController", function () { }); describe("change default Attributes", function () { - test("should change default RepositoryAttribute", async function () { - const firstAttribute = await consumptionController.attributes.createRepositoryAttribute({ + test("should change default RepositoryAttribute if setDefaultRepositoryAttributes is true", async function () { + const firstAttribute = await appConsumptionController.attributes.createRepositoryAttribute({ content: IdentityAttribute.from({ value: { "@type": "GivenName", value: "My default given name" }, - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }); - const secondAttribute = await consumptionController.attributes.createRepositoryAttribute({ + const secondAttribute = await appConsumptionController.attributes.createRepositoryAttribute({ content: IdentityAttribute.from({ value: { "@type": "GivenName", value: "My other given name" }, - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }); expect(secondAttribute.isDefault).toBeUndefined(); - const updatedSecondAttribute = await consumptionController.attributes.setAsDefaultRepositoryAttribute(secondAttribute); + const updatedSecondAttribute = await appConsumptionController.attributes.setAsDefaultRepositoryAttribute(secondAttribute); expect(updatedSecondAttribute.isDefault).toBe(true); - const updatedFirstAttribute = await consumptionController.attributes.getLocalAttribute(firstAttribute.id); + const updatedFirstAttribute = await appConsumptionController.attributes.getLocalAttribute(firstAttribute.id); expect(updatedFirstAttribute!.isDefault).toBeUndefined(); }); - test("should not change default RepositoryAttribute if candidate is already default", async function () { - const firstAttribute = await consumptionController.attributes.createRepositoryAttribute({ + test("should not change default RepositoryAttribute if candidate is already default and setDefaultRepositoryAttributes is true", async function () { + const firstAttribute = await appConsumptionController.attributes.createRepositoryAttribute({ content: IdentityAttribute.from({ value: { "@type": "GivenName", value: "My default given name" }, - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }) }); expect(firstAttribute.isDefault).toBe(true); - const updatedFirstAttribute = await consumptionController.attributes.setAsDefaultRepositoryAttribute(firstAttribute); + const updatedFirstAttribute = await appConsumptionController.attributes.setAsDefaultRepositoryAttribute(firstAttribute); expect(updatedFirstAttribute.isDefault).toBe(true); }); - test("should throw an error if the new default Attribute is not a RepositoryAttribute", async function () { - const sharedAttribute = await consumptionController.attributes.createAttributeUnsafe({ + test("should throw an error if the new default Attribute is not a RepositoryAttribute and setDefaultRepositoryAttributes is true", async function () { + const sharedAttribute = await appConsumptionController.attributes.createAttributeUnsafe({ content: IdentityAttribute.from({ value: { "@type": "GivenName", value: "My shared given name" }, - owner: consumptionController.accountController.identity.address + owner: appConsumptionController.accountController.identity.address }), shareInfo: LocalAttributeShareInfo.from({ peer: CoreAddress.from("peer"), @@ -2401,10 +2457,28 @@ describe("AttributesController", function () { }); await TestUtil.expectThrowsAsync( - consumptionController.attributes.setAsDefaultRepositoryAttribute(sharedAttribute), + appConsumptionController.attributes.setAsDefaultRepositoryAttribute(sharedAttribute), "error.consumption.attributes.isNotRepositoryAttribute" ); }); + + test("should throw an error trying to change the default RepositoryAttribute if setDefaultRepositoryAttributes is false", async function () { + const repositoryAttribute = await consumptionController.attributes.createRepositoryAttribute({ + content: IdentityAttribute.from({ + value: { + "@type": "GivenName", + value: "My default given name" + }, + owner: consumptionController.accountController.identity.address + }) + }); + expect(repositoryAttribute.isDefault).toBeUndefined(); + + await TestUtil.expectThrowsAsync( + consumptionController.attributes.setAsDefaultRepositoryAttribute(repositoryAttribute), + "error.consumption.attributes.setDefaultRepositoryAttributesIsDisabled" + ); + }); }); describe("get Attributes", function () { diff --git a/packages/consumption/test/modules/attributes/LocalAttributeDeletionInfo.test.ts b/packages/consumption/test/modules/attributes/LocalAttributeDeletionInfo.test.ts index 1c2a81172..0b7cca259 100644 --- a/packages/consumption/test/modules/attributes/LocalAttributeDeletionInfo.test.ts +++ b/packages/consumption/test/modules/attributes/LocalAttributeDeletionInfo.test.ts @@ -20,7 +20,6 @@ describe("LocalAttributeDeletionInfo", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection); - await transport.init(); const account = (await TestUtil.provideAccounts(transport, 1))[0]; diff --git a/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/OwnSharedAttributeDeletedByOwnerNotificationItemProcessor.test.ts b/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/OwnSharedAttributeDeletedByOwnerNotificationItemProcessor.test.ts index 8e2890aba..6f0f40bd0 100644 --- a/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/OwnSharedAttributeDeletedByOwnerNotificationItemProcessor.test.ts +++ b/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/OwnSharedAttributeDeletedByOwnerNotificationItemProcessor.test.ts @@ -25,7 +25,6 @@ describe("OwnSharedAttributeDeletedByPeerNotificationItemProcessor", function () beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection, mockEventBus); - await transport.init(); const account = (await TestUtil.provideAccounts(transport, 1))[0]; diff --git a/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/PeerSharedAttributeDeletedByPeerNotificationItemProcessor.test.ts b/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/PeerSharedAttributeDeletedByPeerNotificationItemProcessor.test.ts index 33c402d0f..5d53178a5 100644 --- a/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/PeerSharedAttributeDeletedByPeerNotificationItemProcessor.test.ts +++ b/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/PeerSharedAttributeDeletedByPeerNotificationItemProcessor.test.ts @@ -26,7 +26,6 @@ describe("PeerSharedAttributeDeletedByPeerNotificationItemProcessor", function ( beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection, mockEventBus); - await transport.init(); const account = (await TestUtil.provideAccounts(transport, 1))[0]; diff --git a/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/ThirdPartyOwnedRelationshipAttributeDeletedByPeerNotificationItemProcessor.test.ts b/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/ThirdPartyOwnedRelationshipAttributeDeletedByPeerNotificationItemProcessor.test.ts index 963337ec6..7f97467af 100644 --- a/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/ThirdPartyOwnedRelationshipAttributeDeletedByPeerNotificationItemProcessor.test.ts +++ b/packages/consumption/test/modules/notifications/itemProcessors/attributeDeleted/ThirdPartyOwnedRelationshipAttributeDeletedByPeerNotificationItemProcessor.test.ts @@ -25,7 +25,6 @@ describe("ThirdPartyOwnedRelationshipAttributeDeletedByPeerNotificationItemProce beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection, mockEventBus); - await transport.init(); const account = (await TestUtil.provideAccounts(transport, 1))[0]; diff --git a/packages/consumption/test/modules/notifications/itemProcessors/attributeSucceeded/PeerSharedAttributeSucceededNotificationItemProcessor.test.ts b/packages/consumption/test/modules/notifications/itemProcessors/attributeSucceeded/PeerSharedAttributeSucceededNotificationItemProcessor.test.ts index 15cd9c32e..2ae8e67c8 100644 --- a/packages/consumption/test/modules/notifications/itemProcessors/attributeSucceeded/PeerSharedAttributeSucceededNotificationItemProcessor.test.ts +++ b/packages/consumption/test/modules/notifications/itemProcessors/attributeSucceeded/PeerSharedAttributeSucceededNotificationItemProcessor.test.ts @@ -24,7 +24,6 @@ describe("PeerSharedAttributeSucceededNotificationItemProcessor", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection, mockEventBus); - await transport.init(); const account = (await TestUtil.provideAccounts(transport, 1))[0]; diff --git a/packages/consumption/test/modules/requests/itemProcessors/deleteAttribute/DeleteAttributeRequestItemProcessor.test.ts b/packages/consumption/test/modules/requests/itemProcessors/deleteAttribute/DeleteAttributeRequestItemProcessor.test.ts index aa30d5973..15ebc7499 100644 --- a/packages/consumption/test/modules/requests/itemProcessors/deleteAttribute/DeleteAttributeRequestItemProcessor.test.ts +++ b/packages/consumption/test/modules/requests/itemProcessors/deleteAttribute/DeleteAttributeRequestItemProcessor.test.ts @@ -36,7 +36,6 @@ describe("DeleteAttributeRequestItemProcessor", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection); - await transport.init(); const accounts = await TestUtil.provideAccounts(transport, 2); diff --git a/packages/consumption/test/modules/requests/itemProcessors/freeText/FreeTextRequestItemProcessor.test.ts b/packages/consumption/test/modules/requests/itemProcessors/freeText/FreeTextRequestItemProcessor.test.ts index 21ae253d5..79efc311a 100644 --- a/packages/consumption/test/modules/requests/itemProcessors/freeText/FreeTextRequestItemProcessor.test.ts +++ b/packages/consumption/test/modules/requests/itemProcessors/freeText/FreeTextRequestItemProcessor.test.ts @@ -15,7 +15,6 @@ describe("FreeTextRequestItemProcessor", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection); - await transport.init(); const account = (await TestUtil.provideAccounts(transport, 1))[0]; diff --git a/packages/consumption/test/modules/requests/itemProcessors/proposeAttribute/ProposeAttributeRequestItemProcessor.test.ts b/packages/consumption/test/modules/requests/itemProcessors/proposeAttribute/ProposeAttributeRequestItemProcessor.test.ts index 72c279893..0535d3127 100644 --- a/packages/consumption/test/modules/requests/itemProcessors/proposeAttribute/ProposeAttributeRequestItemProcessor.test.ts +++ b/packages/consumption/test/modules/requests/itemProcessors/proposeAttribute/ProposeAttributeRequestItemProcessor.test.ts @@ -43,7 +43,6 @@ describe("ProposeAttributeRequestItemProcessor", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection); - await transport.init(); const accounts = await TestUtil.provideAccounts(transport, 2); diff --git a/packages/consumption/test/modules/requests/itemProcessors/readAttribute/ReadAttributeRequestItemProcessor.test.ts b/packages/consumption/test/modules/requests/itemProcessors/readAttribute/ReadAttributeRequestItemProcessor.test.ts index 7c7b37a69..0abc35a4b 100644 --- a/packages/consumption/test/modules/requests/itemProcessors/readAttribute/ReadAttributeRequestItemProcessor.test.ts +++ b/packages/consumption/test/modules/requests/itemProcessors/readAttribute/ReadAttributeRequestItemProcessor.test.ts @@ -49,7 +49,6 @@ describe("ReadAttributeRequestItemProcessor", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection); - await transport.init(); const accounts = await TestUtil.provideAccounts(transport, 2); diff --git a/packages/consumption/test/modules/requests/itemProcessors/registerAttributeListener/RegisterAttributeListenerRequestItemProcessor.test.ts b/packages/consumption/test/modules/requests/itemProcessors/registerAttributeListener/RegisterAttributeListenerRequestItemProcessor.test.ts index e547b5a07..5d1931937 100644 --- a/packages/consumption/test/modules/requests/itemProcessors/registerAttributeListener/RegisterAttributeListenerRequestItemProcessor.test.ts +++ b/packages/consumption/test/modules/requests/itemProcessors/registerAttributeListener/RegisterAttributeListenerRequestItemProcessor.test.ts @@ -15,7 +15,6 @@ describe("CreateAttributeRequestItemProcessor", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection); - await transport.init(); const account = (await TestUtil.provideAccounts(transport, 1))[0]; diff --git a/packages/consumption/test/modules/requests/itemProcessors/shareAttribute/ShareAttributeRequestItemProcessor.test.ts b/packages/consumption/test/modules/requests/itemProcessors/shareAttribute/ShareAttributeRequestItemProcessor.test.ts index e579ef352..33ada8d16 100644 --- a/packages/consumption/test/modules/requests/itemProcessors/shareAttribute/ShareAttributeRequestItemProcessor.test.ts +++ b/packages/consumption/test/modules/requests/itemProcessors/shareAttribute/ShareAttributeRequestItemProcessor.test.ts @@ -34,7 +34,6 @@ describe("ShareAttributeRequestItemProcessor", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection); - await transport.init(); const accounts = await TestUtil.provideAccounts(transport, 2); diff --git a/packages/consumption/test/modules/requests/itemProcessors/utility/validateAttributeMatchesWithQuery.test.ts b/packages/consumption/test/modules/requests/itemProcessors/utility/validateAttributeMatchesWithQuery.test.ts index 418210deb..d00eaaebf 100644 --- a/packages/consumption/test/modules/requests/itemProcessors/utility/validateAttributeMatchesWithQuery.test.ts +++ b/packages/consumption/test/modules/requests/itemProcessors/utility/validateAttributeMatchesWithQuery.test.ts @@ -42,7 +42,6 @@ describe("validateAttributeMatchesWithQuery", function () { beforeAll(async function () { connection = await TestUtil.createConnection(); transport = TestUtil.createTransport(connection); - await transport.init(); const accounts = await TestUtil.provideAccounts(transport, 2); diff --git a/packages/runtime/src/useCases/common/RuntimeErrors.ts b/packages/runtime/src/useCases/common/RuntimeErrors.ts index dda47bf4f..dd2745b4c 100644 --- a/packages/runtime/src/useCases/common/RuntimeErrors.ts +++ b/packages/runtime/src/useCases/common/RuntimeErrors.ts @@ -207,6 +207,10 @@ class Attributes { `Attribute '${attributeId.toString()}' is a child of a complex Attribute. If you want to delete it, you must delete its parent.` ); } + + public setDefaultRepositoryAttributesIsDisabled(): ApplicationError { + return new ApplicationError("error.runtime.attributes.setDefaultRepositoryAttributesIsDisabled", "Setting default RepositoryAttributes is disabled for this Account."); + } } class IdentityDeletionProcess { diff --git a/packages/runtime/src/useCases/consumption/attributes/ChangeDefaultRepositoryAttribute.ts b/packages/runtime/src/useCases/consumption/attributes/ChangeDefaultRepositoryAttribute.ts index 3773107fd..a50001c15 100644 --- a/packages/runtime/src/useCases/consumption/attributes/ChangeDefaultRepositoryAttribute.ts +++ b/packages/runtime/src/useCases/consumption/attributes/ChangeDefaultRepositoryAttribute.ts @@ -26,6 +26,10 @@ export class ChangeDefaultRepositoryAttributeUseCase extends UseCase> { + if (!this.attributesController.parent.consumptionConfig.setDefaultRepositoryAttributes) { + return Result.fail(RuntimeErrors.attributes.setDefaultRepositoryAttributesIsDisabled()); + } + const newDefaultAttribute = await this.attributesController.getLocalAttribute(CoreId.from(request.attributeId)); if (!newDefaultAttribute) return Result.fail(RuntimeErrors.general.recordNotFound(LocalAttribute)); diff --git a/packages/runtime/test/consumption/attributes.test.ts b/packages/runtime/test/consumption/attributes.test.ts index 62c8c4d18..e642e0d5e 100644 --- a/packages/runtime/test/consumption/attributes.test.ts +++ b/packages/runtime/test/consumption/attributes.test.ts @@ -68,6 +68,8 @@ let services1: TestRuntimeServices; let services2: TestRuntimeServices; let services3: TestRuntimeServices; +let appService: TestRuntimeServices; + beforeAll(async () => { const numberOfServices = 3; [services1, services2, services3] = await runtimeServiceProvider.launch(numberOfServices, { @@ -79,6 +81,15 @@ beforeAll(async () => { await establishRelationship(services1.transport, services2.transport); await establishRelationship(services1.transport, services3.transport); await establishRelationship(services2.transport, services3.transport); + + appService = ( + await runtimeServiceProvider.launch(1, { + enableDefaultRepositoryAttributes: true, + enableRequestModule: true + }) + )[0]; + + await establishRelationship(appService.transport, services2.transport); }, 30000); afterAll(async () => await runtimeServiceProvider.stop()); @@ -90,7 +101,7 @@ beforeEach(() => { async function cleanupAttributes() { await Promise.all( - [services1, services2, services3].map(async (services) => { + [services1, services2, services3, appService].map(async (services) => { const servicesAttributeController = (services.consumption.attributes as any).getAttributeUseCase.attributeController as AttributesController; const servicesAttributesResult = await services.consumption.attributes.getAttributes({}); @@ -104,7 +115,7 @@ async function cleanupAttributes() { describe("get attribute(s)", () => { let relationshipAttributeId: string; let identityAttributeIds: string[]; - + let appAttributeIds: string[]; beforeAll(async function () { const senderRequests: CreateRepositoryAttributeRequest[] = [ { @@ -152,6 +163,12 @@ describe("get attribute(s)", () => { } }); relationshipAttributeId = relationshipAttribute.id; + + appAttributeIds = []; + for (const request of senderRequests) { + const appAttribute = (await appService.consumption.attributes.createRepositoryAttribute(request)).value; + appAttributeIds.push(appAttribute.id); + } }); afterAll(async function () { @@ -226,7 +243,7 @@ describe("get attribute(s)", () => { }); test("should allow to get only default attributes", async function () { - const result = await services1.consumption.attributes.getAttributes({ + const result = await appService.consumption.attributes.getAttributes({ query: { isDefault: "true" } }); expect(result).toBeSuccessful(); @@ -235,24 +252,21 @@ describe("get attribute(s)", () => { expect(attributes).toHaveLength(2); const attributeIds = attributes.map((attr) => attr.id); - expect(attributeIds).toContain(identityAttributeIds[0]); - expect(attributeIds).toContain(identityAttributeIds[1]); - expect(attributeIds).not.toContain(identityAttributeIds[2]); - expect(attributeIds).not.toContain(relationshipAttributeId); + expect(attributeIds).toContain(appAttributeIds[0]); + expect(attributeIds).toContain(appAttributeIds[1]); + expect(attributeIds).not.toContain(appAttributeIds[2]); }); test("should allow not to get default attributes", async function () { - const result = await services1.consumption.attributes.getAttributes({ + const result = await appService.consumption.attributes.getAttributes({ query: { isDefault: "!true" } }); expect(result).toBeSuccessful(); const attributes = result.value; - expect(attributes).toHaveLength(2); + expect(attributes).toHaveLength(1); - const attributeIds = attributes.map((attr) => attr.id); - expect(attributeIds).toContain(relationshipAttributeId); - expect(attributeIds).toContain(identityAttributeIds[2]); + expect(attributes[0].id).toBe(appAttributeIds[2]); }); }); }); @@ -496,7 +510,40 @@ describe("get repository, own shared and peer shared attributes", () => { }); test("should allow to get only default attributes", async function () { - const result = await services1.consumption.attributes.getRepositoryAttributes({ + const defaultGivenName = ( + await appService.consumption.attributes.createRepositoryAttribute({ + content: { + value: { + "@type": "GivenName", + value: "AGivenName" + } + } + }) + ).value; + + const defaultSurname = ( + await appService.consumption.attributes.createRepositoryAttribute({ + content: { + value: { + "@type": "Surname", + value: "ASurname" + } + } + }) + ).value; + + const otherSurname = ( + await appService.consumption.attributes.createRepositoryAttribute({ + content: { + value: { + "@type": "Surname", + value: "AnotherSurname" + } + } + }) + ).value; + + const result = await appService.consumption.attributes.getRepositoryAttributes({ query: { isDefault: "true" } @@ -507,8 +554,9 @@ describe("get repository, own shared and peer shared attributes", () => { expect(attributes).toHaveLength(2); const attributeIds = attributes.map((attr) => attr.id); - expect(attributeIds).toContain(services1RepoSurnameV1.id); - expect(attributeIds).toContain(services1RepoGivenNameV1.id); + expect(attributeIds).toContain(defaultGivenName.id); + expect(attributeIds).toContain(defaultSurname.id); + expect(attributeIds).not.toContain(otherSurname.id); }); }); @@ -679,7 +727,7 @@ describe(CreateRepositoryAttributeUseCase.name, () => { } } }; - const result = await services1.consumption.attributes.createRepositoryAttribute(request); + const result = await appService.consumption.attributes.createRepositoryAttribute(request); const attribute = result.value; expect(attribute.isDefault).toBe(true); }); @@ -693,8 +741,8 @@ describe(CreateRepositoryAttributeUseCase.name, () => { } } }; - await services1.consumption.attributes.createRepositoryAttribute(request); - const result = await services1.consumption.attributes.createRepositoryAttribute(request); + await appService.consumption.attributes.createRepositoryAttribute(request); + const result = await appService.consumption.attributes.createRepositoryAttribute(request); const attribute = result.value; expect(attribute.isDefault).toBeUndefined(); }); @@ -1352,7 +1400,7 @@ describe(ChangeDefaultRepositoryAttributeUseCase.name, () => { test("should change default RepositoryAttribute", async () => { const defaultAttribute = ( - await services1.consumption.attributes.createRepositoryAttribute({ + await appService.consumption.attributes.createRepositoryAttribute({ content: { value: { "@type": "GivenName", @@ -1364,7 +1412,7 @@ describe(ChangeDefaultRepositoryAttributeUseCase.name, () => { expect(defaultAttribute.isDefault).toBe(true); const desiredDefaultAttribute = ( - await services1.consumption.attributes.createRepositoryAttribute({ + await appService.consumption.attributes.createRepositoryAttribute({ content: { value: { "@type": "GivenName", @@ -1375,20 +1423,20 @@ describe(ChangeDefaultRepositoryAttributeUseCase.name, () => { ).value; expect(desiredDefaultAttribute.isDefault).toBeUndefined(); - const result = await services1.consumption.attributes.changeDefaultRepositoryAttribute({ attributeId: desiredDefaultAttribute.id }); + const result = await appService.consumption.attributes.changeDefaultRepositoryAttribute({ attributeId: desiredDefaultAttribute.id }); expect(result.isSuccess).toBe(true); const newDefaultAttribute = result.value; expect(newDefaultAttribute.isDefault).toBe(true); - const updatedFormerDesiredDefaultAttribute = (await services1.consumption.attributes.getAttribute({ id: desiredDefaultAttribute.id })).value; + const updatedFormerDesiredDefaultAttribute = (await appService.consumption.attributes.getAttribute({ id: desiredDefaultAttribute.id })).value; expect(updatedFormerDesiredDefaultAttribute.isDefault).toBe(true); - const updatedFormerDefaultAttribute = (await services1.consumption.attributes.getAttribute({ id: defaultAttribute.id })).value; + const updatedFormerDefaultAttribute = (await appService.consumption.attributes.getAttribute({ id: defaultAttribute.id })).value; expect(updatedFormerDefaultAttribute.isDefault).toBeUndefined(); }); test("should return an error if the new default attribute is not a RepositoryAttribute", async () => { - await services1.consumption.attributes.createRepositoryAttribute({ + await appService.consumption.attributes.createRepositoryAttribute({ content: { value: { "@type": "GivenName", @@ -1397,7 +1445,7 @@ describe(ChangeDefaultRepositoryAttributeUseCase.name, () => { } }); - const desiredSharedDefaultAttribute = await executeFullCreateAndShareRepositoryAttributeFlow(services1, services2, { + const desiredSharedDefaultAttribute = await executeFullCreateAndShareRepositoryAttributeFlow(appService, services2, { content: { value: { "@type": "GivenName", @@ -1405,12 +1453,12 @@ describe(ChangeDefaultRepositoryAttributeUseCase.name, () => { } } }); - const result = await services1.consumption.attributes.changeDefaultRepositoryAttribute({ attributeId: desiredSharedDefaultAttribute.id }); + const result = await appService.consumption.attributes.changeDefaultRepositoryAttribute({ attributeId: desiredSharedDefaultAttribute.id }); expect(result).toBeAnError(`Attribute '${desiredSharedDefaultAttribute.id.toString()}' is not a RepositoryAttribute.`, "error.runtime.attributes.isNotRepositoryAttribute"); }); test("should return an error if the new default attribute has a successor", async () => { - await services1.consumption.attributes.createRepositoryAttribute({ + await appService.consumption.attributes.createRepositoryAttribute({ content: { value: { "@type": "GivenName", @@ -1420,7 +1468,7 @@ describe(ChangeDefaultRepositoryAttributeUseCase.name, () => { }); const desiredDefaultAttribute = ( - await services1.consumption.attributes.createRepositoryAttribute({ + await appService.consumption.attributes.createRepositoryAttribute({ content: { value: { "@type": "GivenName", @@ -1431,7 +1479,7 @@ describe(ChangeDefaultRepositoryAttributeUseCase.name, () => { ).value; const successionResult = ( - await services1.consumption.attributes.succeedRepositoryAttribute({ + await appService.consumption.attributes.succeedRepositoryAttribute({ predecessorId: desiredDefaultAttribute.id, successorContent: { value: { @@ -1445,12 +1493,29 @@ describe(ChangeDefaultRepositoryAttributeUseCase.name, () => { const updatedDesiredDefaultAttribute = successionResult.predecessor; const desiredDefaultAttributeSuccessor = successionResult.successor; - const result = await services1.consumption.attributes.changeDefaultRepositoryAttribute({ attributeId: updatedDesiredDefaultAttribute.id }); + const result = await appService.consumption.attributes.changeDefaultRepositoryAttribute({ attributeId: updatedDesiredDefaultAttribute.id }); expect(result).toBeAnError( `Attribute '${updatedDesiredDefaultAttribute.id.toString()}' already has a successor ${desiredDefaultAttributeSuccessor.id.toString()}.`, "error.runtime.attributes.hasSuccessor" ); }); + + test("should return an error trying to set a default attribute if setDefaultRepositoryAttributes is false", async () => { + const attribute = ( + await services1.consumption.attributes.createRepositoryAttribute({ + content: { + value: { + "@type": "GivenName", + value: "My default name" + } + } + }) + ).value; + expect(attribute.isDefault).toBeUndefined(); + + const result = await services1.consumption.attributes.changeDefaultRepositoryAttribute({ attributeId: attribute.id }); + expect(result).toBeAnError("Setting default RepositoryAttributes is disabled for this Account.", "error.runtime.attributes.setDefaultRepositoryAttributesIsDisabled"); + }); }); describe("Get (shared) versions of attribute", () => { diff --git a/packages/runtime/test/dataViews/IdentityAttributeQueryExpanded.test.ts b/packages/runtime/test/dataViews/IdentityAttributeQueryExpanded.test.ts index 9bb5dfb5e..c57a154a3 100644 --- a/packages/runtime/test/dataViews/IdentityAttributeQueryExpanded.test.ts +++ b/packages/runtime/test/dataViews/IdentityAttributeQueryExpanded.test.ts @@ -7,7 +7,9 @@ let consumptionServices1: ConsumptionServices; let expander1: DataViewExpander; beforeAll(async () => { - const runtimeServices = await serviceProvider.launch(1); + const runtimeServices = await serviceProvider.launch(1, { + enableDefaultRepositoryAttributes: true + }); consumptionServices1 = runtimeServices[0].consumption; expander1 = runtimeServices[0].expander; }, 30000); diff --git a/packages/runtime/test/lib/RuntimeServiceProvider.ts b/packages/runtime/test/lib/RuntimeServiceProvider.ts index b543c025e..bbb02d379 100644 --- a/packages/runtime/test/lib/RuntimeServiceProvider.ts +++ b/packages/runtime/test/lib/RuntimeServiceProvider.ts @@ -17,6 +17,7 @@ export interface LaunchConfiguration { enableRequestModule?: boolean; enableAttributeListenerModule?: boolean; enableNotificationModule?: boolean; + enableDefaultRepositoryAttributes?: boolean; } export class RuntimeServiceProvider { @@ -83,7 +84,9 @@ export class RuntimeServiceProvider { if (launchConfiguration.enableAttributeListenerModule) config.modules.attributeListener.enabled = true; if (launchConfiguration.enableNotificationModule) config.modules.notification.enabled = true; - const runtime = new TestRuntime(config); + const runtime = new TestRuntime(config, { + setDefaultRepositoryAttributes: launchConfiguration.enableDefaultRepositoryAttributes ?? false + }); this.runtimes.push(runtime); await runtime.init(); diff --git a/packages/runtime/test/lib/TestRuntime.ts b/packages/runtime/test/lib/TestRuntime.ts index 31121b4eb..787741d36 100644 --- a/packages/runtime/test/lib/TestRuntime.ts +++ b/packages/runtime/test/lib/TestRuntime.ts @@ -2,7 +2,7 @@ import { IDatabaseConnection } from "@js-soft/docdb-access-abstractions"; import { LokiJsConnection } from "@js-soft/docdb-access-loki"; import { MongoDbConnection } from "@js-soft/docdb-access-mongo"; import { NodeLoggerFactory } from "@js-soft/node-logger"; -import { ConsumptionController, GenericRequestItemProcessor } from "@nmshd/consumption"; +import { ConsumptionConfig, ConsumptionController, GenericRequestItemProcessor } from "@nmshd/consumption"; import { AccountController, ICoreAddress } from "@nmshd/transport"; import { ConsumptionServices, DataViewExpander, ModuleConfiguration, Runtime, RuntimeConfig, RuntimeHealth, RuntimeServices, TransportServices } from "../../src"; import { MockEventBus } from "./MockEventBus"; @@ -16,7 +16,10 @@ export class TestRuntime extends Runtime { private _consumptionServices: ConsumptionServices; private _dataViewExpander: DataViewExpander; - public constructor(runtimeConfig: RuntimeConfig) { + public constructor( + runtimeConfig: RuntimeConfig, + private readonly consumptionConfig: ConsumptionConfig + ) { super( runtimeConfig, new NodeLoggerFactory({ @@ -88,7 +91,10 @@ export class TestRuntime extends Runtime { const requestItemProcessorOverrides = new Map([[TestRequestItem, GenericRequestItemProcessor]]); const notificationItemProcessorOverrides = new Map([[TestNotificationItem, TestNotificationItemProcessor]]); - const consumptionController = await new ConsumptionController(this.transport, accountController).init(requestItemProcessorOverrides, notificationItemProcessorOverrides); + const consumptionController = await new ConsumptionController(this.transport, accountController, this.consumptionConfig).init( + requestItemProcessorOverrides, + notificationItemProcessorOverrides + ); ({ transportServices: this._transportServices, @@ -119,6 +125,10 @@ export class TestRuntime extends Runtime { } export class NoLoginTestRuntime extends TestRuntime { + public constructor(runtimeConfig: RuntimeConfig) { + super(runtimeConfig, { setDefaultRepositoryAttributes: false }); + } + protected override async initAccount(): Promise { // Do not login } diff --git a/packages/runtime/test/misc/DatabaseSchemaUpgrader.test.ts b/packages/runtime/test/misc/DatabaseSchemaUpgrader.test.ts index 902471478..60286202e 100644 --- a/packages/runtime/test/misc/DatabaseSchemaUpgrader.test.ts +++ b/packages/runtime/test/misc/DatabaseSchemaUpgrader.test.ts @@ -56,7 +56,7 @@ beforeAll(async () => { const db = await transport.createDatabase(`acc-${randomAccountName}`); accountController = await new AccountController(transport, db, transport.config).init(); - consumptionController = await new ConsumptionController(transport, accountController).init(); + consumptionController = await new ConsumptionController(transport, accountController, { setDefaultRepositoryAttributes: false }).init(); }, 30000); afterAll(async () => {