Skip to content

Commit 36191b6

Browse files
authored
Merge branch 'develop' into logger-improvement
2 parents bdc7b83 + 8ab8be5 commit 36191b6

14 files changed

+473
-419
lines changed

.env.example

+4
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,10 @@ AWS_SECRET_ACCESS_KEY=
550550
AWS_REGION=
551551
AWS_S3_BUCKET=
552552
AWS_S3_UPLOAD_PATH=
553+
AWS_S3_ENDPOINT=
554+
AWS_S3_SSL_ENABLED=
555+
AWS_S3_FORCE_PATH_STYLE=
556+
553557

554558
# Deepgram
555559
DEEPGRAM_API_KEY=
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
import { validateGithubConfig, githubEnvSchema } from '../src/environment';
3+
import { IAgentRuntime } from '@elizaos/core';
4+
5+
describe('GitHub Environment Configuration', () => {
6+
const mockRuntime: IAgentRuntime = {
7+
getSetting: vi.fn(),
8+
} as unknown as IAgentRuntime;
9+
10+
it('validates correct GitHub configuration', async () => {
11+
const validConfig = {
12+
GITHUB_OWNER: 'testowner',
13+
GITHUB_REPO: 'testrepo',
14+
GITHUB_BRANCH: 'main',
15+
GITHUB_PATH: 'src',
16+
GITHUB_API_TOKEN: 'ghp_test123',
17+
};
18+
19+
vi.mocked(mockRuntime.getSetting).mockImplementation((key: string) => validConfig[key as keyof typeof validConfig]);
20+
21+
const config = await validateGithubConfig(mockRuntime);
22+
expect(config).toEqual(validConfig);
23+
});
24+
25+
it('throws error for missing configuration', async () => {
26+
const invalidConfig = {
27+
GITHUB_OWNER: '',
28+
GITHUB_REPO: '',
29+
GITHUB_BRANCH: '',
30+
GITHUB_PATH: '',
31+
GITHUB_API_TOKEN: '',
32+
};
33+
34+
vi.mocked(mockRuntime.getSetting).mockImplementation((key: string) => invalidConfig[key as keyof typeof invalidConfig]);
35+
36+
await expect(validateGithubConfig(mockRuntime)).rejects.toThrow();
37+
});
38+
39+
it('throws error for partial configuration', async () => {
40+
const partialConfig = {
41+
GITHUB_OWNER: 'testowner',
42+
GITHUB_REPO: 'testrepo',
43+
// Missing other required fields
44+
};
45+
46+
vi.mocked(mockRuntime.getSetting).mockImplementation((key: string) => partialConfig[key as keyof typeof partialConfig]);
47+
48+
await expect(validateGithubConfig(mockRuntime)).rejects.toThrow();
49+
});
50+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { describe, it, expect, vi, beforeEach } from 'vitest';
2+
import { GitHubClient, GitHubClientInterface } from '../src';
3+
import { AgentRuntime, IAgentRuntime } from '@elizaos/core';
4+
import { Octokit } from '@octokit/rest';
5+
import simpleGit from 'simple-git';
6+
import fs from 'fs';
7+
import fsPromises from 'fs/promises';
8+
9+
// Mock external dependencies
10+
vi.mock('@octokit/rest', () => ({
11+
Octokit: vi.fn(),
12+
}));
13+
14+
vi.mock('simple-git', () => ({
15+
default: vi.fn(() => ({
16+
clone: vi.fn(),
17+
pull: vi.fn(),
18+
checkout: vi.fn(),
19+
})),
20+
}));
21+
22+
vi.mock('fs/promises', async (importOriginal) => {
23+
const actual = await importOriginal() as typeof fsPromises;
24+
return {
25+
...actual,
26+
mkdir: vi.fn(),
27+
lstat: vi.fn(),
28+
readdir: vi.fn(),
29+
readFile: vi.fn(),
30+
writeFile: vi.fn(),
31+
};
32+
});
33+
34+
vi.mock('fs', async (importOriginal) => {
35+
const actual = await importOriginal() as typeof fs;
36+
return {
37+
...actual,
38+
existsSync: vi.fn(),
39+
realpathSync: vi.fn(),
40+
lstatSync: vi.fn(),
41+
readdirSync: vi.fn(),
42+
};
43+
});
44+
45+
describe('GitHubClient', () => {
46+
let mockRuntime: AgentRuntime;
47+
const mockConfig = {
48+
GITHUB_OWNER: 'testowner',
49+
GITHUB_REPO: 'testrepo',
50+
GITHUB_BRANCH: 'main',
51+
GITHUB_PATH: 'src',
52+
GITHUB_API_TOKEN: 'ghp_test123',
53+
};
54+
55+
beforeEach(() => {
56+
vi.clearAllMocks();
57+
mockRuntime = {
58+
getSetting: vi.fn((key: string) => mockConfig[key as keyof typeof mockConfig]),
59+
} as unknown as AgentRuntime;
60+
});
61+
62+
it('initializes with correct configuration', () => {
63+
const client = new GitHubClient(mockRuntime);
64+
expect(Octokit).toHaveBeenCalledWith({ auth: mockConfig.GITHUB_API_TOKEN });
65+
});
66+
67+
describe('GitHubClientInterface', () => {
68+
it('has start and stop methods', () => {
69+
expect(GitHubClientInterface.start).toBeDefined();
70+
expect(GitHubClientInterface.stop).toBeDefined();
71+
});
72+
73+
it('start method initializes client', async () => {
74+
const runtime = {
75+
getSetting: vi.fn((key: string) => mockConfig[key as keyof typeof mockConfig]),
76+
} as unknown as IAgentRuntime;
77+
78+
await GitHubClientInterface.start(runtime);
79+
// Add more specific assertions based on what start should do
80+
});
81+
82+
it('stop method cleans up resources', () => {
83+
const runtime = {} as IAgentRuntime;
84+
GitHubClientInterface.stop(runtime);
85+
// Add assertions for cleanup if needed
86+
});
87+
});
88+
});

packages/client-github/package.json

+5-2
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@
2727
},
2828
"devDependencies": {
2929
"@types/glob": "8.1.0",
30-
"tsup": "8.3.5"
30+
"tsup": "8.3.5",
31+
"vitest": "^1.2.1"
3132
},
3233
"scripts": {
3334
"build": "tsup --format esm --dts",
3435
"dev": "tsup --format esm --dts --watch",
35-
"lint": "eslint --fix --cache ."
36+
"lint": "eslint --fix --cache .",
37+
"test": "vitest run",
38+
"test:watch": "vitest"
3639
}
3740
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { describe, it, expect, vi, beforeEach } from 'vitest';
2+
import { MessageManager } from '../src/messages';
3+
import { WebClient } from '@slack/web-api';
4+
import { IAgentRuntime } from '@elizaos/core';
5+
6+
// Mock dependencies
7+
vi.mock('@slack/web-api');
8+
vi.mock('@elizaos/core');
9+
10+
describe('MessageManager', () => {
11+
let mockWebClient: WebClient;
12+
let mockRuntime: IAgentRuntime;
13+
let messageManager: MessageManager;
14+
const mockBotUserId = 'U123456';
15+
16+
beforeEach(() => {
17+
// Setup mock WebClient
18+
mockWebClient = {
19+
chat: {
20+
postMessage: vi.fn()
21+
}
22+
} as unknown as WebClient;
23+
24+
// Setup mock runtime
25+
mockRuntime = {
26+
getSetting: vi.fn(),
27+
character: {
28+
name: 'TestBot'
29+
}
30+
} as unknown as IAgentRuntime;
31+
32+
messageManager = new MessageManager(mockWebClient, mockRuntime, mockBotUserId);
33+
});
34+
35+
it('should initialize with correct parameters', () => {
36+
expect(messageManager).toBeDefined();
37+
});
38+
39+
it('should not process duplicate events', () => {
40+
const eventId = 'evt_123';
41+
const result1 = messageManager['processedEvents'].has(eventId);
42+
expect(result1).toBe(false);
43+
44+
// Add event to processed set
45+
messageManager['processedEvents'].add(eventId);
46+
const result2 = messageManager['processedEvents'].has(eventId);
47+
expect(result2).toBe(true);
48+
});
49+
50+
it('should handle message processing lock correctly', () => {
51+
const messageId = 'msg_123';
52+
const isLocked1 = messageManager['messageProcessingLock'].has(messageId);
53+
expect(isLocked1).toBe(false);
54+
55+
// Lock message
56+
messageManager['messageProcessingLock'].add(messageId);
57+
const isLocked2 = messageManager['messageProcessingLock'].has(messageId);
58+
expect(isLocked2).toBe(true);
59+
});
60+
61+
it('should clean up old processed messages', () => {
62+
vi.useFakeTimers();
63+
const oldMessageId = 'old_msg';
64+
const newMessageId = 'new_msg';
65+
66+
// Add messages with different timestamps
67+
messageManager['processedMessages'].set(oldMessageId, Date.now() - 3700000); // older than 1 hour
68+
messageManager['processedMessages'].set(newMessageId, Date.now()); // current
69+
70+
// Trigger cleanup by advancing time and running interval callback
71+
const cleanupInterval = setInterval(() => {
72+
const oneHourAgo = Date.now() - 3600000;
73+
for (const [key, timestamp] of messageManager['processedMessages'].entries()) {
74+
if (timestamp < oneHourAgo) {
75+
messageManager['processedMessages'].delete(key);
76+
}
77+
}
78+
}, 3600000);
79+
80+
vi.advanceTimersByTime(3600000);
81+
82+
// Check if old message was cleaned up
83+
expect(messageManager['processedMessages'].has(oldMessageId)).toBe(false);
84+
expect(messageManager['processedMessages'].has(newMessageId)).toBe(true);
85+
86+
clearInterval(cleanupInterval);
87+
vi.useRealTimers();
88+
});
89+
});

0 commit comments

Comments
 (0)