Skip to content

Commit

Permalink
Merge pull request #3247 from ai16z-demirix/tests/plugin-conflux
Browse files Browse the repository at this point in the history
feat (chore) plugin conflux: test config and coverage
  • Loading branch information
shakkernerd authored Feb 5, 2025
2 parents 89fa5a4 + 934d6b2 commit ac823d7
Show file tree
Hide file tree
Showing 5 changed files with 390 additions and 2 deletions.
191 changes: 191 additions & 0 deletions packages/plugin-conflux/__tests__/actions/bridgeTransfer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { bridgeTransfer } from '../../src/actions/bridgeTransfer';
import {
type IAgentRuntime,
type Memory,
ModelClass,
ModelProviderName,
type State,
type HandlerCallback,
} from '@elizaos/core';
import * as core from '@elizaos/core';
import { createPublicClient, createWalletClient, encodeFunctionData } from 'cive';
import { hexAddressToBase32 } from 'cive/utils';

// Mock generateObject
vi.mock('@elizaos/core', async () => {
const actual = await vi.importActual('@elizaos/core');
return {
...actual,
generateObject: vi.fn().mockResolvedValue({
object: {
to: '0x119DA8bbe74B1C5c987D0c64D10eC1dB301d4752',
amount: 1
}
}),
};
});

// Mock cive functions
vi.mock('cive', () => ({
createPublicClient: vi.fn(() => ({
getChainId: vi.fn().mockResolvedValue(1),
})),
createWalletClient: vi.fn(() => ({
sendTransaction: vi.fn().mockResolvedValue('0x123'),
})),
http: vi.fn(),
parseCFX: vi.fn().mockReturnValue(BigInt(1000000000000000000)), // 1 CFX
encodeFunctionData: vi.fn().mockReturnValue('0x123456'),
}));

vi.mock('cive/accounts', () => ({
privateKeyToAccount: vi.fn().mockReturnValue({
address: '0x123',
signTransaction: vi.fn(),
}),
}));

vi.mock('cive/utils', () => ({
hexAddressToBase32: vi.fn().mockReturnValue('cfxtest:test-address'),
}));

describe('bridgeTransfer action', () => {
const mockRuntime: IAgentRuntime = {
getSetting: vi.fn((key: string) => {
switch (key) {
case 'CONFLUX_CORE_PRIVATE_KEY':
return '0x1234567890abcdef';
case 'CONFLUX_CORE_SPACE_RPC_URL':
return 'https://test.confluxrpc.com';
default:
return undefined;
}
}),
composeState: vi.fn().mockResolvedValue({}),
updateRecentMessageState: vi.fn().mockResolvedValue({}),
generateText: vi.fn(),
model: {
[ModelClass.SMALL]: {
name: 'gpt-4',
maxInputTokens: 128000,
maxOutputTokens: 8192,
frequency_penalty: 0.0,
presence_penalty: 0.0,
temperature: 0.6,
stop: [],
},
[ModelClass.MEDIUM]: {
name: 'gpt-4',
maxInputTokens: 128000,
maxOutputTokens: 8192,
frequency_penalty: 0.0,
presence_penalty: 0.0,
temperature: 0.6,
stop: [],
},
[ModelClass.LARGE]: {
name: 'gpt-4',
maxInputTokens: 128000,
maxOutputTokens: 8192,
frequency_penalty: 0.0,
presence_penalty: 0.0,
temperature: 0.6,
stop: [],
}
},
modelProvider: ModelProviderName.OPENAI,
};

const mockMessage: Memory = {
content: {
text: 'Send 1 CFX to eSpace Address 0x119DA8bbe74B1C5c987D0c64D10eC1dB301d4752',
},
};

const mockCallback: HandlerCallback = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
});

it('should validate successfully', async () => {
const result = await bridgeTransfer.validate(mockRuntime, mockMessage);
expect(result).toBe(true);
});

it('should handle successful bridge transfer', async () => {
const result = await bridgeTransfer.handler(
mockRuntime,
mockMessage,
undefined,
undefined,
mockCallback
);

expect(result).toBe(true);
expect(mockCallback).toHaveBeenCalledWith({
text: expect.stringContaining('1 CFX sent to 0x119DA8bbe74B1C5c987D0c64D10eC1dB301d4752'),
content: {
to: '0x119DA8bbe74B1C5c987D0c64D10eC1dB301d4752',
amount: 1
}
});
});

it('should handle bridge transfer with existing state', async () => {
const mockState = {};
const result = await bridgeTransfer.handler(
mockRuntime,
mockMessage,
mockState,
undefined,
mockCallback
);

expect(result).toBe(true);
expect(mockRuntime.updateRecentMessageState).toHaveBeenCalledWith(mockState);
});

it('should handle invalid content generation', async () => {
vi.mocked(core.generateObject).mockRejectedValueOnce(new Error('Invalid content'));
await expect(
bridgeTransfer.handler(mockRuntime, mockMessage)
).rejects.toThrow('Invalid content');
});

it('should handle bridge transfer failure', async () => {
const mockError = new Error('Bridge transfer failed');
vi.mocked(createWalletClient).mockImplementationOnce(() => ({
sendTransaction: vi.fn().mockRejectedValue(mockError),
}));

const result = await bridgeTransfer.handler(
mockRuntime,
mockMessage,
undefined,
undefined,
mockCallback
);

expect(result).toBe(false);
expect(mockCallback).toHaveBeenCalledWith({
text: expect.stringContaining('Failed to send 1 CFX to 0x119DA8bbe74B1C5c987D0c64D10eC1dB301d4752'),
});
});

