Initial commit, project structure and domain models

This commit is contained in:
2026-04-07 09:14:06 -07:00
commit 7b15086fe5
111 changed files with 19818 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
using NUnit.Framework;
using MicCheck.Api.ApiKeys;
namespace MicCheck.Api.Tests.Unit.ApiKeys;
[TestFixture]
public class ApiKeyTests
{
[Test]
public void WhenAnApiKeyIsCreated_ThenRequiredFieldsAreSet()
{
var apiKey = new ApiKey
{
Key = "hashed-value",
Prefix = "abc12345",
Name = "CI Pipeline Key",
OrganizationId = 1
};
Assert.That(apiKey.Key, Is.EqualTo("hashed-value"));
Assert.That(apiKey.Prefix, Is.EqualTo("hashed-value".Substring(0, 8)).Or.EqualTo("abc12345"));
Assert.That(apiKey.Name, Is.EqualTo("CI Pipeline Key"));
Assert.That(apiKey.OrganizationId, Is.EqualTo(1));
}
[Test]
public void WhenAnApiKeyIsCreated_ThenIsActiveDefaultsToFalse()
{
var apiKey = new ApiKey
{
Key = "hashed-value",
Prefix = "abc12345",
Name = "Test Key",
OrganizationId = 1
};
Assert.That(apiKey.IsActive, Is.False);
}
[Test]
public void WhenAnApiKeyIsCreated_ThenExpiresAtDefaultsToNull()
{
var apiKey = new ApiKey
{
Key = "hashed-value",
Prefix = "abc12345",
Name = "Test Key",
OrganizationId = 1
};
Assert.That(apiKey.ExpiresAt, Is.Null);
}
}

View File

@@ -0,0 +1,42 @@
using NUnit.Framework;
using MicCheck.Api.Audit;
namespace MicCheck.Api.Tests.Unit.Audit;
[TestFixture]
public class AuditLogTests
{
[Test]
public void WhenAnAuditLogIsCreated_ThenRequiredFieldsAreSet()
{
var log = new AuditLog
{
ResourceType = "Feature",
ResourceId = "42",
Action = "Created",
OrganizationId = 1
};
Assert.That(log.ResourceType, Is.EqualTo("Feature"));
Assert.That(log.ResourceId, Is.EqualTo("42"));
Assert.That(log.Action, Is.EqualTo("Created"));
Assert.That(log.OrganizationId, Is.EqualTo(1));
}
[Test]
public void WhenAnAuditLogIsCreated_ThenOptionalFieldsDefaultToNull()
{
var log = new AuditLog
{
ResourceType = "Feature",
ResourceId = "1",
Action = "Deleted",
OrganizationId = 1
};
Assert.That(log.Changes, Is.Null);
Assert.That(log.ProjectId, Is.Null);
Assert.That(log.EnvironmentId, Is.Null);
Assert.That(log.ActorUserId, Is.Null);
}
}

View File

@@ -0,0 +1,75 @@
using System.Net;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using NUnit.Framework;
using MicCheck.Api.Auth;
namespace MicCheck.Api.Tests.Unit.Auth;
[TestFixture]
public class AuthEndpointsTests
{
private WebApplicationFactory<Program> _factory = null!;
private Mock<ITokenService> _tokenService = null!;
[SetUp]
public void SetUp()
{
_tokenService = new Mock<ITokenService>();
_factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(host =>
{
host.ConfigureServices(services =>
{
services.AddScoped<ITokenService>(_ => _tokenService.Object);
});
});
}
[TearDown]
public void TearDown() => _factory.Dispose();
[Test]
public async Task WhenUsernameIsEmpty_ThenBadRequestIsReturned()
{
var client = _factory.CreateClient();
var response = await client.PostAsJsonAsync("/auth/token",
new TokenRequest("", "password123"));
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task WhenPasswordIsEmpty_ThenBadRequestIsReturned()
{
var client = _factory.CreateClient();
var response = await client.PostAsJsonAsync("/auth/token",
new TokenRequest("testuser", ""));
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task WhenValidCredentialsAreProvided_ThenOkIsReturnedWithToken()
{
var expectedResponse = new TokenResponse("signed.jwt.token", DateTime.UtcNow.AddHours(1));
_tokenService
.Setup(s => s.GenerateToken("testuser"))
.Returns(expectedResponse);
var client = _factory.CreateClient();
var response = await client.PostAsJsonAsync("/auth/token",
new TokenRequest("testuser", "password123"));
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var body = await response.Content.ReadFromJsonAsync<TokenResponse>();
Assert.That(body?.Token, Is.EqualTo(expectedResponse.Token));
}
}

View File

@@ -0,0 +1,67 @@
using System.IdentityModel.Tokens.Jwt;
using Microsoft.Extensions.Configuration;
using MicCheck.Api.Auth;
using NUnit.Framework;
namespace MicCheck.Api.Tests.Unit.Auth;
[TestFixture]
public class TokenServiceTests
{
private IConfiguration _configuration = null!;
private TokenService _tokenService = null!;
[SetUp]
public void SetUp()
{
_configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Jwt:SecretKey"] = "test-secret-key-that-is-long-enough-32c",
["Jwt:Issuer"] = "MicCheck",
["Jwt:Audience"] = "MicCheck",
["Jwt:ExpiryMinutes"] = "60",
})
.Build();
_tokenService = new TokenService(_configuration);
}
[Test]
public void WhenAUsernameIsProvided_ThenATokenIsReturned()
{
var result = _tokenService.GenerateToken("testuser");
Assert.That(result.Token, Is.Not.Null.And.Not.Empty);
}
[Test]
public void WhenATokenIsGenerated_ThenItContainsTheUsernameAsSubjectClaim()
{
var result = _tokenService.GenerateToken("testuser");
var handler = new JwtSecurityTokenHandler();
var jwt = handler.ReadJwtToken(result.Token);
Assert.That(jwt.Subject, Is.EqualTo("testuser"));
}
[Test]
public void WhenATokenIsGenerated_ThenItHasAFutureExpiry()
{
var result = _tokenService.GenerateToken("testuser");
Assert.That(result.ExpiresAt, Is.GreaterThan(DateTime.UtcNow));
}
[Test]
public void WhenATokenIsGenerated_ThenItHasTheConfiguredIssuer()
{
var result = _tokenService.GenerateToken("testuser");
var handler = new JwtSecurityTokenHandler();
var jwt = handler.ReadJwtToken(result.Token);
Assert.That(jwt.Issuer, Is.EqualTo("MicCheck"));
}
}

View File

@@ -0,0 +1,25 @@
using NUnit.Framework;
using AppEnvironment = MicCheck.Api.Environments.Environment;
namespace MicCheck.Api.Tests.Unit.Environments;
[TestFixture]
public class EnvironmentTests
{
[Test]
public void WhenAnEnvironmentIsCreated_ThenFeatureStatesCollectionIsInitializedEmpty()
{
var environment = new AppEnvironment { Name = "Production", ApiKey = "env-key-abc" };
Assert.That(environment.FeatureStates, Is.Empty);
}
[Test]
public void WhenAnEnvironmentIsCreated_ThenNameAndApiKeyAreSet()
{
var environment = new AppEnvironment { Name = "Staging", ApiKey = "env-key-xyz" };
Assert.That(environment.Name, Is.EqualTo("Staging"));
Assert.That(environment.ApiKey, Is.EqualTo("env-key-xyz"));
}
}

View File

@@ -0,0 +1,110 @@
using NUnit.Framework;
using MicCheck.Api.Features;
namespace MicCheck.Api.Tests.Unit.Features;
[TestFixture]
public class FeatureTests
{
[Test]
public void WhenAFeatureIsCreated_ThenCollectionsAreInitializedEmpty()
{
var feature = new Feature { Name = "dark_mode", ProjectId = 1 };
Assert.That(feature.FeatureStates, Is.Empty);
Assert.That(feature.Tags, Is.Empty);
}
[Test]
public void WhenAFeatureIsCreated_ThenTypeDefaultsToStandard()
{
var feature = new Feature { Name = "dark_mode", ProjectId = 1 };
Assert.That(feature.Type, Is.EqualTo(FeatureType.Standard));
}
[Test]
public void WhenAFeatureIsCreated_ThenDefaultEnabledIsFalse()
{
var feature = new Feature { Name = "dark_mode", ProjectId = 1 };
Assert.That(feature.DefaultEnabled, Is.False);
}
[Test]
public void WhenAFeatureTypeIsSetToMultiVariate_ThenThePropertyReflectsTheChange()
{
var feature = new Feature { Name = "experiment", ProjectId = 1, Type = FeatureType.MultiVariate };
Assert.That(feature.Type, Is.EqualTo(FeatureType.MultiVariate));
}
}
[TestFixture]
public class FeatureStateTests
{
[Test]
public void WhenAFeatureStateIsCreated_ThenEnabledDefaultsToFalse()
{
var state = new FeatureState { FeatureId = 1, EnvironmentId = 1 };
Assert.That(state.Enabled, Is.False);
}
[Test]
public void WhenAFeatureStateIdentityIdIsNull_ThenItRepresentsAnEnvironmentLevelState()
{
var state = new FeatureState { FeatureId = 1, EnvironmentId = 1 };
Assert.That(state.IdentityId, Is.Null);
}
[Test]
public void WhenAFeatureStateFeatureSegmentIdIsNull_ThenItIsNotASegmentOverride()
{
var state = new FeatureState { FeatureId = 1, EnvironmentId = 1 };
Assert.That(state.FeatureSegmentId, Is.Null);
}
}
[TestFixture]
public class FeatureStateResultTests
{
[Test]
public void WhenAFeatureStateResultIsCreated_ThenFeatureAndEnabledAreSet()
{
var feature = new Feature { Name = "dark_mode", ProjectId = 1 };
var result = new FeatureStateResult { Feature = feature, Enabled = true };
Assert.That(result.Feature, Is.SameAs(feature));
Assert.That(result.Enabled, Is.True);
Assert.That(result.Value, Is.Null);
}
}
[TestFixture]
public class FeatureSegmentTests
{
[Test]
public void WhenAFeatureSegmentIsCreated_ThenFeatureStateIsNull()
{
var segment = new FeatureSegment { FeatureId = 1, SegmentId = 2, EnvironmentId = 3 };
Assert.That(segment.FeatureState, Is.Null);
}
}
[TestFixture]
public class TagTests
{
[Test]
public void WhenATagIsCreated_ThenLabelColorAndProjectIdAreSet()
{
var tag = new Tag { Label = "Beta", Color = "#FF0000", ProjectId = 1 };
Assert.That(tag.Label, Is.EqualTo("Beta"));
Assert.That(tag.Color, Is.EqualTo("#FF0000"));
Assert.That(tag.ProjectId, Is.EqualTo(1));
}
}

View File

@@ -0,0 +1,64 @@
using NUnit.Framework;
using MicCheck.Api.Identities;
namespace MicCheck.Api.Tests.Unit.Identities;
[TestFixture]
public class IdentityTests
{
[Test]
public void WhenAnIdentityIsCreated_ThenCollectionsAreInitializedEmpty()
{
var identity = new Identity { Identifier = "user-123", EnvironmentId = 1 };
Assert.That(identity.Traits, Is.Empty);
Assert.That(identity.FeatureStateOverrides, Is.Empty);
}
[Test]
public void WhenAnIdentityIsCreated_ThenIdentifierAndEnvironmentIdAreSet()
{
var identity = new Identity { Identifier = "user-123", EnvironmentId = 5 };
Assert.That(identity.Identifier, Is.EqualTo("user-123"));
Assert.That(identity.EnvironmentId, Is.EqualTo(5));
}
}
[TestFixture]
public class IdentityTraitTests
{
[Test]
public void WhenAnIdentityTraitIsCreated_ThenKeyAndValueAreSet()
{
var trait = new IdentityTrait { IdentityId = 1, Key = "plan", Value = "premium" };
Assert.That(trait.Key, Is.EqualTo("plan"));
Assert.That(trait.Value, Is.EqualTo("premium"));
}
[Test]
public void WhenAnIdentityTraitValueTypeIsSet_ThenTheTypeIsStored()
{
var trait = new IdentityTrait
{
IdentityId = 1,
Key = "age",
Value = "30",
ValueType = TraitValueType.Integer
};
Assert.That(trait.ValueType, Is.EqualTo(TraitValueType.Integer));
}
[Test]
public void WhenAllTraitValueTypesAreChecked_ThenAllExpectedValuesExist()
{
var types = Enum.GetValues<TraitValueType>();
Assert.That(types, Contains.Item(TraitValueType.String));
Assert.That(types, Contains.Item(TraitValueType.Integer));
Assert.That(types, Contains.Item(TraitValueType.Float));
Assert.That(types, Contains.Item(TraitValueType.Boolean));
}
}

View File

@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="NUnit" Version="4.5.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../../src/api/MicCheck.Api/MicCheck.Api.csproj" />
<ProjectReference Include="../../../src/infrastructure/MicCheck.Infrastructure/MicCheck.Infrastructure.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,70 @@
using NUnit.Framework;
using MicCheck.Api.ApiKeys;
using MicCheck.Api.Organizations;
using MicCheck.Api.Projects;
namespace MicCheck.Api.Tests.Unit.Organizations;
[TestFixture]
public class OrganizationTests
{
[Test]
public void WhenAnOrganizationIsCreated_ThenCollectionsAreInitializedEmpty()
{
var organization = new Organization { Name = "Acme" };
Assert.That(organization.Projects, Is.Empty);
Assert.That(organization.Members, Is.Empty);
Assert.That(organization.ApiKeys, Is.Empty);
}
[Test]
public void WhenAnOrganizationIsCreated_ThenNameIsSet()
{
var organization = new Organization { Name = "Acme" };
Assert.That(organization.Name, Is.EqualTo("Acme"));
}
[Test]
public void WhenAProjectIsAddedToAnOrganization_ThenItAppearsInTheProjectsCollection()
{
var organization = new Organization { Name = "Acme" };
var project = new Project { Name = "My Project", OrganizationId = organization.Id };
organization.Projects.Add(project);
Assert.That(organization.Projects, Has.Count.EqualTo(1));
}
[Test]
public void WhenAnApiKeyIsAddedToAnOrganization_ThenItAppearsInTheApiKeysCollection()
{
var organization = new Organization { Name = "Acme" };
var apiKey = new ApiKey { Key = "hashed-key", Prefix = "abc12345", Name = "CI Key", OrganizationId = organization.Id };
organization.ApiKeys.Add(apiKey);
Assert.That(organization.ApiKeys, Has.Count.EqualTo(1));
}
}
[TestFixture]
public class OrganizationUserTests
{
[Test]
public void WhenAnOrganizationUserIsCreated_ThenRoleDefaultsToUser()
{
var member = new OrganizationUser { OrganizationId = 1, UserId = 1 };
Assert.That(member.Role, Is.EqualTo(OrganizationRole.User));
}
[Test]
public void WhenAnOrganizationUserRoleIsSetToAdmin_ThenRoleIsAdmin()
{
var member = new OrganizationUser { OrganizationId = 1, UserId = 1, Role = OrganizationRole.Admin };
Assert.That(member.Role, Is.EqualTo(OrganizationRole.Admin));
}
}

View File

@@ -0,0 +1,36 @@
using NUnit.Framework;
using MicCheck.Api.Projects;
namespace MicCheck.Api.Tests.Unit.Projects;
[TestFixture]
public class ProjectTests
{
[Test]
public void WhenAProjectIsCreated_ThenCollectionsAreInitializedEmpty()
{
var project = new Project { Name = "My Project", OrganizationId = 1 };
Assert.That(project.Environments, Is.Empty);
Assert.That(project.Features, Is.Empty);
Assert.That(project.Segments, Is.Empty);
}
[Test]
public void WhenAProjectIsCreated_ThenHideDisabledFlagsDefaultsToFalse()
{
var project = new Project { Name = "My Project", OrganizationId = 1 };
Assert.That(project.HideDisabledFlags, Is.False);
}
[Test]
public void WhenAProjectHideDisabledFlagsIsEnabled_ThenThePropertyReflectsTheChange()
{
var project = new Project { Name = "My Project", OrganizationId = 1 };
project.HideDisabledFlags = true;
Assert.That(project.HideDisabledFlags, Is.True);
}
}

View File

@@ -0,0 +1,100 @@
using NUnit.Framework;
using MicCheck.Api.Segments;
namespace MicCheck.Api.Tests.Unit.Segments;
[TestFixture]
public class SegmentTests
{
[Test]
public void WhenASegmentIsCreated_ThenRulesCollectionIsInitializedEmpty()
{
var segment = new Segment { Name = "Premium Users", ProjectId = 1 };
Assert.That(segment.Rules, Is.Empty);
}
[Test]
public void WhenASegmentIsCreated_ThenNameAndProjectIdAreSet()
{
var segment = new Segment { Name = "Beta Testers", ProjectId = 5 };
Assert.That(segment.Name, Is.EqualTo("Beta Testers"));
Assert.That(segment.ProjectId, Is.EqualTo(5));
}
}
[TestFixture]
public class SegmentRuleTests
{
[Test]
public void WhenASegmentRuleIsCreated_ThenConditionsAndChildRulesAreInitializedEmpty()
{
var rule = new SegmentRule { SegmentId = 1 };
Assert.That(rule.Conditions, Is.Empty);
Assert.That(rule.ChildRules, Is.Empty);
}
[Test]
public void WhenASegmentRuleIsCreated_ThenParentRuleIdIsNull()
{
var rule = new SegmentRule { SegmentId = 1 };
Assert.That(rule.ParentRuleId, Is.Null);
}
[TestCase(SegmentRuleType.All)]
[TestCase(SegmentRuleType.Any)]
[TestCase(SegmentRuleType.None)]
public void WhenASegmentRuleTypeIsSet_ThenTheTypeIsStored(SegmentRuleType type)
{
var rule = new SegmentRule { SegmentId = 1, Type = type };
Assert.That(rule.Type, Is.EqualTo(type));
}
}
[TestFixture]
public class SegmentConditionTests
{
[Test]
public void WhenASegmentConditionIsCreated_ThenPropertyAndValueAreSet()
{
var condition = new SegmentCondition
{
RuleId = 1,
Property = "plan",
Operator = SegmentConditionOperator.Equal,
Value = "premium"
};
Assert.That(condition.Property, Is.EqualTo("plan"));
Assert.That(condition.Value, Is.EqualTo("premium"));
Assert.That(condition.Operator, Is.EqualTo(SegmentConditionOperator.Equal));
}
[Test]
public void WhenAllSegmentConditionOperatorsAreChecked_ThenAllExpectedValuesExist()
{
var operators = Enum.GetValues<SegmentConditionOperator>();
Assert.That(operators, Contains.Item(SegmentConditionOperator.Equal));
Assert.That(operators, Contains.Item(SegmentConditionOperator.NotEqual));
Assert.That(operators, Contains.Item(SegmentConditionOperator.GreaterThan));
Assert.That(operators, Contains.Item(SegmentConditionOperator.GreaterThanOrEqual));
Assert.That(operators, Contains.Item(SegmentConditionOperator.LessThan));
Assert.That(operators, Contains.Item(SegmentConditionOperator.LessThanOrEqual));
Assert.That(operators, Contains.Item(SegmentConditionOperator.Contains));
Assert.That(operators, Contains.Item(SegmentConditionOperator.NotContains));
Assert.That(operators, Contains.Item(SegmentConditionOperator.Regex));
Assert.That(operators, Contains.Item(SegmentConditionOperator.IsSet));
Assert.That(operators, Contains.Item(SegmentConditionOperator.IsNotSet));
Assert.That(operators, Contains.Item(SegmentConditionOperator.In));
Assert.That(operators, Contains.Item(SegmentConditionOperator.NotIn));
Assert.That(operators, Contains.Item(SegmentConditionOperator.PercentageSplit));
Assert.That(operators, Contains.Item(SegmentConditionOperator.ModuloValueDivisorRemainder));
Assert.That(operators, Contains.Item(SegmentConditionOperator.IsTrue));
Assert.That(operators, Contains.Item(SegmentConditionOperator.IsFalse));
}
}

View File

@@ -0,0 +1,64 @@
using NUnit.Framework;
using MicCheck.Api.Users;
namespace MicCheck.Api.Tests.Unit.Users;
[TestFixture]
public class UserTests
{
[Test]
public void WhenAUserIsCreated_ThenOrganizationsCollectionIsInitializedEmpty()
{
var user = new User
{
Email = "alice@example.com",
PasswordHash = "hashed",
FirstName = "Alice",
LastName = "Smith"
};
Assert.That(user.Organizations, Is.Empty);
}
[Test]
public void WhenAUserIsCreated_ThenIsActiveDefaultsToFalse()
{
var user = new User
{
Email = "alice@example.com",
PasswordHash = "hashed",
FirstName = "Alice",
LastName = "Smith"
};
Assert.That(user.IsActive, Is.False);
}
[Test]
public void WhenAUserIsCreated_ThenIsTwoFactorEnabledDefaultsToFalse()
{
var user = new User
{
Email = "alice@example.com",
PasswordHash = "hashed",
FirstName = "Alice",
LastName = "Smith"
};
Assert.That(user.IsTwoFactorEnabled, Is.False);
}
[Test]
public void WhenAUserIsCreated_ThenLastLoginAtDefaultsToNull()
{
var user = new User
{
Email = "alice@example.com",
PasswordHash = "hashed",
FirstName = "Alice",
LastName = "Smith"
};
Assert.That(user.LastLoginAt, Is.Null);
}
}

View File

@@ -0,0 +1,89 @@
using NUnit.Framework;
using MicCheck.Api.Webhooks;
namespace MicCheck.Api.Tests.Unit.Webhooks;
[TestFixture]
public class WebhookTests
{
[Test]
public void WhenAWebhookIsCreated_ThenUrlAndScopeAreSet()
{
var webhook = new Webhook { Url = "https://example.com/hook", Scope = WebhookScope.Environment };
Assert.That(webhook.Url, Is.EqualTo("https://example.com/hook"));
Assert.That(webhook.Scope, Is.EqualTo(WebhookScope.Environment));
}
[Test]
public void WhenAWebhookIsCreated_ThenSecretDefaultsToNull()
{
var webhook = new Webhook { Url = "https://example.com/hook", Scope = WebhookScope.Organization };
Assert.That(webhook.Secret, Is.Null);
}
[Test]
public void WhenAWebhookIsCreated_ThenEnabledDefaultsToFalse()
{
var webhook = new Webhook { Url = "https://example.com/hook", Scope = WebhookScope.Environment };
Assert.That(webhook.Enabled, Is.False);
}
[Test]
public void WhenAllWebhookScopesAreChecked_ThenAllExpectedValuesExist()
{
var scopes = Enum.GetValues<WebhookScope>();
Assert.That(scopes, Contains.Item(WebhookScope.Environment));
Assert.That(scopes, Contains.Item(WebhookScope.Organization));
}
}
[TestFixture]
public class WebhookDeliveryLogTests
{
[Test]
public void WhenAWebhookDeliveryLogIsCreated_ThenRequiredFieldsAreSet()
{
var log = new WebhookDeliveryLog
{
WebhookId = 1,
EventType = "FLAG_UPDATED",
PayloadJson = "{}"
};
Assert.That(log.WebhookId, Is.EqualTo(1));
Assert.That(log.EventType, Is.EqualTo("FLAG_UPDATED"));
Assert.That(log.PayloadJson, Is.EqualTo("{}"));
}
[Test]
public void WhenAWebhookDeliveryLogIsCreated_ThenOptionalFieldsDefaultToNull()
{
var log = new WebhookDeliveryLog
{
WebhookId = 1,
EventType = "FLAG_UPDATED",
PayloadJson = "{}"
};
Assert.That(log.ResponseStatusCode, Is.Null);
Assert.That(log.ResponseBody, Is.Null);
Assert.That(log.ErrorMessage, Is.Null);
}
[Test]
public void WhenAWebhookDeliveryLogIsCreated_ThenSuccessDefaultsToFalse()
{
var log = new WebhookDeliveryLog
{
WebhookId = 1,
EventType = "FLAG_UPDATED",
PayloadJson = "{}"
};
Assert.That(log.Success, Is.False);
}
}