mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-03-25 09:25:50 +00:00
175 lines
No EOL
4.9 KiB
TypeScript
175 lines
No EOL
4.9 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as net from 'net';
|
|
import * as path from 'path';
|
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
import {
|
|
type GitFollowRequest,
|
|
type GitFollowResponse,
|
|
MessageBuilder,
|
|
MessageParser,
|
|
MessageType,
|
|
type StatusResponse,
|
|
} from './pty/socket-protocol.js';
|
|
|
|
describe('API Socket Integration Tests', () => {
|
|
const testSocketPath = path.join(process.env.HOME || '/tmp', '.vibetunnel-test', 'api.sock');
|
|
let server: net.Server;
|
|
|
|
beforeAll(async () => {
|
|
// Create test socket directory
|
|
const socketDir = path.dirname(testSocketPath);
|
|
if (!fs.existsSync(socketDir)) {
|
|
fs.mkdirSync(socketDir, { recursive: true });
|
|
}
|
|
|
|
// Clean up any existing socket
|
|
try {
|
|
fs.unlinkSync(testSocketPath);
|
|
} catch (_error) {
|
|
// Ignore
|
|
}
|
|
|
|
// Create a simple test server
|
|
server = net.createServer((socket) => {
|
|
const parser = new MessageParser();
|
|
|
|
socket.on('data', (data) => {
|
|
parser.addData(data);
|
|
|
|
for (const message of parser.parseMessages()) {
|
|
switch (message.type) {
|
|
case MessageType.STATUS_REQUEST:
|
|
const statusResponse: StatusResponse = {
|
|
running: true,
|
|
port: 4020,
|
|
url: 'http://localhost:4020',
|
|
followMode: {
|
|
enabled: true,
|
|
branch: 'main',
|
|
repoPath: '/test/repo',
|
|
},
|
|
};
|
|
socket.write(MessageBuilder.statusResponse(statusResponse));
|
|
break;
|
|
|
|
case MessageType.GIT_FOLLOW_REQUEST:
|
|
const request = JSON.parse(message.payload.toString()) as GitFollowRequest;
|
|
const followResponse: GitFollowResponse = {
|
|
success: true,
|
|
currentBranch: request.branch,
|
|
};
|
|
socket.write(MessageBuilder.gitFollowResponse(followResponse));
|
|
break;
|
|
|
|
case MessageType.GIT_EVENT_NOTIFY:
|
|
socket.write(MessageBuilder.gitEventAck({ handled: true }));
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
await new Promise<void>((resolve) => {
|
|
server.listen(testSocketPath, resolve);
|
|
});
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await new Promise<void>((resolve) => {
|
|
server.close(() => resolve());
|
|
});
|
|
|
|
// Clean up socket file
|
|
try {
|
|
fs.unlinkSync(testSocketPath);
|
|
} catch (_error) {
|
|
// Ignore
|
|
}
|
|
});
|
|
|
|
it('should handle status request', async () => {
|
|
const response = await sendMessageAndGetResponse(
|
|
testSocketPath,
|
|
MessageBuilder.statusRequest()
|
|
);
|
|
|
|
expect(response.type).toBe(MessageType.STATUS_RESPONSE);
|
|
const status = response.payload as StatusResponse;
|
|
expect(status.running).toBe(true);
|
|
expect(status.port).toBe(4020);
|
|
expect(status.url).toBe('http://localhost:4020');
|
|
expect(status.followMode).toEqual({
|
|
enabled: true,
|
|
branch: 'main',
|
|
repoPath: '/test/repo',
|
|
});
|
|
});
|
|
|
|
it('should handle follow mode request', async () => {
|
|
const request: GitFollowRequest = {
|
|
repoPath: '/test/repo',
|
|
branch: 'feature-branch',
|
|
enable: true,
|
|
};
|
|
|
|
const response = await sendMessageAndGetResponse(
|
|
testSocketPath,
|
|
MessageBuilder.gitFollowRequest(request)
|
|
);
|
|
|
|
expect(response.type).toBe(MessageType.GIT_FOLLOW_RESPONSE);
|
|
const followResponse = response.payload as GitFollowResponse;
|
|
expect(followResponse.success).toBe(true);
|
|
expect(followResponse.currentBranch).toBe('feature-branch');
|
|
});
|
|
|
|
it('should handle git event notification', async () => {
|
|
const response = await sendMessageAndGetResponse(
|
|
testSocketPath,
|
|
MessageBuilder.gitEventNotify({
|
|
repoPath: '/test/repo',
|
|
type: 'checkout',
|
|
})
|
|
);
|
|
|
|
expect(response.type).toBe(MessageType.GIT_EVENT_ACK);
|
|
const ack = response.payload as { handled: boolean };
|
|
expect(ack.handled).toBe(true);
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Helper function to send a message and get response
|
|
*/
|
|
async function sendMessageAndGetResponse(
|
|
socketPath: string,
|
|
message: Buffer
|
|
): Promise<{ type: MessageType; payload: any }> {
|
|
return new Promise((resolve, reject) => {
|
|
const client = net.createConnection(socketPath);
|
|
const parser = new MessageParser();
|
|
|
|
client.on('connect', () => {
|
|
client.write(message);
|
|
});
|
|
|
|
client.on('data', (data) => {
|
|
parser.addData(data);
|
|
for (const msg of parser.parseMessages()) {
|
|
client.end();
|
|
resolve({
|
|
type: msg.type,
|
|
payload: JSON.parse(msg.payload.toString('utf8')),
|
|
});
|
|
}
|
|
});
|
|
|
|
client.on('error', reject);
|
|
|
|
// Timeout after 2 seconds
|
|
setTimeout(() => {
|
|
client.destroy();
|
|
reject(new Error('Response timeout'));
|
|
}, 2000);
|
|
});
|
|
} |