using System.Net; using PnvPanel.IntegrationTests.TestSupport; using Xunit; using static PnvPanel.IntegrationTests.TestSupport.AuthTestHelper; namespace PnvPanel.IntegrationTests.Admin; [Collection(IntegrationTestCollection.Name)] public class NodeInboundCrudTests(PnvPanelWebApplicationFactory factory) { private sealed record NodeResponse(Guid Id, string Name, string BaseAddress, string Username, string? Location, string Status, bool IsEnabled); private sealed record InboundResponse( Guid Id, Guid NodeId, string RemoteInboundId, string Protocol, string Remark, int Port, bool IsPublished, string? DisplayName, int? MaxClients, IReadOnlyList AllowedRoleIds); private sealed record SyncNodeResponse(int InboundsSynced, string Status); [Fact] public async Task RegisterSyncListPublish_FullNodeInboundLifecycle_Succeeds() { using var adminClient = factory.CreateClient(); var adminToken = await LoginAsAdminAsync(adminClient); adminClient.UseBearerToken(adminToken); var registerResponse = await adminClient.PostJsonAsync("/api/admin/nodes", new { name = $"Node-{Guid.NewGuid():N}"[..20], baseAddress = "https://node.example.com:2053", username = "admin", password = "node-panel-password", location = "Germany", }); Assert.Equal(HttpStatusCode.OK, registerResponse.StatusCode); var node = await registerResponse.ReadAsAsync(); Assert.NotNull(node); var listNodesResponse = await adminClient.GetAsync("/api/admin/nodes"); Assert.Equal(HttpStatusCode.OK, listNodesResponse.StatusCode); var nodes = await listNodesResponse.ReadAsAsync>(); Assert.Contains(nodes!, n => n.Id == node!.Id); var syncResponse = await adminClient.PostAsync($"/api/admin/nodes/{node!.Id}/sync", content: null); Assert.Equal(HttpStatusCode.OK, syncResponse.StatusCode); var sync = await syncResponse.ReadAsAsync(); Assert.Equal(1, sync!.InboundsSynced); var listInboundsResponse = await adminClient.GetAsync($"/api/admin/inbounds?nodeId={node.Id}"); Assert.Equal(HttpStatusCode.OK, listInboundsResponse.StatusCode); var inbounds = await listInboundsResponse.ReadAsAsync>(); var inbound = Assert.Single(inbounds!); Assert.False(inbound.IsPublished); var publishResponse = await adminClient.SendPutJsonAsync($"/api/admin/inbounds/{inbound.Id}/publish", new { isPublished = true, displayName = "Germany (VLESS)", allowedRoleIds = Array.Empty(), maxClients = (int?)null, }); Assert.Equal(HttpStatusCode.OK, publishResponse.StatusCode); var published = await publishResponse.ReadAsAsync(); Assert.True(published!.IsPublished); Assert.Equal("Germany (VLESS)", published.DisplayName); } [Fact] public async Task RegisterNode_AsNonAdmin_ReturnsForbidden() { using var userClient = factory.CreateClient(); var userName = $"greg_{Guid.NewGuid():N}"[..20]; var (_, userToken) = await RegisterAndLoginAsync(userClient, userName, "P@ssw0rd123"); userClient.UseBearerToken(userToken); var response = await userClient.PostJsonAsync("/api/admin/nodes", new { name = "Node", baseAddress = "https://node.example.com", username = "admin", password = "pw", location = (string?)null, }); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); } }