Skip to content

chore(maintenance): simplify Utility class #3682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 2 additions & 27 deletions packages/commons/src/Utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
*/
export class Utility {
protected coldStart = true;
private readonly defaultServiceName: string = 'service_undefined';
protected readonly defaultServiceName: string = 'service_undefined';

/**
* Get the cold start status of the current execution environment.
Expand All @@ -68,7 +68,7 @@ export class Utility {
*
* The method also flips the cold start status to `false` after the first invocation.
*/
public getColdStart(): boolean {
protected getColdStart(): boolean {
if (this.coldStart) {
this.coldStart = false;

Expand All @@ -78,31 +78,6 @@ export class Utility {
return false;
}

/**
* Get the cold start status of the current execution environment.
*
* @example
* ```typescript
* import { Utility } from '@aws-lambda-powertools/commons';
*
* const utility = new Utility();
* utility.isColdStart(); // true
* utility.isColdStart(); // false
* ```
*
* @see {@link getColdStart}
*/
public isColdStart(): boolean {
return this.getColdStart();
}

/**
* Get the default service name.
*/
protected getDefaultServiceName(): string {
return this.defaultServiceName;
}

/**
* Validate that the service name provided is valid.
* Used internally during initialization.
Expand Down
180 changes: 40 additions & 140 deletions packages/commons/tests/unit/Utility.test.ts
Original file line number Diff line number Diff line change
@@ -1,157 +1,57 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { describe, expect, it } from 'vitest';
import { Utility } from '../../src/index.js';

describe('Class: Utility', () => {
beforeEach(() => {
vi.clearAllMocks();
vi.resetModules();
});
class TestUtility extends Utility {
public dummyMethod(): boolean {
return this.getColdStart();
}
public isColdStart(): boolean {
return this.coldStart;
}
public getServiceName(): string {
return this.defaultServiceName;
}
public validateServiceName(serviceName: string): boolean {
return this.isValidServiceName(serviceName);
}
}

describe('Method: getDefaultServiceName', () => {
it('returns the default service name', () => {
class PowerTool extends Utility {
public dummyMethod(): string {
return this.getDefaultServiceName();
}
}
it('returns the correct cold start value', () => {
// Prepare
const utility = new TestUtility();

const powertool = new PowerTool();
const result = powertool.dummyMethod();
expect(result).toBe('service_undefined');
});
// Act & Assess
expect(utility.dummyMethod()).toBe(true);
expect(utility.dummyMethod()).toBe(false);
expect(utility.dummyMethod()).toBe(false);
});

describe('Method: getColdStart', () => {
it('it returns true the first time, then false afterwards, when called multiple times', () => {
// Prepare
const utility = new Utility();
const getColdStartSpy = vi.spyOn(utility, 'getColdStart');

// Act
utility.getColdStart();
utility.getColdStart();
utility.getColdStart();
utility.getColdStart();
utility.getColdStart();

// Assess
expect(getColdStartSpy).toHaveBeenCalledTimes(5);
expect(getColdStartSpy.mock.results).toEqual([
expect.objectContaining({ value: true }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
]);
});

it('returns the correct values when subclassed', () => {
// Prepare
class PowerTool extends Utility {
public dummyMethod(): boolean {
return this.getColdStart();
}
}
const powertool = new PowerTool();
const dummyMethodSpy = vi.spyOn(powertool, 'dummyMethod');
const getColdStartSpy = vi.spyOn(powertool, 'getColdStart');
it('flips the cold start value', () => {
// Prepare
const utility = new TestUtility();

// Act
powertool.dummyMethod();
powertool.dummyMethod();
powertool.dummyMethod();
powertool.dummyMethod();
powertool.dummyMethod();
// Act
utility.dummyMethod();

// Assess
expect(dummyMethodSpy).toHaveBeenCalledTimes(5);
expect(getColdStartSpy).toHaveBeenCalledTimes(5);
expect(dummyMethodSpy.mock.results).toEqual([
expect.objectContaining({ value: true }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
]);
});
// Assess
expect(utility.isColdStart()).toBe(false);
});

describe('Method: isColdStart', () => {
it('returns true the first time, then false afterwards when called multiple times', () => {
// Prepare
const utility = new Utility();
const isColdStartSpy = vi.spyOn(utility, 'isColdStart');
it('returns the correct default service name', () => {
// Prepare
const utility = new TestUtility();

// Act
utility.isColdStart();
utility.isColdStart();
utility.isColdStart();
utility.isColdStart();
utility.isColdStart();

// Assess
expect(isColdStartSpy).toHaveBeenCalledTimes(5);
expect(isColdStartSpy.mock.results).toEqual([
expect.objectContaining({ value: true }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
]);
});

it('returns the correct values when subclassed', () => {
// Prepare
class PowerTool extends Utility {
public dummyMethod(): boolean {
return this.isColdStart();
}
}
const powertool = new PowerTool();
const dummyMethodSpy = vi.spyOn(powertool, 'dummyMethod');
const isColdStartSpy = vi.spyOn(powertool, 'isColdStart');

// Act
powertool.dummyMethod();
powertool.dummyMethod();
powertool.dummyMethod();
powertool.dummyMethod();
powertool.dummyMethod();

// Assess
expect(dummyMethodSpy).toHaveBeenCalledTimes(5);
expect(isColdStartSpy).toHaveBeenCalledTimes(5);
expect(dummyMethodSpy.mock.results).toEqual([
expect.objectContaining({ value: true }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
expect.objectContaining({ value: false }),
]);
});
// Assess
expect(utility.getServiceName()).toBe('service_undefined');
});

describe('Method: isValidServiceName', () => {
class PowerTool extends Utility {
public dummyMethod(name: string): boolean {
return this.isValidServiceName(name);
}
}
it('allows valid strings', () => {
const powertool = new PowerTool();
const goodName = 'serverlessAirline';

const result = powertool.dummyMethod(goodName);

expect(result).toBe(true);
});

it("doesn't allow empty strings", () => {
const tooShort = '';
const powertool = new PowerTool();
const result = powertool.dummyMethod(tooShort);
it('validates service name', () => {
// Prepare
const utility = new TestUtility();

expect(result).toBe(false);
});
// Act & Assess
expect(utility.validateServiceName('serverlessAirline')).toBe(true);
expect(utility.validateServiceName('')).toBe(false);
});
});
2 changes: 1 addition & 1 deletion packages/logger/src/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1259,7 +1259,7 @@ class Logger extends Utility implements LoggerInterface {
serviceName ||
this.getCustomConfigService()?.getServiceName() ||
this.getEnvVarsService().getServiceName() ||
this.getDefaultServiceName(),
this.defaultServiceName,
});
persistentKeys && this.appendPersistentKeys(persistentKeys);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/metrics/src/Metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ class Metrics extends Utility implements MetricsInterface {
* ```
*/
public captureColdStartMetric(): void {
if (!this.isColdStart()) return;
if (!this.getColdStart()) return;
const singleMetric = this.singleMetric();

if (this.defaultDimensions.service) {
Expand Down Expand Up @@ -975,7 +975,7 @@ class Metrics extends Utility implements MetricsInterface {
((service ||
this.getCustomConfigService()?.getServiceName() ||
this.getEnvVarsService().getServiceName()) as string) ||
this.getDefaultServiceName();
this.defaultServiceName;
if (targetService.length > 0) {
this.setDefaultDimensions({ service: targetService });
}
Expand Down
2 changes: 1 addition & 1 deletion packages/tracer/src/Tracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ class Tracer extends Utility implements TracerInterface {

return;
}
this.serviceName = this.getDefaultServiceName();
this.serviceName = this.defaultServiceName;
}

/**
Expand Down
Loading