mirror of
https://github.com/bitwarden/server
synced 2025-12-12 14:23:38 +00:00
223 lines
8.0 KiB
C#
223 lines
8.0 KiB
C#
using System.Net;
|
|
using Bit.SeederApi.Models.Request;
|
|
using Bit.SeederApi.Models.Response;
|
|
using Xunit;
|
|
|
|
namespace Bit.SeederApi.IntegrationTest;
|
|
|
|
public class SeedControllerTests : IClassFixture<SeederApiApplicationFactory>, IAsyncLifetime
|
|
{
|
|
private readonly HttpClient _client;
|
|
private readonly SeederApiApplicationFactory _factory;
|
|
|
|
public SeedControllerTests(SeederApiApplicationFactory factory)
|
|
{
|
|
_factory = factory;
|
|
_client = _factory.CreateClient();
|
|
}
|
|
|
|
public Task InitializeAsync()
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public async Task DisposeAsync()
|
|
{
|
|
// Clean up any seeded data after each test
|
|
await _client.DeleteAsync("/seed");
|
|
_client.Dispose();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SeedEndpoint_WithValidScene_ReturnsOk()
|
|
{
|
|
var testEmail = $"seed-test-{Guid.NewGuid()}@bitwarden.com";
|
|
var playId = Guid.NewGuid().ToString();
|
|
|
|
var response = await _client.PostAsJsonAsync("/seed", new SeedRequestModel
|
|
{
|
|
Template = "SingleUserScene",
|
|
Arguments = System.Text.Json.JsonSerializer.SerializeToElement(new { email = testEmail })
|
|
}, playId);
|
|
|
|
response.EnsureSuccessStatusCode();
|
|
var result = await response.Content.ReadFromJsonAsync<SceneResponseModel>();
|
|
|
|
Assert.NotNull(result);
|
|
Assert.NotNull(result.MangleMap);
|
|
Assert.Null(result.Result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SeedEndpoint_WithInvalidSceneName_ReturnsNotFound()
|
|
{
|
|
var response = await _client.PostAsJsonAsync("/seed", new SeedRequestModel
|
|
{
|
|
Template = "NonExistentScene",
|
|
Arguments = System.Text.Json.JsonSerializer.SerializeToElement(new { email = "test@example.com" })
|
|
});
|
|
|
|
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SeedEndpoint_WithMissingRequiredField_ReturnsBadRequest()
|
|
{
|
|
// SingleUserScene requires 'email' field
|
|
var response = await _client.PostAsJsonAsync("/seed", new SeedRequestModel
|
|
{
|
|
Template = "SingleUserScene",
|
|
Arguments = System.Text.Json.JsonSerializer.SerializeToElement(new { wrongField = "value" })
|
|
});
|
|
|
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteEndpoint_WithValidPlayId_ReturnsOk()
|
|
{
|
|
var testEmail = $"delete-test-{Guid.NewGuid()}@bitwarden.com";
|
|
var playId = Guid.NewGuid().ToString();
|
|
|
|
var seedResponse = await _client.PostAsJsonAsync("/seed", new SeedRequestModel
|
|
{
|
|
Template = "SingleUserScene",
|
|
Arguments = System.Text.Json.JsonSerializer.SerializeToElement(new { email = testEmail })
|
|
}, playId);
|
|
|
|
seedResponse.EnsureSuccessStatusCode();
|
|
var seedResult = await seedResponse.Content.ReadFromJsonAsync<SceneResponseModel>();
|
|
Assert.NotNull(seedResult);
|
|
|
|
var deleteResponse = await _client.DeleteAsync($"/seed/{playId}");
|
|
deleteResponse.EnsureSuccessStatusCode();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteEndpoint_WithInvalidPlayId_ReturnsOk()
|
|
{
|
|
// DestroyRecipe is idempotent - returns null for non-existent play IDs
|
|
var nonExistentPlayId = Guid.NewGuid().ToString();
|
|
var response = await _client.DeleteAsync($"/seed/{nonExistentPlayId}");
|
|
|
|
response.EnsureSuccessStatusCode();
|
|
var content = await response.Content.ReadAsStringAsync();
|
|
Assert.Equal($$"""{"playId":"{{nonExistentPlayId}}"}""", content);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteBatchEndpoint_WithValidPlayIds_ReturnsOk()
|
|
{
|
|
// Create multiple seeds with different play IDs
|
|
var playIds = new List<string>();
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
var playId = Guid.NewGuid().ToString();
|
|
playIds.Add(playId);
|
|
|
|
var testEmail = $"batch-test-{Guid.NewGuid()}@bitwarden.com";
|
|
var seedResponse = await _client.PostAsJsonAsync("/seed", new SeedRequestModel
|
|
{
|
|
Template = "SingleUserScene",
|
|
Arguments = System.Text.Json.JsonSerializer.SerializeToElement(new { email = testEmail })
|
|
}, playId);
|
|
|
|
seedResponse.EnsureSuccessStatusCode();
|
|
var seedResult = await seedResponse.Content.ReadFromJsonAsync<SceneResponseModel>();
|
|
Assert.NotNull(seedResult);
|
|
}
|
|
|
|
// Delete them in batch
|
|
var request = new HttpRequestMessage(HttpMethod.Delete, "/seed/batch")
|
|
{
|
|
Content = JsonContent.Create(playIds)
|
|
};
|
|
var deleteResponse = await _client.SendAsync(request);
|
|
deleteResponse.EnsureSuccessStatusCode();
|
|
|
|
var result = await deleteResponse.Content.ReadFromJsonAsync<BatchDeleteResponse>();
|
|
Assert.NotNull(result);
|
|
Assert.Equal("Batch delete completed successfully", result.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteBatchEndpoint_WithSomeInvalidIds_ReturnsOk()
|
|
{
|
|
// DestroyRecipe is idempotent - batch delete succeeds even with non-existent IDs
|
|
// Create one valid seed with a play ID
|
|
var validPlayId = Guid.NewGuid().ToString();
|
|
var testEmail = $"batch-partial-test-{Guid.NewGuid()}@bitwarden.com";
|
|
|
|
var seedResponse = await _client.PostAsJsonAsync("/seed", new SeedRequestModel
|
|
{
|
|
Template = "SingleUserScene",
|
|
Arguments = System.Text.Json.JsonSerializer.SerializeToElement(new { email = testEmail })
|
|
}, validPlayId);
|
|
|
|
seedResponse.EnsureSuccessStatusCode();
|
|
var seedResult = await seedResponse.Content.ReadFromJsonAsync<SceneResponseModel>();
|
|
Assert.NotNull(seedResult);
|
|
|
|
// Try to delete with mix of valid and invalid IDs
|
|
var playIds = new List<string> { validPlayId, Guid.NewGuid().ToString(), Guid.NewGuid().ToString() };
|
|
var request = new HttpRequestMessage(HttpMethod.Delete, "/seed/batch")
|
|
{
|
|
Content = JsonContent.Create(playIds)
|
|
};
|
|
var deleteResponse = await _client.SendAsync(request);
|
|
|
|
deleteResponse.EnsureSuccessStatusCode();
|
|
var result = await deleteResponse.Content.ReadFromJsonAsync<BatchDeleteResponse>();
|
|
Assert.NotNull(result);
|
|
Assert.Equal("Batch delete completed successfully", result.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteAllEndpoint_DeletesAllSeededData()
|
|
{
|
|
// Create multiple seeds
|
|
for (var i = 0; i < 2; i++)
|
|
{
|
|
var playId = Guid.NewGuid().ToString();
|
|
var testEmail = $"deleteall-test-{Guid.NewGuid()}@bitwarden.com";
|
|
|
|
var seedResponse = await _client.PostAsJsonAsync("/seed", new SeedRequestModel
|
|
{
|
|
Template = "SingleUserScene",
|
|
Arguments = System.Text.Json.JsonSerializer.SerializeToElement(new { email = testEmail })
|
|
}, playId);
|
|
|
|
seedResponse.EnsureSuccessStatusCode();
|
|
}
|
|
|
|
// Delete all
|
|
var deleteResponse = await _client.DeleteAsync("/seed");
|
|
Assert.Equal(HttpStatusCode.NoContent, deleteResponse.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SeedEndpoint_VerifyResponseContainsMangleMapAndResult()
|
|
{
|
|
var testEmail = $"verify-response-{Guid.NewGuid()}@bitwarden.com";
|
|
var playId = Guid.NewGuid().ToString();
|
|
|
|
var response = await _client.PostAsJsonAsync("/seed", new SeedRequestModel
|
|
{
|
|
Template = "SingleUserScene",
|
|
Arguments = System.Text.Json.JsonSerializer.SerializeToElement(new { email = testEmail })
|
|
}, playId);
|
|
|
|
response.EnsureSuccessStatusCode();
|
|
var jsonString = await response.Content.ReadAsStringAsync();
|
|
|
|
// Verify the response contains MangleMap and Result fields
|
|
Assert.Contains("mangleMap", jsonString, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("result", jsonString, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private class BatchDeleteResponse
|
|
{
|
|
public string? Message { get; set; }
|
|
}
|
|
}
|