perf(repo): parallelise api tests and cache image builds in ghcr (#1984)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-24 21:24:39 +02:00
1 parent 3afad20e36
commit c226eb7211
38 files changed
+701 -264

No files matched your search

@@ -89,6 +89,15 @@ class BannedAvatarHashCache {
return this.banned.size;
}
resetForTesting(): void {
this.shutdown();
this.banned = new Set();
this.kvClient = null;
this.subscriberInitialized = false;
this.consecutiveFailures = 0;
this.isInitialized = false;
}
shutdown(): void {
if (this.kvSubscription && this.messageHandler) {
this.kvSubscription.off('message', this.messageHandler);
@@ -85,6 +85,15 @@ class FileShaCache {
return this.banned.size;
}
resetForTesting(): void {
this.shutdown();
this.banned = new Set();
this.kvClient = null;
this.subscriberInitialized = false;
this.consecutiveFailures = 0;
this.isInitialized = false;
}
shutdown(): void {
if (this.kvSubscription && this.messageHandler) {
this.kvSubscription.off('message', this.messageHandler);
@@ -144,6 +144,17 @@ export class PhraseBlocklistCache {
return this.rawPhraseSet.size;
}
resetForTesting(): void {
this.shutdown();
this.rawPhrases = [];
this.rawPhraseSet = new Set();
this.rebuildMatchers();
this.kvClient = null;
this.subscriberInitialized = false;
this.consecutiveFailures = 0;
this.isInitialized = false;
}
shutdown(): void {
if (this.kvSubscription && this.messageHandler) {
this.kvSubscription.off('message', this.messageHandler);
@@ -180,6 +180,15 @@ export class ProfileSubstringBlocklistCache {
return !!canonical && this.getMatchersForCheck(scope).some((matchers) => matchers.rawSet.has(canonical));
}
resetForTesting(): void {
this.shutdown();
this.byScope = new Map();
this.kvClient = null;
this.subscriberInitialized = false;
this.consecutiveFailures = 0;
this.isInitialized = false;
}
shutdown(): void {
if (this.kvSubscription && this.messageHandler) {
this.kvSubscription.off('message', this.messageHandler);
@@ -763,3 +763,15 @@ export const ServiceMiddleware = createMiddleware<HonoEnv>(async (ctx, next) =>
ctx.set('ncmecSubmissionService', getNcmecSubmissionService());
await next();
});
export function resetServiceMiddlewareForTesting(): void {
shutdownReportService();
_inboundSmsChallengeService = null;
_registrationEventsRepository = null;
_riskAssessmentRepository = null;
_historicalOutcomeRepository = null;
_suspiciousIpRepository = null;
_ipInfoService = null;
_registrationRiskEvaluator = null;
_liveKitWebhookService = null;
}
@@ -306,3 +306,20 @@ export function getLiveKitServiceInstance(): ILiveKitService | null {
export function getVoiceRoomStoreInstance(): IVoiceRoomStore | null {
return voiceRoomStoreInstance;
}
export function resetServiceRegistryForTesting(): void {
_kvClient = null;
_snowflakeService = null;
_billingRepository = null;
_blueskyOAuthService = undefined;
_blueskyOAuthInitializationPromise = null;
_blueskyOAuthConfigSignature = null;
_blueskyOAuthInitializationSignature = null;
_disabledBlueskyOAuthService = undefined;
voiceTopology = null;
voiceAvailabilityService = null;
liveKitServiceInstance = null;
voiceRoomStoreInstance = null;
voiceConfigSubscriber = null;
voiceInitializationPromise = null;
}
@@ -97,7 +97,7 @@ import {
getSnowflakeService,
getWorkerService,
} from './ServiceRegistry';
import {singleton} from './Singleton';
import {clearSingletonsForTesting, singleton} from './Singleton';
export const getUserRepository = singleton(() => new UserRepository(getKVClient()));
export const getGuildRepository = singleton(() => new GuildRepository());
@@ -121,7 +121,10 @@ export const getPasswordChangeRepository = singleton(() => new PasswordChangeRep
const getUserContactChangeLogRepository = singleton(() => new UserContactChangeLogRepository());
export const getDonationRepository = singleton(() => new DonationRepository());
const getAdminApiKeyRepository = singleton(() => new AdminApiKeyRepository());
export const getInstanceConfigRepository = singleton(() => new InstanceConfigRepository(getKVClient()));
export const getInstanceConfigRepository = singleton(
() => new InstanceConfigRepository(getKVClient()),
(repository) => repository.shutdown(),
);
export const getGatewayRolloutConfigPublisher = singleton(
() =>
new GatewayRolloutConfigPublisher(
@@ -200,6 +203,7 @@ const getDownloadsStorageService: () => IStorageService = (() => {
export const getErrorI18nService = singleton(() => new ErrorI18nService());
export const getLimitConfigService = singleton(
() => new LimitConfigService(getInstanceConfigRepository(), getCacheService(), getKVClient()),
(service) => service.shutdown(),
);
export const getPurgeQueue: () => IPurgeQueue = singleton(() =>
Config.bunny.purgeEnabled ? new BunnyPurgeQueue(getKVClient()) : new NoopPurgeQueue(),
@@ -434,3 +438,20 @@ export async function initializeServiceSingletons(): Promise<void> {
}
await serviceSingletonInitializationPromise;
}
export function resetServiceSingletonsForTesting(): void {
activityTracker?.shutdown();
clearSingletonsForTesting();
_virusScanInitPromise = null;
serviceSingletonInitializationPromise = null;
bulkMessageDeletionQueue = null;
bulkMessageDeletionQueueClient = null;
premiumStateQueue = null;
premiumStateQueueClient = null;
activityTracker = null;
activityTrackerClient = null;
activityBuffer = null;
activityBufferClient = null;
accountDeletionQueue = null;
accountDeletionQueueClient = null;
}
+15 -1
View File
@@ -1,7 +1,15 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
export function singleton<T>(factory: () => T): () => T {
const singletonClearers: Array<() => void> = [];
export function singleton<T>(factory: () => T, teardown?: (instance: T) => void): () => T {
let instance: T | undefined;
singletonClearers.push(() => {
if (instance !== undefined) {
teardown?.(instance);
}
instance = undefined;
});
return () => {
if (instance === undefined) {
instance = factory();
@@ -9,3 +17,9 @@ export function singleton<T>(factory: () => T): () => T {
return instance;
};
}
export function clearSingletonsForTesting(): void {
for (const clear of singletonClearers) {
clear();
}
}
@@ -146,6 +146,17 @@ class UrlBlocklistCache {
};
}
resetForTesting(): void {
this.shutdown();
this.exactUrls = new Set();
this.blockedDomains = new Set();
this.kvClient = null;
this.storageService = null;
this.subscriberInitialized = false;
this.consecutiveFailures = 0;
this.isInitialized = false;
}
shutdown(): void {
if (this.kvSubscription && this.messageHandler) {
this.kvSubscription.off('message', this.messageHandler);