318 lines
10 KiB
C#
318 lines
10 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Security.Claims;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using Xunit;
|
|
using FluentAssertions;
|
|
using IamService.API.Application.Common;
|
|
using IamService.API.Controllers;
|
|
|
|
namespace IamService.FunctionalTests.Controllers;
|
|
|
|
/// <summary>
|
|
/// EN: Functional tests for RolesController endpoints.
|
|
/// VI: Functional tests cho các endpoints của RolesController.
|
|
/// </summary>
|
|
public class RolesControllerTests : IClassFixture<CustomWebApplicationFactory>
|
|
{
|
|
private readonly HttpClient _client;
|
|
private readonly CustomWebApplicationFactory _factory;
|
|
|
|
public RolesControllerTests(CustomWebApplicationFactory factory)
|
|
{
|
|
_factory = factory;
|
|
_client = factory.CreateClient();
|
|
|
|
// EN: Add authorization header with test token
|
|
// VI: Thêm authorization header với test token
|
|
_client.DefaultRequestHeaders.Authorization =
|
|
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", GenerateTestToken());
|
|
}
|
|
|
|
#region Create Role Tests
|
|
|
|
[Fact]
|
|
public async Task CreateRole_ValidRequest_Returns201()
|
|
{
|
|
// Arrange
|
|
var request = new CreateRoleRequest
|
|
{
|
|
Name = $"TestRole_{Guid.NewGuid():N}",
|
|
Description = "A test role"
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync("/api/v1/roles", request);
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
response.Headers.Location.Should().NotBeNull();
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<ApiResponse<RoleResponse>>();
|
|
result.Should().NotBeNull();
|
|
result!.Success.Should().BeTrue();
|
|
result.Data.Should().NotBeNull();
|
|
result.Data!.Name.Should().Be(request.Name);
|
|
result.Data.Description.Should().Be(request.Description);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateRole_WithoutDescription_Returns201()
|
|
{
|
|
// Arrange
|
|
var request = new CreateRoleRequest
|
|
{
|
|
Name = $"NoDescRole_{Guid.NewGuid():N}"
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync("/api/v1/roles", request);
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<ApiResponse<RoleResponse>>();
|
|
result!.Data!.Description.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateRole_DuplicateName_Returns409()
|
|
{
|
|
// Arrange
|
|
var uniqueName = $"DupRole_{Guid.NewGuid():N}";
|
|
var request = new CreateRoleRequest { Name = uniqueName };
|
|
|
|
// First creation - should succeed
|
|
var firstResponse = await _client.PostAsJsonAsync("/api/v1/roles", request);
|
|
firstResponse.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
|
|
// Second creation with same name - should fail
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync("/api/v1/roles", request);
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.Conflict);
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<ApiResponse<RoleResponse>>();
|
|
result!.Success.Should().BeFalse();
|
|
result.Error!.Code.Should().Be("ROLE_EXISTS");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Get Role Tests
|
|
|
|
[Fact]
|
|
public async Task GetRoleById_ExistingId_Returns200()
|
|
{
|
|
// Arrange - Create role first
|
|
var createRequest = new CreateRoleRequest
|
|
{
|
|
Name = $"GetRole_{Guid.NewGuid():N}"
|
|
};
|
|
var createResponse = await _client.PostAsJsonAsync("/api/v1/roles", createRequest);
|
|
var createResult = await createResponse.Content.ReadFromJsonAsync<ApiResponse<RoleResponse>>();
|
|
var roleId = createResult!.Data!.Id;
|
|
|
|
// Act
|
|
var response = await _client.GetAsync($"/api/v1/roles/{roleId}");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<ApiResponse<RoleResponse>>();
|
|
result!.Data!.Id.Should().Be(roleId);
|
|
result.Data.Name.Should().Be(createRequest.Name);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetRoleById_NonExistingId_Returns404()
|
|
{
|
|
// Arrange
|
|
var nonExistentId = Guid.NewGuid();
|
|
|
|
// Act
|
|
var response = await _client.GetAsync($"/api/v1/roles/{nonExistentId}");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<ApiResponse<RoleResponse>>();
|
|
result!.Error!.Code.Should().Be("ROLE_NOT_FOUND");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetRoles_Returns200WithPagination()
|
|
{
|
|
// Arrange - Create at least one role
|
|
var createRequest = new CreateRoleRequest
|
|
{
|
|
Name = $"ListRole_{Guid.NewGuid():N}"
|
|
};
|
|
await _client.PostAsJsonAsync("/api/v1/roles", createRequest);
|
|
|
|
// Act
|
|
var response = await _client.GetAsync("/api/v1/roles?pageNumber=1&pageSize=10");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<ApiResponse<IEnumerable<RoleResponse>>>();
|
|
result!.Success.Should().BeTrue();
|
|
result.Pagination.Should().NotBeNull();
|
|
result.Pagination!.PageNumber.Should().Be(1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Update Role Tests
|
|
|
|
[Fact]
|
|
public async Task UpdateRole_ValidRequest_Returns200()
|
|
{
|
|
// Arrange - Create role first
|
|
var createRequest = new CreateRoleRequest
|
|
{
|
|
Name = $"UpdateRole_{Guid.NewGuid():N}",
|
|
Description = "Original description"
|
|
};
|
|
var createResponse = await _client.PostAsJsonAsync("/api/v1/roles", createRequest);
|
|
var createResult = await createResponse.Content.ReadFromJsonAsync<ApiResponse<RoleResponse>>();
|
|
var roleId = createResult!.Data!.Id;
|
|
|
|
var updateRequest = new UpdateRoleRequest
|
|
{
|
|
Name = $"UpdatedRole_{Guid.NewGuid():N}",
|
|
Description = "Updated description"
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PutAsJsonAsync($"/api/v1/roles/{roleId}", updateRequest);
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<ApiResponse<RoleResponse>>();
|
|
result!.Data!.Name.Should().Be(updateRequest.Name);
|
|
result.Data.Description.Should().Be(updateRequest.Description);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateRole_NonExistingId_Returns404()
|
|
{
|
|
// Arrange
|
|
var updateRequest = new UpdateRoleRequest
|
|
{
|
|
Name = "UpdatedRole"
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PutAsJsonAsync($"/api/v1/roles/{Guid.NewGuid()}", updateRequest);
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Delete Role Tests
|
|
|
|
[Fact]
|
|
public async Task DeleteRole_ExistingRole_Returns200()
|
|
{
|
|
// Arrange - Create role first
|
|
var createRequest = new CreateRoleRequest
|
|
{
|
|
Name = $"DeleteRole_{Guid.NewGuid():N}"
|
|
};
|
|
var createResponse = await _client.PostAsJsonAsync("/api/v1/roles", createRequest);
|
|
var createResult = await createResponse.Content.ReadFromJsonAsync<ApiResponse<RoleResponse>>();
|
|
var roleId = createResult!.Data!.Id;
|
|
|
|
// Act
|
|
var response = await _client.DeleteAsync($"/api/v1/roles/{roleId}");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteRole_NonExistingId_Returns404()
|
|
{
|
|
// Act
|
|
var response = await _client.DeleteAsync($"/api/v1/roles/{Guid.NewGuid()}");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Assign/Remove Role Tests
|
|
|
|
[Fact]
|
|
public async Task AssignRoleToUser_ValidRequest_Returns200()
|
|
{
|
|
// Arrange - Create role first
|
|
var roleName = $"AssignRole_{Guid.NewGuid():N}";
|
|
await _client.PostAsJsonAsync("/api/v1/roles", new CreateRoleRequest { Name = roleName });
|
|
|
|
// Create user via registration
|
|
var registerRequest = new
|
|
{
|
|
Email = $"assign-test-{Guid.NewGuid():N}@example.com",
|
|
Password = "Test123!",
|
|
FirstName = "Test",
|
|
LastName = "User"
|
|
};
|
|
var registerResponse = await _client.PostAsJsonAsync("/api/v1/auth/register", registerRequest);
|
|
if (!registerResponse.IsSuccessStatusCode)
|
|
{
|
|
// Skip if can't register user
|
|
return;
|
|
}
|
|
|
|
// Get user ID from response - may vary based on response structure
|
|
var userId = Guid.NewGuid(); // Placeholder if user creation works differently
|
|
|
|
var assignRequest = new AssignRoleRequest { RoleName = roleName };
|
|
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync($"/api/v1/users/{userId}/roles", assignRequest);
|
|
|
|
// Assert - Accept 200 or 404 (if user registration flow is different)
|
|
response.StatusCode.Should().BeOneOf(HttpStatusCode.OK, HttpStatusCode.NotFound);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Helper Methods
|
|
|
|
private static string GenerateTestToken()
|
|
{
|
|
var claims = new[]
|
|
{
|
|
new Claim(JwtRegisteredClaimNames.Sub, Guid.NewGuid().ToString()),
|
|
new Claim(JwtRegisteredClaimNames.Email, "test@example.com"),
|
|
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
|
new Claim("name", "Test User")
|
|
};
|
|
|
|
var key = new SymmetricSecurityKey("test-secret-key-for-testing-purposes-only-32-chars!"u8.ToArray());
|
|
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
|
|
|
var token = new JwtSecurityToken(
|
|
issuer: "http://localhost",
|
|
audience: "api",
|
|
claims: claims,
|
|
expires: DateTime.UtcNow.AddHours(1),
|
|
signingCredentials: creds
|
|
);
|
|
|
|
return new JwtSecurityTokenHandler().WriteToken(token);
|
|
}
|
|
|
|
#endregion
|
|
}
|