mockStorageService.ts•4.83 kB
/**
 * @fileoverview Mock Storage service implementation for testing tools in isolation.
 * @module tests/mcp-server/tools/definitions/helpers/mockStorageService
 */
import type { RequestContext } from '@/utils/index.js';
import type {
  StorageOptions,
  ListOptions,
  ListResult,
} from '@/storage/core/IStorageProvider.js';
/**
 * Get tenant ID from context with graceful degradation (matches real implementation)
 */
function getTenantId(context: RequestContext): string {
  return context.tenantId || 'default-tenant';
}
/**
 * Mock implementation of StorageService for testing.
 * Provides in-memory storage with tenant isolation.
 * Matches the real StorageService API exactly.
 */
export class MockStorageService {
  private store: Map<string, Map<string, unknown>> = new Map();
  async get<T>(key: string, context: RequestContext): Promise<T | null> {
    const tenantId = getTenantId(context);
    const tenantStore = this.store.get(tenantId);
    if (!tenantStore) {
      return null;
    }
    return (tenantStore.get(key) as T) || null;
  }
  async set(
    key: string,
    value: unknown,
    context: RequestContext,
    _options?: StorageOptions,
  ): Promise<void> {
    const tenantId = getTenantId(context);
    let tenantStore = this.store.get(tenantId);
    if (!tenantStore) {
      tenantStore = new Map();
      this.store.set(tenantId, tenantStore);
    }
    tenantStore.set(key, value);
  }
  async delete(key: string, context: RequestContext): Promise<boolean> {
    const tenantId = getTenantId(context);
    const tenantStore = this.store.get(tenantId);
    if (!tenantStore) {
      return false;
    }
    return tenantStore.delete(key);
  }
  async list(
    prefix: string,
    context: RequestContext,
    _options?: ListOptions,
  ): Promise<ListResult> {
    const tenantId = getTenantId(context);
    const tenantStore = this.store.get(tenantId);
    if (!tenantStore) {
      return { keys: [] };
    }
    const keys = Array.from(tenantStore.keys()).filter((key) =>
      key.startsWith(prefix),
    );
    return { keys };
  }
  async getMany<T>(
    keys: string[],
    context: RequestContext,
  ): Promise<Map<string, T>> {
    const tenantId = getTenantId(context);
    const tenantStore = this.store.get(tenantId);
    const result = new Map<string, T>();
    if (!tenantStore) {
      return result;
    }
    for (const key of keys) {
      const value = tenantStore.get(key);
      if (value !== undefined) {
        result.set(key, value as T);
      }
    }
    return result;
  }
  async setMany(
    entries: Map<string, unknown>,
    context: RequestContext,
    _options?: StorageOptions,
  ): Promise<void> {
    const tenantId = getTenantId(context);
    let tenantStore = this.store.get(tenantId);
    if (!tenantStore) {
      tenantStore = new Map();
      this.store.set(tenantId, tenantStore);
    }
    for (const [key, value] of entries.entries()) {
      tenantStore.set(key, value);
    }
  }
  async deleteMany(keys: string[], context: RequestContext): Promise<number> {
    const tenantId = getTenantId(context);
    const tenantStore = this.store.get(tenantId);
    if (!tenantStore) {
      return 0;
    }
    let count = 0;
    for (const key of keys) {
      if (tenantStore.delete(key)) {
        count++;
      }
    }
    return count;
  }
  async clear(context: RequestContext): Promise<number> {
    const tenantId = getTenantId(context);
    const tenantStore = this.store.get(tenantId);
    if (!tenantStore) {
      return 0;
    }
    const count = tenantStore.size;
    this.store.delete(tenantId);
    return count;
  }
  /**
   * Clear all data across all tenants (test utility)
   */
  clearAll(): void {
    this.store.clear();
  }
  /**
   * Get all keys for a tenant (test utility)
   */
  getAllKeys(tenantId: string): string[] {
    const tenantStore = this.store.get(tenantId);
    if (!tenantStore) {
      return [];
    }
    return Array.from(tenantStore.keys());
  }
  /**
   * Check if a tenant exists (test utility)
   */
  hasTenant(tenantId: string): boolean {
    return this.store.has(tenantId);
  }
}
/**
 * Factory function to create a fresh MockStorageService instance
 */
export function createMockStorageService(): MockStorageService {
  return new MockStorageService();
}
/**
 * Creates a MockStorageService with pre-populated session data
 */
export function createMockStorageWithSession(
  tenantId: string,
  workingDir: string,
): MockStorageService {
  const storage = new MockStorageService();
  const context = {
    requestId: 'test-request-id',
    sessionId: 'test-session-id',
    timestamp: new Date().toISOString(),
    tenantId,
  } as RequestContext;
  // Set working directory in session storage
  storage.set(`session:workingDir:${tenantId}`, workingDir, context);
  return storage;
}