implement MockEnvService and fix tests
This commit is contained in:
parent
f83a403106
commit
8e000ae313
3 changed files with 96 additions and 14 deletions
66
packages/backend/test/misc/MockEnvService.ts
Normal file
66
packages/backend/test/misc/MockEnvService.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import process from 'node:process';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EnvService } from '@/core/EnvService.js';
|
||||
import { CacheManagementService } from '@/core/CacheManagementService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
|
||||
/**
|
||||
* Implementation of EnvService with support for mocking values.
|
||||
* Environment and package versions are loaded from their original sources, but can be overridden as-needed.
|
||||
*/
|
||||
@Injectable()
|
||||
export class MockEnvService extends EnvService {
|
||||
private _env: Partial<Record<string, string>>;
|
||||
|
||||
constructor(cacheManagementService: CacheManagementService) {
|
||||
super(cacheManagementService);
|
||||
this._env = process.env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mocked environment.
|
||||
* The returned object is "live" and can be modified without polluting the actual application environment.
|
||||
*/
|
||||
get env(): Partial<Record<string, string>> {
|
||||
return this._env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the entire mocked environment.
|
||||
* Pass undefined to restore the original un-mocked values.
|
||||
*/
|
||||
set env(value: Partial<Record<string, string>> | undefined) {
|
||||
if (value !== undefined) {
|
||||
this._env = value;
|
||||
} else {
|
||||
this._env = process.env;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the version for a dependency.
|
||||
* Pass a string or null to override the version, or pass undefined to clear the override and restore the original value.
|
||||
*/
|
||||
@bindThis
|
||||
public setDependencyVersion(dependency: string, version: string | null | undefined) {
|
||||
if (version !== undefined) {
|
||||
this.dependencyVersionCache.set(dependency, version);
|
||||
} else {
|
||||
this.dependencyVersionCache.delete(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the mock to initial values.
|
||||
*/
|
||||
@bindThis
|
||||
public mockReset(): void {
|
||||
this._env = process.env;
|
||||
this.dependencyVersionCache.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { FakeCacheManagementService } from '../misc/FakeCacheManagementService.js';
|
||||
import type { MiMeta } from '@/models/_.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import type { SoftwareSuspension } from '@/models/Meta.js';
|
||||
|
|
@ -31,7 +32,7 @@ describe('UtilityService', () => {
|
|||
federation: 'all',
|
||||
} as unknown as MiMeta;
|
||||
|
||||
const envService = new EnvService();
|
||||
const envService = new EnvService(new FakeCacheManagementService());
|
||||
utilityService = new UtilityService(config, meta, envService);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
*/
|
||||
|
||||
import { GodOfTimeService } from '../../../misc/GodOfTimeService.js';
|
||||
import { MockEnvService } from '../../../misc/MockEnvService.js';
|
||||
import { MockInternalEventService } from '../../../misc/MockInternalEventService.js';
|
||||
import type Redis from 'ioredis';
|
||||
import type { MiUser } from '@/models/User.js';
|
||||
import type { RolePolicies, RoleService } from '@/core/RoleService.js';
|
||||
|
|
@ -11,18 +13,19 @@ import type { Config } from '@/config.js';
|
|||
import { SkRateLimiterService } from '@/server/SkRateLimiterService.js';
|
||||
import { BucketRateLimit, Keyed, LegacyRateLimit } from '@/misc/rate-limit-utils.js';
|
||||
import { CacheManagementService } from '@/core/CacheManagementService.js';
|
||||
import { InternalEventService } from '@/core/InternalEventService.js';
|
||||
|
||||
describe(SkRateLimiterService, () => {
|
||||
let cacheManagementService: CacheManagementService;
|
||||
let mockInternalEventService: MockInternalEventService;
|
||||
let mockTimeService: GodOfTimeService;
|
||||
let mockRedis: Array<(command: [string, ...unknown[]]) => [Error | null, unknown] | null>;
|
||||
let mockRedisExec: (batch: [string, ...unknown[]][]) => Promise<[Error | null, unknown][] | null>;
|
||||
let mockEnvironment: Record<string, string | undefined>;
|
||||
let mockEnvService: MockEnvService;
|
||||
let serviceUnderTest: () => SkRateLimiterService;
|
||||
let mockDefaultUserPolicies: Partial<RolePolicies>;
|
||||
let mockUserPolicies: Record<string, Partial<RolePolicies>>;
|
||||
|
||||
beforeEach(() => {
|
||||
beforeAll(() => {
|
||||
mockTimeService = new GodOfTimeService();
|
||||
|
||||
function callMockRedis(command: [string, ...unknown[]]) {
|
||||
|
|
@ -65,11 +68,12 @@ describe(SkRateLimiterService, () => {
|
|||
off() {},
|
||||
} as unknown as Redis.Redis;
|
||||
|
||||
mockEnvironment = Object.create(process.env);
|
||||
mockEnvironment.NODE_ENV = 'production';
|
||||
const mockEnvService = {
|
||||
env: mockEnvironment,
|
||||
};
|
||||
const fakeConfig = { host: 'example.com' } as unknown as Config;
|
||||
mockInternalEventService = new MockInternalEventService(fakeConfig);
|
||||
cacheManagementService = new CacheManagementService(mockRedisClient, mockTimeService, mockInternalEventService);
|
||||
|
||||
mockEnvService = new MockEnvService(cacheManagementService);
|
||||
mockEnvService.env.NODE_ENV = 'production';
|
||||
|
||||
mockDefaultUserPolicies = { rateLimitFactor: 1 };
|
||||
mockUserPolicies = {};
|
||||
|
|
@ -80,16 +84,27 @@ describe(SkRateLimiterService, () => {
|
|||
},
|
||||
} as unknown as RoleService;
|
||||
|
||||
const fakeConfig = { host: 'example.com' } as unknown as Config;
|
||||
const internalEventService = new InternalEventService(mockRedisClient, mockRedisClient, fakeConfig);
|
||||
const cacheManagementService = new CacheManagementService(mockRedisClient, mockTimeService, internalEventService);
|
||||
|
||||
let service: SkRateLimiterService | undefined = undefined;
|
||||
serviceUnderTest = () => {
|
||||
return service ??= new SkRateLimiterService(mockRedisClient, mockRoleService, mockTimeService, mockEnvService, cacheManagementService);
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
cacheManagementService.dispose();
|
||||
mockInternalEventService.dispose();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockTimeService.reset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cacheManagementService.clear();
|
||||
mockInternalEventService.mockReset();
|
||||
mockEnvService.mockReset();
|
||||
});
|
||||
|
||||
describe('limit', () => {
|
||||
const actor = 'actor';
|
||||
const key = 'test';
|
||||
|
|
@ -173,7 +188,7 @@ describe(SkRateLimiterService, () => {
|
|||
});
|
||||
|
||||
it('should bypass in test environment', async () => {
|
||||
mockEnvironment.NODE_ENV = 'test';
|
||||
mockEnvService.env.NODE_ENV = 'test';
|
||||
|
||||
const info = await serviceUnderTest().limit({ key: 'l', type: undefined, max: 0 }, actor);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue