mirror of
https://github.com/fosrl/pangolin.git
synced 2025-07-22 19:55:37 +02:00
Fix ip range pick initial range; add test
This commit is contained in:
parent
2ff6d1d117
commit
a418195b28
2 changed files with 196 additions and 6 deletions
183
server/lib/ip.test.ts
Normal file
183
server/lib/ip.test.ts
Normal file
|
@ -0,0 +1,183 @@
|
|||
import { cidrToRange, findNextAvailableCidr } from "./ip";
|
||||
|
||||
/**
|
||||
* Compares two objects for deep equality
|
||||
* @param actual The actual value to test
|
||||
* @param expected The expected value to compare against
|
||||
* @param message The message to display if assertion fails
|
||||
* @throws Error if objects are not equal
|
||||
*/
|
||||
export function assertEqualsObj<T>(actual: T, expected: T, message: string): void {
|
||||
const actualStr = JSON.stringify(actual);
|
||||
const expectedStr = JSON.stringify(expected);
|
||||
if (actualStr !== expectedStr) {
|
||||
throw new Error(`${message}\nExpected: ${expectedStr}\nActual: ${actualStr}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two primitive values for equality
|
||||
* @param actual The actual value to test
|
||||
* @param expected The expected value to compare against
|
||||
* @param message The message to display if assertion fails
|
||||
* @throws Error if values are not equal
|
||||
*/
|
||||
export function assertEquals<T>(actual: T, expected: T, message: string): void {
|
||||
if (actual !== expected) {
|
||||
throw new Error(`${message}\nExpected: ${expected}\nActual: ${actual}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a function throws an expected error
|
||||
* @param fn The function to test
|
||||
* @param expectedError The expected error message or part of it
|
||||
* @param message The message to display if assertion fails
|
||||
* @throws Error if function doesn't throw or throws unexpected error
|
||||
*/
|
||||
export function assertThrows(
|
||||
fn: () => void,
|
||||
expectedError: string,
|
||||
message: string
|
||||
): void {
|
||||
try {
|
||||
fn();
|
||||
throw new Error(`${message}: Expected to throw "${expectedError}"`);
|
||||
} catch (error) {
|
||||
if (!(error instanceof Error)) {
|
||||
throw new Error(`${message}\nUnexpected error type: ${typeof error}`);
|
||||
}
|
||||
|
||||
if (!error.message.includes(expectedError)) {
|
||||
throw new Error(
|
||||
`${message}\nExpected error: ${expectedError}\nActual error: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test cases
|
||||
function testFindNextAvailableCidr() {
|
||||
console.log("Running findNextAvailableCidr tests...");
|
||||
|
||||
// Test 1: Basic IPv4 allocation
|
||||
{
|
||||
const existing = ["10.0.0.0/16", "10.1.0.0/16"];
|
||||
const result = findNextAvailableCidr(existing, 16, "10.0.0.0/8");
|
||||
assertEquals(result, "10.2.0.0/16", "Basic IPv4 allocation failed");
|
||||
}
|
||||
|
||||
// Test 2: Finding gap between allocations
|
||||
{
|
||||
const existing = ["10.0.0.0/16", "10.2.0.0/16"];
|
||||
const result = findNextAvailableCidr(existing, 16, "10.0.0.0/8");
|
||||
assertEquals(result, "10.1.0.0/16", "Finding gap between allocations failed");
|
||||
}
|
||||
|
||||
// Test 3: No available space
|
||||
{
|
||||
const existing = ["10.0.0.0/8"];
|
||||
const result = findNextAvailableCidr(existing, 8, "10.0.0.0/8");
|
||||
assertEquals(result, null, "No available space test failed");
|
||||
}
|
||||
|
||||
// // Test 4: IPv6 allocation
|
||||
// {
|
||||
// const existing = ["2001:db8::/32", "2001:db8:1::/32"];
|
||||
// const result = findNextAvailableCidr(existing, 32, "2001:db8::/16");
|
||||
// assertEquals(result, "2001:db8:2::/32", "Basic IPv6 allocation failed");
|
||||
// }
|
||||
|
||||
// // Test 5: Mixed IP versions
|
||||
// {
|
||||
// const existing = ["10.0.0.0/16", "2001:db8::/32"];
|
||||
// assertThrows(
|
||||
// () => findNextAvailableCidr(existing, 16),
|
||||
// "All CIDRs must be of the same IP version",
|
||||
// "Mixed IP versions test failed"
|
||||
// );
|
||||
// }
|
||||
|
||||
// Test 6: Empty input
|
||||
{
|
||||
const existing: string[] = [];
|
||||
const result = findNextAvailableCidr(existing, 16);
|
||||
assertEquals(result, null, "Empty input test failed");
|
||||
}
|
||||
|
||||
// Test 7: Block size alignment
|
||||
{
|
||||
const existing = ["10.0.0.0/24"];
|
||||
const result = findNextAvailableCidr(existing, 24, "10.0.0.0/16");
|
||||
assertEquals(result, "10.0.1.0/24", "Block size alignment test failed");
|
||||
}
|
||||
|
||||
// Test 8: Block size alignment
|
||||
{
|
||||
const existing: string[] = [];
|
||||
const result = findNextAvailableCidr(existing, 24, "10.0.0.0/16");
|
||||
assertEquals(result, "10.0.0.0/24", "Block size alignment test failed");
|
||||
}
|
||||
|
||||
// Test 9: Large block size request
|
||||
{
|
||||
const existing = ["10.0.0.0/24", "10.0.1.0/24"];
|
||||
const result = findNextAvailableCidr(existing, 16, "10.0.0.0/16");
|
||||
assertEquals(result, null, "Large block size request test failed");
|
||||
}
|
||||
|
||||
console.log("All findNextAvailableCidr tests passed!");
|
||||
}
|
||||
|
||||
// function testCidrToRange() {
|
||||
// console.log("Running cidrToRange tests...");
|
||||
|
||||
// // Test 1: Basic IPv4 conversion
|
||||
// {
|
||||
// const result = cidrToRange("192.168.0.0/24");
|
||||
// assertEqualsObj(result, {
|
||||
// start: BigInt("3232235520"),
|
||||
// end: BigInt("3232235775")
|
||||
// }, "Basic IPv4 conversion failed");
|
||||
// }
|
||||
|
||||
// // Test 2: IPv6 conversion
|
||||
// {
|
||||
// const result = cidrToRange("2001:db8::/32");
|
||||
// assertEqualsObj(result, {
|
||||
// start: BigInt("42540766411282592856903984951653826560"),
|
||||
// end: BigInt("42540766411282592875350729025363378175")
|
||||
// }, "IPv6 conversion failed");
|
||||
// }
|
||||
|
||||
// // Test 3: Invalid prefix length
|
||||
// {
|
||||
// assertThrows(
|
||||
// () => cidrToRange("192.168.0.0/33"),
|
||||
// "Invalid prefix length for IPv4",
|
||||
// "Invalid IPv4 prefix test failed"
|
||||
// );
|
||||
// }
|
||||
|
||||
// // Test 4: Invalid IPv6 prefix
|
||||
// {
|
||||
// assertThrows(
|
||||
// () => cidrToRange("2001:db8::/129"),
|
||||
// "Invalid prefix length for IPv6",
|
||||
// "Invalid IPv6 prefix test failed"
|
||||
// );
|
||||
// }
|
||||
|
||||
// console.log("All cidrToRange tests passed!");
|
||||
// }
|
||||
|
||||
// Run all tests
|
||||
try {
|
||||
// testCidrToRange();
|
||||
testFindNextAvailableCidr();
|
||||
console.log("All tests passed successfully!");
|
||||
} catch (error) {
|
||||
console.error("Test failed:", error);
|
||||
process.exit(1);
|
||||
}
|
|
@ -100,7 +100,7 @@ function bigIntToIp(num: bigint, version: IPVersion): string {
|
|||
/**
|
||||
* Converts CIDR to IP range
|
||||
*/
|
||||
function cidrToRange(cidr: string): IPRange {
|
||||
export function cidrToRange(cidr: string): IPRange {
|
||||
const [ip, prefix] = cidr.split('/');
|
||||
const version = detectIpVersion(ip);
|
||||
const prefixBits = parseInt(prefix);
|
||||
|
@ -132,15 +132,22 @@ export function findNextAvailableCidr(
|
|||
blockSize: number,
|
||||
startCidr?: string
|
||||
): string | null {
|
||||
if (existingCidrs.length === 0) return null;
|
||||
|
||||
if (!startCidr && existingCidrs.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If no existing CIDRs, use the IP version from startCidr
|
||||
const version = startCidr
|
||||
? detectIpVersion(startCidr.split('/')[0])
|
||||
: 4; // Default to IPv4 if no startCidr provided
|
||||
|
||||
// Determine IP version from first CIDR
|
||||
const version = detectIpVersion(existingCidrs[0].split('/')[0]);
|
||||
// Use appropriate default startCidr if none provided
|
||||
startCidr = startCidr || (version === 4 ? "0.0.0.0/0" : "::/0");
|
||||
|
||||
// Ensure all CIDRs are same version
|
||||
if (existingCidrs.some(cidr => detectIpVersion(cidr.split('/')[0]) !== version)) {
|
||||
// If there are existing CIDRs, ensure all are same version
|
||||
if (existingCidrs.length > 0 &&
|
||||
existingCidrs.some(cidr => detectIpVersion(cidr.split('/')[0]) !== version)) {
|
||||
throw new Error('All CIDRs must be of the same IP version');
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue