mirror of
https://github.com/bitwarden/server.git
synced 2026-01-31 22:23:18 +08:00
* Scenes should return resulting data in the result object The result is for data that cannot be known by the client requesting the scene and the mangle map used for mangling input values to enable parallelizing tests * Fix filenames * SingleUserScene now has a return value of various created User data * 1/100 too frequent for false test failures
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.NotNull(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; }
|
|
}
|
|
}
|