Skip to content

Commit 5fa14d9

Browse files
committed
test: add test cases and config
1 parent 6055a07 commit 5fa14d9

File tree

4 files changed

+233
-1
lines changed

4 files changed

+233
-1
lines changed

jest.config.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} **/
2+
module.exports = {
3+
preset: 'ts-jest',
4+
testEnvironment: "node",
5+
transform: {
6+
"^.+.tsx?$": ["ts-jest",{}],
7+
},
8+
collectCoverage: true,
9+
collectCoverageFrom: [
10+
'src/**/*.ts',
11+
'!src/**/*.test.ts',
12+
'!src/index.ts',
13+
'!**/node_modules/**',
14+
],
15+
coverageDirectory: 'coverage',
16+
coverageReporters: ['text', 'lcov'],
17+
};

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77
"build": "tsc",
88
"start": "node dist/index.js",
99
"lint": "eslint .",
10-
"dev": "nodemon --watch src --exec ts-node src/index.ts"
10+
"dev": "nodemon --watch src --exec ts-node src/index.ts",
11+
"test": "jest"
1112
},
1213
"author": "Nimisha G J",
1314
"license": "ISC",
1415
"devDependencies": {
1516
"@eslint/js": "^9.13.0",
17+
"@types/jest": "^29.5.14",
1618
"@types/node": "^22.7.5",
1719
"eslint": "^9.13.0",
1820
"globals": "^15.11.0",
21+
"jest": "^29.7.0",
1922
"nodemon": "^3.1.7",
23+
"ts-jest": "^29.2.5",
2024
"ts-node": "^10.9.2",
2125
"typescript": "^5.6.3",
2226
"typescript-eslint": "^8.11.0"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { MikroTikSSHClient } from '../lib/MikrotikSSHClient';
2+
import { executeSSHCommand } from '../utils/ssh';
3+
4+
jest.mock('../utils/ssh');
5+
6+
describe('MikroTikSSHClient', () => {
7+
const host = '192.168.1.1';
8+
const port = 22;
9+
const username = 'admin';
10+
const password = 'password';
11+
let client: MikroTikSSHClient;
12+
13+
beforeEach(() => {
14+
client = new MikroTikSSHClient(host, port, username, password);
15+
});
16+
17+
it('should execute a command successfully', async () => {
18+
const command = 'test command';
19+
(executeSSHCommand as jest.Mock).mockResolvedValue('command output');
20+
21+
const result = await client.executeCommand(command);
22+
23+
expect(result).toBe('command output');
24+
expect(executeSSHCommand).toHaveBeenCalledWith(command, host, port, username, password);
25+
});
26+
27+
it('should throw an error when the command fails', async () => {
28+
const command = 'test command';
29+
(executeSSHCommand as jest.Mock).mockRejectedValue(new Error('Command failed'));
30+
31+
await expect(client.executeCommand(command)).rejects.toThrow('Command failed');
32+
});
33+
});
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import { MikroTikWireGuardClientManager } from '../lib/MikroTikWireGuardClientManager';
2+
import { SSHClient } from '../lib/MikrotikSSHClient';
3+
import { AddClientResponse, RemoveClientResponse } from '../types/responses';
4+
import { PeerClient } from '../types/peerClient';
5+
6+
const mockSSHClient: SSHClient = {
7+
executeCommand: jest.fn(),
8+
};
9+
10+
describe('MikroTikWireGuardClientManager', () => {
11+
let manager: MikroTikWireGuardClientManager;
12+
13+
beforeEach(() => {
14+
manager = new MikroTikWireGuardClientManager(mockSSHClient);
15+
jest.spyOn(manager, 'listClients'); // Ensure that listClients is mocked
16+
});
17+
18+
it('should add a client successfully', async () => {
19+
const publicKey = 'testPublicKey';
20+
const comment = 'Test Comment';
21+
const mockIp = '192.168.1.2/24';
22+
23+
// Mock the methods
24+
(mockSSHClient.executeCommand as jest.Mock).mockResolvedValueOnce('output with public key');
25+
(manager as any).getNextAvailableIp = jest.fn().mockResolvedValue(mockIp);
26+
(manager as any).getWireGuardInterfaceInfo = jest.fn().mockResolvedValue({ publicKey: 'routerPublicKey', listenPort: 51820 });
27+
28+
const response: AddClientResponse = await manager.addClient(publicKey, comment);
29+
30+
expect(response.success).toBe(true);
31+
expect(response.message).toBe('VPN client added successfully');
32+
expect(response.config).toEqual({ clientAddress: mockIp, routerPublicKey: 'routerPublicKey', listenPort: 51820 });
33+
expect(mockSSHClient.executeCommand).toHaveBeenCalledWith(expect.stringContaining(comment));
34+
});
35+
36+
it('should fail to add a client and return an error message', async () => {
37+
const publicKey = 'testPublicKey';
38+
const comment = 'Test Comment';
39+
40+
(mockSSHClient.executeCommand as jest.Mock).mockRejectedValue(new Error('Command failed'));
41+
42+
const response: AddClientResponse = await manager.addClient(publicKey, comment);
43+
44+
expect(response.success).toBe(false);
45+
expect(response.message).toContain('VPN client added failed:Error: Error listing VPN clients');
46+
});
47+
48+
it('should remove a client successfully', async () => {
49+
const publicKey = 'testPublicKey';
50+
51+
(mockSSHClient.executeCommand as jest.Mock).mockResolvedValueOnce('output');
52+
53+
const response: RemoveClientResponse = await manager.removeClient(publicKey);
54+
55+
expect(response.success).toBe(true);
56+
expect(response.message).toBe('VPN client removed successfully');
57+
expect(mockSSHClient.executeCommand).toHaveBeenCalledWith(expect.stringContaining(publicKey));
58+
});
59+
60+
it('should fail to remove a client and return an error message', async () => {
61+
const publicKey = 'testPublicKey';
62+
63+
(mockSSHClient.executeCommand as jest.Mock).mockRejectedValue(new Error('Command failed'));
64+
65+
const response: RemoveClientResponse = await manager.removeClient(publicKey);
66+
67+
expect(response.success).toBe(false);
68+
expect(response.message).toContain('VPN client removal failed:Error: Command failed');
69+
});
70+
71+
// New test cases
72+
73+
it('should list clients successfully', async () => {
74+
const mockOutput = `
75+
index interface publicKey endpoint-port allowedIp
76+
;;; Test-Comment
77+
0 wg0 testPublicKey 0 192.168.1.2/24
78+
`;
79+
80+
(mockSSHClient.executeCommand as jest.Mock).mockResolvedValueOnce(mockOutput);
81+
82+
const clients: PeerClient[] = await manager.listClients();
83+
84+
expect(clients.length).toBe(2);
85+
expect(clients[1]).toEqual({
86+
index: '0',
87+
interface: 'wg0',
88+
publicKey: 'testPublicKey',
89+
allowedIp: '192.168.1.2/24',
90+
comment: 'Test-Comment',
91+
});
92+
});
93+
94+
it('should throw an error when listing clients fails', async () => {
95+
(mockSSHClient.executeCommand as jest.Mock).mockRejectedValue(new Error('Command failed'));
96+
97+
await expect(manager.listClients()).rejects.toThrow('Error listing VPN clients');
98+
});
99+
100+
it('should parse wireguard peers correctly', () => {
101+
const mockOutput = `
102+
index interface publicKey endpoint-port allowedIp
103+
;;; Test-Comment
104+
0 wg0 testPublicKey 0 192.168.1.2/24
105+
`;
106+
107+
const clients = manager['parseWireGuardPeers'](mockOutput);
108+
109+
expect(clients.length).toBe(2);
110+
expect(clients[1]).toEqual({
111+
index: '0',
112+
interface: 'wg0',
113+
publicKey: 'testPublicKey',
114+
allowedIp: '192.168.1.2/24',
115+
comment: 'Test-Comment',
116+
});
117+
});
118+
119+
it('should return an empty array if there are no clients to parse', () => {
120+
const mockOutput = '';
121+
122+
const clients = manager['parseWireGuardPeers'](mockOutput);
123+
124+
expect(clients.length).toBe(0);
125+
});
126+
127+
it('should get wireguard interface info successfully', async () => {
128+
const mockOutput = `
129+
Flags: X - disabled; R - running
130+
0 R name="wg0" mtu=1420 listen-port=51820 private-key="routerPrivateKey" public-key="routerPublicKey"
131+
`;
132+
133+
(mockSSHClient.executeCommand as jest.Mock).mockResolvedValueOnce(mockOutput);
134+
135+
const info = await manager['getWireGuardInterfaceInfo']();
136+
137+
expect(info).toEqual({ publicKey: 'routerPublicKey', listenPort: 51820 });
138+
});
139+
140+
it('should throw an error if the public key is missing', async () => {
141+
const mockOutput = `
142+
Listen Port: 51820
143+
`;
144+
145+
(mockSSHClient.executeCommand as jest.Mock).mockResolvedValueOnce(mockOutput);
146+
147+
await expect(manager['getWireGuardInterfaceInfo']()).rejects.toThrow('Failed to retrieve public-key from the WireGuard interface output');
148+
});
149+
150+
it('should throw an error if the listen port is missing', async () => {
151+
const mockOutput = `
152+
Flags: X - disabled; R - running
153+
0 R name="wg0" mtu=1420 private-key="routerPrivateKey" public-key="routerPublicKey"
154+
`;
155+
156+
(mockSSHClient.executeCommand as jest.Mock).mockResolvedValueOnce(mockOutput);
157+
158+
await expect(manager['getWireGuardInterfaceInfo']()).rejects.toThrow('Failed to retrieve listen-port from the WireGuard interface output');
159+
});
160+
161+
it('should get the next available IP successfully', async () => {
162+
const mockClients: PeerClient[] = [
163+
{ index: '0', interface: 'wg0', publicKey: 'testPublicKey', allowedIp: '192.168.1.2/24', comment: 'Test Comment' },
164+
{ index: '1', interface: 'wg0', publicKey: 'testPublicKey', allowedIp: '192.168.1.3/24', comment: 'Test Comment' },
165+
];
166+
167+
(manager.listClients as jest.Mock).mockResolvedValueOnce(mockClients);
168+
const nextIp = await manager['getNextAvailableIp']();
169+
170+
expect(nextIp).toBe('192.168.1.4/24');
171+
});
172+
173+
it('should throw an error when getting the next available IP if no clients are found', async () => {
174+
(manager.listClients as jest.Mock).mockResolvedValueOnce([]);
175+
176+
await expect(manager['getNextAvailableIp']()).rejects.toThrow('No valid IP addresses found from the clients.');
177+
});
178+
});

0 commit comments

Comments
 (0)