it('should use correct cross-space call contract address', async () => {
await bridgeTransfer.handler(
mockRuntime,
mockMessage,
undefined,
undefined,
mockCallback
);

expect(hexAddressToBase32).toHaveBeenCalledWith({
hexAddress: '0x0888000000000000000000000000000000000006',
networkId: 1,
});
});
});
175 changes: 175 additions & 0 deletions packages/plugin-conflux/__tests__/actions/transfer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { transfer } from '../../src/actions/transfer';
import {
ModelClass,
ModelProviderName,
type IAgentRuntime,
type Memory,
type State,
type HandlerCallback
} from '@elizaos/core';
import * as core from '@elizaos/core';
import { createPublicClient, createWalletClient } from 'cive';

// Mock generateObject
vi.mock('@elizaos/core', async () => {
const actual = await vi.importActual('@elizaos/core');
return {
...actual,
generateObject: vi.fn().mockResolvedValue({
object: {
to: 'cfxtest:test-address',
amount: 1
}
}),
};
});

// Mock cive functions
vi.mock('cive', () => ({
createPublicClient: vi.fn(() => ({
getChainId: vi.fn().mockResolvedValue(1),
waitForTransactionReceipt: vi.fn().mockResolvedValue({}),
})),
createWalletClient: vi.fn(() => ({
sendTransaction: vi.fn().mockResolvedValue('0x123'),
})),
privateKeyToAccount: vi.fn().mockReturnValue({
address: '0x123',
}),
http: vi.fn(),
parseCFX: vi.fn().mockReturnValue(BigInt(1)),
testnet: {},
}));

vi.mock('cive/accounts', () => ({
privateKeyToAccount: vi.fn().mockReturnValue({
address: '0x123',
signTransaction: vi.fn(),
}),
}));

describe('transfer action', () => {
const mockRuntime: IAgentRuntime = {
getSetting: vi.fn((key: string) => {
switch (key) {
case 'CONFLUX_CORE_PRIVATE_KEY':
return '0x1234567890abcdef';
case 'CONFLUX_CORE_SPACE_RPC_URL':
return 'https://test.confluxrpc.com';
default:
return undefined;
}
}),
composeState: vi.fn().mockResolvedValue({}),
updateRecentMessageState: vi.fn().mockResolvedValue({}),
generateText: vi.fn(),
model: {
[ModelClass.SMALL]: {
name: 'gpt-4',
maxInputTokens: 128000,
maxOutputTokens: 8192,
frequency_penalty: 0.0,
presence_penalty: 0.0,
temperature: 0.6,
stop: [],
},
[ModelClass.MEDIUM]: {
name: 'gpt-4',
maxInputTokens: 128000,
maxOutputTokens: 8192,
frequency_penalty: 0.0,
presence_penalty: 0.0,
temperature: 0.6,
stop: [],
},
[ModelClass.LARGE]: {
name: 'gpt-4',
maxInputTokens: 128000,
maxOutputTokens: 8192,
frequency_penalty: 0.0,
presence_penalty: 0.0,
temperature: 0.6,
stop: [],
}
},
modelProvider: ModelProviderName.OPENAI,
};

const mockMessage: Memory = {
content: {
text: 'Send 1 CFX to cfxtest:test-address',
},
};

const mockCallback: HandlerCallback = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
});

it('should validate successfully', async () => {
const result = await transfer.validate(mockRuntime, mockMessage);
expect(result).toBe(true);
});

it('should handle successful transfer', async () => {
const result = await transfer.handler(
mockRuntime,
mockMessage,
undefined,
undefined,
mockCallback
);

expect(result).toBe(true);
expect(mockCallback).toHaveBeenCalledWith({
text: '1 CFX sent to cfxtest:test-address: 0x123',
content: {
to: 'cfxtest:test-address',
amount: 1
}
});
});

it('should handle transfer with existing state', async () => {
const mockState = {};
const result = await transfer.handler(
mockRuntime,
mockMessage,
mockState,
undefined,
mockCallback
);

expect(result).toBe(true);
expect(mockRuntime.updateRecentMessageState).toHaveBeenCalledWith(mockState);
});

it('should handle invalid content generation', async () => {
vi.mocked(core.generateObject).mockRejectedValueOnce(new Error('Invalid content'));
await expect(
transfer.handler(mockRuntime, mockMessage)
).rejects.toThrow('Invalid content');
});

it('should handle transfer failure', async () => {
const mockError = new Error('Transfer failed');
vi.mocked(createWalletClient).mockImplementationOnce(() => ({
sendTransaction: vi.fn().mockRejectedValue(mockError),
}));

const result = await transfer.handler(
mockRuntime,
mockMessage,
undefined,
undefined,
mockCallback
);

expect(result).toBe(false);
expect(mockCallback).toHaveBeenCalledWith({
text: expect.stringContaining('Failed to send 1 CFX to cfxtest:test-address'),
});
});
});
10 changes: 10 additions & 0 deletions packages/plugin-conflux/__tests__/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { vi } from 'vitest';
// Mock console methods to avoid cluttering test output
global.console = {
...console,
log: vi.fn(),
error: vi.fn(),
warn: vi.fn(),
info: vi.fn(),
debug: vi.fn(),
};
6 changes: 4 additions & 2 deletions packages/plugin-conflux/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"cive": "0.7.1"
},
"devDependencies": {
"@biomejs/biome": "1.9.4"
"@biomejs/biome": "1.9.4",
"vitest": "1.4.0"
},
"scripts": {
"build": "tsup --format esm --dts",
Expand All @@ -32,6 +33,7 @@
"lint": "biome lint .",
"lint:fix": "biome check --apply .",
"format": "biome format .",
"format:fix": "biome format --write ."
"format:fix": "biome format --write .",
"test": "vitest run"
}
}
Loading

0 comments on commit ac823d7

Please sign in to comment.