146 lines
4.7 KiB
TypeScript
146 lines
4.7 KiB
TypeScript
import { Test, TestingModule } from '@nestjs/testing';
|
|
import { HttpException, HttpStatus } from '@nestjs/common';
|
|
import { SandboxService } from '../sandbox.service';
|
|
import { PrismaService } from '../../../prisma/prisma.service';
|
|
import { AIGatewayService } from '../../ai/ai-gateway.service';
|
|
|
|
describe('SandboxService', () => {
|
|
let service: SandboxService;
|
|
let prisma: PrismaService;
|
|
let aiGateway: AIGatewayService;
|
|
|
|
const mockPrisma = {
|
|
user: {
|
|
findUnique: jest.fn(),
|
|
},
|
|
sandboxSession: {
|
|
findMany: jest.fn(),
|
|
findUnique: jest.fn(),
|
|
count: jest.fn(),
|
|
create: jest.fn(),
|
|
upsert: jest.fn(),
|
|
},
|
|
};
|
|
|
|
const mockAIGateway = {
|
|
chat: jest.fn(),
|
|
};
|
|
|
|
beforeEach(async () => {
|
|
const module: TestingModule = await Test.createTestingModule({
|
|
providers: [
|
|
SandboxService,
|
|
{ provide: PrismaService, useValue: mockPrisma },
|
|
{ provide: AIGatewayService, useValue: mockAIGateway },
|
|
],
|
|
}).compile();
|
|
|
|
service = module.get<SandboxService>(SandboxService);
|
|
prisma = module.get<PrismaService>(PrismaService);
|
|
aiGateway = module.get<AIGatewayService>(AIGatewayService);
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe('chat', () => {
|
|
it('should throw if user not found', async () => {
|
|
mockPrisma.user.findUnique.mockResolvedValue(null);
|
|
|
|
await expect(
|
|
service.chat(1, 'test-conv', 'gpt-3.5', [{ role: 'user', content: 'Hello' }])
|
|
).rejects.toThrow(HttpException);
|
|
});
|
|
|
|
it('should throw if user not active', async () => {
|
|
mockPrisma.user.findUnique.mockResolvedValue({ id: 1, status: 'INACTIVE' });
|
|
|
|
await expect(
|
|
service.chat(1, 'test-conv', 'gpt-3.5', [{ role: 'user', content: 'Hello' }])
|
|
).rejects.toThrow(HttpException);
|
|
});
|
|
|
|
it('should throw if daily quota exceeded for new conversation', async () => {
|
|
mockPrisma.user.findUnique.mockResolvedValue({
|
|
id: 1, status: 'ACTIVE', sandboxDaily: 10
|
|
});
|
|
mockPrisma.sandboxSession.findUnique.mockResolvedValue(null);
|
|
mockPrisma.sandboxSession.count.mockResolvedValue(10);
|
|
|
|
await expect(
|
|
service.chat(1, 'new-conv', 'gpt-3.5', [{ role: 'user', content: 'Hello' }])
|
|
).rejects.toThrow(HttpException);
|
|
});
|
|
|
|
it('should not count quota for existing conversation', async () => {
|
|
mockPrisma.user.findUnique.mockResolvedValue({
|
|
id: 1, status: 'ACTIVE', sandboxDaily: 10
|
|
});
|
|
mockPrisma.sandboxSession.findUnique.mockResolvedValue({ id: 1 });
|
|
mockAIGateway.chat.mockResolvedValue('AI回复');
|
|
mockPrisma.sandboxSession.upsert.mockResolvedValue({ id: 2 });
|
|
|
|
const result = await service.chat(1, 'existing-conv', 'gpt-3.5', [
|
|
{ role: 'user', content: 'Hello' }
|
|
]);
|
|
|
|
expect(result.reply).toBe('AI回复');
|
|
expect(mockPrisma.sandboxSession.count).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call AI gateway and save session', async () => {
|
|
mockPrisma.user.findUnique.mockResolvedValue({
|
|
id: 1, status: 'ACTIVE', sandboxDaily: 10
|
|
});
|
|
mockPrisma.sandboxSession.findUnique.mockResolvedValue(null);
|
|
mockPrisma.sandboxSession.count.mockResolvedValue(5);
|
|
mockAIGateway.chat.mockResolvedValue('AI回复');
|
|
mockPrisma.sandboxSession.upsert.mockResolvedValue({ id: 1 });
|
|
|
|
const result = await service.chat(1, 'test-conv', 'gpt-3.5', [
|
|
{ role: 'user', content: 'Hello' }
|
|
]);
|
|
|
|
expect(result.reply).toBe('AI回复');
|
|
expect(result.conversationId).toBe('test-conv');
|
|
expect(result.sessionId).toBeDefined();
|
|
expect(mockAIGateway.chat).toHaveBeenCalledWith('gpt-3.5', expect.any(Array), undefined);
|
|
expect(mockPrisma.sandboxSession.upsert).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('getHistory', () => {
|
|
it('should return paginated history', async () => {
|
|
const mockSessions = [
|
|
{ id: 1, conversationId: 'conv-1', model: 'gpt-3.5', title: 'Test', createdAt: new Date(), tokens: 10 }
|
|
];
|
|
mockPrisma.sandboxSession.findMany.mockResolvedValue(mockSessions);
|
|
mockPrisma.sandboxSession.count.mockResolvedValue(1);
|
|
|
|
const result = await service.getHistory(1, { page: 1, pageSize: 20 });
|
|
|
|
expect(result).toEqual({
|
|
items: mockSessions,
|
|
total: 1,
|
|
page: 1,
|
|
pageSize: 20,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getQuota', () => {
|
|
it('should return quota info', async () => {
|
|
mockPrisma.user.findUnique.mockResolvedValue({
|
|
id: 1, sandboxDaily: 10
|
|
});
|
|
mockPrisma.sandboxSession.count.mockResolvedValue(3);
|
|
|
|
const result = await service.getQuota(1);
|
|
|
|
expect(result).toEqual({
|
|
dailyLimit: 10,
|
|
used: 3,
|
|
remaining: 7,
|
|
});
|
|
});
|
|
});
|
|
});
|