diff --git a/packages/node/src/attributes/ApplicationInformationAttributeProvider.ts b/packages/node/src/attributes/ApplicationInformationAttributeProvider.ts index a8e94392..b931a236 100644 --- a/packages/node/src/attributes/ApplicationInformationAttributeProvider.ts +++ b/packages/node/src/attributes/ApplicationInformationAttributeProvider.ts @@ -36,12 +36,6 @@ export class ApplicationInformationAttributeProvider implements BacktraceAttribu this._applicationVersion = this._applicationVersion ?? (applicationData['version'] as string); } - if (!this._application || !this._applicationVersion) { - throw new Error( - 'Cannot find information about the package. Please define application and application.version attribute', - ); - } - return { package: applicationData, [this.APPLICATION_ATTRIBUTE]: this._application, diff --git a/packages/node/tests/attributes/applicationInformationAttributeProviderTests.spec.ts b/packages/node/tests/attributes/applicationInformationAttributeProviderTests.spec.ts index 351df4f5..d2563c42 100644 --- a/packages/node/tests/attributes/applicationInformationAttributeProviderTests.spec.ts +++ b/packages/node/tests/attributes/applicationInformationAttributeProviderTests.spec.ts @@ -26,12 +26,5 @@ describe('Application information attribute provider tests', () => { expect(attributes[provider.APPLICATION_VERSION_ATTRIBUTE]).toBe(expectedPackageJson.version); }); - - it('Should throw an error when the package.json information does not exist', () => { - const testedPackageDir = path.join('/foo', 'bar', 'baz', '123', 'foo', 'bar'); - const provider = new ApplicationInformationAttributeProvider([testedPackageDir], {}); - - expect(() => provider.get()).toThrow(Error); - }); }); }); diff --git a/packages/sdk-core/src/BacktraceCoreClient.ts b/packages/sdk-core/src/BacktraceCoreClient.ts index e9ff9c14..82ed9dd2 100644 --- a/packages/sdk-core/src/BacktraceCoreClient.ts +++ b/packages/sdk-core/src/BacktraceCoreClient.ts @@ -218,6 +218,8 @@ export abstract class BacktraceCoreClient< } public initialize() { + this.validateAttributes(); + if (this.fileSystem && this.options.database?.createDatabaseDirectory) { if (!this.options.database.path) { throw new Error( @@ -418,4 +420,28 @@ export abstract class BacktraceCoreClient< private static destroy() { this._instance = undefined; } + + private validateAttributes() { + function validateApplicationAndVersion(attributes: Record) { + if (!attributes['application'] || !attributes['application.version']) { + return 'application and application.version attributes must be defined.'; + } + } + + // Validate scoped attributes first. If they return no errors, there is no point + // in checking all attributes, which resolving of may be slower. + const scoped = this.attributeManager.get('scoped'); + const scopedError = validateApplicationAndVersion(scoped.attributes); + if (!scopedError) { + return; + } + + const allAttributes = this.attributeManager.get(); + const error = validateApplicationAndVersion(allAttributes.attributes); + if (!error) { + return; + } + + throw new Error(error); + } } diff --git a/packages/sdk-core/tests/client/clientTests.spec.ts b/packages/sdk-core/tests/client/clientTests.spec.ts index 019db8c0..3e6d3f65 100644 --- a/packages/sdk-core/tests/client/clientTests.spec.ts +++ b/packages/sdk-core/tests/client/clientTests.spec.ts @@ -1,6 +1,12 @@ import { BacktraceReport, BacktraceStringAttachment } from '../../src/index.js'; +import { AttributeManager } from '../../src/modules/attribute/AttributeManager.js'; import { BacktraceTestClient } from '../mocks/BacktraceTestClient.js'; +import { testHttpClient } from '../mocks/testHttpClient.js'; describe('Client tests', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + describe('Send tests', () => { const client = BacktraceTestClient.buildFakeClient(); @@ -128,4 +134,103 @@ describe('Client tests', () => { ); }); }); + + describe('Validation tests', () => { + it('should throw on initialize when application and application.version attributes are missing', () => { + const instance = new BacktraceTestClient({}, testHttpClient); + expect(() => instance.initialize()).toThrow( + 'application and application.version attributes must be defined.', + ); + }); + + it('should throw on initialize when application attribute is missing', () => { + const instance = new BacktraceTestClient({}, testHttpClient, [ + { + type: 'scoped', + get: () => ({ + 'application.version': '1.2.3', + }), + }, + ]); + expect(() => instance.initialize()).toThrow( + 'application and application.version attributes must be defined.', + ); + }); + + it('should throw on initialize when application.version attribute is missing', () => { + const instance = new BacktraceTestClient({}, testHttpClient, [ + { + type: 'scoped', + get: () => ({ + application: 'my-app', + }), + }, + ]); + expect(() => instance.initialize()).toThrow( + 'application and application.version attributes must be defined.', + ); + }); + + it('should not throw on initialize when application and application.version attributes are defined as scoped', () => { + const instance = new BacktraceTestClient({}, testHttpClient, [ + { + type: 'scoped', + get: () => ({ + application: 'my-app', + 'application.version': '1.2.3', + }), + }, + ]); + expect(() => instance.initialize()).not.toThrow(); + }); + + it('should not throw on initialize when application and application.version attributes are defined as dynamic', () => { + const instance = new BacktraceTestClient({}, testHttpClient, [ + { + type: 'dynamic', + get: () => ({ + application: 'my-app', + 'application.version': '1.2.3', + }), + }, + ]); + expect(() => instance.initialize()).not.toThrow(); + }); + + it('should only test scoped attributes and not all when application and application.version attributes are defined as scoped', () => { + const instance = new BacktraceTestClient({}, testHttpClient, [ + { + type: 'scoped', + get: () => ({ + application: 'my-app', + 'application.version': '1.2.3', + }), + }, + ]); + + const getAttributesSpy = jest.spyOn(AttributeManager.prototype, 'get'); + instance.initialize(); + + expect(getAttributesSpy).toHaveBeenCalledWith('scoped'); + expect(getAttributesSpy).not.toHaveBeenCalledWith(); + }); + + it('should test both scoped attributes and all when application and application.version attributes are defined as dynamic', () => { + const instance = new BacktraceTestClient({}, testHttpClient, [ + { + type: 'dynamic', + get: () => ({ + application: 'my-app', + 'application.version': '1.2.3', + }), + }, + ]); + + const getAttributesSpy = jest.spyOn(AttributeManager.prototype, 'get'); + instance.initialize(); + + expect(getAttributesSpy).toHaveBeenCalledWith('scoped'); + expect(getAttributesSpy).toHaveBeenCalledWith(); + }); + }); });