186 lines
7.2 KiB
C#
186 lines
7.2 KiB
C#
using System.Net;
|
|
using System.Net.Http.Headers;
|
|
using System.Net.Http.Json;
|
|
using api.Features.Auth.Common;
|
|
using api.Features.Workspaces.Common;
|
|
using FluentAssertions;
|
|
|
|
namespace Api.Tests;
|
|
|
|
public class WorkspaceEndpointTests(ApiWebApplicationFactory factory)
|
|
: IClassFixture<ApiWebApplicationFactory>
|
|
{
|
|
private readonly HttpClient _client = factory.CreateClient();
|
|
|
|
private async Task<string> GetAuthTokenAsync(string email = "workspace-test@example.com")
|
|
{
|
|
var response = await _client.PostAsJsonAsync("/auth/register", new { Email = email, Password = "password123" });
|
|
if (response.StatusCode == HttpStatusCode.Conflict)
|
|
{
|
|
response = await _client.PostAsJsonAsync("/auth/login", new { Email = email, Password = "password123" });
|
|
}
|
|
var result = await response.Content.ReadFromJsonAsync<AuthResponse>();
|
|
return result!.Token;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ListWorkspaces_WithValidToken_ReturnsWorkspaces()
|
|
{
|
|
// Arrange
|
|
var token = await GetAuthTokenAsync("list-ws@example.com");
|
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
|
|
// Act
|
|
var response = await _client.GetAsync("/workspaces");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
var result = await response.Content.ReadFromJsonAsync<WorkspaceListResponse>();
|
|
result.Should().NotBeNull();
|
|
result!.Workspaces.Should().HaveCountGreaterThanOrEqualTo(1); // Default workspace created on registration
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ListWorkspaces_WithoutToken_ReturnsUnauthorized()
|
|
{
|
|
// Act
|
|
var response = await _client.GetAsync("/workspaces");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateWorkspace_WithValidData_ReturnsCreated()
|
|
{
|
|
// Arrange
|
|
var token = await GetAuthTokenAsync("create-ws@example.com");
|
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync("/workspaces", new { Name = "Test Workspace" });
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
var result = await response.Content.ReadFromJsonAsync<WorkspaceResponse>();
|
|
result.Should().NotBeNull();
|
|
result!.Name.Should().Be("Test Workspace");
|
|
result.Plan.Should().Be("Free");
|
|
result.Id.Should().NotBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateWorkspace_WithEmptyName_ReturnsBadRequest()
|
|
{
|
|
// Arrange
|
|
var token = await GetAuthTokenAsync("create-ws-invalid@example.com");
|
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync("/workspaces", new { Name = "" });
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetWorkspace_WithValidId_ReturnsWorkspace()
|
|
{
|
|
// Arrange
|
|
var token = await GetAuthTokenAsync("get-ws@example.com");
|
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
|
|
var createResponse = await _client.PostAsJsonAsync("/workspaces", new { Name = "Get Test" });
|
|
var created = await createResponse.Content.ReadFromJsonAsync<WorkspaceResponse>();
|
|
|
|
// Act
|
|
var response = await _client.GetAsync($"/workspaces/{created!.Id}");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
var result = await response.Content.ReadFromJsonAsync<WorkspaceResponse>();
|
|
result!.Id.Should().Be(created.Id);
|
|
result.Name.Should().Be("Get Test");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetWorkspace_WithInvalidId_ReturnsNotFound()
|
|
{
|
|
// Arrange
|
|
var token = await GetAuthTokenAsync("get-ws-invalid@example.com");
|
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
|
|
// Act
|
|
var response = await _client.GetAsync($"/workspaces/{Guid.NewGuid()}");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateWorkspace_WithValidData_ReturnsUpdated()
|
|
{
|
|
// Arrange
|
|
var token = await GetAuthTokenAsync("update-ws@example.com");
|
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
|
|
var createResponse = await _client.PostAsJsonAsync("/workspaces", new { Name = "Original Name" });
|
|
var created = await createResponse.Content.ReadFromJsonAsync<WorkspaceResponse>();
|
|
|
|
// Act
|
|
var response = await _client.PutAsJsonAsync($"/workspaces/{created!.Id}", new { Name = "Updated Name" });
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
var result = await response.Content.ReadFromJsonAsync<WorkspaceResponse>();
|
|
result!.Name.Should().Be("Updated Name");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteWorkspace_WithValidId_ReturnsSuccess()
|
|
{
|
|
// Arrange
|
|
var token = await GetAuthTokenAsync("delete-ws@example.com");
|
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
|
|
var createResponse = await _client.PostAsJsonAsync("/workspaces", new { Name = "To Delete" });
|
|
var created = await createResponse.Content.ReadFromJsonAsync<WorkspaceResponse>();
|
|
|
|
// Act
|
|
var response = await _client.DeleteAsync($"/workspaces/{created!.Id}");
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
|
|
// Verify it's deleted
|
|
var getResponse = await _client.GetAsync($"/workspaces/{created.Id}");
|
|
getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Workspace_CannotAccessOtherUsersWorkspace()
|
|
{
|
|
// Arrange - Create two users
|
|
var token1 = await GetAuthTokenAsync("user1-ws@example.com");
|
|
var token2 = await GetAuthTokenAsync("user2-ws@example.com");
|
|
|
|
// Create workspace as user1
|
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token1);
|
|
var createResponse = await _client.PostAsJsonAsync("/workspaces", new { Name = "User1 Workspace" });
|
|
var created = await createResponse.Content.ReadFromJsonAsync<WorkspaceResponse>();
|
|
|
|
// Try to access as user2
|
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token2);
|
|
|
|
// Act
|
|
var getResponse = await _client.GetAsync($"/workspaces/{created!.Id}");
|
|
var updateResponse = await _client.PutAsJsonAsync($"/workspaces/{created.Id}", new { Name = "Hacked" });
|
|
var deleteResponse = await _client.DeleteAsync($"/workspaces/{created.Id}");
|
|
|
|
// Assert - All should return NotFound (not exposing existence)
|
|
getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
updateResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
deleteResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
}
|
|
}
|