@clduab11/gemini-flow
Version:
Revolutionary AI agent swarm coordination platform with Google Services integration, multimedia processing, and production-ready monitoring. Features 8 Google AI services, quantum computing capabilities, and enterprise-grade security.
348 lines (292 loc) • 11 kB
text/typescript
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
import { VertexAIConnector } from '../../../src/core/vertex-ai-connector';
import type { VertexAIConfig, VertexRequest } from '../../../src/core/vertex-ai-connector';
// Mock Google Cloud AI Platform
jest.mock('@google-cloud/aiplatform', () => ({
VertexAI: jest.fn().mockImplementation(() => ({
getGenerativeModel: jest.fn().mockReturnValue({
generateContent: jest.fn().mockResolvedValue({
response: {
text: () => 'Vertex AI response',
usageMetadata: {
promptTokenCount: 100,
candidatesTokenCount: 50,
totalTokenCount: 150
}
}
})
})
}))
}));
// Mock Google Auth Library
jest.mock('google-auth-library', () => ({
GoogleAuth: jest.fn().mockImplementation(() => ({
getClient: jest.fn().mockResolvedValue({
getAccessToken: jest.fn().mockResolvedValue('mock-access-token')
})
}))
}));
describe('VertexAIConnector', () => {
let connector: VertexAIConnector;
const config: VertexAIConfig = {
projectId: 'test-project',
location: 'us-central1',
apiEndpoint: 'https://us-central1-aiplatform.googleapis.com',
maxConcurrentRequests: 5,
requestTimeout: 30000
};
beforeEach(() => {
connector = new VertexAIConnector(config);
jest.clearAllMocks();
});
describe('initialization', () => {
it('should initialize Vertex AI client successfully', (done) => {
connector.on('initialized', () => {
expect(connector).toBeDefined();
done();
});
});
it('should load available models', async () => {
// Wait for initialization
await new Promise(resolve => connector.on('initialized', resolve));
const models = connector.getAvailableModels();
expect(models.length).toBeGreaterThan(0);
expect(models.some(m => m.name === 'gemini-1.5-pro')).toBe(true);
expect(models.some(m => m.name === 'gemini-1.5-flash')).toBe(true);
});
});
describe('model management', () => {
it('should get model configuration', () => {
const modelConfig = connector.getModelConfig('gemini-1.5-pro');
expect(modelConfig).toMatchObject({
name: 'gemini-1.5-pro',
publisher: 'google',
inputTokenLimit: 1000000,
supportsBatch: true,
supportsStreaming: true
});
});
it('should check model capabilities', () => {
expect(connector.supportsCapability('gemini-1.5-pro', 'multimodal')).toBe(true);
expect(connector.supportsCapability('gemini-1.5-pro', 'long-context')).toBe(true);
expect(connector.supportsCapability('gemini-1.0-pro', 'fast')).toBe(false);
});
});
describe('prediction', () => {
it('should execute single prediction successfully', async () => {
const request: VertexRequest = {
model: 'gemini-1.5-flash',
instances: ['Test prompt'],
parameters: {
temperature: 0.7,
maxOutputTokens: 100
}
};
const response = await connector.predict(request);
expect(response.predictions).toHaveLength(1);
expect(response.predictions[0]).toEqual({ content: 'Vertex AI response' });
expect(response.metadata.tokenUsage).toEqual({
input: 100,
output: 50,
total: 150
});
expect(response.metadata.cost).toBeGreaterThan(0);
});
it('should handle model not available error', async () => {
const request: VertexRequest = {
model: 'non-existent-model',
instances: ['Test']
};
await expect(connector.predict(request)).rejects.toThrow('Model not available');
});
it('should cache successful responses', async () => {
const request: VertexRequest = {
model: 'gemini-1.5-flash',
instances: ['Cached prompt']
};
// First call
const response1 = await connector.predict(request);
// Second call (should be cached)
const response2 = await connector.predict(request);
// Check that responses are identical (indicating cache hit)
expect(response1.predictions).toEqual(response2.predictions);
});
it('should handle concurrent request limits', async () => {
const requests = Array(10).fill(null).map((_, i) => ({
model: 'gemini-1.5-flash',
instances: [`Concurrent test ${i}`]
}));
// Should queue requests beyond max concurrent
const promises = requests.map(req => connector.predict(req));
const results = await Promise.all(promises);
expect(results).toHaveLength(10);
results.forEach(result => {
expect(result.predictions).toHaveLength(1);
});
});
});
describe('batch prediction', () => {
it('should execute batch prediction with chunking', async () => {
const instances = Array(25).fill(null).map((_, i) => `Batch prompt ${i}`);
const response = await connector.batchPredict(
'gemini-1.5-pro',
instances,
{ temperature: 0.5 },
10 // chunk size
);
expect(response.predictions).toHaveLength(25);
expect(response.metadata.tokenUsage.total).toBeGreaterThan(0);
});
it('should reject batch prediction for unsupported models', async () => {
// Mock a model that doesn't support batch
const modelConfig = connector.getModelConfig('gemini-1.0-pro');
if (modelConfig) {
modelConfig.supportsBatch = false;
}
await expect(
connector.batchPredict('gemini-1.0-pro', ['test'])
).rejects.toThrow('does not support batch processing');
});
});
describe('streaming prediction', () => {
it('should stream predictions for supported models', async () => {
const chunks = [];
for await (const chunk of connector.streamPredict('gemini-1.5-flash', 'Stream test')) {
chunks.push(chunk);
}
expect(chunks).toHaveLength(1);
expect(chunks[0]).toEqual({ content: 'Vertex AI response' });
});
it('should reject streaming for unsupported models', async () => {
expect(() =>
connector.streamPredict('gemini-1.0-pro', 'Stream test')
).rejects.toThrow('does not support streaming');
});
});
describe('performance monitoring', () => {
it('should track request metrics', async () => {
await connector.predict({
model: 'gemini-1.5-flash',
instances: ['Test metrics']
});
const metrics = connector.getMetrics();
expect(metrics.totalRequests).toBe(1);
expect(metrics.successfulRequests).toBe(1);
expect(metrics.failedRequests).toBe(0);
expect(metrics.avgLatency).toBeGreaterThan(0);
expect(metrics.successRate).toBe(1);
});
it('should emit events for request lifecycle', (done) => {
let eventCount = 0;
connector.on('request_completed', (data) => {
expect(data.success).toBe(true);
expect(data.model).toBe('gemini-1.5-flash');
eventCount++;
if (eventCount === 1) done();
});
connector.predict({
model: 'gemini-1.5-flash',
instances: ['Event test']
});
});
it('should track failed requests', async () => {
// Mock a failure
const VertexAI = require('@google-cloud/aiplatform').VertexAI;
VertexAI.mockImplementationOnce(() => ({
getGenerativeModel: jest.fn().mockReturnValue({
generateContent: jest.fn().mockRejectedValue(new Error('API Error'))
})
}));
const failingConnector = new VertexAIConnector(config);
try {
await failingConnector.predict({
model: 'gemini-1.5-flash',
instances: ['Fail test']
});
} catch (error) {
// Expected to fail
}
const metrics = failingConnector.getMetrics();
expect(metrics.failedRequests).toBe(1);
});
});
describe('health check', () => {
it('should report healthy status', async () => {
const health = await connector.healthCheck();
expect(health.status).toBe('healthy');
expect(health.latency).toBeGreaterThan(0);
expect(health.error).toBeUndefined();
});
it('should report unhealthy status on error', async () => {
// Mock a failure
const VertexAI = require('@google-cloud/aiplatform').VertexAI;
VertexAI.mockImplementationOnce(() => ({
getGenerativeModel: jest.fn().mockReturnValue({
generateContent: jest.fn().mockRejectedValue(new Error('Health check failed'))
})
}));
const unhealthyConnector = new VertexAIConnector(config);
const health = await unhealthyConnector.healthCheck();
expect(health.status).toBe('unhealthy');
expect(health.error).toBe('Health check failed');
});
});
describe('cost calculation', () => {
it('should calculate costs based on model and token usage', async () => {
const models = ['gemini-1.5-pro', 'gemini-1.5-flash', 'gemini-1.0-pro'];
for (const model of models) {
const response = await connector.predict({
model,
instances: ['Cost test']
});
expect(response.metadata.cost).toBeGreaterThan(0);
// Flash should be cheaper than Pro
if (model === 'gemini-1.5-flash') {
const proResponse = await connector.predict({
model: 'gemini-1.5-pro',
instances: ['Cost test']
});
expect(response.metadata.cost).toBeLessThan(proResponse.metadata.cost);
}
}
});
});
describe('request formatting', () => {
it('should format different instance types correctly', async () => {
const testCases = [
'Simple string',
{ prompt: 'Object with prompt' },
{ text: 'Object with text' },
{ complex: 'data', nested: { value: 123 } }
];
for (const testCase of testCases) {
const response = await connector.predict({
model: 'gemini-1.5-flash',
instances: [testCase]
});
expect(response.predictions).toHaveLength(1);
}
});
});
describe('cache management', () => {
it('should include cache statistics in metrics', async () => {
// Make a cached request
const request: VertexRequest = {
model: 'gemini-1.5-flash',
instances: ['Cache stats test']
};
await connector.predict(request);
await connector.predict(request); // Should hit cache
const metrics = connector.getMetrics();
expect(metrics.cacheStats).toBeDefined();
expect(metrics.cacheStats.hits).toBeGreaterThan(0);
});
});
describe('shutdown', () => {
it('should shutdown cleanly', () => {
const logSpy = jest.spyOn(connector['logger'], 'info');
connector.shutdown();
expect(logSpy).toHaveBeenCalledWith('Vertex AI connector shutdown');
});
});
});