From 08dd74ba65aa2d7113664f899cd29745876e4070 Mon Sep 17 00:00:00 2001 From: Sayo Date: Tue, 11 Feb 2025 21:55:36 +0530 Subject: [PATCH] add tests (#3445) --- .../__tests__/sqlite-adapter.test.ts | 337 +++++++++++++++++- 1 file changed, 331 insertions(+), 6 deletions(-) diff --git a/packages/plugin-sqlite/__tests__/sqlite-adapter.test.ts b/packages/plugin-sqlite/__tests__/sqlite-adapter.test.ts index 315228a31d7..e94a9607b35 100644 --- a/packages/plugin-sqlite/__tests__/sqlite-adapter.test.ts +++ b/packages/plugin-sqlite/__tests__/sqlite-adapter.test.ts @@ -1,14 +1,15 @@ -import type { UUID } from '@elizaos/core'; +import type { Account, Actor, Character, UUID } from '@elizaos/core'; +import { stringToUuid } from '@elizaos/core'; +import type { Database } from 'better-sqlite3'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { SqliteDatabaseAdapter } from '../src'; import { load } from '../src/sqlite_vec'; -import type { Database } from 'better-sqlite3'; // Mock the logger vi.mock('@elizaos/core', async () => { - const actual = await vi.importActual('@elizaos/core'); + const actual = await vi.importActual('@elizaos/core'); return { - ...actual as any, + ...actual, logger: { error: vi.fn() } @@ -20,9 +21,17 @@ vi.mock('../src/sqlite_vec', () => ({ load: vi.fn() })); + +interface MockDatabase { + prepare: ReturnType; + exec: ReturnType; + close: ReturnType; +} + describe('SqliteDatabaseAdapter', () => { let adapter: SqliteDatabaseAdapter; - let mockDb: any; + let mockDb: MockDatabase; + const testUuid = stringToUuid('test-character-id'); beforeEach(() => { // Create mock database methods @@ -38,7 +47,7 @@ describe('SqliteDatabaseAdapter', () => { }; // Initialize adapter with mock db - adapter = new SqliteDatabaseAdapter(mockDb as Database); + adapter = new SqliteDatabaseAdapter(mockDb as unknown as Database); }); afterEach(() => { @@ -168,4 +177,320 @@ describe('SqliteDatabaseAdapter', () => { expect(mockDb.close).toHaveBeenCalled(); }); }); + + describe('createAccount', () => { + it('should create an account successfully', async () => { + const runMock = vi.fn(); + mockDb.prepare.mockReturnValueOnce({ + run: runMock + }); + + const account: Account = { + id: 'test-id' as UUID, + name: 'Test User', + username: 'testuser', + email: 'test@example.com', + avatarUrl: 'https://example.com/avatar.png' + }; + + const result = await adapter.createAccount(account); + + expect(mockDb.prepare).toHaveBeenCalledWith( + 'INSERT INTO accounts (id, name, username, email, avatarUrl) VALUES (?, ?, ?, ?, ?)' + ); + expect(runMock).toHaveBeenCalledWith( + account.id, + account.name, + account.username, + account.email, + account.avatarUrl + ); + expect(result).toBe(true); + }); + + it('should handle errors when creating account', async () => { + mockDb.prepare.mockReturnValueOnce({ + run: vi.fn().mockImplementationOnce(() => { + throw new Error('Database error'); + }) + }); + + const account: Account = { + id: 'test-id' as UUID, + name: 'Test User', + username: 'testuser', + email: 'test@example.com', + avatarUrl: 'https://example.com/avatar.png' + }; + + const result = await adapter.createAccount(account); + expect(result).toBe(false); + }); + }); + + describe('getActorDetails', () => { + it('should return actor details', async () => { + const mockActors: Actor[] = [ + { id: 'actor-1' as UUID, name: 'Actor 1', username: 'actor1' }, + { id: 'actor-2' as UUID, name: 'Actor 2', username: 'actor2' } + ]; + + mockDb.prepare.mockReturnValueOnce({ + all: vi.fn().mockReturnValueOnce(mockActors) + }); + + const result = await adapter.getActorDetails({ roomId: 'room-1' as UUID }); + + expect(mockDb.prepare).toHaveBeenCalledWith(expect.stringContaining('SELECT a.id, a.name, a.username')); + expect(result).toEqual(mockActors); + }); + + it('should filter out null actors', async () => { + mockDb.prepare.mockReturnValueOnce({ + all: vi.fn().mockReturnValueOnce([null, { id: 'actor-1' as UUID, name: 'Actor 1', username: 'actor1' }, null]) + }); + + const result = await adapter.getActorDetails({ roomId: 'room-1' as UUID }); + + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ id: 'actor-1', name: 'Actor 1', username: 'actor1' }); + }); + }); + + describe('getMemoryById', () => { + it('should return memory when it exists', async () => { + const mockMemory = { + id: 'memory-1' as UUID, + content: JSON.stringify({ text: 'Test memory' }) + }; + + mockDb.prepare.mockReturnValueOnce({ + get: vi.fn().mockReturnValueOnce(mockMemory), + bind: vi.fn() + }); + + const result = await adapter.getMemoryById('memory-1' as UUID); + + expect(mockDb.prepare).toHaveBeenCalledWith('SELECT * FROM memories WHERE id = ?'); + expect(result).toEqual({ + ...mockMemory, + content: { text: 'Test memory' } + }); + }); + + it('should return null when memory does not exist', async () => { + mockDb.prepare.mockReturnValueOnce({ + get: vi.fn().mockReturnValueOnce(undefined), + bind: vi.fn() + }); + + const result = await adapter.getMemoryById('non-existent' as UUID); + expect(result).toBeNull(); + }); + }); + + describe('Character operations', () => { + const mockCharacter: Required> = { + id: testUuid, + name: 'Test Character', + bio: 'Test Bio', + lore: ['Test lore'], + messageExamples: [[]], + postExamples: ['Test post'], + topics: ['Test topic'], + adjectives: ['Test adjective'], + style: { + all: ['Test style'], + chat: ['Test chat style'], + post: ['Test post style'] + } + }; + + it('should create a character', async () => { + const runMock = vi.fn(); + mockDb.prepare.mockReturnValueOnce({ + run: runMock + }); + + await adapter.createCharacter(mockCharacter); + + expect(mockDb.prepare).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO characters')); + expect(runMock).toHaveBeenCalledWith( + mockCharacter.id, + mockCharacter.name, + mockCharacter.bio, + JSON.stringify(mockCharacter) + ); + }); + + it('should create a character with generated UUID', async () => { + const runMock = vi.fn(); + mockDb.prepare.mockReturnValueOnce({ + run: runMock + }); + + const characterWithoutId: Omit = { + name: mockCharacter.name, + bio: mockCharacter.bio, + lore: mockCharacter.lore, + messageExamples: mockCharacter.messageExamples, + postExamples: mockCharacter.postExamples, + topics: mockCharacter.topics, + adjectives: mockCharacter.adjectives, + style: mockCharacter.style + }; + + await adapter.createCharacter(characterWithoutId as Character); + + expect(mockDb.prepare).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO characters')); + expect(runMock).toHaveBeenCalledWith( + expect.any(String), + characterWithoutId.name, + characterWithoutId.bio, + expect.any(String) + ); + }); + + it('should update a character', async () => { + const runMock = vi.fn(); + mockDb.prepare.mockReturnValueOnce({ + run: runMock + }); + + await adapter.updateCharacter(mockCharacter); + + expect(mockDb.prepare).toHaveBeenCalledWith(expect.stringContaining('UPDATE characters')); + expect(runMock).toHaveBeenCalledWith( + mockCharacter.name, + mockCharacter.bio, + JSON.stringify(mockCharacter), + mockCharacter.id + ); + }); + + it('should get a character', async () => { + mockDb.prepare.mockReturnValueOnce({ + get: vi.fn().mockReturnValueOnce(mockCharacter) + }); + + const result = await adapter.getCharacter(mockCharacter.id); + + expect(mockDb.prepare).toHaveBeenCalledWith('SELECT * FROM characters WHERE id = ?'); + expect(result).toEqual(mockCharacter); + }); + + it('should return null when getting non-existent character', async () => { + mockDb.prepare.mockReturnValueOnce({ + get: vi.fn().mockReturnValueOnce(null) + }); + + const result = await adapter.getCharacter(testUuid); + + expect(mockDb.prepare).toHaveBeenCalledWith('SELECT * FROM characters WHERE id = ?'); + expect(result).toBeNull(); + }); + + it('should remove a character', async () => { + const runMock = vi.fn(); + mockDb.prepare.mockReturnValueOnce({ + run: runMock + }); + + await adapter.removeCharacter(mockCharacter.id); + + expect(mockDb.prepare).toHaveBeenCalledWith('DELETE FROM characters WHERE id = ?'); + expect(runMock).toHaveBeenCalledWith(mockCharacter.id); + }); + + it('should list all characters', async () => { + const mockCharacters = [mockCharacter]; + mockDb.prepare.mockReturnValueOnce({ + all: vi.fn().mockReturnValueOnce(mockCharacters) + }); + + const result = await adapter.listCharacters(); + + expect(mockDb.prepare).toHaveBeenCalledWith('SELECT * FROM characters'); + expect(result).toEqual(mockCharacters); + }); + + it('should import a character', async () => { + const runMock = vi.fn(); + mockDb.prepare.mockReturnValueOnce({ + run: runMock + }); + + await adapter.importCharacter(mockCharacter); + + expect(mockDb.prepare).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO characters')); + expect(runMock).toHaveBeenCalledWith( + mockCharacter.id, + mockCharacter.name, + mockCharacter.bio, + JSON.stringify(mockCharacter) + ); + }); + + it('should export a character', async () => { + mockDb.prepare.mockReturnValueOnce({ + get: vi.fn().mockReturnValueOnce(mockCharacter) + }); + + const result = await adapter.exportCharacter(mockCharacter.id); + + expect(mockDb.prepare).toHaveBeenCalledWith('SELECT * FROM characters WHERE id = ?'); + expect(result).toEqual(mockCharacter); + }); + }); + + describe('Cache operations', () => { + const mockParams = { + key: 'test-key', + agentId: 'agent-1' as UUID, + value: 'test-value' + }; + + it('should set cache value', async () => { + const runMock = vi.fn(); + mockDb.prepare.mockReturnValueOnce({ + run: runMock + }); + + const result = await adapter.setCache(mockParams); + + expect(mockDb.prepare).toHaveBeenCalledWith(expect.stringContaining('INSERT OR REPLACE INTO cache')); + expect(runMock).toHaveBeenCalledWith(mockParams.key, mockParams.agentId, mockParams.value); + expect(result).toBe(true); + }); + + it('should get cache value', async () => { + mockDb.prepare.mockReturnValueOnce({ + get: vi.fn().mockReturnValueOnce({ value: mockParams.value }) + }); + + const result = await adapter.getCache({ + key: mockParams.key, + agentId: mockParams.agentId + }); + + expect(mockDb.prepare).toHaveBeenCalledWith(expect.stringContaining('SELECT value FROM cache')); + expect(result).toBe(mockParams.value); + }); + + it('should delete cache value', async () => { + const runMock = vi.fn(); + mockDb.prepare.mockReturnValueOnce({ + run: runMock + }); + + const result = await adapter.deleteCache({ + key: mockParams.key, + agentId: mockParams.agentId + }); + + expect(mockDb.prepare).toHaveBeenCalledWith('DELETE FROM cache WHERE key = ? AND agentId = ?'); + expect(runMock).toHaveBeenCalledWith(mockParams.key, mockParams.agentId); + expect(result).toBe(true); + }); + }); });