/**
* mysql-mcp - MySQL Adapter Mock
*
* Provides mock implementation of MySQLAdapter for testing
* tools, resources, and prompts without database dependency.
*/
import { vi } from 'vitest';
import type { MySQLAdapter } from '../../adapters/mysql/MySQLAdapter.js';
import type { QueryResult, TableInfo, IndexInfo, SchemaInfo, HealthStatus, ColumnInfo } from '../../types/index.js';
/**
* Create a mock query result
*/
export function createMockQueryResult(
rows: Record<string, unknown>[] = [],
affectedRows = 0
): QueryResult {
return {
rows,
rowsAffected: affectedRows,
executionTimeMs: 5
};
}
/**
* Create a mock column info
*/
export function createMockColumnInfo(name: string, type: string, nullable = true, primaryKey = false): ColumnInfo {
return {
name,
type,
nullable,
primaryKey
};
}
/**
* Create a mock table info
*/
export function createMockTableInfo(name: string, rowCount = 100): TableInfo {
return {
name,
type: 'table',
columns: [
createMockColumnInfo('id', 'int', false, true),
createMockColumnInfo('name', 'varchar(255)', true, false),
createMockColumnInfo('created_at', 'datetime', false, false)
],
rowCount,
engine: 'InnoDB',
collation: 'utf8mb4_unicode_ci'
};
}
/**
* Create mock index info
*/
export function createMockIndexInfo(tableName: string, indexName: string): IndexInfo {
return {
name: indexName,
tableName,
columns: ['id'],
unique: indexName === 'PRIMARY',
type: 'BTREE'
};
}
/**
* Create mock schema info
*/
export function createMockSchemaInfo(): SchemaInfo {
return {
tables: [createMockTableInfo('users'), createMockTableInfo('products')],
views: [],
indexes: [createMockIndexInfo('users', 'PRIMARY')]
};
}
/**
* Create mock health status
*/
export function createMockHealthStatus(connected = true): HealthStatus {
return {
connected,
latencyMs: 5,
version: '8.0.35',
poolStats: {
total: 10,
active: 2,
idle: 8,
waiting: 0,
totalQueries: 100
}
};
}
/**
* Create a mock MySQLAdapter
*/
export function createMockMySQLAdapter(): Partial<MySQLAdapter> & {
executeQuery: ReturnType<typeof vi.fn>;
executeReadQuery: ReturnType<typeof vi.fn>;
executeWriteQuery: ReturnType<typeof vi.fn>;
rawQuery: ReturnType<typeof vi.fn>;
getTableIndexes: ReturnType<typeof vi.fn>;
describeTable: ReturnType<typeof vi.fn>;
listTables: ReturnType<typeof vi.fn>;
getSchema: ReturnType<typeof vi.fn>;
} {
const mockQueryResult = createMockQueryResult([{ id: 1, name: 'test' }]);
return {
type: 'mysql' as const,
name: 'MySQL Adapter',
version: '0.1.0',
// Connection methods
connect: vi.fn().mockResolvedValue(undefined),
disconnect: vi.fn().mockResolvedValue(undefined),
getHealth: vi.fn().mockResolvedValue(createMockHealthStatus()),
isConnected: vi.fn().mockReturnValue(true),
// Query execution
executeQuery: vi.fn().mockResolvedValue(mockQueryResult),
executeReadQuery: vi.fn().mockResolvedValue(mockQueryResult),
executeWriteQuery: vi.fn().mockResolvedValue(mockQueryResult),
rawQuery: vi.fn().mockResolvedValue(mockQueryResult),
// Transaction methods
beginTransaction: vi.fn().mockResolvedValue('txn-123'),
commitTransaction: vi.fn().mockResolvedValue(undefined),
rollbackTransaction: vi.fn().mockResolvedValue(undefined),
getTransactionConnection: vi.fn().mockReturnValue(undefined),
// Schema methods
getSchema: vi.fn().mockResolvedValue(createMockSchemaInfo()),
listTables: vi.fn().mockResolvedValue([createMockTableInfo('users')]),
describeTable: vi.fn().mockResolvedValue(createMockTableInfo('users')),
listSchemas: vi.fn().mockResolvedValue(['testdb', 'information_schema']),
getTableIndexes: vi.fn().mockResolvedValue([createMockIndexInfo('users', 'PRIMARY')]),
// Capabilities
getCapabilities: vi.fn().mockReturnValue({
json: true,
fullTextSearch: true,
vector: false,
geospatial: true,
transactions: true,
preparedStatements: true,
connectionPooling: true,
partitioning: true,
replication: true
}),
getSupportedToolGroups: vi.fn().mockReturnValue([
'core', 'transactions', 'json', 'text', 'fulltext',
'performance', 'optimization', 'admin', 'monitoring', 'backup'
]),
// Definition getters
getToolDefinitions: vi.fn().mockReturnValue([]),
getResourceDefinitions: vi.fn().mockReturnValue([]),
getPromptDefinitions: vi.fn().mockReturnValue([]),
// Registration methods (used by McpServer)
registerTools: vi.fn(),
registerResources: vi.fn(),
registerPrompts: vi.fn(),
// Pool access
getPool: vi.fn().mockReturnValue(null)
};
}
/**
* Create a mock RequestContext for handler testing
*/
export function createMockRequestContext(): {
timestamp: Date;
requestId: string;
} {
return {
timestamp: new Date(),
requestId: 'test-request-' + Math.random().toString(36).slice(2, 9)
};
}
/**
* Helper to configure mock adapter response for specific queries
*/
export function configureMockAdapterQuery(
adapter: ReturnType<typeof createMockMySQLAdapter>,
pattern: string,
result: QueryResult
): void {
const originalImpl = adapter.executeQuery.getMockImplementation() as ((sql: string) => Promise<QueryResult>) | undefined;
adapter.executeQuery.mockImplementation((sql: string) => {
if (sql.includes(pattern)) {
return Promise.resolve(result);
}
return originalImpl?.(sql) ?? Promise.resolve(createMockQueryResult());
});
}
/**
* Create a mock MySQLAdapter that returns empty results
*/
export function createMockMySQLAdapterEmpty(): ReturnType<typeof createMockMySQLAdapter> {
const adapter = createMockMySQLAdapter();
const emptyResult = createMockQueryResult([]);
adapter.executeQuery.mockResolvedValue(emptyResult);
adapter.executeReadQuery.mockResolvedValue(emptyResult);
adapter.executeWriteQuery.mockResolvedValue({ rows: [], rowsAffected: 0, executionTimeMs: 1 });
adapter.rawQuery.mockResolvedValue(emptyResult);
return adapter;
}
/**
* Create a mock MySQLAdapter that throws on query execution
*/
export function createMockMySQLAdapterWithError(
errorMessage = 'Database connection failed'
): ReturnType<typeof createMockMySQLAdapter> {
const adapter = createMockMySQLAdapter();
const dbError = new Error(errorMessage);
adapter.executeQuery.mockRejectedValue(dbError);
adapter.executeReadQuery.mockRejectedValue(dbError);
adapter.executeWriteQuery.mockRejectedValue(dbError);
adapter.rawQuery.mockRejectedValue(dbError);
(adapter.getHealth as ReturnType<typeof vi.fn>).mockResolvedValue(createMockHealthStatus(false));
return adapter;
}
/**
* Create a mock adapter for transaction testing with a mock connection
*/
export function createMockMySQLAdapterWithTransaction(): ReturnType<typeof createMockMySQLAdapter> & {
mockConnection: {
query: ReturnType<typeof vi.fn>;
execute: ReturnType<typeof vi.fn>;
release: ReturnType<typeof vi.fn>;
};
} {
const adapter = createMockMySQLAdapter();
const mockConnection = {
query: vi.fn().mockResolvedValue([[], []]),
execute: vi.fn().mockResolvedValue([[], []]),
release: vi.fn()
};
(adapter.getTransactionConnection as ReturnType<typeof vi.fn>).mockReturnValue(mockConnection);
return { ...adapter, mockConnection };
}
/**
* Type alias for the mock adapter return type
*/
export type MockMySQLAdapter = ReturnType<typeof createMockMySQLAdapter>;