2024-06-06 12:54:12 +03:00
|
|
|
package stirling.software.SPDF.utils;
|
|
|
|
|
2025-03-13 10:22:44 +01:00
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
2025-05-19 14:12:06 +01:00
|
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
import static org.mockito.Mockito.when;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.net.ServerSocket;
|
2025-03-13 10:22:44 +01:00
|
|
|
|
2024-06-06 12:54:12 +03:00
|
|
|
import org.junit.jupiter.api.Test;
|
2025-05-19 14:12:06 +01:00
|
|
|
import org.junit.jupiter.api.extension.ExtendWith;
|
|
|
|
import org.mockito.Mock;
|
|
|
|
import org.mockito.junit.jupiter.MockitoExtension;
|
2024-06-06 12:54:12 +03:00
|
|
|
|
2025-03-13 10:22:44 +01:00
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
2024-06-06 12:54:12 +03:00
|
|
|
|
2025-05-19 14:12:06 +01:00
|
|
|
@ExtendWith(MockitoExtension.class)
|
|
|
|
class UrlUtilsTest {
|
|
|
|
|
|
|
|
@Mock private HttpServletRequest request;
|
2024-06-06 12:54:12 +03:00
|
|
|
|
|
|
|
@Test
|
|
|
|
void testGetOrigin() {
|
2025-05-19 14:12:06 +01:00
|
|
|
// Arrange
|
|
|
|
when(request.getScheme()).thenReturn("http");
|
|
|
|
when(request.getServerName()).thenReturn("localhost");
|
|
|
|
when(request.getServerPort()).thenReturn(8080);
|
|
|
|
when(request.getContextPath()).thenReturn("/myapp");
|
|
|
|
|
|
|
|
// Act
|
|
|
|
String origin = UrlUtils.getOrigin(request);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
assertEquals(
|
|
|
|
"http://localhost:8080/myapp", origin, "Origin URL should be correctly formatted");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testGetOriginWithHttps() {
|
|
|
|
// Arrange
|
|
|
|
when(request.getScheme()).thenReturn("https");
|
|
|
|
when(request.getServerName()).thenReturn("example.com");
|
|
|
|
when(request.getServerPort()).thenReturn(443);
|
|
|
|
when(request.getContextPath()).thenReturn("");
|
|
|
|
|
|
|
|
// Act
|
|
|
|
String origin = UrlUtils.getOrigin(request);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
assertEquals(
|
|
|
|
"https://example.com:443",
|
|
|
|
origin,
|
|
|
|
"HTTPS origin URL should be correctly formatted");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testGetOriginWithEmptyContextPath() {
|
|
|
|
// Arrange
|
|
|
|
when(request.getScheme()).thenReturn("http");
|
|
|
|
when(request.getServerName()).thenReturn("localhost");
|
|
|
|
when(request.getServerPort()).thenReturn(8080);
|
|
|
|
when(request.getContextPath()).thenReturn("");
|
|
|
|
|
|
|
|
// Act
|
|
|
|
String origin = UrlUtils.getOrigin(request);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
assertEquals(
|
|
|
|
"http://localhost:8080",
|
|
|
|
origin,
|
|
|
|
"Origin URL with empty context path should be correct");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testGetOriginWithSpecialCharacters() {
|
|
|
|
// Arrange - Test with server name containing special characters
|
|
|
|
when(request.getScheme()).thenReturn("https");
|
|
|
|
when(request.getServerName()).thenReturn("internal-server.example-domain.com");
|
|
|
|
when(request.getServerPort()).thenReturn(8443);
|
|
|
|
when(request.getContextPath()).thenReturn("/app-v1.2");
|
|
|
|
|
|
|
|
// Act
|
2024-06-06 12:54:12 +03:00
|
|
|
String origin = UrlUtils.getOrigin(request);
|
|
|
|
|
2025-05-19 14:12:06 +01:00
|
|
|
// Assert
|
|
|
|
assertEquals(
|
|
|
|
"https://internal-server.example-domain.com:8443/app-v1.2",
|
|
|
|
origin,
|
|
|
|
"Origin URL with special characters should be correctly formatted");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testGetOriginWithIPv4Address() {
|
|
|
|
// Arrange
|
|
|
|
when(request.getScheme()).thenReturn("http");
|
|
|
|
when(request.getServerName()).thenReturn("192.168.1.100");
|
|
|
|
when(request.getServerPort()).thenReturn(8080);
|
|
|
|
when(request.getContextPath()).thenReturn("/app");
|
|
|
|
|
|
|
|
// Act
|
|
|
|
String origin = UrlUtils.getOrigin(request);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
assertEquals(
|
|
|
|
"http://192.168.1.100:8080/app",
|
|
|
|
origin,
|
|
|
|
"Origin URL with IPv4 address should be correctly formatted");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testGetOriginWithNonStandardPort() {
|
|
|
|
// Arrange
|
|
|
|
when(request.getScheme()).thenReturn("https");
|
|
|
|
when(request.getServerName()).thenReturn("example.org");
|
|
|
|
when(request.getServerPort()).thenReturn(8443);
|
|
|
|
when(request.getContextPath()).thenReturn("/api");
|
|
|
|
|
|
|
|
// Act
|
|
|
|
String origin = UrlUtils.getOrigin(request);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
assertEquals(
|
|
|
|
"https://example.org:8443/api",
|
|
|
|
origin,
|
|
|
|
"Origin URL with non-standard port should be correctly formatted");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testIsPortAvailable() {
|
|
|
|
// We'll use a real server socket for this test
|
|
|
|
ServerSocket socket = null;
|
|
|
|
int port = 12345; // Choose a port unlikely to be in use
|
|
|
|
|
|
|
|
try {
|
|
|
|
// First check the port is available
|
|
|
|
boolean initialAvailability = UrlUtils.isPortAvailable(port);
|
|
|
|
|
|
|
|
// Then occupy the port
|
|
|
|
socket = new ServerSocket(port);
|
|
|
|
|
|
|
|
// Now check the port is no longer available
|
|
|
|
boolean afterSocketCreation = UrlUtils.isPortAvailable(port);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
assertTrue(initialAvailability, "Port should be available initially");
|
|
|
|
assertFalse(
|
|
|
|
afterSocketCreation, "Port should not be available after socket is created");
|
|
|
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
// This might happen if the port is already in use by another process
|
|
|
|
// We'll just verify the behavior of isPortAvailable matches what we expect
|
|
|
|
assertFalse(
|
|
|
|
UrlUtils.isPortAvailable(port),
|
|
|
|
"Port should not be available if exception is thrown");
|
|
|
|
} finally {
|
|
|
|
if (socket != null && !socket.isClosed()) {
|
|
|
|
try {
|
|
|
|
socket.close();
|
|
|
|
} catch (IOException e) {
|
|
|
|
// Ignore cleanup exceptions
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testFindAvailablePort() {
|
|
|
|
// We'll create a socket on a port and ensure findAvailablePort returns a different port
|
|
|
|
ServerSocket socket = null;
|
|
|
|
int startPort = 12346; // Choose a port unlikely to be in use
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Occupy the start port
|
|
|
|
socket = new ServerSocket(startPort);
|
|
|
|
|
|
|
|
// Find an available port
|
|
|
|
String availablePort = UrlUtils.findAvailablePort(startPort);
|
|
|
|
|
|
|
|
// Assert the returned port is not the occupied one
|
|
|
|
assertNotEquals(
|
|
|
|
String.valueOf(startPort),
|
|
|
|
availablePort,
|
|
|
|
"findAvailablePort should not return an occupied port");
|
|
|
|
|
|
|
|
// Verify the returned port is actually available
|
|
|
|
int portNumber = Integer.parseInt(availablePort);
|
|
|
|
|
|
|
|
// Close our test socket before checking the found port
|
|
|
|
socket.close();
|
|
|
|
socket = null;
|
|
|
|
|
|
|
|
// The port should now be available
|
|
|
|
assertTrue(
|
|
|
|
UrlUtils.isPortAvailable(portNumber),
|
|
|
|
"The port returned by findAvailablePort should be available");
|
|
|
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
// If we can't create the socket, skip this assertion
|
|
|
|
} finally {
|
|
|
|
if (socket != null && !socket.isClosed()) {
|
|
|
|
try {
|
|
|
|
socket.close();
|
|
|
|
} catch (IOException e) {
|
|
|
|
// Ignore cleanup exceptions
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testFindAvailablePortWithAvailableStartPort() {
|
|
|
|
// Find an available port without occupying any
|
|
|
|
int startPort = 23456; // Choose a different unlikely-to-be-used port
|
|
|
|
|
|
|
|
// Make sure the port is available first
|
|
|
|
if (UrlUtils.isPortAvailable(startPort)) {
|
|
|
|
// Find an available port
|
|
|
|
String availablePort = UrlUtils.findAvailablePort(startPort);
|
|
|
|
|
|
|
|
// Assert the returned port is the start port since it's available
|
|
|
|
assertEquals(
|
|
|
|
String.valueOf(startPort),
|
|
|
|
availablePort,
|
|
|
|
"findAvailablePort should return the start port if it's available");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testFindAvailablePortWithSequentialUsedPorts() {
|
|
|
|
// This test checks that findAvailablePort correctly skips multiple occupied ports
|
|
|
|
ServerSocket socket1 = null;
|
|
|
|
ServerSocket socket2 = null;
|
|
|
|
int startPort = 34567; // Another unlikely-to-be-used port
|
|
|
|
|
|
|
|
try {
|
|
|
|
// First verify the port is available
|
|
|
|
if (!UrlUtils.isPortAvailable(startPort)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Occupy two sequential ports
|
|
|
|
socket1 = new ServerSocket(startPort);
|
|
|
|
socket2 = new ServerSocket(startPort + 1);
|
|
|
|
|
|
|
|
// Find an available port starting from our occupied range
|
|
|
|
String availablePort = UrlUtils.findAvailablePort(startPort);
|
|
|
|
int foundPort = Integer.parseInt(availablePort);
|
|
|
|
|
|
|
|
// Should have skipped the two occupied ports
|
|
|
|
assertTrue(
|
|
|
|
foundPort >= startPort + 2,
|
|
|
|
"findAvailablePort should skip sequential occupied ports");
|
|
|
|
|
|
|
|
// Verify the found port is actually available
|
|
|
|
try (ServerSocket testSocket = new ServerSocket(foundPort)) {
|
|
|
|
assertTrue(testSocket.isBound(), "The found port should be bindable");
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
// Skip test if we encounter IO exceptions
|
|
|
|
} finally {
|
|
|
|
// Clean up resources
|
|
|
|
try {
|
|
|
|
if (socket1 != null && !socket1.isClosed()) socket1.close();
|
|
|
|
if (socket2 != null && !socket2.isClosed()) socket2.close();
|
|
|
|
} catch (IOException e) {
|
|
|
|
// Ignore cleanup exceptions
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
void testIsPortAvailableWithPrivilegedPorts() {
|
|
|
|
// Skip tests for privileged ports as they typically require root access
|
|
|
|
// and results are environment-dependent
|
2024-06-06 12:54:12 +03:00
|
|
|
}
|
|
|
|
}
|