Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/index.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/index.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,0BAA0B,EAC1B,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EAChB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC"}
|
||||
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/index.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/index.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,aAAa;AACb,yCAYqB;AAXnB,gHAAA,mBAAmB,OAAA;AACnB,6GAAA,gBAAgB,OAAA;AAChB,2GAAA,cAAc,OAAA;AACd,2GAAA,cAAc,OAAA;AACd,uHAAA,0BAA0B,OAAA;AAC1B,2GAAA,cAAc,OAAA;AAQhB,mBAAmB;AACnB,iDAQyB;AAPvB,yGAAA,QAAQ,OAAA;AACR,+GAAA,cAAc,OAAA;AACd,gHAAA,eAAe,OAAA;AACf,oHAAA,mBAAmB,OAAA;AAMrB,cAAc;AACd,2CAUsB;AATpB,gHAAA,kBAAkB,OAAA;AAClB,oHAAA,sBAAsB,OAAA;AACtB,8GAAA,gBAAgB,OAAA;AAChB,mHAAA,qBAAqB,OAAA;AACrB,gHAAA,kBAAkB,OAAA"}
|
||||
44
vendor/ruvector/npm/packages/ruvbot/tests/mocks/index.ts
vendored
Normal file
44
vendor/ruvector/npm/packages/ruvbot/tests/mocks/index.ts
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Mock Module Index
|
||||
*
|
||||
* Central exports for all RuvBot test mocks
|
||||
*/
|
||||
|
||||
// WASM Mocks
|
||||
export {
|
||||
MockWasmVectorIndex,
|
||||
MockWasmEmbedder,
|
||||
MockWasmRouter,
|
||||
mockWasmLoader,
|
||||
createMockRuVectorBindings,
|
||||
resetWasmMocks,
|
||||
type WasmVectorIndex,
|
||||
type WasmEmbedder,
|
||||
type WasmRouter,
|
||||
type SearchResult,
|
||||
type RouteResult
|
||||
} from './wasm.mock';
|
||||
|
||||
// PostgreSQL Mocks
|
||||
export {
|
||||
MockPool,
|
||||
createMockPool,
|
||||
mockPoolFactory,
|
||||
queryBuilderHelpers,
|
||||
type QueryResult,
|
||||
type PoolClient,
|
||||
type PoolConfig
|
||||
} from './postgres.mock';
|
||||
|
||||
// Slack Mocks
|
||||
export {
|
||||
MockSlackWebClient,
|
||||
MockSlackEventsHandler,
|
||||
MockSlackBoltApp,
|
||||
createMockSlackClient,
|
||||
createMockSlackApp,
|
||||
type SlackMessage,
|
||||
type SlackResponse,
|
||||
type SlackUser,
|
||||
type SlackChannel
|
||||
} from './slack.mock';
|
||||
106
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.d.ts
vendored
Normal file
106
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.d.ts
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* PostgreSQL Mock Module
|
||||
*
|
||||
* Mock implementations for Postgres database operations
|
||||
* Supports transaction testing and query validation
|
||||
*/
|
||||
export interface QueryResult<T = unknown> {
|
||||
rows: T[];
|
||||
rowCount: number;
|
||||
command: string;
|
||||
fields: FieldInfo[];
|
||||
}
|
||||
export interface FieldInfo {
|
||||
name: string;
|
||||
dataTypeID: number;
|
||||
}
|
||||
export interface PoolConfig {
|
||||
host: string;
|
||||
port: number;
|
||||
database: string;
|
||||
user: string;
|
||||
password: string;
|
||||
max?: number;
|
||||
idleTimeoutMillis?: number;
|
||||
}
|
||||
export interface PoolClient {
|
||||
query<T = unknown>(text: string, values?: unknown[]): Promise<QueryResult<T>>;
|
||||
release(): void;
|
||||
}
|
||||
interface MockDataStore {
|
||||
agents: Map<string, unknown>;
|
||||
sessions: Map<string, unknown>;
|
||||
memories: Map<string, unknown>;
|
||||
skills: Map<string, unknown>;
|
||||
tenants: Map<string, unknown>;
|
||||
tasks: Map<string, unknown>;
|
||||
}
|
||||
/**
|
||||
* Mock PostgreSQL Pool
|
||||
*/
|
||||
export declare class MockPool {
|
||||
private config;
|
||||
private connected;
|
||||
private dataStore;
|
||||
private queryLog;
|
||||
private transactionActive;
|
||||
constructor(config: PoolConfig);
|
||||
connect(): Promise<PoolClient>;
|
||||
query<T = unknown>(text: string, values?: unknown[]): Promise<QueryResult<T>>;
|
||||
end(): Promise<void>;
|
||||
isConnected(): boolean;
|
||||
getQueryLog(): Array<{
|
||||
text: string;
|
||||
values?: unknown[];
|
||||
timestamp: Date;
|
||||
}>;
|
||||
clearQueryLog(): void;
|
||||
seedData(table: keyof MockDataStore, data: Array<{
|
||||
id: string;
|
||||
[key: string]: unknown;
|
||||
}>): void;
|
||||
getData(table: keyof MockDataStore): unknown[];
|
||||
private createClient;
|
||||
private logQuery;
|
||||
private executeQuery;
|
||||
private handleSelect;
|
||||
private handleInsert;
|
||||
private handleUpdate;
|
||||
private handleDelete;
|
||||
private extractTableName;
|
||||
private createResult;
|
||||
}
|
||||
/**
|
||||
* Create a mock pool instance
|
||||
*/
|
||||
export declare function createMockPool(config?: Partial<PoolConfig>): MockPool;
|
||||
/**
|
||||
* Mock Pool factory for dependency injection
|
||||
*/
|
||||
export declare const mockPoolFactory: {
|
||||
create: import("vitest").Mock<[config: PoolConfig], MockPool>;
|
||||
createClient: import("vitest").Mock<[config: PoolConfig], Promise<PoolClient>>;
|
||||
};
|
||||
/**
|
||||
* Postgres query builder mock helpers
|
||||
*/
|
||||
export declare const queryBuilderHelpers: {
|
||||
expectQuery: (pool: MockPool, pattern: RegExp) => boolean;
|
||||
expectQueryCount: (pool: MockPool, pattern: RegExp) => number;
|
||||
expectTransaction: (pool: MockPool) => boolean;
|
||||
};
|
||||
declare const _default: {
|
||||
MockPool: typeof MockPool;
|
||||
createMockPool: typeof createMockPool;
|
||||
mockPoolFactory: {
|
||||
create: import("vitest").Mock<[config: PoolConfig], MockPool>;
|
||||
createClient: import("vitest").Mock<[config: PoolConfig], Promise<PoolClient>>;
|
||||
};
|
||||
queryBuilderHelpers: {
|
||||
expectQuery: (pool: MockPool, pattern: RegExp) => boolean;
|
||||
expectQueryCount: (pool: MockPool, pattern: RegExp) => number;
|
||||
expectTransaction: (pool: MockPool) => boolean;
|
||||
};
|
||||
};
|
||||
export default _default;
|
||||
//# sourceMappingURL=postgres.mock.d.ts.map
|
||||
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"postgres.mock.d.ts","sourceRoot":"","sources":["postgres.mock.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,OAAO,IAAI,IAAI,CAAC;CACjB;AAGD,UAAU,aAAa;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,QAAQ;IAaP,OAAO,CAAC,MAAM;IAZ1B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,SAAS,CAOf;IACF,OAAO,CAAC,QAAQ,CAAoE;IACpF,OAAO,CAAC,iBAAiB,CAAkB;gBAEvB,MAAM,EAAE,UAAU;IAEhC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IAK9B,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAK7E,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAY1B,WAAW,IAAI,OAAO;IAItB,WAAW,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IAI3E,aAAa,IAAI,IAAI;IAKrB,QAAQ,CAAC,KAAK,EAAE,MAAM,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,GAAG,IAAI;IAM/F,OAAO,CAAC,KAAK,EAAE,MAAM,aAAa,GAAG,OAAO,EAAE;IAI9C,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,QAAQ;YAIF,YAAY;IAwC1B,OAAO,CAAC,YAAY;IA2BpB,OAAO,CAAC,YAAY;IAiCpB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,YAAY;CAQrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,QAAQ,CASrE;AAED;;GAEG;AACH,eAAO,MAAM,eAAe;;;CAM3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB;wBACV,QAAQ,WAAW,MAAM,KAAG,OAAO;6BAI9B,QAAQ,WAAW,MAAM,KAAG,MAAM;8BAIjC,QAAQ,KAAG,OAAO;CAS7C,CAAC;;;;;;;;;4BAjBoB,QAAQ,WAAW,MAAM,KAAG,OAAO;iCAI9B,QAAQ,WAAW,MAAM,KAAG,MAAM;kCAIjC,QAAQ,KAAG,OAAO;;;AAW9C,wBAKE"}
|
||||
260
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.js
vendored
Normal file
260
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.js
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
"use strict";
|
||||
/**
|
||||
* PostgreSQL Mock Module
|
||||
*
|
||||
* Mock implementations for Postgres database operations
|
||||
* Supports transaction testing and query validation
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.queryBuilderHelpers = exports.mockPoolFactory = exports.MockPool = void 0;
|
||||
exports.createMockPool = createMockPool;
|
||||
const vitest_1 = require("vitest");
|
||||
/**
|
||||
* Mock PostgreSQL Pool
|
||||
*/
|
||||
class MockPool {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.connected = false;
|
||||
this.dataStore = {
|
||||
agents: new Map(),
|
||||
sessions: new Map(),
|
||||
memories: new Map(),
|
||||
skills: new Map(),
|
||||
tenants: new Map(),
|
||||
tasks: new Map()
|
||||
};
|
||||
this.queryLog = [];
|
||||
this.transactionActive = false;
|
||||
}
|
||||
async connect() {
|
||||
this.connected = true;
|
||||
return this.createClient();
|
||||
}
|
||||
async query(text, values) {
|
||||
this.logQuery(text, values);
|
||||
return this.executeQuery(text, values);
|
||||
}
|
||||
async end() {
|
||||
this.connected = false;
|
||||
this.dataStore = {
|
||||
agents: new Map(),
|
||||
sessions: new Map(),
|
||||
memories: new Map(),
|
||||
skills: new Map(),
|
||||
tenants: new Map(),
|
||||
tasks: new Map()
|
||||
};
|
||||
}
|
||||
isConnected() {
|
||||
return this.connected;
|
||||
}
|
||||
getQueryLog() {
|
||||
return [...this.queryLog];
|
||||
}
|
||||
clearQueryLog() {
|
||||
this.queryLog = [];
|
||||
}
|
||||
// Seed data for testing
|
||||
seedData(table, data) {
|
||||
for (const row of data) {
|
||||
this.dataStore[table].set(row.id, row);
|
||||
}
|
||||
}
|
||||
getData(table) {
|
||||
return Array.from(this.dataStore[table].values());
|
||||
}
|
||||
createClient() {
|
||||
return {
|
||||
query: async (text, values) => {
|
||||
return this.executeQuery(text, values);
|
||||
},
|
||||
release: () => {
|
||||
// No-op for mock
|
||||
}
|
||||
};
|
||||
}
|
||||
logQuery(text, values) {
|
||||
this.queryLog.push({ text, values, timestamp: new Date() });
|
||||
}
|
||||
async executeQuery(text, values) {
|
||||
const normalizedQuery = text.trim().toUpperCase();
|
||||
// Handle transaction commands
|
||||
if (normalizedQuery === 'BEGIN') {
|
||||
this.transactionActive = true;
|
||||
return this.createResult([], 'BEGIN');
|
||||
}
|
||||
if (normalizedQuery === 'COMMIT') {
|
||||
this.transactionActive = false;
|
||||
return this.createResult([], 'COMMIT');
|
||||
}
|
||||
if (normalizedQuery === 'ROLLBACK') {
|
||||
this.transactionActive = false;
|
||||
return this.createResult([], 'ROLLBACK');
|
||||
}
|
||||
// Parse and execute query
|
||||
if (normalizedQuery.startsWith('SELECT')) {
|
||||
return this.handleSelect(text, values);
|
||||
}
|
||||
if (normalizedQuery.startsWith('INSERT')) {
|
||||
return this.handleInsert(text, values);
|
||||
}
|
||||
if (normalizedQuery.startsWith('UPDATE')) {
|
||||
return this.handleUpdate(text, values);
|
||||
}
|
||||
if (normalizedQuery.startsWith('DELETE')) {
|
||||
return this.handleDelete(text, values);
|
||||
}
|
||||
// Default: return empty result
|
||||
return this.createResult([], 'UNKNOWN');
|
||||
}
|
||||
handleSelect(text, values) {
|
||||
const tableName = this.extractTableName(text);
|
||||
const store = this.dataStore[tableName];
|
||||
if (!store) {
|
||||
return this.createResult([], 'SELECT');
|
||||
}
|
||||
// Simple ID-based lookup
|
||||
const idMatch = text.match(/WHERE\s+id\s*=\s*\$1/i);
|
||||
if (idMatch && values?.[0]) {
|
||||
const row = store.get(values[0]);
|
||||
return this.createResult(row ? [row] : [], 'SELECT');
|
||||
}
|
||||
// Tenant-based lookup
|
||||
const tenantMatch = text.match(/WHERE\s+tenant_id\s*=\s*\$1/i);
|
||||
if (tenantMatch && values?.[0]) {
|
||||
const rows = Array.from(store.values())
|
||||
.filter((row) => row.tenantId === values[0] || row.tenant_id === values[0]);
|
||||
return this.createResult(rows, 'SELECT');
|
||||
}
|
||||
// Return all rows
|
||||
return this.createResult(Array.from(store.values()), 'SELECT');
|
||||
}
|
||||
handleInsert(text, values) {
|
||||
const tableName = this.extractTableName(text);
|
||||
const store = this.dataStore[tableName];
|
||||
if (!store || !values) {
|
||||
return this.createResult([], 'INSERT', 0);
|
||||
}
|
||||
// Extract column names from query
|
||||
const columnsMatch = text.match(/\(([^)]+)\)/);
|
||||
if (!columnsMatch) {
|
||||
return this.createResult([], 'INSERT', 0);
|
||||
}
|
||||
const columns = columnsMatch[1].split(',').map(c => c.trim());
|
||||
const row = {};
|
||||
columns.forEach((col, idx) => {
|
||||
row[col] = values[idx];
|
||||
});
|
||||
const id = row.id || `generated-${Date.now()}`;
|
||||
row.id = id;
|
||||
store.set(id, row);
|
||||
// Check for RETURNING clause
|
||||
if (text.includes('RETURNING')) {
|
||||
return this.createResult([row], 'INSERT', 1);
|
||||
}
|
||||
return this.createResult([], 'INSERT', 1);
|
||||
}
|
||||
handleUpdate(text, values) {
|
||||
const tableName = this.extractTableName(text);
|
||||
const store = this.dataStore[tableName];
|
||||
if (!store || !values) {
|
||||
return this.createResult([], 'UPDATE', 0);
|
||||
}
|
||||
// Simple ID-based update
|
||||
const idMatch = text.match(/WHERE\s+id\s*=\s*\$(\d+)/i);
|
||||
if (idMatch) {
|
||||
const idParamIndex = parseInt(idMatch[1]) - 1;
|
||||
const id = values[idParamIndex];
|
||||
const row = store.get(id);
|
||||
if (row) {
|
||||
// Update would happen here in real implementation
|
||||
return this.createResult([], 'UPDATE', 1);
|
||||
}
|
||||
}
|
||||
return this.createResult([], 'UPDATE', 0);
|
||||
}
|
||||
handleDelete(text, values) {
|
||||
const tableName = this.extractTableName(text);
|
||||
const store = this.dataStore[tableName];
|
||||
if (!store || !values) {
|
||||
return this.createResult([], 'DELETE', 0);
|
||||
}
|
||||
// Simple ID-based delete
|
||||
const idMatch = text.match(/WHERE\s+id\s*=\s*\$1/i);
|
||||
if (idMatch && values[0]) {
|
||||
const deleted = store.delete(values[0]);
|
||||
return this.createResult([], 'DELETE', deleted ? 1 : 0);
|
||||
}
|
||||
return this.createResult([], 'DELETE', 0);
|
||||
}
|
||||
extractTableName(query) {
|
||||
const fromMatch = query.match(/FROM\s+(\w+)/i);
|
||||
if (fromMatch)
|
||||
return fromMatch[1].toLowerCase();
|
||||
const intoMatch = query.match(/INTO\s+(\w+)/i);
|
||||
if (intoMatch)
|
||||
return intoMatch[1].toLowerCase();
|
||||
const updateMatch = query.match(/UPDATE\s+(\w+)/i);
|
||||
if (updateMatch)
|
||||
return updateMatch[1].toLowerCase();
|
||||
return 'unknown';
|
||||
}
|
||||
createResult(rows, command, rowCount) {
|
||||
return {
|
||||
rows,
|
||||
rowCount: rowCount ?? rows.length,
|
||||
command,
|
||||
fields: []
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.MockPool = MockPool;
|
||||
/**
|
||||
* Create a mock pool instance
|
||||
*/
|
||||
function createMockPool(config) {
|
||||
return new MockPool({
|
||||
host: 'localhost',
|
||||
port: 5432,
|
||||
database: 'ruvbot_test',
|
||||
user: 'test',
|
||||
password: 'test',
|
||||
...config
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Mock Pool factory for dependency injection
|
||||
*/
|
||||
exports.mockPoolFactory = {
|
||||
create: vitest_1.vi.fn((config) => createMockPool(config)),
|
||||
createClient: vitest_1.vi.fn(async (config) => {
|
||||
const pool = createMockPool(config);
|
||||
return pool.connect();
|
||||
})
|
||||
};
|
||||
/**
|
||||
* Postgres query builder mock helpers
|
||||
*/
|
||||
exports.queryBuilderHelpers = {
|
||||
expectQuery: (pool, pattern) => {
|
||||
return pool.getQueryLog().some(q => pattern.test(q.text));
|
||||
},
|
||||
expectQueryCount: (pool, pattern) => {
|
||||
return pool.getQueryLog().filter(q => pattern.test(q.text)).length;
|
||||
},
|
||||
expectTransaction: (pool) => {
|
||||
const log = pool.getQueryLog();
|
||||
const hasBegin = log.some(q => q.text.toUpperCase().includes('BEGIN'));
|
||||
const hasCommitOrRollback = log.some(q => q.text.toUpperCase().includes('COMMIT') ||
|
||||
q.text.toUpperCase().includes('ROLLBACK'));
|
||||
return hasBegin && hasCommitOrRollback;
|
||||
}
|
||||
};
|
||||
exports.default = {
|
||||
MockPool,
|
||||
createMockPool,
|
||||
mockPoolFactory: exports.mockPoolFactory,
|
||||
queryBuilderHelpers: exports.queryBuilderHelpers
|
||||
};
|
||||
//# sourceMappingURL=postgres.mock.js.map
|
||||
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
344
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.ts
vendored
Normal file
344
vendor/ruvector/npm/packages/ruvbot/tests/mocks/postgres.mock.ts
vendored
Normal file
@@ -0,0 +1,344 @@
|
||||
/**
|
||||
* PostgreSQL Mock Module
|
||||
*
|
||||
* Mock implementations for Postgres database operations
|
||||
* Supports transaction testing and query validation
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
// Types
|
||||
export interface QueryResult<T = unknown> {
|
||||
rows: T[];
|
||||
rowCount: number;
|
||||
command: string;
|
||||
fields: FieldInfo[];
|
||||
}
|
||||
|
||||
export interface FieldInfo {
|
||||
name: string;
|
||||
dataTypeID: number;
|
||||
}
|
||||
|
||||
export interface PoolConfig {
|
||||
host: string;
|
||||
port: number;
|
||||
database: string;
|
||||
user: string;
|
||||
password: string;
|
||||
max?: number;
|
||||
idleTimeoutMillis?: number;
|
||||
}
|
||||
|
||||
export interface PoolClient {
|
||||
query<T = unknown>(text: string, values?: unknown[]): Promise<QueryResult<T>>;
|
||||
release(): void;
|
||||
}
|
||||
|
||||
// In-memory data store for mock
|
||||
interface MockDataStore {
|
||||
agents: Map<string, unknown>;
|
||||
sessions: Map<string, unknown>;
|
||||
memories: Map<string, unknown>;
|
||||
skills: Map<string, unknown>;
|
||||
tenants: Map<string, unknown>;
|
||||
tasks: Map<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock PostgreSQL Pool
|
||||
*/
|
||||
export class MockPool {
|
||||
private connected: boolean = false;
|
||||
private dataStore: MockDataStore = {
|
||||
agents: new Map(),
|
||||
sessions: new Map(),
|
||||
memories: new Map(),
|
||||
skills: new Map(),
|
||||
tenants: new Map(),
|
||||
tasks: new Map()
|
||||
};
|
||||
private queryLog: Array<{ text: string; values?: unknown[]; timestamp: Date }> = [];
|
||||
private transactionActive: boolean = false;
|
||||
|
||||
constructor(private config: PoolConfig) {}
|
||||
|
||||
async connect(): Promise<PoolClient> {
|
||||
this.connected = true;
|
||||
return this.createClient();
|
||||
}
|
||||
|
||||
async query<T = unknown>(text: string, values?: unknown[]): Promise<QueryResult<T>> {
|
||||
this.logQuery(text, values);
|
||||
return this.executeQuery<T>(text, values);
|
||||
}
|
||||
|
||||
async end(): Promise<void> {
|
||||
this.connected = false;
|
||||
this.dataStore = {
|
||||
agents: new Map(),
|
||||
sessions: new Map(),
|
||||
memories: new Map(),
|
||||
skills: new Map(),
|
||||
tenants: new Map(),
|
||||
tasks: new Map()
|
||||
};
|
||||
}
|
||||
|
||||
isConnected(): boolean {
|
||||
return this.connected;
|
||||
}
|
||||
|
||||
getQueryLog(): Array<{ text: string; values?: unknown[]; timestamp: Date }> {
|
||||
return [...this.queryLog];
|
||||
}
|
||||
|
||||
clearQueryLog(): void {
|
||||
this.queryLog = [];
|
||||
}
|
||||
|
||||
// Seed data for testing
|
||||
seedData(table: keyof MockDataStore, data: Array<{ id: string; [key: string]: unknown }>): void {
|
||||
for (const row of data) {
|
||||
this.dataStore[table].set(row.id, row);
|
||||
}
|
||||
}
|
||||
|
||||
getData(table: keyof MockDataStore): unknown[] {
|
||||
return Array.from(this.dataStore[table].values());
|
||||
}
|
||||
|
||||
private createClient(): PoolClient {
|
||||
return {
|
||||
query: async <T = unknown>(text: string, values?: unknown[]): Promise<QueryResult<T>> => {
|
||||
return this.executeQuery<T>(text, values);
|
||||
},
|
||||
release: () => {
|
||||
// No-op for mock
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private logQuery(text: string, values?: unknown[]): void {
|
||||
this.queryLog.push({ text, values, timestamp: new Date() });
|
||||
}
|
||||
|
||||
private async executeQuery<T>(text: string, values?: unknown[]): Promise<QueryResult<T>> {
|
||||
const normalizedQuery = text.trim().toUpperCase();
|
||||
|
||||
// Handle transaction commands
|
||||
if (normalizedQuery === 'BEGIN') {
|
||||
this.transactionActive = true;
|
||||
return this.createResult<T>([], 'BEGIN');
|
||||
}
|
||||
|
||||
if (normalizedQuery === 'COMMIT') {
|
||||
this.transactionActive = false;
|
||||
return this.createResult<T>([], 'COMMIT');
|
||||
}
|
||||
|
||||
if (normalizedQuery === 'ROLLBACK') {
|
||||
this.transactionActive = false;
|
||||
return this.createResult<T>([], 'ROLLBACK');
|
||||
}
|
||||
|
||||
// Parse and execute query
|
||||
if (normalizedQuery.startsWith('SELECT')) {
|
||||
return this.handleSelect<T>(text, values);
|
||||
}
|
||||
|
||||
if (normalizedQuery.startsWith('INSERT')) {
|
||||
return this.handleInsert<T>(text, values);
|
||||
}
|
||||
|
||||
if (normalizedQuery.startsWith('UPDATE')) {
|
||||
return this.handleUpdate<T>(text, values);
|
||||
}
|
||||
|
||||
if (normalizedQuery.startsWith('DELETE')) {
|
||||
return this.handleDelete<T>(text, values);
|
||||
}
|
||||
|
||||
// Default: return empty result
|
||||
return this.createResult<T>([], 'UNKNOWN');
|
||||
}
|
||||
|
||||
private handleSelect<T>(text: string, values?: unknown[]): QueryResult<T> {
|
||||
const tableName = this.extractTableName(text);
|
||||
const store = this.dataStore[tableName as keyof MockDataStore];
|
||||
|
||||
if (!store) {
|
||||
return this.createResult<T>([], 'SELECT');
|
||||
}
|
||||
|
||||
// Simple ID-based lookup
|
||||
const idMatch = text.match(/WHERE\s+id\s*=\s*\$1/i);
|
||||
if (idMatch && values?.[0]) {
|
||||
const row = store.get(values[0] as string);
|
||||
return this.createResult<T>(row ? [row as T] : [], 'SELECT');
|
||||
}
|
||||
|
||||
// Tenant-based lookup
|
||||
const tenantMatch = text.match(/WHERE\s+tenant_id\s*=\s*\$1/i);
|
||||
if (tenantMatch && values?.[0]) {
|
||||
const rows = Array.from(store.values())
|
||||
.filter((row: any) => row.tenantId === values[0] || row.tenant_id === values[0]);
|
||||
return this.createResult<T>(rows as T[], 'SELECT');
|
||||
}
|
||||
|
||||
// Return all rows
|
||||
return this.createResult<T>(Array.from(store.values()) as T[], 'SELECT');
|
||||
}
|
||||
|
||||
private handleInsert<T>(text: string, values?: unknown[]): QueryResult<T> {
|
||||
const tableName = this.extractTableName(text);
|
||||
const store = this.dataStore[tableName as keyof MockDataStore];
|
||||
|
||||
if (!store || !values) {
|
||||
return this.createResult<T>([], 'INSERT', 0);
|
||||
}
|
||||
|
||||
// Extract column names from query
|
||||
const columnsMatch = text.match(/\(([^)]+)\)/);
|
||||
if (!columnsMatch) {
|
||||
return this.createResult<T>([], 'INSERT', 0);
|
||||
}
|
||||
|
||||
const columns = columnsMatch[1].split(',').map(c => c.trim());
|
||||
const row: Record<string, unknown> = {};
|
||||
|
||||
columns.forEach((col, idx) => {
|
||||
row[col] = values[idx];
|
||||
});
|
||||
|
||||
const id = row.id as string || `generated-${Date.now()}`;
|
||||
row.id = id;
|
||||
store.set(id, row);
|
||||
|
||||
// Check for RETURNING clause
|
||||
if (text.includes('RETURNING')) {
|
||||
return this.createResult<T>([row as T], 'INSERT', 1);
|
||||
}
|
||||
|
||||
return this.createResult<T>([], 'INSERT', 1);
|
||||
}
|
||||
|
||||
private handleUpdate<T>(text: string, values?: unknown[]): QueryResult<T> {
|
||||
const tableName = this.extractTableName(text);
|
||||
const store = this.dataStore[tableName as keyof MockDataStore];
|
||||
|
||||
if (!store || !values) {
|
||||
return this.createResult<T>([], 'UPDATE', 0);
|
||||
}
|
||||
|
||||
// Simple ID-based update
|
||||
const idMatch = text.match(/WHERE\s+id\s*=\s*\$(\d+)/i);
|
||||
if (idMatch) {
|
||||
const idParamIndex = parseInt(idMatch[1]) - 1;
|
||||
const id = values[idParamIndex] as string;
|
||||
const row = store.get(id);
|
||||
|
||||
if (row) {
|
||||
// Update would happen here in real implementation
|
||||
return this.createResult<T>([], 'UPDATE', 1);
|
||||
}
|
||||
}
|
||||
|
||||
return this.createResult<T>([], 'UPDATE', 0);
|
||||
}
|
||||
|
||||
private handleDelete<T>(text: string, values?: unknown[]): QueryResult<T> {
|
||||
const tableName = this.extractTableName(text);
|
||||
const store = this.dataStore[tableName as keyof MockDataStore];
|
||||
|
||||
if (!store || !values) {
|
||||
return this.createResult<T>([], 'DELETE', 0);
|
||||
}
|
||||
|
||||
// Simple ID-based delete
|
||||
const idMatch = text.match(/WHERE\s+id\s*=\s*\$1/i);
|
||||
if (idMatch && values[0]) {
|
||||
const deleted = store.delete(values[0] as string);
|
||||
return this.createResult<T>([], 'DELETE', deleted ? 1 : 0);
|
||||
}
|
||||
|
||||
return this.createResult<T>([], 'DELETE', 0);
|
||||
}
|
||||
|
||||
private extractTableName(query: string): string {
|
||||
const fromMatch = query.match(/FROM\s+(\w+)/i);
|
||||
if (fromMatch) return fromMatch[1].toLowerCase();
|
||||
|
||||
const intoMatch = query.match(/INTO\s+(\w+)/i);
|
||||
if (intoMatch) return intoMatch[1].toLowerCase();
|
||||
|
||||
const updateMatch = query.match(/UPDATE\s+(\w+)/i);
|
||||
if (updateMatch) return updateMatch[1].toLowerCase();
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
private createResult<T>(rows: T[], command: string, rowCount?: number): QueryResult<T> {
|
||||
return {
|
||||
rows,
|
||||
rowCount: rowCount ?? rows.length,
|
||||
command,
|
||||
fields: []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock pool instance
|
||||
*/
|
||||
export function createMockPool(config?: Partial<PoolConfig>): MockPool {
|
||||
return new MockPool({
|
||||
host: 'localhost',
|
||||
port: 5432,
|
||||
database: 'ruvbot_test',
|
||||
user: 'test',
|
||||
password: 'test',
|
||||
...config
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Pool factory for dependency injection
|
||||
*/
|
||||
export const mockPoolFactory = {
|
||||
create: vi.fn((config: PoolConfig) => createMockPool(config)),
|
||||
createClient: vi.fn(async (config: PoolConfig) => {
|
||||
const pool = createMockPool(config);
|
||||
return pool.connect();
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Postgres query builder mock helpers
|
||||
*/
|
||||
export const queryBuilderHelpers = {
|
||||
expectQuery: (pool: MockPool, pattern: RegExp): boolean => {
|
||||
return pool.getQueryLog().some(q => pattern.test(q.text));
|
||||
},
|
||||
|
||||
expectQueryCount: (pool: MockPool, pattern: RegExp): number => {
|
||||
return pool.getQueryLog().filter(q => pattern.test(q.text)).length;
|
||||
},
|
||||
|
||||
expectTransaction: (pool: MockPool): boolean => {
|
||||
const log = pool.getQueryLog();
|
||||
const hasBegin = log.some(q => q.text.toUpperCase().includes('BEGIN'));
|
||||
const hasCommitOrRollback = log.some(q =>
|
||||
q.text.toUpperCase().includes('COMMIT') ||
|
||||
q.text.toUpperCase().includes('ROLLBACK')
|
||||
);
|
||||
return hasBegin && hasCommitOrRollback;
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
MockPool,
|
||||
createMockPool,
|
||||
mockPoolFactory,
|
||||
queryBuilderHelpers
|
||||
};
|
||||
207
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.d.ts
vendored
Normal file
207
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.d.ts
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* Slack API Mock Module
|
||||
*
|
||||
* Mock implementations for Slack Web API and Events API
|
||||
*/
|
||||
export interface SlackMessage {
|
||||
channel: string;
|
||||
text: string;
|
||||
thread_ts?: string;
|
||||
blocks?: unknown[];
|
||||
attachments?: unknown[];
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
export interface SlackResponse {
|
||||
ok: boolean;
|
||||
error?: string;
|
||||
ts?: string;
|
||||
channel?: string;
|
||||
message?: Record<string, unknown>;
|
||||
}
|
||||
export interface SlackUser {
|
||||
id: string;
|
||||
name: string;
|
||||
real_name: string;
|
||||
is_bot: boolean;
|
||||
team_id: string;
|
||||
}
|
||||
export interface SlackChannel {
|
||||
id: string;
|
||||
name: string;
|
||||
is_private: boolean;
|
||||
is_member: boolean;
|
||||
team_id: string;
|
||||
}
|
||||
/**
|
||||
* Mock Slack Web Client
|
||||
*/
|
||||
export declare class MockSlackWebClient {
|
||||
private messageLog;
|
||||
private _reactionsData;
|
||||
private _filesData;
|
||||
private _usersData;
|
||||
private _channelsData;
|
||||
constructor();
|
||||
chat: {
|
||||
postMessage: import("vitest").Mock<[args: SlackMessage], Promise<SlackResponse>>;
|
||||
update: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
ts: string;
|
||||
text?: string;
|
||||
blocks?: unknown[];
|
||||
}], Promise<SlackResponse>>;
|
||||
delete: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
ts: string;
|
||||
}], Promise<SlackResponse>>;
|
||||
postEphemeral: import("vitest").Mock<[args: SlackMessage & {
|
||||
user: string;
|
||||
}], Promise<SlackResponse>>;
|
||||
};
|
||||
conversations: {
|
||||
info: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
}], Promise<{
|
||||
ok: boolean;
|
||||
channel?: SlackChannel;
|
||||
}>>;
|
||||
members: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
}], Promise<{
|
||||
ok: boolean;
|
||||
members: string[];
|
||||
}>>;
|
||||
history: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
limit?: number;
|
||||
}], Promise<{
|
||||
ok: boolean;
|
||||
messages: unknown[];
|
||||
}>>;
|
||||
replies: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
ts: string;
|
||||
}], Promise<{
|
||||
ok: boolean;
|
||||
messages: unknown[];
|
||||
}>>;
|
||||
join: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
}], Promise<SlackResponse>>;
|
||||
leave: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
}], Promise<SlackResponse>>;
|
||||
};
|
||||
users: {
|
||||
info: import("vitest").Mock<[args: {
|
||||
user: string;
|
||||
}], Promise<{
|
||||
ok: boolean;
|
||||
user?: SlackUser;
|
||||
}>>;
|
||||
list: import("vitest").Mock<[], Promise<{
|
||||
ok: boolean;
|
||||
members: SlackUser[];
|
||||
}>>;
|
||||
};
|
||||
reactions: {
|
||||
add: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
timestamp: string;
|
||||
name: string;
|
||||
}], Promise<SlackResponse>>;
|
||||
remove: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
timestamp: string;
|
||||
name: string;
|
||||
}], Promise<SlackResponse>>;
|
||||
get: import("vitest").Mock<[args: {
|
||||
channel: string;
|
||||
timestamp: string;
|
||||
}], Promise<{
|
||||
ok: boolean;
|
||||
message: {
|
||||
reactions: unknown[];
|
||||
};
|
||||
}>>;
|
||||
};
|
||||
files: {
|
||||
upload: import("vitest").Mock<[args: {
|
||||
channels: string;
|
||||
content: string;
|
||||
filename: string;
|
||||
}], Promise<{
|
||||
ok: boolean;
|
||||
file: unknown;
|
||||
}>>;
|
||||
delete: import("vitest").Mock<[args: {
|
||||
file: string;
|
||||
}], Promise<SlackResponse>>;
|
||||
};
|
||||
auth: {
|
||||
test: import("vitest").Mock<[], Promise<{
|
||||
ok: boolean;
|
||||
user_id: string;
|
||||
team_id: string;
|
||||
bot_id: string;
|
||||
}>>;
|
||||
};
|
||||
getMessageLog(): SlackMessage[];
|
||||
clearMessageLog(): void;
|
||||
getReactions(channel: string, timestamp: string): string[];
|
||||
addUser(user: SlackUser): void;
|
||||
addChannel(channel: SlackChannel): void;
|
||||
reset(): void;
|
||||
private seedDefaultData;
|
||||
}
|
||||
/**
|
||||
* Mock Slack Events Handler
|
||||
*/
|
||||
export declare class MockSlackEventsHandler {
|
||||
private eventHandlers;
|
||||
private processedEvents;
|
||||
on(eventType: string, handler: (event: unknown) => void): void;
|
||||
off(eventType: string, handler: (event: unknown) => void): void;
|
||||
emit(eventType: string, event: unknown): Promise<void>;
|
||||
getProcessedEvents(): unknown[];
|
||||
clearProcessedEvents(): void;
|
||||
reset(): void;
|
||||
}
|
||||
/**
|
||||
* Mock Slack Bolt App
|
||||
*/
|
||||
export declare class MockSlackBoltApp {
|
||||
client: MockSlackWebClient;
|
||||
private eventsHandler;
|
||||
private messageHandlers;
|
||||
private actionHandlers;
|
||||
private commandHandlers;
|
||||
constructor();
|
||||
message(pattern: RegExp | string, handler: Function): void;
|
||||
action(actionId: string | RegExp, handler: Function): void;
|
||||
command(command: string, handler: Function): void;
|
||||
event(eventType: string, handler: Function): void;
|
||||
processMessage(message: {
|
||||
text: string;
|
||||
channel: string;
|
||||
user: string;
|
||||
ts: string;
|
||||
thread_ts?: string;
|
||||
}): Promise<void>;
|
||||
processAction(actionId: string, payload: unknown): Promise<void>;
|
||||
processCommand(command: string, payload: unknown): Promise<void>;
|
||||
start(port?: number): Promise<void>;
|
||||
stop(): Promise<void>;
|
||||
reset(): void;
|
||||
}
|
||||
export declare function createMockSlackClient(): MockSlackWebClient;
|
||||
export declare function createMockSlackApp(): MockSlackBoltApp;
|
||||
declare const _default: {
|
||||
MockSlackWebClient: typeof MockSlackWebClient;
|
||||
MockSlackEventsHandler: typeof MockSlackEventsHandler;
|
||||
MockSlackBoltApp: typeof MockSlackBoltApp;
|
||||
createMockSlackClient: typeof createMockSlackClient;
|
||||
createMockSlackApp: typeof createMockSlackApp;
|
||||
};
|
||||
export default _default;
|
||||
//# sourceMappingURL=slack.mock.d.ts.map
|
||||
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"slack.mock.d.ts","sourceRoot":"","sources":["slack.mock.ts"],"names":[],"mappings":"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"}
|
||||
347
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.js
vendored
Normal file
347
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.js
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
"use strict";
|
||||
/**
|
||||
* Slack API Mock Module
|
||||
*
|
||||
* Mock implementations for Slack Web API and Events API
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MockSlackBoltApp = exports.MockSlackEventsHandler = exports.MockSlackWebClient = void 0;
|
||||
exports.createMockSlackClient = createMockSlackClient;
|
||||
exports.createMockSlackApp = createMockSlackApp;
|
||||
const vitest_1 = require("vitest");
|
||||
/**
|
||||
* Mock Slack Web Client
|
||||
*/
|
||||
class MockSlackWebClient {
|
||||
constructor() {
|
||||
this.messageLog = [];
|
||||
this._reactionsData = new Map();
|
||||
this._filesData = new Map();
|
||||
// User and channel data
|
||||
this._usersData = new Map();
|
||||
this._channelsData = new Map();
|
||||
// Chat API
|
||||
this.chat = {
|
||||
postMessage: vitest_1.vi.fn(async (args) => {
|
||||
this.messageLog.push(args);
|
||||
const ts = `${Date.now()}.${Math.random().toString().slice(2, 8)}`;
|
||||
return {
|
||||
ok: true,
|
||||
ts,
|
||||
channel: args.channel,
|
||||
message: {
|
||||
text: args.text,
|
||||
ts,
|
||||
user: 'U_BOT',
|
||||
type: 'message'
|
||||
}
|
||||
};
|
||||
}),
|
||||
update: vitest_1.vi.fn(async (args) => {
|
||||
return {
|
||||
ok: true,
|
||||
ts: args.ts,
|
||||
channel: args.channel
|
||||
};
|
||||
}),
|
||||
delete: vitest_1.vi.fn(async (args) => {
|
||||
return {
|
||||
ok: true,
|
||||
ts: args.ts,
|
||||
channel: args.channel
|
||||
};
|
||||
}),
|
||||
postEphemeral: vitest_1.vi.fn(async (args) => {
|
||||
this.messageLog.push(args);
|
||||
return {
|
||||
ok: true,
|
||||
message_ts: `${Date.now()}.${Math.random().toString().slice(2, 8)}`
|
||||
};
|
||||
})
|
||||
};
|
||||
// Conversations API
|
||||
this.conversations = {
|
||||
info: vitest_1.vi.fn(async (args) => {
|
||||
const channel = this._channelsData.get(args.channel);
|
||||
return {
|
||||
ok: !!channel,
|
||||
channel
|
||||
};
|
||||
}),
|
||||
members: vitest_1.vi.fn(async (args) => {
|
||||
return {
|
||||
ok: true,
|
||||
members: ['U12345678', 'U87654321', 'U_BOT']
|
||||
};
|
||||
}),
|
||||
history: vitest_1.vi.fn(async (args) => {
|
||||
return {
|
||||
ok: true,
|
||||
messages: this.messageLog
|
||||
.filter(m => m.channel === args.channel)
|
||||
.slice(0, args.limit || 100)
|
||||
};
|
||||
}),
|
||||
replies: vitest_1.vi.fn(async (args) => {
|
||||
return {
|
||||
ok: true,
|
||||
messages: this.messageLog
|
||||
.filter(m => m.channel === args.channel && m.thread_ts === args.ts)
|
||||
};
|
||||
}),
|
||||
join: vitest_1.vi.fn(async (args) => {
|
||||
return { ok: true, channel: args.channel };
|
||||
}),
|
||||
leave: vitest_1.vi.fn(async (args) => {
|
||||
return { ok: true };
|
||||
})
|
||||
};
|
||||
// Users API
|
||||
this.users = {
|
||||
info: vitest_1.vi.fn(async (args) => {
|
||||
const user = this._usersData.get(args.user);
|
||||
return {
|
||||
ok: !!user,
|
||||
user
|
||||
};
|
||||
}),
|
||||
list: vitest_1.vi.fn(async () => {
|
||||
return {
|
||||
ok: true,
|
||||
members: Array.from(this._usersData.values())
|
||||
};
|
||||
})
|
||||
};
|
||||
// Reactions API
|
||||
this.reactions = {
|
||||
add: vitest_1.vi.fn(async (args) => {
|
||||
const key = `${args.channel}:${args.timestamp}`;
|
||||
const existing = this._reactionsData.get(key) || [];
|
||||
this._reactionsData.set(key, [...existing, args.name]);
|
||||
return { ok: true };
|
||||
}),
|
||||
remove: vitest_1.vi.fn(async (args) => {
|
||||
const key = `${args.channel}:${args.timestamp}`;
|
||||
const existing = this._reactionsData.get(key) || [];
|
||||
this._reactionsData.set(key, existing.filter(r => r !== args.name));
|
||||
return { ok: true };
|
||||
}),
|
||||
get: vitest_1.vi.fn(async (args) => {
|
||||
const key = `${args.channel}:${args.timestamp}`;
|
||||
const reactions = this._reactionsData.get(key) || [];
|
||||
return {
|
||||
ok: true,
|
||||
message: {
|
||||
reactions: reactions.map(name => ({ name, count: 1, users: ['U12345678'] }))
|
||||
}
|
||||
};
|
||||
})
|
||||
};
|
||||
// Files API
|
||||
this.files = {
|
||||
upload: vitest_1.vi.fn(async (args) => {
|
||||
const fileId = `F${Date.now()}`;
|
||||
const file = { id: fileId, name: args.filename, content: args.content };
|
||||
this._filesData.set(fileId, file);
|
||||
return { ok: true, file };
|
||||
}),
|
||||
delete: vitest_1.vi.fn(async (args) => {
|
||||
this._filesData.delete(args.file);
|
||||
return { ok: true };
|
||||
})
|
||||
};
|
||||
// Auth API
|
||||
this.auth = {
|
||||
test: vitest_1.vi.fn(async () => {
|
||||
return {
|
||||
ok: true,
|
||||
user_id: 'U_BOT',
|
||||
team_id: 'T12345678',
|
||||
bot_id: 'B12345678'
|
||||
};
|
||||
})
|
||||
};
|
||||
// Seed default test data
|
||||
this.seedDefaultData();
|
||||
}
|
||||
// Test helpers
|
||||
getMessageLog() {
|
||||
return [...this.messageLog];
|
||||
}
|
||||
clearMessageLog() {
|
||||
this.messageLog = [];
|
||||
}
|
||||
getReactions(channel, timestamp) {
|
||||
return this._reactionsData.get(`${channel}:${timestamp}`) || [];
|
||||
}
|
||||
addUser(user) {
|
||||
this._usersData.set(user.id, user);
|
||||
}
|
||||
addChannel(channel) {
|
||||
this._channelsData.set(channel.id, channel);
|
||||
}
|
||||
reset() {
|
||||
this.messageLog = [];
|
||||
this._reactionsData.clear();
|
||||
this._filesData.clear();
|
||||
this.seedDefaultData();
|
||||
// Reset all mocks
|
||||
vitest_1.vi.clearAllMocks();
|
||||
}
|
||||
seedDefaultData() {
|
||||
// Default users
|
||||
this._usersData.set('U12345678', {
|
||||
id: 'U12345678',
|
||||
name: 'testuser',
|
||||
real_name: 'Test User',
|
||||
is_bot: false,
|
||||
team_id: 'T12345678'
|
||||
});
|
||||
this._usersData.set('U_BOT', {
|
||||
id: 'U_BOT',
|
||||
name: 'ruvbot',
|
||||
real_name: 'RuvBot',
|
||||
is_bot: true,
|
||||
team_id: 'T12345678'
|
||||
});
|
||||
// Default channels
|
||||
this._channelsData.set('C12345678', {
|
||||
id: 'C12345678',
|
||||
name: 'general',
|
||||
is_private: false,
|
||||
is_member: true,
|
||||
team_id: 'T12345678'
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.MockSlackWebClient = MockSlackWebClient;
|
||||
/**
|
||||
* Mock Slack Events Handler
|
||||
*/
|
||||
class MockSlackEventsHandler {
|
||||
constructor() {
|
||||
this.eventHandlers = new Map();
|
||||
this.processedEvents = [];
|
||||
}
|
||||
on(eventType, handler) {
|
||||
const handlers = this.eventHandlers.get(eventType) || [];
|
||||
handlers.push(handler);
|
||||
this.eventHandlers.set(eventType, handlers);
|
||||
}
|
||||
off(eventType, handler) {
|
||||
const handlers = this.eventHandlers.get(eventType) || [];
|
||||
this.eventHandlers.set(eventType, handlers.filter(h => h !== handler));
|
||||
}
|
||||
async emit(eventType, event) {
|
||||
const handlers = this.eventHandlers.get(eventType) || [];
|
||||
this.processedEvents.push({ type: eventType, event, timestamp: new Date() });
|
||||
for (const handler of handlers) {
|
||||
await handler(event);
|
||||
}
|
||||
}
|
||||
getProcessedEvents() {
|
||||
return [...this.processedEvents];
|
||||
}
|
||||
clearProcessedEvents() {
|
||||
this.processedEvents = [];
|
||||
}
|
||||
reset() {
|
||||
this.eventHandlers.clear();
|
||||
this.processedEvents = [];
|
||||
}
|
||||
}
|
||||
exports.MockSlackEventsHandler = MockSlackEventsHandler;
|
||||
/**
|
||||
* Mock Slack Bolt App
|
||||
*/
|
||||
class MockSlackBoltApp {
|
||||
constructor() {
|
||||
this.messageHandlers = [];
|
||||
this.actionHandlers = new Map();
|
||||
this.commandHandlers = new Map();
|
||||
this.client = new MockSlackWebClient();
|
||||
this.eventsHandler = new MockSlackEventsHandler();
|
||||
}
|
||||
message(pattern, handler) {
|
||||
this.messageHandlers.push({ pattern, handler });
|
||||
}
|
||||
action(actionId, handler) {
|
||||
this.actionHandlers.set(actionId.toString(), handler);
|
||||
}
|
||||
command(command, handler) {
|
||||
this.commandHandlers.set(command, handler);
|
||||
}
|
||||
event(eventType, handler) {
|
||||
this.eventsHandler.on(eventType, handler);
|
||||
}
|
||||
async processMessage(message) {
|
||||
for (const { pattern, handler } of this.messageHandlers) {
|
||||
const matches = typeof pattern === 'string'
|
||||
? message.text.includes(pattern)
|
||||
: pattern.test(message.text);
|
||||
if (matches) {
|
||||
const context = {
|
||||
say: vitest_1.vi.fn(this.client.chat.postMessage),
|
||||
client: this.client,
|
||||
message,
|
||||
event: message
|
||||
};
|
||||
await handler(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
async processAction(actionId, payload) {
|
||||
const handler = this.actionHandlers.get(actionId);
|
||||
if (handler) {
|
||||
const context = {
|
||||
ack: vitest_1.vi.fn(async () => { }),
|
||||
respond: vitest_1.vi.fn(async () => { }),
|
||||
client: this.client,
|
||||
body: payload,
|
||||
action: { action_id: actionId }
|
||||
};
|
||||
await handler(context);
|
||||
}
|
||||
}
|
||||
async processCommand(command, payload) {
|
||||
const handler = this.commandHandlers.get(command);
|
||||
if (handler) {
|
||||
const context = {
|
||||
ack: vitest_1.vi.fn(async () => { }),
|
||||
respond: vitest_1.vi.fn(async () => { }),
|
||||
client: this.client,
|
||||
command: payload
|
||||
};
|
||||
await handler(context);
|
||||
}
|
||||
}
|
||||
async start(port) {
|
||||
// No-op for mock
|
||||
}
|
||||
async stop() {
|
||||
// No-op for mock
|
||||
}
|
||||
reset() {
|
||||
this.client.reset();
|
||||
this.eventsHandler.reset();
|
||||
this.messageHandlers = [];
|
||||
this.actionHandlers.clear();
|
||||
this.commandHandlers.clear();
|
||||
}
|
||||
}
|
||||
exports.MockSlackBoltApp = MockSlackBoltApp;
|
||||
// Factory functions
|
||||
function createMockSlackClient() {
|
||||
return new MockSlackWebClient();
|
||||
}
|
||||
function createMockSlackApp() {
|
||||
return new MockSlackBoltApp();
|
||||
}
|
||||
exports.default = {
|
||||
MockSlackWebClient,
|
||||
MockSlackEventsHandler,
|
||||
MockSlackBoltApp,
|
||||
createMockSlackClient,
|
||||
createMockSlackApp
|
||||
};
|
||||
//# sourceMappingURL=slack.mock.js.map
|
||||
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
428
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.ts
vendored
Normal file
428
vendor/ruvector/npm/packages/ruvbot/tests/mocks/slack.mock.ts
vendored
Normal file
@@ -0,0 +1,428 @@
|
||||
/**
|
||||
* Slack API Mock Module
|
||||
*
|
||||
* Mock implementations for Slack Web API and Events API
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
// Types
|
||||
export interface SlackMessage {
|
||||
channel: string;
|
||||
text: string;
|
||||
thread_ts?: string;
|
||||
blocks?: unknown[];
|
||||
attachments?: unknown[];
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface SlackResponse {
|
||||
ok: boolean;
|
||||
error?: string;
|
||||
ts?: string;
|
||||
channel?: string;
|
||||
message?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface SlackUser {
|
||||
id: string;
|
||||
name: string;
|
||||
real_name: string;
|
||||
is_bot: boolean;
|
||||
team_id: string;
|
||||
}
|
||||
|
||||
export interface SlackChannel {
|
||||
id: string;
|
||||
name: string;
|
||||
is_private: boolean;
|
||||
is_member: boolean;
|
||||
team_id: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Slack Web Client
|
||||
*/
|
||||
export class MockSlackWebClient {
|
||||
private messageLog: SlackMessage[] = [];
|
||||
private _reactionsData: Map<string, string[]> = new Map();
|
||||
private _filesData: Map<string, unknown> = new Map();
|
||||
|
||||
// User and channel data
|
||||
private _usersData: Map<string, SlackUser> = new Map();
|
||||
private _channelsData: Map<string, SlackChannel> = new Map();
|
||||
|
||||
constructor() {
|
||||
// Seed default test data
|
||||
this.seedDefaultData();
|
||||
}
|
||||
|
||||
// Chat API
|
||||
chat = {
|
||||
postMessage: vi.fn(async (args: SlackMessage): Promise<SlackResponse> => {
|
||||
this.messageLog.push(args);
|
||||
const ts = `${Date.now()}.${Math.random().toString().slice(2, 8)}`;
|
||||
return {
|
||||
ok: true,
|
||||
ts,
|
||||
channel: args.channel,
|
||||
message: {
|
||||
text: args.text,
|
||||
ts,
|
||||
user: 'U_BOT',
|
||||
type: 'message'
|
||||
}
|
||||
};
|
||||
}),
|
||||
|
||||
update: vi.fn(async (args: { channel: string; ts: string; text?: string; blocks?: unknown[] }): Promise<SlackResponse> => {
|
||||
return {
|
||||
ok: true,
|
||||
ts: args.ts,
|
||||
channel: args.channel
|
||||
};
|
||||
}),
|
||||
|
||||
delete: vi.fn(async (args: { channel: string; ts: string }): Promise<SlackResponse> => {
|
||||
return {
|
||||
ok: true,
|
||||
ts: args.ts,
|
||||
channel: args.channel
|
||||
};
|
||||
}),
|
||||
|
||||
postEphemeral: vi.fn(async (args: SlackMessage & { user: string }): Promise<SlackResponse> => {
|
||||
this.messageLog.push(args);
|
||||
return {
|
||||
ok: true,
|
||||
message_ts: `${Date.now()}.${Math.random().toString().slice(2, 8)}`
|
||||
} as SlackResponse;
|
||||
})
|
||||
};
|
||||
|
||||
// Conversations API
|
||||
conversations = {
|
||||
info: vi.fn(async (args: { channel: string }): Promise<{ ok: boolean; channel?: SlackChannel }> => {
|
||||
const channel = this._channelsData.get(args.channel);
|
||||
return {
|
||||
ok: !!channel,
|
||||
channel
|
||||
};
|
||||
}),
|
||||
|
||||
members: vi.fn(async (args: { channel: string }): Promise<{ ok: boolean; members: string[] }> => {
|
||||
return {
|
||||
ok: true,
|
||||
members: ['U12345678', 'U87654321', 'U_BOT']
|
||||
};
|
||||
}),
|
||||
|
||||
history: vi.fn(async (args: { channel: string; limit?: number }): Promise<{ ok: boolean; messages: unknown[] }> => {
|
||||
return {
|
||||
ok: true,
|
||||
messages: this.messageLog
|
||||
.filter(m => m.channel === args.channel)
|
||||
.slice(0, args.limit || 100)
|
||||
};
|
||||
}),
|
||||
|
||||
replies: vi.fn(async (args: { channel: string; ts: string }): Promise<{ ok: boolean; messages: unknown[] }> => {
|
||||
return {
|
||||
ok: true,
|
||||
messages: this.messageLog
|
||||
.filter(m => m.channel === args.channel && m.thread_ts === args.ts)
|
||||
};
|
||||
}),
|
||||
|
||||
join: vi.fn(async (args: { channel: string }): Promise<SlackResponse> => {
|
||||
return { ok: true, channel: args.channel };
|
||||
}),
|
||||
|
||||
leave: vi.fn(async (args: { channel: string }): Promise<SlackResponse> => {
|
||||
return { ok: true };
|
||||
})
|
||||
};
|
||||
|
||||
// Users API
|
||||
users = {
|
||||
info: vi.fn(async (args: { user: string }): Promise<{ ok: boolean; user?: SlackUser }> => {
|
||||
const user = this._usersData.get(args.user);
|
||||
return {
|
||||
ok: !!user,
|
||||
user
|
||||
};
|
||||
}),
|
||||
|
||||
list: vi.fn(async (): Promise<{ ok: boolean; members: SlackUser[] }> => {
|
||||
return {
|
||||
ok: true,
|
||||
members: Array.from(this._usersData.values())
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
// Reactions API
|
||||
reactions = {
|
||||
add: vi.fn(async (args: { channel: string; timestamp: string; name: string }): Promise<SlackResponse> => {
|
||||
const key = `${args.channel}:${args.timestamp}`;
|
||||
const existing = this._reactionsData.get(key) || [];
|
||||
this._reactionsData.set(key, [...existing, args.name]);
|
||||
return { ok: true };
|
||||
}),
|
||||
|
||||
remove: vi.fn(async (args: { channel: string; timestamp: string; name: string }): Promise<SlackResponse> => {
|
||||
const key = `${args.channel}:${args.timestamp}`;
|
||||
const existing = this._reactionsData.get(key) || [];
|
||||
this._reactionsData.set(key, existing.filter(r => r !== args.name));
|
||||
return { ok: true };
|
||||
}),
|
||||
|
||||
get: vi.fn(async (args: { channel: string; timestamp: string }): Promise<{ ok: boolean; message: { reactions: unknown[] } }> => {
|
||||
const key = `${args.channel}:${args.timestamp}`;
|
||||
const reactions = this._reactionsData.get(key) || [];
|
||||
return {
|
||||
ok: true,
|
||||
message: {
|
||||
reactions: reactions.map(name => ({ name, count: 1, users: ['U12345678'] }))
|
||||
}
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
// Files API
|
||||
files = {
|
||||
upload: vi.fn(async (args: { channels: string; content: string; filename: string }): Promise<{ ok: boolean; file: unknown }> => {
|
||||
const fileId = `F${Date.now()}`;
|
||||
const file = { id: fileId, name: args.filename, content: args.content };
|
||||
this._filesData.set(fileId, file);
|
||||
return { ok: true, file };
|
||||
}),
|
||||
|
||||
delete: vi.fn(async (args: { file: string }): Promise<SlackResponse> => {
|
||||
this._filesData.delete(args.file);
|
||||
return { ok: true };
|
||||
})
|
||||
};
|
||||
|
||||
// Auth API
|
||||
auth = {
|
||||
test: vi.fn(async (): Promise<{ ok: boolean; user_id: string; team_id: string; bot_id: string }> => {
|
||||
return {
|
||||
ok: true,
|
||||
user_id: 'U_BOT',
|
||||
team_id: 'T12345678',
|
||||
bot_id: 'B12345678'
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
// Test helpers
|
||||
getMessageLog(): SlackMessage[] {
|
||||
return [...this.messageLog];
|
||||
}
|
||||
|
||||
clearMessageLog(): void {
|
||||
this.messageLog = [];
|
||||
}
|
||||
|
||||
getReactions(channel: string, timestamp: string): string[] {
|
||||
return this._reactionsData.get(`${channel}:${timestamp}`) || [];
|
||||
}
|
||||
|
||||
addUser(user: SlackUser): void {
|
||||
this._usersData.set(user.id, user);
|
||||
}
|
||||
|
||||
addChannel(channel: SlackChannel): void {
|
||||
this._channelsData.set(channel.id, channel);
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.messageLog = [];
|
||||
this._reactionsData.clear();
|
||||
this._filesData.clear();
|
||||
this.seedDefaultData();
|
||||
|
||||
// Reset all mocks
|
||||
vi.clearAllMocks();
|
||||
}
|
||||
|
||||
private seedDefaultData(): void {
|
||||
// Default users
|
||||
this._usersData.set('U12345678', {
|
||||
id: 'U12345678',
|
||||
name: 'testuser',
|
||||
real_name: 'Test User',
|
||||
is_bot: false,
|
||||
team_id: 'T12345678'
|
||||
});
|
||||
|
||||
this._usersData.set('U_BOT', {
|
||||
id: 'U_BOT',
|
||||
name: 'ruvbot',
|
||||
real_name: 'RuvBot',
|
||||
is_bot: true,
|
||||
team_id: 'T12345678'
|
||||
});
|
||||
|
||||
// Default channels
|
||||
this._channelsData.set('C12345678', {
|
||||
id: 'C12345678',
|
||||
name: 'general',
|
||||
is_private: false,
|
||||
is_member: true,
|
||||
team_id: 'T12345678'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Slack Events Handler
|
||||
*/
|
||||
export class MockSlackEventsHandler {
|
||||
private eventHandlers: Map<string, Array<(event: unknown) => void>> = new Map();
|
||||
private processedEvents: unknown[] = [];
|
||||
|
||||
on(eventType: string, handler: (event: unknown) => void): void {
|
||||
const handlers = this.eventHandlers.get(eventType) || [];
|
||||
handlers.push(handler);
|
||||
this.eventHandlers.set(eventType, handlers);
|
||||
}
|
||||
|
||||
off(eventType: string, handler: (event: unknown) => void): void {
|
||||
const handlers = this.eventHandlers.get(eventType) || [];
|
||||
this.eventHandlers.set(eventType, handlers.filter(h => h !== handler));
|
||||
}
|
||||
|
||||
async emit(eventType: string, event: unknown): Promise<void> {
|
||||
const handlers = this.eventHandlers.get(eventType) || [];
|
||||
this.processedEvents.push({ type: eventType, event, timestamp: new Date() });
|
||||
|
||||
for (const handler of handlers) {
|
||||
await handler(event);
|
||||
}
|
||||
}
|
||||
|
||||
getProcessedEvents(): unknown[] {
|
||||
return [...this.processedEvents];
|
||||
}
|
||||
|
||||
clearProcessedEvents(): void {
|
||||
this.processedEvents = [];
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.eventHandlers.clear();
|
||||
this.processedEvents = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Slack Bolt App
|
||||
*/
|
||||
export class MockSlackBoltApp {
|
||||
client: MockSlackWebClient;
|
||||
private eventsHandler: MockSlackEventsHandler;
|
||||
private messageHandlers: Array<{ pattern: RegExp | string; handler: Function }> = [];
|
||||
private actionHandlers: Map<string, Function> = new Map();
|
||||
private commandHandlers: Map<string, Function> = new Map();
|
||||
|
||||
constructor() {
|
||||
this.client = new MockSlackWebClient();
|
||||
this.eventsHandler = new MockSlackEventsHandler();
|
||||
}
|
||||
|
||||
message(pattern: RegExp | string, handler: Function): void {
|
||||
this.messageHandlers.push({ pattern, handler });
|
||||
}
|
||||
|
||||
action(actionId: string | RegExp, handler: Function): void {
|
||||
this.actionHandlers.set(actionId.toString(), handler);
|
||||
}
|
||||
|
||||
command(command: string, handler: Function): void {
|
||||
this.commandHandlers.set(command, handler);
|
||||
}
|
||||
|
||||
event(eventType: string, handler: Function): void {
|
||||
this.eventsHandler.on(eventType, handler as (event: unknown) => void);
|
||||
}
|
||||
|
||||
async processMessage(message: { text: string; channel: string; user: string; ts: string; thread_ts?: string }): Promise<void> {
|
||||
for (const { pattern, handler } of this.messageHandlers) {
|
||||
const matches = typeof pattern === 'string'
|
||||
? message.text.includes(pattern)
|
||||
: pattern.test(message.text);
|
||||
|
||||
if (matches) {
|
||||
const context = {
|
||||
say: vi.fn(this.client.chat.postMessage),
|
||||
client: this.client,
|
||||
message,
|
||||
event: message
|
||||
};
|
||||
await handler(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async processAction(actionId: string, payload: unknown): Promise<void> {
|
||||
const handler = this.actionHandlers.get(actionId);
|
||||
if (handler) {
|
||||
const context = {
|
||||
ack: vi.fn(async () => {}),
|
||||
respond: vi.fn(async () => {}),
|
||||
client: this.client,
|
||||
body: payload,
|
||||
action: { action_id: actionId }
|
||||
};
|
||||
await handler(context);
|
||||
}
|
||||
}
|
||||
|
||||
async processCommand(command: string, payload: unknown): Promise<void> {
|
||||
const handler = this.commandHandlers.get(command);
|
||||
if (handler) {
|
||||
const context = {
|
||||
ack: vi.fn(async () => {}),
|
||||
respond: vi.fn(async () => {}),
|
||||
client: this.client,
|
||||
command: payload
|
||||
};
|
||||
await handler(context);
|
||||
}
|
||||
}
|
||||
|
||||
async start(port?: number): Promise<void> {
|
||||
// No-op for mock
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
// No-op for mock
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.client.reset();
|
||||
this.eventsHandler.reset();
|
||||
this.messageHandlers = [];
|
||||
this.actionHandlers.clear();
|
||||
this.commandHandlers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Factory functions
|
||||
export function createMockSlackClient(): MockSlackWebClient {
|
||||
return new MockSlackWebClient();
|
||||
}
|
||||
|
||||
export function createMockSlackApp(): MockSlackBoltApp {
|
||||
return new MockSlackBoltApp();
|
||||
}
|
||||
|
||||
export default {
|
||||
MockSlackWebClient,
|
||||
MockSlackEventsHandler,
|
||||
MockSlackBoltApp,
|
||||
createMockSlackClient,
|
||||
createMockSlackApp
|
||||
};
|
||||
118
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.d.ts
vendored
Normal file
118
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.d.ts
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* WASM Mock Module
|
||||
*
|
||||
* Mock implementations for RuVector WASM bindings
|
||||
* Used to test code that depends on WASM modules without loading actual binaries
|
||||
*/
|
||||
export interface WasmVectorIndex {
|
||||
add(id: string, vector: Float32Array): void;
|
||||
search(query: Float32Array, topK: number): SearchResult[];
|
||||
delete(id: string): boolean;
|
||||
size(): number;
|
||||
clear(): void;
|
||||
}
|
||||
export interface SearchResult {
|
||||
id: string;
|
||||
score: number;
|
||||
distance: number;
|
||||
}
|
||||
export interface WasmEmbedder {
|
||||
embed(text: string): Float32Array;
|
||||
embedBatch(texts: string[]): Float32Array[];
|
||||
dimension(): number;
|
||||
}
|
||||
export interface WasmRouter {
|
||||
route(input: string, context?: Record<string, unknown>): RouteResult;
|
||||
addRoute(pattern: string, handler: string): void;
|
||||
removeRoute(pattern: string): boolean;
|
||||
}
|
||||
export interface RouteResult {
|
||||
handler: string;
|
||||
confidence: number;
|
||||
metadata: Record<string, unknown>;
|
||||
}
|
||||
/**
|
||||
* Mock WASM Vector Index
|
||||
*/
|
||||
export declare class MockWasmVectorIndex implements WasmVectorIndex {
|
||||
private vectors;
|
||||
private dimension;
|
||||
constructor(dimension?: number);
|
||||
add(id: string, vector: Float32Array): void;
|
||||
search(query: Float32Array, topK: number): SearchResult[];
|
||||
delete(id: string): boolean;
|
||||
size(): number;
|
||||
clear(): void;
|
||||
private cosineSimilarity;
|
||||
}
|
||||
/**
|
||||
* Mock WASM Embedder
|
||||
*/
|
||||
export declare class MockWasmEmbedder implements WasmEmbedder {
|
||||
private dim;
|
||||
private cache;
|
||||
constructor(dimension?: number);
|
||||
embed(text: string): Float32Array;
|
||||
embedBatch(texts: string[]): Float32Array[];
|
||||
dimension(): number;
|
||||
private hashCode;
|
||||
}
|
||||
/**
|
||||
* Mock WASM Router
|
||||
*/
|
||||
export declare class MockWasmRouter implements WasmRouter {
|
||||
private routes;
|
||||
route(input: string, context?: Record<string, unknown>): RouteResult;
|
||||
addRoute(pattern: string, handler: string): void;
|
||||
removeRoute(pattern: string): boolean;
|
||||
}
|
||||
/**
|
||||
* Mock WASM Module Loader
|
||||
*/
|
||||
export declare const mockWasmLoader: {
|
||||
loadVectorIndex: import("vitest").Mock<[dimension?: number | undefined], Promise<WasmVectorIndex>>;
|
||||
loadEmbedder: import("vitest").Mock<[dimension?: number | undefined], Promise<WasmEmbedder>>;
|
||||
loadRouter: import("vitest").Mock<[], Promise<WasmRouter>>;
|
||||
isWasmSupported: import("vitest").Mock<[], boolean>;
|
||||
getWasmMemory: import("vitest").Mock<[], {
|
||||
used: number;
|
||||
total: number;
|
||||
}>;
|
||||
};
|
||||
/**
|
||||
* Create mock WASM bindings for RuVector
|
||||
*/
|
||||
export declare function createMockRuVectorBindings(): {
|
||||
vectorIndex: MockWasmVectorIndex;
|
||||
embedder: MockWasmEmbedder;
|
||||
router: MockWasmRouter;
|
||||
search(query: string, topK?: number): Promise<SearchResult[]>;
|
||||
index(id: string, text: string): Promise<void>;
|
||||
batchIndex(items: Array<{
|
||||
id: string;
|
||||
text: string;
|
||||
}>): Promise<void>;
|
||||
};
|
||||
/**
|
||||
* Reset all WASM mocks
|
||||
*/
|
||||
export declare function resetWasmMocks(): void;
|
||||
declare const _default: {
|
||||
MockWasmVectorIndex: typeof MockWasmVectorIndex;
|
||||
MockWasmEmbedder: typeof MockWasmEmbedder;
|
||||
MockWasmRouter: typeof MockWasmRouter;
|
||||
mockWasmLoader: {
|
||||
loadVectorIndex: import("vitest").Mock<[dimension?: number | undefined], Promise<WasmVectorIndex>>;
|
||||
loadEmbedder: import("vitest").Mock<[dimension?: number | undefined], Promise<WasmEmbedder>>;
|
||||
loadRouter: import("vitest").Mock<[], Promise<WasmRouter>>;
|
||||
isWasmSupported: import("vitest").Mock<[], boolean>;
|
||||
getWasmMemory: import("vitest").Mock<[], {
|
||||
used: number;
|
||||
total: number;
|
||||
}>;
|
||||
};
|
||||
createMockRuVectorBindings: typeof createMockRuVectorBindings;
|
||||
resetWasmMocks: typeof resetWasmMocks;
|
||||
};
|
||||
export default _default;
|
||||
//# sourceMappingURL=wasm.mock.d.ts.map
|
||||
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wasm.mock.d.ts","sourceRoot":"","sources":["wasm.mock.ts"],"names":[],"mappings":"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"}
|
||||
212
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.js
vendored
Normal file
212
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.js
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
"use strict";
|
||||
/**
|
||||
* WASM Mock Module
|
||||
*
|
||||
* Mock implementations for RuVector WASM bindings
|
||||
* Used to test code that depends on WASM modules without loading actual binaries
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.mockWasmLoader = exports.MockWasmRouter = exports.MockWasmEmbedder = exports.MockWasmVectorIndex = void 0;
|
||||
exports.createMockRuVectorBindings = createMockRuVectorBindings;
|
||||
exports.resetWasmMocks = resetWasmMocks;
|
||||
const vitest_1 = require("vitest");
|
||||
// Mock implementations
|
||||
/**
|
||||
* Mock WASM Vector Index
|
||||
*/
|
||||
class MockWasmVectorIndex {
|
||||
constructor(dimension = 384) {
|
||||
this.vectors = new Map();
|
||||
this.dimension = dimension;
|
||||
}
|
||||
add(id, vector) {
|
||||
if (vector.length !== this.dimension) {
|
||||
throw new Error(`Vector dimension mismatch: expected ${this.dimension}, got ${vector.length}`);
|
||||
}
|
||||
this.vectors.set(id, vector);
|
||||
}
|
||||
search(query, topK) {
|
||||
if (query.length !== this.dimension) {
|
||||
throw new Error(`Query dimension mismatch: expected ${this.dimension}, got ${query.length}`);
|
||||
}
|
||||
const results = [];
|
||||
for (const [id, vector] of this.vectors) {
|
||||
const distance = this.cosineSimilarity(query, vector);
|
||||
results.push({
|
||||
id,
|
||||
score: distance,
|
||||
distance: 1 - distance
|
||||
});
|
||||
}
|
||||
return results
|
||||
.sort((a, b) => b.score - a.score)
|
||||
.slice(0, topK);
|
||||
}
|
||||
delete(id) {
|
||||
return this.vectors.delete(id);
|
||||
}
|
||||
size() {
|
||||
return this.vectors.size;
|
||||
}
|
||||
clear() {
|
||||
this.vectors.clear();
|
||||
}
|
||||
cosineSimilarity(a, b) {
|
||||
let dotProduct = 0;
|
||||
let normA = 0;
|
||||
let normB = 0;
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
dotProduct += a[i] * b[i];
|
||||
normA += a[i] * a[i];
|
||||
normB += b[i] * b[i];
|
||||
}
|
||||
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
||||
}
|
||||
}
|
||||
exports.MockWasmVectorIndex = MockWasmVectorIndex;
|
||||
/**
|
||||
* Mock WASM Embedder
|
||||
*/
|
||||
class MockWasmEmbedder {
|
||||
constructor(dimension = 384) {
|
||||
this.cache = new Map();
|
||||
this.dim = dimension;
|
||||
}
|
||||
embed(text) {
|
||||
// Check cache first
|
||||
if (this.cache.has(text)) {
|
||||
return this.cache.get(text);
|
||||
}
|
||||
// Generate deterministic pseudo-random embedding based on text hash
|
||||
const embedding = new Float32Array(this.dim);
|
||||
let hash = this.hashCode(text);
|
||||
for (let i = 0; i < this.dim; i++) {
|
||||
hash = ((hash * 1103515245) + 12345) & 0x7fffffff;
|
||||
embedding[i] = (hash / 0x7fffffff) * 2 - 1;
|
||||
}
|
||||
// Normalize the embedding
|
||||
const norm = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
|
||||
for (let i = 0; i < this.dim; i++) {
|
||||
embedding[i] /= norm;
|
||||
}
|
||||
this.cache.set(text, embedding);
|
||||
return embedding;
|
||||
}
|
||||
embedBatch(texts) {
|
||||
return texts.map(text => this.embed(text));
|
||||
}
|
||||
dimension() {
|
||||
return this.dim;
|
||||
}
|
||||
hashCode(str) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash;
|
||||
}
|
||||
return Math.abs(hash);
|
||||
}
|
||||
}
|
||||
exports.MockWasmEmbedder = MockWasmEmbedder;
|
||||
/**
|
||||
* Mock WASM Router
|
||||
*/
|
||||
class MockWasmRouter {
|
||||
constructor() {
|
||||
this.routes = new Map();
|
||||
}
|
||||
route(input, context) {
|
||||
for (const [key, route] of this.routes) {
|
||||
if (route.pattern.test(input)) {
|
||||
return {
|
||||
handler: route.handler,
|
||||
confidence: 0.95,
|
||||
metadata: { matchedPattern: key, context }
|
||||
};
|
||||
}
|
||||
}
|
||||
// Default fallback
|
||||
return {
|
||||
handler: 'default',
|
||||
confidence: 0.5,
|
||||
metadata: { fallback: true, context }
|
||||
};
|
||||
}
|
||||
addRoute(pattern, handler) {
|
||||
this.routes.set(pattern, {
|
||||
pattern: new RegExp(pattern, 'i'),
|
||||
handler
|
||||
});
|
||||
}
|
||||
removeRoute(pattern) {
|
||||
return this.routes.delete(pattern);
|
||||
}
|
||||
}
|
||||
exports.MockWasmRouter = MockWasmRouter;
|
||||
/**
|
||||
* Mock WASM Module Loader
|
||||
*/
|
||||
exports.mockWasmLoader = {
|
||||
loadVectorIndex: vitest_1.vi.fn(async (dimension) => {
|
||||
return new MockWasmVectorIndex(dimension);
|
||||
}),
|
||||
loadEmbedder: vitest_1.vi.fn(async (dimension) => {
|
||||
return new MockWasmEmbedder(dimension);
|
||||
}),
|
||||
loadRouter: vitest_1.vi.fn(async () => {
|
||||
return new MockWasmRouter();
|
||||
}),
|
||||
isWasmSupported: vitest_1.vi.fn(() => true),
|
||||
getWasmMemory: vitest_1.vi.fn(() => ({
|
||||
used: 1024 * 1024 * 50, // 50MB
|
||||
total: 1024 * 1024 * 256 // 256MB
|
||||
}))
|
||||
};
|
||||
/**
|
||||
* Create mock WASM bindings for RuVector
|
||||
*/
|
||||
function createMockRuVectorBindings() {
|
||||
const vectorIndex = new MockWasmVectorIndex(384);
|
||||
const embedder = new MockWasmEmbedder(384);
|
||||
const router = new MockWasmRouter();
|
||||
return {
|
||||
vectorIndex,
|
||||
embedder,
|
||||
router,
|
||||
// Convenience methods
|
||||
async search(query, topK = 10) {
|
||||
const embedding = embedder.embed(query);
|
||||
return vectorIndex.search(embedding, topK);
|
||||
},
|
||||
async index(id, text) {
|
||||
const embedding = embedder.embed(text);
|
||||
vectorIndex.add(id, embedding);
|
||||
},
|
||||
async batchIndex(items) {
|
||||
for (const item of items) {
|
||||
const embedding = embedder.embed(item.text);
|
||||
vectorIndex.add(item.id, embedding);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Reset all WASM mocks
|
||||
*/
|
||||
function resetWasmMocks() {
|
||||
vitest_1.vi.clearAllMocks();
|
||||
exports.mockWasmLoader.loadVectorIndex.mockClear();
|
||||
exports.mockWasmLoader.loadEmbedder.mockClear();
|
||||
exports.mockWasmLoader.loadRouter.mockClear();
|
||||
}
|
||||
// Default export for easy mocking
|
||||
exports.default = {
|
||||
MockWasmVectorIndex,
|
||||
MockWasmEmbedder,
|
||||
MockWasmRouter,
|
||||
mockWasmLoader: exports.mockWasmLoader,
|
||||
createMockRuVectorBindings,
|
||||
resetWasmMocks
|
||||
};
|
||||
//# sourceMappingURL=wasm.mock.js.map
|
||||
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
278
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.ts
vendored
Normal file
278
vendor/ruvector/npm/packages/ruvbot/tests/mocks/wasm.mock.ts
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* WASM Mock Module
|
||||
*
|
||||
* Mock implementations for RuVector WASM bindings
|
||||
* Used to test code that depends on WASM modules without loading actual binaries
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
// Types for WASM interfaces
|
||||
export interface WasmVectorIndex {
|
||||
add(id: string, vector: Float32Array): void;
|
||||
search(query: Float32Array, topK: number): SearchResult[];
|
||||
delete(id: string): boolean;
|
||||
size(): number;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
export interface SearchResult {
|
||||
id: string;
|
||||
score: number;
|
||||
distance: number;
|
||||
}
|
||||
|
||||
export interface WasmEmbedder {
|
||||
embed(text: string): Float32Array;
|
||||
embedBatch(texts: string[]): Float32Array[];
|
||||
dimension(): number;
|
||||
}
|
||||
|
||||
export interface WasmRouter {
|
||||
route(input: string, context?: Record<string, unknown>): RouteResult;
|
||||
addRoute(pattern: string, handler: string): void;
|
||||
removeRoute(pattern: string): boolean;
|
||||
}
|
||||
|
||||
export interface RouteResult {
|
||||
handler: string;
|
||||
confidence: number;
|
||||
metadata: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// Mock implementations
|
||||
|
||||
/**
|
||||
* Mock WASM Vector Index
|
||||
*/
|
||||
export class MockWasmVectorIndex implements WasmVectorIndex {
|
||||
private vectors: Map<string, Float32Array> = new Map();
|
||||
private dimension: number;
|
||||
|
||||
constructor(dimension: number = 384) {
|
||||
this.dimension = dimension;
|
||||
}
|
||||
|
||||
add(id: string, vector: Float32Array): void {
|
||||
if (vector.length !== this.dimension) {
|
||||
throw new Error(`Vector dimension mismatch: expected ${this.dimension}, got ${vector.length}`);
|
||||
}
|
||||
this.vectors.set(id, vector);
|
||||
}
|
||||
|
||||
search(query: Float32Array, topK: number): SearchResult[] {
|
||||
if (query.length !== this.dimension) {
|
||||
throw new Error(`Query dimension mismatch: expected ${this.dimension}, got ${query.length}`);
|
||||
}
|
||||
|
||||
const results: SearchResult[] = [];
|
||||
|
||||
for (const [id, vector] of this.vectors) {
|
||||
const distance = this.cosineSimilarity(query, vector);
|
||||
results.push({
|
||||
id,
|
||||
score: distance,
|
||||
distance: 1 - distance
|
||||
});
|
||||
}
|
||||
|
||||
return results
|
||||
.sort((a, b) => b.score - a.score)
|
||||
.slice(0, topK);
|
||||
}
|
||||
|
||||
delete(id: string): boolean {
|
||||
return this.vectors.delete(id);
|
||||
}
|
||||
|
||||
size(): number {
|
||||
return this.vectors.size;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.vectors.clear();
|
||||
}
|
||||
|
||||
private cosineSimilarity(a: Float32Array, b: Float32Array): number {
|
||||
let dotProduct = 0;
|
||||
let normA = 0;
|
||||
let normB = 0;
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
dotProduct += a[i] * b[i];
|
||||
normA += a[i] * a[i];
|
||||
normB += b[i] * b[i];
|
||||
}
|
||||
|
||||
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock WASM Embedder
|
||||
*/
|
||||
export class MockWasmEmbedder implements WasmEmbedder {
|
||||
private dim: number;
|
||||
private cache: Map<string, Float32Array> = new Map();
|
||||
|
||||
constructor(dimension: number = 384) {
|
||||
this.dim = dimension;
|
||||
}
|
||||
|
||||
embed(text: string): Float32Array {
|
||||
// Check cache first
|
||||
if (this.cache.has(text)) {
|
||||
return this.cache.get(text)!;
|
||||
}
|
||||
|
||||
// Generate deterministic pseudo-random embedding based on text hash
|
||||
const embedding = new Float32Array(this.dim);
|
||||
let hash = this.hashCode(text);
|
||||
|
||||
for (let i = 0; i < this.dim; i++) {
|
||||
hash = ((hash * 1103515245) + 12345) & 0x7fffffff;
|
||||
embedding[i] = (hash / 0x7fffffff) * 2 - 1;
|
||||
}
|
||||
|
||||
// Normalize the embedding
|
||||
const norm = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
|
||||
for (let i = 0; i < this.dim; i++) {
|
||||
embedding[i] /= norm;
|
||||
}
|
||||
|
||||
this.cache.set(text, embedding);
|
||||
return embedding;
|
||||
}
|
||||
|
||||
embedBatch(texts: string[]): Float32Array[] {
|
||||
return texts.map(text => this.embed(text));
|
||||
}
|
||||
|
||||
dimension(): number {
|
||||
return this.dim;
|
||||
}
|
||||
|
||||
private hashCode(str: string): number {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash;
|
||||
}
|
||||
return Math.abs(hash);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock WASM Router
|
||||
*/
|
||||
export class MockWasmRouter implements WasmRouter {
|
||||
private routes: Map<string, { pattern: RegExp; handler: string }> = new Map();
|
||||
|
||||
route(input: string, context?: Record<string, unknown>): RouteResult {
|
||||
for (const [key, route] of this.routes) {
|
||||
if (route.pattern.test(input)) {
|
||||
return {
|
||||
handler: route.handler,
|
||||
confidence: 0.95,
|
||||
metadata: { matchedPattern: key, context }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Default fallback
|
||||
return {
|
||||
handler: 'default',
|
||||
confidence: 0.5,
|
||||
metadata: { fallback: true, context }
|
||||
};
|
||||
}
|
||||
|
||||
addRoute(pattern: string, handler: string): void {
|
||||
this.routes.set(pattern, {
|
||||
pattern: new RegExp(pattern, 'i'),
|
||||
handler
|
||||
});
|
||||
}
|
||||
|
||||
removeRoute(pattern: string): boolean {
|
||||
return this.routes.delete(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock WASM Module Loader
|
||||
*/
|
||||
export const mockWasmLoader = {
|
||||
loadVectorIndex: vi.fn(async (dimension?: number): Promise<WasmVectorIndex> => {
|
||||
return new MockWasmVectorIndex(dimension);
|
||||
}),
|
||||
|
||||
loadEmbedder: vi.fn(async (dimension?: number): Promise<WasmEmbedder> => {
|
||||
return new MockWasmEmbedder(dimension);
|
||||
}),
|
||||
|
||||
loadRouter: vi.fn(async (): Promise<WasmRouter> => {
|
||||
return new MockWasmRouter();
|
||||
}),
|
||||
|
||||
isWasmSupported: vi.fn((): boolean => true),
|
||||
|
||||
getWasmMemory: vi.fn((): { used: number; total: number } => ({
|
||||
used: 1024 * 1024 * 50, // 50MB
|
||||
total: 1024 * 1024 * 256 // 256MB
|
||||
}))
|
||||
};
|
||||
|
||||
/**
|
||||
* Create mock WASM bindings for RuVector
|
||||
*/
|
||||
export function createMockRuVectorBindings() {
|
||||
const vectorIndex = new MockWasmVectorIndex(384);
|
||||
const embedder = new MockWasmEmbedder(384);
|
||||
const router = new MockWasmRouter();
|
||||
|
||||
return {
|
||||
vectorIndex,
|
||||
embedder,
|
||||
router,
|
||||
|
||||
// Convenience methods
|
||||
async search(query: string, topK: number = 10): Promise<SearchResult[]> {
|
||||
const embedding = embedder.embed(query);
|
||||
return vectorIndex.search(embedding, topK);
|
||||
},
|
||||
|
||||
async index(id: string, text: string): Promise<void> {
|
||||
const embedding = embedder.embed(text);
|
||||
vectorIndex.add(id, embedding);
|
||||
},
|
||||
|
||||
async batchIndex(items: Array<{ id: string; text: string }>): Promise<void> {
|
||||
for (const item of items) {
|
||||
const embedding = embedder.embed(item.text);
|
||||
vectorIndex.add(item.id, embedding);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all WASM mocks
|
||||
*/
|
||||
export function resetWasmMocks(): void {
|
||||
vi.clearAllMocks();
|
||||
mockWasmLoader.loadVectorIndex.mockClear();
|
||||
mockWasmLoader.loadEmbedder.mockClear();
|
||||
mockWasmLoader.loadRouter.mockClear();
|
||||
}
|
||||
|
||||
// Default export for easy mocking
|
||||
export default {
|
||||
MockWasmVectorIndex,
|
||||
MockWasmEmbedder,
|
||||
MockWasmRouter,
|
||||
mockWasmLoader,
|
||||
createMockRuVectorBindings,
|
||||
resetWasmMocks
|
||||
};
|
||||
Reference in New Issue
Block a user