using Bit.Seeder; using Bit.Seeder.Pipeline; using Xunit; namespace Bit.SeederApi.IntegrationTest; public class RecipeBuilderValidationTests { [Fact] public void UseRoster_AfterAddUsers_ThrowsInvalidOperationException() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.AddUsers(10); var ex = Assert.Throws(() => builder.UseRoster("test")); Assert.Contains("Cannot call UseRoster() after AddUsers()", ex.Message); } [Fact] public void AddUsers_AfterUseRoster_ThrowsInvalidOperationException() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.UseRoster("test"); var ex = Assert.Throws(() => builder.AddUsers(10)); Assert.Contains("Cannot call AddUsers() after UseRoster()", ex.Message); } [Fact] public void UseCiphers_AfterAddCiphers_ThrowsInvalidOperationException() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.AddCiphers(10); var ex = Assert.Throws(() => builder.UseCiphers("test")); Assert.Contains("Cannot call UseCiphers() after AddCiphers()", ex.Message); } [Fact] public void AddCiphers_AfterUseCiphers_ThrowsInvalidOperationException() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.UseCiphers("test"); var ex = Assert.Throws(() => builder.AddCiphers(10)); Assert.Contains("Cannot call AddCiphers() after UseCiphers()", ex.Message); } [Fact] public void AddGroups_WithoutUsers_ThrowsInvalidOperationException() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); var ex = Assert.Throws(() => builder.AddGroups(5)); Assert.Contains("Groups require users", ex.Message); } [Fact] public void AddCollections_WithoutUsers_ThrowsInvalidOperationException() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); var ex = Assert.Throws(() => builder.AddCollections(5)); Assert.Contains("Collections require users", ex.Message); } [Fact] public void AddGroups_AfterAddUsers_Succeeds() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.AddUsers(10); builder.AddGroups(5); } [Fact] public void AddCollections_AfterUseRoster_Succeeds() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.UseRoster("test"); builder.AddCollections(5); } [Fact] public void Validate_WithoutOrg_ThrowsInvalidOperationException() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.AddOwner(); var ex = Assert.Throws(() => builder.Validate()); Assert.Contains("Organization is required", ex.Message); } [Fact] public void Validate_WithoutOwner_ThrowsInvalidOperationException() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.UseOrganization("test"); var ex = Assert.Throws(() => builder.Validate()); Assert.Contains("Owner is required", ex.Message); } [Fact] public void Validate_AddCiphersWithoutGenerator_ThrowsInvalidOperationException() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.UseOrganization("test"); builder.AddOwner(); builder.AddUsers(10); builder.AddCiphers(50); var ex = Assert.Throws(() => builder.Validate()); Assert.Contains("Generated ciphers require a generator", ex.Message); } [Fact] public void StepsExecuteInRegistrationOrder() { var services = new ServiceCollection(); var builder = services.AddRecipe("test"); builder.UseOrganization("test-org"); builder.AddOwner(); builder.WithGenerator("test.com"); builder.AddUsers(5); builder.AddGroups(2); builder.AddCollections(3); builder.AddCiphers(10); builder.Validate(); using var provider = services.BuildServiceProvider(); var steps = provider.GetKeyedServices("test").ToList(); Assert.Equal(7, steps.Count); // Verify steps are wrapped in OrderedStep with sequential order values var orderedSteps = steps.Cast().ToList(); for (var i = 0; i < orderedSteps.Count; i++) { Assert.Equal(i, orderedSteps[i].Order); } } }