Refactored subnet object methods and enhanced related documentation

This commit is contained in:
2026-01-19 14:44:52 +03:00
parent f8f240e313
commit 010cce0fd8
4 changed files with 1102 additions and 0 deletions

View File

@@ -0,0 +1,503 @@
namespace PS.IPAM.Tests.Helpers;
using System.Net;
using FluentAssertions;
using PS.IPAM;
using PS.IPAM.Helpers;
using PS.IPAM.Tests.Mocks;
using Xunit;
[Collection("Sequential")]
public class RequestHelperTests : IDisposable
{
private MockHttpMessageHandler? _mockHandler;
public RequestHelperTests()
{
// Clean state before each test
SessionManager.CloseSession();
RequestHelper.TestHttpHandler = null;
}
public void Dispose()
{
// Clean up after each test
SessionManager.CloseSession();
RequestHelper.TestHttpHandler = null;
_mockHandler?.ForceDispose();
}
private void SetupSession(AuthType authType = AuthType.token)
{
if (authType == AuthType.token)
{
SessionManager.CreateSessionWithToken("https://ipam.example.com", "testapp", "test-token");
}
else
{
// For credentials auth, we need to set up a session manually with future expiry
var session = new Session(
AuthType.credentials,
"cred-token",
"testapp",
"https://ipam.example.com",
DateTime.Now.AddHours(1),
null
);
SessionManager.CurrentSession = session;
}
}
private MockHttpMessageHandler SetupMockHandler()
{
_mockHandler = new MockHttpMessageHandler();
RequestHelper.TestHttpHandler = _mockHandler;
return _mockHandler;
}
[Fact]
public async Task InvokeRequest_WithNoSession_ThrowsException()
{
// Arrange - no session set up
// Act
var action = async () => await RequestHelper.InvokeRequest("GET", controllers.addresses);
// Assert
await action.Should().ThrowAsync<Exception>().WithMessage("No session available!");
}
[Fact]
public async Task InvokeRequest_WithValidSession_BuildsCorrectUri()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithSuccessResponse("{\"id\":1,\"ip\":\"192.168.1.1\"}");
// Act
await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "1" });
// Assert
handler.LastRequest.Should().NotBeNull();
handler.LastRequest!.RequestUri!.ToString().Should().Be("https://ipam.example.com/api/testapp/addresses/1/");
}
[Fact]
public async Task InvokeRequest_WithSubController_BuildsCorrectUri()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithSuccessResponse("[]");
// Act
await RequestHelper.InvokeRequest("GET", controllers.subnets, null, subcontrollers.tags, null, new[] { "1" });
// Assert
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/subnets/tags/1/");
}
[Fact]
public async Task InvokeRequest_WithTokenAuth_AddsPhpipamTokenHeader()
{
// Arrange
SetupSession(AuthType.token);
var handler = SetupMockHandler();
handler.WithSuccessResponse("{}");
// Act
await RequestHelper.InvokeRequest("GET", controllers.addresses);
// Assert
handler.GetLastRequestHeader("phpipam-token").Should().Be("test-token");
}
[Fact]
public async Task InvokeRequest_WithCredentialsAuth_AddsTokenHeader()
{
// Arrange
SetupSession(AuthType.credentials);
var handler = SetupMockHandler();
handler.WithSuccessResponse("{}");
// Act
await RequestHelper.InvokeRequest("GET", controllers.addresses);
// Assert
handler.GetLastRequestHeader("token").Should().Be("cred-token");
}
[Fact]
public async Task InvokeRequest_GetMethod_UsesHttpGet()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithSuccessResponse("{}");
// Act
await RequestHelper.InvokeRequest("GET", controllers.addresses);
// Assert
handler.LastRequest!.Method.Should().Be(HttpMethod.Get);
}
[Fact]
public async Task InvokeRequest_PostMethod_UsesHttpPost()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithSuccessResponse("{\"id\":1}");
// Act
await RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, new { ip = "10.0.0.1" });
// Assert
handler.LastRequest!.Method.Should().Be(HttpMethod.Post);
}
[Fact]
public async Task InvokeRequest_PatchMethod_UsesHttpPatch()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithSuccessResponse("{\"id\":1}");
// Act
await RequestHelper.InvokeRequest("PATCH", controllers.addresses, null, null, new { description = "updated" }, new[] { "1" });
// Assert
handler.LastRequest!.Method.Should().Be(new HttpMethod("PATCH"));
}
[Fact]
public async Task InvokeRequest_DeleteMethod_UsesHttpDelete()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithSuccessResponse("{}");
// Act
await RequestHelper.InvokeRequest("DELETE", controllers.addresses, null, null, null, new[] { "1" });
// Assert
handler.LastRequest!.Method.Should().Be(HttpMethod.Delete);
}
[Fact]
public async Task InvokeRequest_With404Response_ReturnsNull()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithNotFoundResponse();
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "999" });
// Assert
result.Should().BeNull();
}
[Fact]
public async Task InvokeRequest_WithErrorResponse_ThrowsHttpRequestException()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithErrorResponse(HttpStatusCode.InternalServerError, "Server error");
// Act
var action = async () => await RequestHelper.InvokeRequest("GET", controllers.addresses);
// Assert
await action.Should().ThrowAsync<HttpRequestException>();
}
[Fact]
public async Task InvokeRequest_WithAddressType_ReturnsAddressObject()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
var addressJson = @"{
""id"": 1,
""subnetId"": 10,
""ip"": ""192.168.1.100"",
""is_gateway"": false,
""description"": ""Test server"",
""hostname"": ""server01"",
""mac"": ""00:11:22:33:44:55"",
""owner"": ""admin"",
""tag"": 2,
""deviceId"": 0,
""location"": """",
""port"": """",
""note"": """",
""lastSeen"": null,
""excludePing"": false,
""PTRignore"": false,
""PTR"": 0,
""firewallAddressObject"": """",
""editDate"": null,
""customer_id"": 0
}";
handler.WithSuccessResponse(addressJson);
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "1" });
// Assert
result.Should().BeOfType<Address>();
var address = (Address)result!;
address.Id.Should().Be(1);
address.Ip.Should().Be("192.168.1.100");
address.Hostname.Should().Be("server01");
}
[Fact]
public async Task InvokeRequest_WithAddressArray_ReturnsListOfAddresses()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
var addressArrayJson = @"[
{""id"": 1, ""subnetId"": 10, ""ip"": ""192.168.1.1"", ""hostname"": ""host1""},
{""id"": 2, ""subnetId"": 10, ""ip"": ""192.168.1.2"", ""hostname"": ""host2""}
]";
handler.WithSuccessResponse(addressArrayJson);
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.subnets, types.Address, null, null, new[] { "10", "addresses" });
// Assert
result.Should().BeAssignableTo<IEnumerable<object>>();
var addresses = ((IEnumerable<object>)result!).ToList();
addresses.Should().HaveCount(2);
addresses[0].Should().BeOfType<Address>();
((Address)addresses[0]).Ip.Should().Be("192.168.1.1");
}
[Fact]
public async Task InvokeRequest_WithVlanType_ReturnsVlanObject()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
var vlanJson = @"{
""vlanId"": 100,
""domainId"": 1,
""name"": ""Production"",
""number"": 100,
""description"": ""Production VLAN"",
""editDate"": null,
""customer_id"": 0
}";
handler.WithSuccessResponse(vlanJson);
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.vlan, types.Vlan, null, null, new[] { "100" });
// Assert
result.Should().BeOfType<Vlan>();
var vlan = (Vlan)result!;
vlan.Name.Should().Be("Production");
vlan.Number.Should().Be(100);
}
[Fact]
public async Task InvokeRequest_WithSubnetworkType_ReturnsSubnetworkObject()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
var subnetJson = @"{
""id"": 1,
""subnet"": ""192.168.1.0"",
""mask"": 24,
""sectionId"": 1,
""description"": ""Test subnet"",
""linked_subnet"": """",
""firewallAddressObject"": """",
""vrfId"": 0,
""masterSubnetId"": 0,
""allowRequests"": false,
""vlanId"": 100,
""showName"": false,
""deviceId"": 0,
""permissions"": """",
""pingSubnet"": false,
""discoverSubnet"": false,
""resolveDNS"": false,
""DNSrecursive"": false,
""DNSrecords"": false,
""nameserverId"": 0,
""scanAgent"": false,
""isFolder"": false,
""isFull"": false,
""isPool"": false,
""state"": 1,
""threshold"": 0,
""location"": 0,
""editDate"": null,
""lastScan"": null,
""lastDiscovery"": null,
""calculation"": {}
}";
handler.WithSuccessResponse(subnetJson);
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "1" });
// Assert
result.Should().BeOfType<Subnetwork>();
var subnet = (Subnetwork)result!;
subnet.Subnet.Should().Be("192.168.1.0");
subnet.Mask.Should().Be(24);
subnet.GetCIDR().Should().Be("192.168.1.0/24");
}
[Fact]
public async Task InvokeRequest_WithSectionType_ReturnsSectionObject()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
var sectionJson = @"{
""id"": 1,
""name"": ""Production"",
""description"": ""Production section"",
""masterSection"": 0,
""permissions"": """",
""strictMode"": false,
""subnetOrdering"": ""default"",
""order"": 1,
""editDate"": null,
""showSubnet"": true,
""showVlan"": true,
""showVRF"": false,
""showSupernetOnly"": false,
""DNS"": 0
}";
handler.WithSuccessResponse(sectionJson);
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { "1" });
// Assert
result.Should().BeOfType<Section>();
var section = (Section)result!;
section.Name.Should().Be("Production");
}
[Fact]
public async Task InvokeRequest_WithCustomFields_ParsesExtendedData()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
var addressJson = @"{
""id"": 1,
""subnetId"": 10,
""ip"": ""192.168.1.100"",
""hostname"": ""server01"",
""custom_environment"": ""production"",
""custom_owner"": ""team-a""
}";
handler.WithSuccessResponse(addressJson);
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "1" });
// Assert
var address = (Address)result!;
address.ExtendedData.Should().NotBeNull();
var extendedData = (Dictionary<string, object>)address.ExtendedData!;
extendedData.Should().ContainKey("custom_environment");
extendedData.Should().ContainKey("custom_owner");
}
[Fact]
public async Task InvokeRequest_WithNoType_ReturnsDynamicData()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithSuccessResponse(@"{""some"": ""data""}");
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.tools);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task InvokeRequest_PostWithParameters_SerializesJsonBody()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithSuccessResponse(@"{""id"": 1}");
var parameters = new { ip = "10.0.0.1", subnetId = 5, description = "New address" };
// Act
await RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, parameters);
// Assert
handler.LastRequest!.Content.Should().NotBeNull();
var content = await handler.LastRequest.Content!.ReadAsStringAsync();
content.Should().Contain("10.0.0.1");
content.Should().Contain("subnetId");
}
[Fact]
public async Task InvokeRequest_SetsAcceptJsonHeader()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithSuccessResponse("{}");
// Act
await RequestHelper.InvokeRequest("GET", controllers.addresses);
// Assert
handler.LastRequest!.Headers.Accept.Should().Contain(h => h.MediaType == "application/json");
}
[Fact]
public async Task InvokeRequest_WithEmptyResponse_ReturnsNull()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithResponse(HttpStatusCode.OK, "", "application/json");
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses);
// Assert
result.Should().BeNull();
}
[Fact]
public async Task InvokeRequest_WithNullDataInResponse_ReturnsNull()
{
// Arrange
SetupSession();
var handler = SetupMockHandler();
handler.WithJsonResponse(@"{""code"": 200, ""success"": true, ""data"": null}");
// Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address);
// Assert
result.Should().BeNull();
}
}