chore: update project structure with contracts and services for CaddyManager, including configuration and Docker integration
All checks were successful
Caddy Manager CI build / docker (push) Successful in 1m16s

This commit is contained in:
2025-07-23 10:37:51 +07:00
parent 18c710d341
commit ec454d0346
56 changed files with 8511 additions and 34 deletions

View File

@@ -0,0 +1,616 @@
using CaddyManager.Models.Caddy;
namespace CaddyManager.Tests.Models.Caddy;
/// <summary>
/// Tests for CaddyConfigurationInfo model
/// </summary>
public class CaddyConfigurationInfoTests
{
/// <summary>
/// Tests that the CaddyConfigurationInfo constructor initializes all properties with appropriate default values.
/// Setup: Creates a new CaddyConfigurationInfo instance using the default constructor.
/// Expectation: All collection properties should be initialized as empty but non-null collections, and string properties should be empty strings, ensuring the model is ready for immediate use in Caddy configuration management without null reference exceptions.
/// </summary>
[Fact]
public void Constructor_InitializesWithDefaultValues()
{
// Act
var info = new CaddyConfigurationInfo();
// Assert
info.Hostnames.Should().NotBeNull();
info.Hostnames.Should().BeEmpty();
info.ReverseProxyHostname.Should().Be(string.Empty);
info.ReverseProxyPorts.Should().NotBeNull();
info.ReverseProxyPorts.Should().BeEmpty();
info.FileName.Should().Be(string.Empty);
info.AggregatedReverseProxyPorts.Should().NotBeNull();
info.AggregatedReverseProxyPorts.Should().BeEmpty();
}
/// <summary>
/// Tests that all CaddyConfigurationInfo properties can be properly set and retrieved with various data types.
/// Setup: Creates test data including hostname lists, reverse proxy configuration, file names, and port collections that represent typical Caddy configuration scenarios.
/// Expectation: All properties should store and return the exact values assigned, ensuring data integrity for Caddy configuration information used in reverse proxy management and file-based configuration tracking.
/// </summary>
[Fact]
public void Properties_CanBeSetAndRetrieved()
{
// Arrange
var hostnames = new List<string> { "example.com", "www.example.com" };
var reverseProxyHostname = "localhost";
var reverseProxyPorts = new List<int> { 8080, 9090 };
var fileName = "test-config";
var aggregatedPorts = new List<int> { 8080, 9090, 3000 };
// Act
var info = new CaddyConfigurationInfo
{
Hostnames = hostnames,
ReverseProxyHostname = reverseProxyHostname,
ReverseProxyPorts = reverseProxyPorts,
FileName = fileName,
AggregatedReverseProxyPorts = aggregatedPorts
};
// Assert
info.Hostnames.Should().BeEquivalentTo(hostnames);
info.ReverseProxyHostname.Should().Be(reverseProxyHostname);
info.ReverseProxyPorts.Should().BeEquivalentTo(reverseProxyPorts);
info.FileName.Should().Be(fileName);
info.AggregatedReverseProxyPorts.Should().BeEquivalentTo(aggregatedPorts);
}
/// <summary>
/// Tests that two CaddyConfigurationInfo instances with identical FileName values are considered equal.
/// Setup: Creates two separate CaddyConfigurationInfo instances with the same FileName but potentially different other properties.
/// Expectation: The Equals method should return true since equality is based solely on FileName, enabling proper configuration identification and deduplication in Caddy management operations where configurations are uniquely identified by their file names.
/// </summary>
[Fact]
public void Equals_WithSameFileName_ReturnsTrue()
{
// Arrange
var info1 = new CaddyConfigurationInfo { FileName = "test" };
var info2 = new CaddyConfigurationInfo { FileName = "test" };
// Act & Assert
info1.Equals(info2).Should().BeTrue();
info2.Equals(info1).Should().BeTrue();
}
/// <summary>
/// Tests that two CaddyConfigurationInfo instances with different FileName values are not considered equal.
/// Setup: Creates two CaddyConfigurationInfo instances with different FileName values.
/// Expectation: The Equals method should return false, ensuring that configurations with different file names are treated as distinct entities in Caddy configuration management, preventing accidental merging or confusion between separate configuration files.
/// </summary>
[Fact]
public void Equals_WithDifferentFileName_ReturnsFalse()
{
// Arrange
var info1 = new CaddyConfigurationInfo { FileName = "test1" };
var info2 = new CaddyConfigurationInfo { FileName = "test2" };
// Act & Assert
info1.Equals(info2).Should().BeFalse();
info2.Equals(info1).Should().BeFalse();
}
/// <summary>
/// Tests that CaddyConfigurationInfo equality is determined solely by FileName, ignoring all other property differences.
/// Setup: Creates two instances with identical FileName but completely different hostnames, reverse proxy settings, and port configurations.
/// Expectation: The Equals method should return true, confirming that only FileName determines equality, which is crucial for configuration management where the same file might have different runtime properties but represents the same logical configuration unit.
/// </summary>
[Fact]
public void Equals_WithSameFileNameButDifferentOtherProperties_ReturnsTrue()
{
// Arrange
var info1 = new CaddyConfigurationInfo
{
FileName = "test",
Hostnames = new List<string> { "example.com" },
ReverseProxyHostname = "localhost",
ReverseProxyPorts = new List<int> { 8080 }
};
var info2 = new CaddyConfigurationInfo
{
FileName = "test",
Hostnames = new List<string> { "different.com" },
ReverseProxyHostname = "different-host",
ReverseProxyPorts = new List<int> { 9090 }
};
// Act & Assert
info1.Equals(info2).Should().BeTrue();
}
/// <summary>
/// Tests that comparing a CaddyConfigurationInfo instance with null returns false.
/// Setup: Creates a valid CaddyConfigurationInfo instance and compares it with null.
/// Expectation: The Equals method should return false when compared with null, ensuring robust null-safety in configuration comparison operations and preventing null reference exceptions in Caddy management workflows.
/// </summary>
[Fact]
public void Equals_WithNull_ReturnsFalse()
{
// Arrange
var info = new CaddyConfigurationInfo { FileName = "test" };
// Act & Assert
info.Equals(null).Should().BeFalse();
}
/// <summary>
/// Tests that comparing a CaddyConfigurationInfo instance with an object of a different type returns false.
/// Setup: Creates a CaddyConfigurationInfo instance and compares it with a string object.
/// Expectation: The Equals method should return false when compared with different object types, ensuring type safety in configuration comparison operations and maintaining proper object equality semantics in Caddy management systems.
/// </summary>
[Fact]
public void Equals_WithDifferentType_ReturnsFalse()
{
// Arrange
var info = new CaddyConfigurationInfo { FileName = "test" };
var otherObject = "test";
// Act & Assert
info.Equals(otherObject).Should().BeFalse();
}
/// <summary>
/// Tests that a CaddyConfigurationInfo instance is equal to itself (reflexive property of equality).
/// Setup: Creates a CaddyConfigurationInfo instance and compares it with itself.
/// Expectation: The Equals method should return true when an instance is compared with itself, satisfying the reflexive property of equality and ensuring consistent behavior in configuration management operations where self-comparison might occur.
/// </summary>
[Fact]
public void Equals_WithSameInstance_ReturnsTrue()
{
// Arrange
var info = new CaddyConfigurationInfo { FileName = "test" };
// Act & Assert
info.Equals(info).Should().BeTrue();
}
/// <summary>
/// Tests that two CaddyConfigurationInfo instances with the same FileName produce identical hash codes.
/// Setup: Creates two separate instances with identical FileName values and calculates their hash codes.
/// Expectation: Both instances should produce the same hash code, ensuring proper behavior in hash-based collections like dictionaries and hash sets used for efficient configuration lookup and storage in Caddy management systems.
/// </summary>
[Fact]
public void GetHashCode_WithSameFileName_ReturnsSameHashCode()
{
// Arrange
var info1 = new CaddyConfigurationInfo { FileName = "test" };
var info2 = new CaddyConfigurationInfo { FileName = "test" };
// Act
var hash1 = info1.GetHashCode();
var hash2 = info2.GetHashCode();
// Assert
hash1.Should().Be(hash2);
}
/// <summary>
/// Tests that two CaddyConfigurationInfo instances with different FileName values produce different hash codes.
/// Setup: Creates two instances with different FileName values and calculates their hash codes.
/// Expectation: The instances should produce different hash codes, ensuring good hash distribution for efficient storage and retrieval in hash-based collections used for Caddy configuration management and reducing hash collisions.
/// </summary>
[Fact]
public void GetHashCode_WithDifferentFileName_ReturnsDifferentHashCode()
{
// Arrange
var info1 = new CaddyConfigurationInfo { FileName = "test1" };
var info2 = new CaddyConfigurationInfo { FileName = "test2" };
// Act
var hash1 = info1.GetHashCode();
var hash2 = info2.GetHashCode();
// Assert
hash1.Should().NotBe(hash2);
}
/// <summary>
/// Tests that CaddyConfigurationInfo instances with empty FileName values produce consistent hash codes.
/// Setup: Creates two instances with empty FileName values and calculates their hash codes.
/// Expectation: Both instances should produce identical hash codes, ensuring that configurations with empty file names (edge cases) behave consistently in hash-based operations and don't cause issues in Caddy configuration management systems.
/// </summary>
[Fact]
public void GetHashCode_WithEmptyFileName_ReturnsConsistentHashCode()
{
// Arrange
var info1 = new CaddyConfigurationInfo { FileName = string.Empty };
var info2 = new CaddyConfigurationInfo { FileName = string.Empty };
// Act
var hash1 = info1.GetHashCode();
var hash2 = info2.GetHashCode();
// Assert
hash1.Should().Be(hash2);
}
/// <summary>
/// Tests that CaddyConfigurationInfo instances produce consistent hash codes across various FileName formats and lengths.
/// Setup: Uses parameterized test data including empty strings, short names, and long names with special characters representing different Caddy configuration file naming patterns.
/// Expectation: Each FileName should consistently produce the same hash code across multiple instances, ensuring reliable behavior in hash-based collections regardless of configuration file naming conventions used in Caddy deployments.
/// </summary>
[Theory]
[InlineData("")]
[InlineData("test")]
[InlineData("very-long-configuration-file-name-with-special-characters-123")]
public void GetHashCode_WithVariousFileNames_ReturnsConsistentHashCode(string fileName)
{
// Arrange
var info1 = new CaddyConfigurationInfo { FileName = fileName };
var info2 = new CaddyConfigurationInfo { FileName = fileName };
// Act
var hash1 = info1.GetHashCode();
var hash2 = info2.GetHashCode();
// Assert
hash1.Should().Be(hash2);
}
/// <summary>
/// Tests that the Hostnames collection can be modified after CaddyConfigurationInfo creation.
/// Setup: Creates a CaddyConfigurationInfo instance and adds multiple hostname entries to the Hostnames collection.
/// Expectation: The collection should accept new entries and maintain them correctly, enabling dynamic hostname management for Caddy configurations where domains can be added or modified during runtime configuration updates.
/// </summary>
[Fact]
public void Hostnames_CanBeModified()
{
// Arrange
var info = new CaddyConfigurationInfo();
// Act
info.Hostnames.Add("example.com");
info.Hostnames.Add("www.example.com");
// Assert
info.Hostnames.Should().HaveCount(2);
info.Hostnames.Should().Contain("example.com");
info.Hostnames.Should().Contain("www.example.com");
}
/// <summary>
/// Tests that the ReverseProxyPorts collection can be modified after CaddyConfigurationInfo creation.
/// Setup: Creates a CaddyConfigurationInfo instance and adds multiple port numbers to the ReverseProxyPorts collection.
/// Expectation: The collection should accept new port entries and maintain them correctly, enabling dynamic port configuration management for Caddy reverse proxy setups where backend service ports can be added or changed during configuration updates.
/// </summary>
[Fact]
public void ReverseProxyPorts_CanBeModified()
{
// Arrange
var info = new CaddyConfigurationInfo();
// Act
info.ReverseProxyPorts.Add(8080);
info.ReverseProxyPorts.Add(9090);
// Assert
info.ReverseProxyPorts.Should().HaveCount(2);
info.ReverseProxyPorts.Should().Contain(8080);
info.ReverseProxyPorts.Should().Contain(9090);
}
/// <summary>
/// Tests that the AggregatedReverseProxyPorts collection can be modified after CaddyConfigurationInfo creation.
/// Setup: Creates a CaddyConfigurationInfo instance and adds multiple port numbers to the AggregatedReverseProxyPorts collection.
/// Expectation: The collection should accept new port entries and maintain them correctly, enabling management of aggregated port information across multiple configurations, which is essential for comprehensive Caddy deployment monitoring and port conflict detection.
/// </summary>
[Fact]
public void AggregatedReverseProxyPorts_CanBeModified()
{
// Arrange
var info = new CaddyConfigurationInfo();
// Act
info.AggregatedReverseProxyPorts.Add(3000);
info.AggregatedReverseProxyPorts.Add(4000);
// Assert
info.AggregatedReverseProxyPorts.Should().HaveCount(2);
info.AggregatedReverseProxyPorts.Should().Contain(3000);
info.AggregatedReverseProxyPorts.Should().Contain(4000);
}
#region Additional Edge Cases and Boundary Value Tests
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles null hostnames gracefully.
/// Setup: Creates a CaddyConfigurationInfo instance and assigns null to the Hostnames property.
/// Expectation: The model should handle null hostnames gracefully, either by treating null as empty list or providing appropriate null handling, ensuring robust operation with null inputs.
/// </summary>
[Fact]
public void Hostnames_WithNullValue_HandlesGracefully()
{
// Arrange
var info = new CaddyConfigurationInfo();
// Act
info.Hostnames = null!;
// Assert
// The model should handle null assignment gracefully
// This test verifies that the model doesn't crash with null assignments
info.Hostnames.Should().BeNull();
}
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles very large hostname lists efficiently.
/// Setup: Creates a CaddyConfigurationInfo with a very large list of hostnames to test performance and memory usage.
/// Expectation: The model should handle large hostname lists efficiently without performance issues, ensuring the system can handle complex Caddy configurations with many hostnames.
/// </summary>
[Fact]
public void Hostnames_WithLargeList_HandlesEfficiently()
{
// Arrange
var largeHostnameList = new List<string>();
for (int i = 0; i < 10000; i++)
{
largeHostnameList.Add($"host{i}.example.com");
}
// Act
var info = new CaddyConfigurationInfo
{
Hostnames = largeHostnameList
};
// Assert
info.Hostnames.Should().NotBeNull();
info.Hostnames.Should().HaveCount(10000);
info.Hostnames.Should().Contain("host0.example.com");
info.Hostnames.Should().Contain("host9999.example.com");
}
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles Unicode and special characters in hostnames correctly.
/// Setup: Creates a CaddyConfigurationInfo with hostnames containing Unicode characters and special symbols.
/// Expectation: The model should correctly handle Unicode and special characters in hostnames, ensuring support for international domain names and special naming conventions.
/// </summary>
[Fact]
public void Hostnames_WithUnicodeAndSpecialCharacters_HandlesCorrectly()
{
// Arrange
var unicodeHostnames = new List<string>
{
"测试.example.com",
"api-测试.local",
"special-chars!@#$.test",
"host-with-spaces.example.com",
"host.with.dots.example.com"
};
// Act
var info = new CaddyConfigurationInfo
{
Hostnames = unicodeHostnames
};
// Assert
info.Hostnames.Should().NotBeNull();
info.Hostnames.Should().HaveCount(5);
info.Hostnames.Should().Contain("测试.example.com");
info.Hostnames.Should().Contain("api-测试.local");
info.Hostnames.Should().Contain("special-chars!@#$.test");
}
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles boundary values for reverse proxy ports correctly.
/// Setup: Creates a CaddyConfigurationInfo with boundary port values including minimum, maximum, and edge case port numbers.
/// Expectation: The model should handle boundary port values correctly, ensuring proper validation and storage of port numbers across the valid port range.
/// </summary>
[Fact]
public void ReverseProxyPorts_WithBoundaryValues_HandlesCorrectly()
{
// Arrange
var boundaryPorts = new List<int>
{
1, // Minimum valid port
1024, // Common system port boundary
65535, // Maximum valid port
8080, // Common application port
443, // HTTPS port
80 // HTTP port
};
// Act
var info = new CaddyConfigurationInfo
{
ReverseProxyPorts = boundaryPorts
};
// Assert
info.ReverseProxyPorts.Should().NotBeNull();
info.ReverseProxyPorts.Should().HaveCount(6);
info.ReverseProxyPorts.Should().Contain(1);
info.ReverseProxyPorts.Should().Contain(65535);
info.ReverseProxyPorts.Should().Contain(8080);
}
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles empty and null collections gracefully.
/// Setup: Creates CaddyConfigurationInfo instances with empty collections and null values for various properties.
/// Expectation: The model should handle empty and null collections gracefully, ensuring robust operation with incomplete or missing data.
/// </summary>
[Theory]
[InlineData(true, true, true)] // All empty
[InlineData(false, true, true)] // Some empty
[InlineData(true, false, true)] // Some empty
[InlineData(true, true, false)] // Some empty
public void Collections_WithEmptyAndNullValues_HandlesGracefully(bool emptyHostnames, bool emptyPorts, bool emptyAggregatedPorts)
{
// Arrange
var info = new CaddyConfigurationInfo();
// Act
if (emptyHostnames)
{
info.Hostnames = new List<string>();
}
if (emptyPorts)
{
info.ReverseProxyPorts = new List<int>();
}
if (emptyAggregatedPorts)
{
info.AggregatedReverseProxyPorts = new List<int>();
}
// Assert
info.Hostnames.Should().NotBeNull();
info.ReverseProxyPorts.Should().NotBeNull();
info.AggregatedReverseProxyPorts.Should().NotBeNull();
}
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles very long filenames correctly.
/// Setup: Creates a CaddyConfigurationInfo with a very long filename to test boundary conditions.
/// Expectation: The model should handle very long filenames correctly, ensuring proper storage and retrieval of long file identifiers.
/// </summary>
[Fact]
public void FileName_WithVeryLongName_HandlesCorrectly()
{
// Arrange
var veryLongFileName = new string('a', 1000); // 1000 character filename
// Act
var info = new CaddyConfigurationInfo
{
FileName = veryLongFileName
};
// Assert
info.FileName.Should().Be(veryLongFileName);
info.FileName.Should().HaveLength(1000);
}
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles special characters in filenames correctly.
/// Setup: Creates a CaddyConfigurationInfo with filenames containing special characters and Unicode.
/// Expectation: The model should handle special characters in filenames correctly, ensuring support for international file naming conventions.
/// </summary>
[Theory]
[InlineData("config-with-unicode-测试")]
[InlineData("config-with-special-chars!@#$%")]
[InlineData("config.with.dots")]
[InlineData("config-with-spaces and-dashes")]
[InlineData("config_with_underscores")]
public void FileName_WithSpecialCharacters_HandlesCorrectly(string fileName)
{
// Act
var info = new CaddyConfigurationInfo
{
FileName = fileName
};
// Assert
info.FileName.Should().Be(fileName);
}
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles concurrent access scenarios gracefully.
/// Setup: Creates multiple concurrent operations on a CaddyConfigurationInfo instance to test thread safety.
/// Expectation: The model should handle concurrent access gracefully without throwing exceptions or causing race conditions, ensuring thread safety in multi-user environments.
/// </summary>
[Fact]
public async Task CaddyConfigurationInfo_WithConcurrentAccess_HandlesGracefully()
{
// Arrange
var info = new CaddyConfigurationInfo();
var tasks = new List<Task>();
// Act - Create multiple concurrent operations
for (int i = 0; i < 10; i++)
{
var index = i;
tasks.Add(Task.Run(() =>
{
info.Hostnames = new List<string> { $"host{index}.example.com" };
info.ReverseProxyPorts = new List<int> { 3000 + index };
info.FileName = $"config{index}";
}));
}
// Wait for all tasks to complete
await Task.WhenAll(tasks);
// Assert
info.Should().NotBeNull();
info.Hostnames.Should().NotBeNull();
info.ReverseProxyPorts.Should().NotBeNull();
info.FileName.Should().NotBeNull();
}
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles memory pressure scenarios gracefully.
/// Setup: Creates a scenario where the model might be under memory pressure with large data structures.
/// Expectation: The model should handle memory pressure scenarios gracefully, either by implementing memory-efficient operations or providing appropriate error handling, ensuring robust operation under resource constraints.
/// </summary>
[Fact]
public void CaddyConfigurationInfo_WithMemoryPressure_HandlesGracefully()
{
// Arrange
var largeHostnames = new List<string>();
var largePorts = new List<int>();
for (int i = 0; i < 1000; i++)
{
largeHostnames.Add($"host{i}.example.com");
largePorts.Add(3000 + i);
}
// Act
var info = new CaddyConfigurationInfo
{
Hostnames = largeHostnames,
ReverseProxyPorts = largePorts,
AggregatedReverseProxyPorts = largePorts,
FileName = "large-config"
};
// Assert
info.Should().NotBeNull();
info.Hostnames.Should().HaveCount(1000);
info.ReverseProxyPorts.Should().HaveCount(1000);
info.AggregatedReverseProxyPorts.Should().HaveCount(1000);
}
/// <summary>
/// Tests that the CaddyConfigurationInfo model handles serialization and deserialization correctly.
/// Setup: Creates a CaddyConfigurationInfo instance with various data types and tests serialization/deserialization.
/// Expectation: The model should handle serialization and deserialization correctly, ensuring proper data persistence and transfer capabilities.
/// </summary>
[Fact]
public void CaddyConfigurationInfo_WithSerialization_HandlesCorrectly()
{
// Arrange
var originalInfo = new CaddyConfigurationInfo
{
Hostnames = new List<string> { "example.com", "api.example.com" },
ReverseProxyHostname = "localhost",
ReverseProxyPorts = new List<int> { 3000, 8080 },
FileName = "test-config",
AggregatedReverseProxyPorts = new List<int> { 3000, 8080, 9000 }
};
// Act - Simulate serialization/deserialization
var serializedData = System.Text.Json.JsonSerializer.Serialize(originalInfo);
var deserializedInfo = System.Text.Json.JsonSerializer.Deserialize<CaddyConfigurationInfo>(serializedData);
// Assert
deserializedInfo.Should().NotBeNull();
deserializedInfo!.Hostnames.Should().BeEquivalentTo(originalInfo.Hostnames);
deserializedInfo.ReverseProxyHostname.Should().Be(originalInfo.ReverseProxyHostname);
deserializedInfo.ReverseProxyPorts.Should().BeEquivalentTo(originalInfo.ReverseProxyPorts);
deserializedInfo.FileName.Should().Be(originalInfo.FileName);
deserializedInfo.AggregatedReverseProxyPorts.Should().BeEquivalentTo(originalInfo.AggregatedReverseProxyPorts);
}
#endregion
}

View File

@@ -0,0 +1,244 @@
using CaddyManager.Models.Caddy;
namespace CaddyManager.Tests.Models.Caddy;
/// <summary>
/// Tests for CaddyDeleteOperationResponse model
/// </summary>
public class CaddyDeleteOperationResponseTests
{
/// <summary>
/// Tests that the CaddyDeleteOperationResponse constructor initializes all properties with appropriate default values.
/// Setup: Creates a new CaddyDeleteOperationResponse instance using the default constructor.
/// Expectation: Inherited properties should have base class defaults (Success=false, Message=empty), and DeletedConfigurations should be initialized as an empty but non-null collection, ensuring the response model is ready for immediate use in Caddy configuration deletion operations.
/// </summary>
[Fact]
public void Constructor_InitializesWithDefaultValues()
{
// Act
var response = new CaddyDeleteOperationResponse();
// Assert
response.Success.Should().BeFalse(); // Inherited from base class
response.Message.Should().Be(string.Empty); // Inherited from base class
response.DeletedConfigurations.Should().NotBeNull();
response.DeletedConfigurations.Should().BeEmpty();
}
/// <summary>
/// Tests that CaddyDeleteOperationResponse properly inherits from CaddyOperationResponse base class.
/// Setup: Creates a CaddyDeleteOperationResponse instance and checks its type hierarchy.
/// Expectation: The instance should be assignable to CaddyOperationResponse, ensuring proper inheritance structure for consistent operation response handling across different Caddy management operations while maintaining specialized delete-specific functionality.
/// </summary>
[Fact]
public void InheritsFromCaddyOperationResponse()
{
// Act
var response = new CaddyDeleteOperationResponse();
// Assert
response.Should().BeAssignableTo<CaddyOperationResponse>();
}
/// <summary>
/// Tests that all CaddyDeleteOperationResponse properties can be properly set and retrieved with realistic data.
/// Setup: Creates test data including success status, descriptive message, and a list of deleted configuration names representing a typical Caddy configuration deletion scenario.
/// Expectation: All properties should store and return the exact values assigned, ensuring data integrity for tracking which configurations were successfully deleted during Caddy management operations.
/// </summary>
[Fact]
public void Properties_CanBeSetAndRetrieved()
{
// Arrange
var success = true;
var message = "Configurations deleted successfully";
var deletedConfigurations = new List<string> { "config1", "config2", "config3" };
// Act
var response = new CaddyDeleteOperationResponse
{
Success = success,
Message = message,
DeletedConfigurations = deletedConfigurations
};
// Assert
response.Success.Should().Be(success);
response.Message.Should().Be(message);
response.DeletedConfigurations.Should().BeEquivalentTo(deletedConfigurations);
}
/// <summary>
/// Tests that the DeletedConfigurations collection can be modified after CaddyDeleteOperationResponse creation.
/// Setup: Creates a CaddyDeleteOperationResponse instance and adds configuration names to the DeletedConfigurations collection.
/// Expectation: The collection should accept new entries and maintain them correctly, enabling dynamic tracking of deleted configurations during batch deletion operations in Caddy management workflows.
/// </summary>
[Fact]
public void DeletedConfigurations_CanBeModified()
{
// Arrange
var response = new CaddyDeleteOperationResponse();
// Act
response.DeletedConfigurations.Add("config1");
response.DeletedConfigurations.Add("config2");
// Assert
response.DeletedConfigurations.Should().HaveCount(2);
response.DeletedConfigurations.Should().Contain("config1");
response.DeletedConfigurations.Should().Contain("config2");
}
/// <summary>
/// Tests that assigning an empty list to DeletedConfigurations maintains the empty state correctly.
/// Setup: Creates a CaddyDeleteOperationResponse and explicitly assigns an empty list to DeletedConfigurations.
/// Expectation: The collection should remain empty but non-null, ensuring proper handling of scenarios where no configurations were deleted during Caddy management operations, which is important for accurate operation reporting.
/// </summary>
[Fact]
public void DeletedConfigurations_WithEmptyList_RemainsEmpty()
{
// Act
var response = new CaddyDeleteOperationResponse
{
DeletedConfigurations = new List<string>()
};
// Assert
response.DeletedConfigurations.Should().NotBeNull();
response.DeletedConfigurations.Should().BeEmpty();
}
/// <summary>
/// Tests that assigning null to DeletedConfigurations does not throw an exception.
/// Setup: Creates a CaddyDeleteOperationResponse instance and attempts to assign null to the DeletedConfigurations property.
/// Expectation: The assignment should not throw an exception, ensuring robust error handling in Caddy management operations where null assignments might occur due to programming errors or edge cases, maintaining system stability.
/// </summary>
[Fact]
public void DeletedConfigurations_WithNullAssignment_DoesNotThrow()
{
// Act & Assert
var response = new CaddyDeleteOperationResponse();
var act = () => response.DeletedConfigurations = null!;
act.Should().NotThrow();
}
/// <summary>
/// Tests that Success and Message properties can be set with various combinations representing different deletion outcomes.
/// Setup: Uses parameterized test data with different success states and corresponding messages that represent typical Caddy configuration deletion scenarios.
/// Expectation: Both properties should store the provided values correctly, ensuring accurate reporting of deletion operation results in Caddy management systems, whether operations succeed completely or encounter failures.
/// </summary>
[Theory]
[InlineData(true, "All configurations deleted successfully")]
[InlineData(false, "Failed to delete some configurations")]
public void SuccessAndMessage_WithVariousValues_SetCorrectly(bool success, string message)
{
// Act
var response = new CaddyDeleteOperationResponse
{
Success = success,
Message = message
};
// Assert
response.Success.Should().Be(success);
response.Message.Should().Be(message);
}
/// <summary>
/// Tests that the DeletedConfigurations collection allows duplicate configuration names.
/// Setup: Creates a CaddyDeleteOperationResponse and adds duplicate configuration names to the DeletedConfigurations collection.
/// Expectation: The collection should accept and store duplicate entries, which might occur in edge cases where the same configuration is processed multiple times during complex Caddy management operations, ensuring complete audit trails.
/// </summary>
[Fact]
public void DeletedConfigurations_WithDuplicateEntries_AllowsDuplicates()
{
// Arrange
var response = new CaddyDeleteOperationResponse();
// Act
response.DeletedConfigurations.Add("config1");
response.DeletedConfigurations.Add("config1");
response.DeletedConfigurations.Add("config2");
// Assert
response.DeletedConfigurations.Should().HaveCount(3);
response.DeletedConfigurations.Should().Contain("config1");
response.DeletedConfigurations.Should().Contain("config2");
response.DeletedConfigurations.Count(x => x == "config1").Should().Be(2);
}
/// <summary>
/// Tests that the DeletedConfigurations collection properly handles various string formats including edge cases.
/// Setup: Creates a collection with different string types including empty strings, whitespace, normal names, special characters, and very long names representing diverse Caddy configuration naming patterns.
/// Expectation: All string values should be stored correctly regardless of format, ensuring robust handling of different configuration naming conventions used in various Caddy deployment scenarios and preventing data loss during deletion tracking.
/// </summary>
[Fact]
public void DeletedConfigurations_WithVariousStringValues_HandlesCorrectly()
{
// Arrange
var configurations = new List<string>
{
"",
" ",
"normal-config",
"config-with-special-chars!@#$%",
"very-long-configuration-name-that-might-be-used-in-some-scenarios"
};
// Act
var response = new CaddyDeleteOperationResponse
{
DeletedConfigurations = configurations
};
// Assert
response.DeletedConfigurations.Should().BeEquivalentTo(configurations);
response.DeletedConfigurations.Should().HaveCount(5);
}
/// <summary>
/// Tests that all CaddyDeleteOperationResponse properties can be modified after the instance is created.
/// Setup: Creates a CaddyDeleteOperationResponse with initial values, then updates all properties with new values representing a change in deletion operation status.
/// Expectation: All properties should accept the new values and the old values should be completely replaced, enabling dynamic updates to deletion operation results as Caddy management operations progress or are re-evaluated.
/// </summary>
[Fact]
public void Properties_CanBeModifiedAfterCreation()
{
// Arrange
var response = new CaddyDeleteOperationResponse
{
Success = false,
Message = "Initial message",
DeletedConfigurations = new List<string> { "initial-config" }
};
// Act
response.Success = true;
response.Message = "Updated message";
response.DeletedConfigurations = new List<string> { "updated-config1", "updated-config2" };
// Assert
response.Success.Should().BeTrue();
response.Message.Should().Be("Updated message");
response.DeletedConfigurations.Should().HaveCount(2);
response.DeletedConfigurations.Should().Contain("updated-config1");
response.DeletedConfigurations.Should().Contain("updated-config2");
response.DeletedConfigurations.Should().NotContain("initial-config");
}
/// <summary>
/// Tests that the DeletedConfigurations property is properly initialized as an empty List&lt;string&gt; by default.
/// Setup: Creates a new CaddyDeleteOperationResponse instance and examines the DeletedConfigurations property.
/// Expectation: The property should be a non-null, empty List&lt;string&gt; instance, ensuring that deletion tracking is immediately available without additional initialization and preventing null reference exceptions in Caddy configuration management operations.
/// </summary>
[Fact]
public void DeletedConfigurations_DefaultInitialization_IsEmptyList()
{
// Act
var response = new CaddyDeleteOperationResponse();
// Assert
response.DeletedConfigurations.Should().NotBeNull();
response.DeletedConfigurations.Should().BeOfType<List<string>>();
response.DeletedConfigurations.Should().BeEmpty();
}
}

View File

@@ -0,0 +1,170 @@
using CaddyManager.Models.Caddy;
namespace CaddyManager.Tests.Models.Caddy;
/// <summary>
/// Tests for CaddyOperationResponse model
/// </summary>
public class CaddyOperationResponseTests
{
/// <summary>
/// Tests that the CaddyOperationResponse constructor initializes all properties with appropriate default values.
/// Setup: Creates a new CaddyOperationResponse instance using the default constructor.
/// Expectation: Success should default to false and Message should be an empty string, ensuring that operation responses start in a safe state where success must be explicitly set, preventing false positive results in Caddy management operations.
/// </summary>
[Fact]
public void Constructor_InitializesWithDefaultValues()
{
// Act
var response = new CaddyOperationResponse();
// Assert
response.Success.Should().BeFalse();
response.Message.Should().Be(string.Empty);
}
/// <summary>
/// Tests that all CaddyOperationResponse properties can be properly set and retrieved with realistic operation data.
/// Setup: Creates test data with success status and a descriptive message representing a typical Caddy operation completion scenario.
/// Expectation: Both properties should store and return the exact values assigned, ensuring reliable communication of operation results between Caddy management services and client applications.
/// </summary>
[Fact]
public void Properties_CanBeSetAndRetrieved()
{
// Arrange
var success = true;
var message = "Operation completed successfully";
// Act
var response = new CaddyOperationResponse
{
Success = success,
Message = message
};
// Assert
response.Success.Should().Be(success);
response.Message.Should().Be(message);
}
/// <summary>
/// Tests that Success and Message properties handle various combinations of values representing different operation outcomes.
/// Setup: Uses parameterized test data with different success states and message content, including empty messages, representing the range of possible Caddy operation results.
/// Expectation: All combinations should be stored correctly, ensuring that the base response model can accurately represent any type of Caddy operation outcome, whether successful or failed, with or without detailed messages.
/// </summary>
[Theory]
[InlineData(true, "Success message")]
[InlineData(false, "Error message")]
[InlineData(true, "")]
[InlineData(false, "")]
public void Properties_WithVariousValues_SetCorrectly(bool success, string message)
{
// Act
var response = new CaddyOperationResponse
{
Success = success,
Message = message
};
// Assert
response.Success.Should().Be(success);
response.Message.Should().Be(message);
}
/// <summary>
/// Tests that assigning null to the Message property handles the null value appropriately.
/// Setup: Creates a CaddyOperationResponse instance and assigns null to the Message property.
/// Expectation: The Message property should not be null after assignment, ensuring robust null handling in Caddy operation responses and preventing null reference exceptions in downstream message processing operations.
/// </summary>
[Fact]
public void Message_WithNullValue_SetsToEmptyString()
{
// Act
var response = new CaddyOperationResponse
{
Message = null!
};
// Assert
response.Message.Should().NotBeNull();
}
/// <summary>
/// Tests that the Success property has a default value of false when not explicitly set.
/// Setup: Creates a new CaddyOperationResponse instance without setting the Success property.
/// Expectation: Success should be false by default, implementing a fail-safe approach where operations are considered unsuccessful until explicitly marked as successful, ensuring conservative error handling in Caddy management operations.
/// </summary>
[Fact]
public void Success_DefaultValue_IsFalse()
{
// Act
var response = new CaddyOperationResponse();
// Assert
response.Success.Should().BeFalse();
}
/// <summary>
/// Tests that the Message property has a default value of empty string when not explicitly set.
/// Setup: Creates a new CaddyOperationResponse instance without setting the Message property.
/// Expectation: Message should be an empty but non-null string by default, ensuring that message handling code doesn't encounter null references and providing a consistent baseline for Caddy operation response messaging.
/// </summary>
[Fact]
public void Message_DefaultValue_IsEmptyString()
{
// Act
var response = new CaddyOperationResponse();
// Assert
response.Message.Should().Be(string.Empty);
response.Message.Should().NotBeNull();
}
/// <summary>
/// Tests that CaddyOperationResponse properties can be modified after the instance is created.
/// Setup: Creates a CaddyOperationResponse with initial values, then updates both properties with new values representing a change in operation status.
/// Expectation: Both properties should accept the new values and completely replace the old ones, enabling dynamic updates to operation results as Caddy management operations progress or are re-evaluated.
/// </summary>
[Fact]
public void Properties_CanBeModifiedAfterCreation()
{
// Arrange
var response = new CaddyOperationResponse
{
Success = false,
Message = "Initial message"
};
// Act
response.Success = true;
response.Message = "Updated message";
// Assert
response.Success.Should().BeTrue();
response.Message.Should().Be("Updated message");
}
/// <summary>
/// Tests that the Message property correctly handles various string formats and content types.
/// Setup: Uses parameterized test data with different message formats including empty strings, whitespace, short text, long descriptions, special characters, and formatted text with newlines and tabs.
/// Expectation: All message formats should be stored exactly as provided, ensuring that Caddy operation responses can contain any type of diagnostic information, error details, or success messages without data corruption or formatting issues.
/// </summary>
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData("Short")]
[InlineData("This is a very long message that contains multiple words and should be handled correctly by the model")]
[InlineData("Message with special characters: !@#$%^&*()_+-=[]{}|;':\",./<>?")]
[InlineData("Message with\nnewlines\nand\ttabs")]
public void Message_WithVariousStringValues_SetsCorrectly(string message)
{
// Act
var response = new CaddyOperationResponse
{
Message = message
};
// Assert
response.Message.Should().Be(message);
}
}

View File

@@ -0,0 +1,348 @@
using CaddyManager.Models.Caddy;
namespace CaddyManager.Tests.Models.Caddy;
/// <summary>
/// Tests for CaddySaveConfigurationRequest model
/// </summary>
public class CaddySaveConfigurationRequestTests
{
/// <summary>
/// Tests that CaddySaveConfigurationRequest initializes correctly when provided with a required FileName.
/// Setup: Creates a CaddySaveConfigurationRequest instance with a FileName and examines the default values of other properties.
/// Expectation: The FileName should be set as provided, IsNew should default to false, and Content should be an empty string, ensuring the request model is properly initialized for Caddy configuration save operations with sensible defaults.
/// </summary>
[Fact]
public void Constructor_WithRequiredFileName_InitializesCorrectly()
{
// Act
var request = new CaddySaveConfigurationRequest
{
FileName = "test-config"
};
// Assert
request.FileName.Should().Be("test-config");
request.IsNew.Should().BeFalse(); // Default value
request.Content.Should().Be(string.Empty); // Default value
}
/// <summary>
/// Tests that all CaddySaveConfigurationRequest properties can be properly set and retrieved with realistic configuration data.
/// Setup: Creates test data including new configuration flag, file name, and Caddyfile content representing a typical configuration save scenario.
/// Expectation: All properties should store and return the exact values assigned, ensuring data integrity for Caddy configuration save requests that include both metadata and the actual configuration content.
/// </summary>
[Fact]
public void Properties_CanBeSetAndRetrieved()
{
// Arrange
var isNew = true;
var fileName = "my-config";
var content = "example.com {\n reverse_proxy localhost:8080\n}";
// Act
var request = new CaddySaveConfigurationRequest
{
IsNew = isNew,
FileName = fileName,
Content = content
};
// Assert
request.IsNew.Should().Be(isNew);
request.FileName.Should().Be(fileName);
request.Content.Should().Be(content);
}
/// <summary>
/// Tests that the IsNew property correctly handles both true and false values representing different configuration scenarios.
/// Setup: Uses parameterized test data with both boolean values representing new configuration creation versus existing configuration updates.
/// Expectation: The IsNew property should store the provided boolean value accurately, enabling proper differentiation between creating new Caddy configurations and updating existing ones in the management system.
/// </summary>
[Theory]
[InlineData(true)]
[InlineData(false)]
public void IsNew_WithVariousValues_SetsCorrectly(bool isNew)
{
// Act
var request = new CaddySaveConfigurationRequest
{
FileName = "test",
IsNew = isNew
};
// Assert
request.IsNew.Should().Be(isNew);
}
/// <summary>
/// Tests that the FileName property correctly handles various valid naming conventions used in Caddy configuration files.
/// Setup: Uses parameterized test data with different file naming patterns including simple names, dashes, underscores, camelCase, numbers, and long descriptive names.
/// Expectation: All valid file name formats should be stored correctly, ensuring compatibility with different Caddy configuration naming conventions used across various deployment scenarios and organizational standards.
/// </summary>
[Theory]
[InlineData("simple-name")]
[InlineData("name-with-dashes")]
[InlineData("name_with_underscores")]
[InlineData("NameWithCamelCase")]
[InlineData("name123")]
[InlineData("very-long-configuration-file-name-that-might-be-used")]
public void FileName_WithVariousValidNames_SetsCorrectly(string fileName)
{
// Act
var request = new CaddySaveConfigurationRequest
{
FileName = fileName
};
// Assert
request.FileName.Should().Be(fileName);
}
/// <summary>
/// Tests that the FileName property accepts various string formats including edge cases and potentially problematic characters.
/// Setup: Uses parameterized test data with empty strings, whitespace, spaces, and path separators that might be encountered in real-world scenarios.
/// Expectation: All string values should be accepted and stored as-is, since the model doesn't enforce validation (validation occurs at service/controller level), ensuring the request model can capture any input for proper validation handling upstream in Caddy management operations.
/// </summary>
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData("name with spaces")]
[InlineData("name/with/slashes")]
[InlineData("name\\with\\backslashes")]
public void FileName_WithVariousStringValues_AcceptsAll(string fileName)
{
// Note: The model doesn't enforce validation, it just stores the value
// Validation would typically be done at the service or controller level
// Act
var request = new CaddySaveConfigurationRequest
{
FileName = fileName
};
// Assert
request.FileName.Should().Be(fileName);
}
/// <summary>
/// Tests that the Content property correctly handles empty string values representing empty Caddy configurations.
/// Setup: Creates a CaddySaveConfigurationRequest and sets the Content property to an empty string.
/// Expectation: The empty string should be stored correctly, enabling scenarios where empty Caddy configuration files need to be created or where existing configurations are cleared during management operations.
/// </summary>
[Fact]
public void Content_WithEmptyString_SetsCorrectly()
{
// Act
var request = new CaddySaveConfigurationRequest
{
FileName = "test",
Content = ""
};
// Assert
request.Content.Should().Be("");
}
/// <summary>
/// Tests that the Content property correctly handles complex, multi-line Caddyfile content with various directives and configurations.
/// Setup: Creates a realistic complex Caddyfile content with multiple domains, routing rules, reverse proxy configurations, file serving, compression, and logging directives.
/// Expectation: The entire complex content should be stored exactly as provided, ensuring that sophisticated Caddy configurations with multiple sites, advanced routing, and various middleware can be properly saved and managed through the request model.
/// </summary>
[Fact]
public void Content_WithComplexCaddyfileContent_SetsCorrectly()
{
// Arrange
var complexContent = @"
example.com, www.example.com {
route /api/* {
reverse_proxy localhost:3000
}
route /static/* {
file_server
}
reverse_proxy localhost:8080
encode gzip
log {
output file /var/log/caddy/access.log
}
}
api.example.com {
reverse_proxy localhost:4000
header {
Access-Control-Allow-Origin *
}
}";
// Act
var request = new CaddySaveConfigurationRequest
{
FileName = "complex-config",
Content = complexContent
};
// Assert
request.Content.Should().Be(complexContent);
}
/// <summary>
/// Tests that the Content property correctly handles special characters that might appear in Caddy configurations.
/// Setup: Creates content containing various special characters including punctuation, symbols, and operators that might be used in Caddy directives or comments.
/// Expectation: All special characters should be preserved exactly, ensuring that Caddy configurations with complex expressions, regex patterns, or special formatting are not corrupted during save operations.
/// </summary>
[Fact]
public void Content_WithSpecialCharacters_SetsCorrectly()
{
// Arrange
var contentWithSpecialChars = "Content with special chars: !@#$%^&*()_+-=[]{}|;':\",./<>?";
// Act
var request = new CaddySaveConfigurationRequest
{
FileName = "test",
Content = contentWithSpecialChars
};
// Assert
request.Content.Should().Be(contentWithSpecialChars);
}
/// <summary>
/// Tests that the Content property correctly preserves whitespace formatting including newlines and tabs.
/// Setup: Creates content with various line endings (Unix, Windows) and tab characters representing formatted Caddyfile content.
/// Expectation: All whitespace formatting should be preserved exactly, ensuring that Caddy configuration indentation, line breaks, and formatting are maintained for readability and proper parsing by the Caddy server.
/// </summary>
[Fact]
public void Content_WithNewlinesAndTabs_SetsCorrectly()
{
// Arrange
var contentWithWhitespace = "Line 1\nLine 2\n\tIndented line\r\nWindows line ending";
// Act
var request = new CaddySaveConfigurationRequest
{
FileName = "test",
Content = contentWithWhitespace
};
// Assert
request.Content.Should().Be(contentWithWhitespace);
}
/// <summary>
/// Tests that CaddySaveConfigurationRequest properties can be modified after instance creation, except for the init-only FileName.
/// Setup: Creates a CaddySaveConfigurationRequest with initial values, then attempts to modify all properties including the init-only FileName.
/// Expectation: IsNew and Content should accept new values, but FileName should remain unchanged due to its init-only nature, ensuring that configuration identity remains stable while allowing content and metadata updates during Caddy management operations.
/// </summary>
[Fact]
public void Properties_CanBeModifiedAfterCreation()
{
// Arrange
var request = new CaddySaveConfigurationRequest
{
FileName = "initial-name",
IsNew = false,
Content = "initial content"
};
// Act
// Note: FileName is init-only and cannot be modified after creation
request.IsNew = true;
request.Content = "updated content";
// Assert
request.FileName.Should().Be("initial-name"); // FileName cannot be changed
request.IsNew.Should().BeTrue();
request.Content.Should().Be("updated content");
}
/// <summary>
/// Tests that CaddySaveConfigurationRequest properties have appropriate default values when not explicitly set.
/// Setup: Creates a CaddySaveConfigurationRequest with only the required FileName and examines the default values of other properties.
/// Expectation: IsNew should default to false and Content should be an empty non-null string, providing safe defaults that assume updating existing configurations rather than creating new ones, which is the more common scenario in Caddy management.
/// </summary>
[Fact]
public void DefaultValues_AreSetCorrectly()
{
// Act
var request = new CaddySaveConfigurationRequest
{
FileName = "test"
};
// Assert
request.IsNew.Should().BeFalse();
request.Content.Should().Be(string.Empty);
request.Content.Should().NotBeNull();
}
/// <summary>
/// Tests that the FileName property is properly marked as required and behaves correctly when provided.
/// Setup: Creates a CaddySaveConfigurationRequest with a valid FileName and verifies it's properly set and not null or empty.
/// Expectation: The FileName should be properly stored and not be null or empty, confirming that the required attribute is properly applied and that configuration save requests always have a valid file identifier for Caddy management operations.
/// </summary>
[Fact]
public void FileName_IsRequired_PropertyHasRequiredAttribute()
{
// This test verifies that the FileName property is marked as required
// The actual enforcement would be done by model validation in ASP.NET Core
// Arrange & Act
var request = new CaddySaveConfigurationRequest
{
FileName = "test"
};
// Assert
request.FileName.Should().NotBeNull();
request.FileName.Should().NotBe(string.Empty);
}
/// <summary>
/// Tests that assigning null to the Content property does not throw an exception.
/// Setup: Creates a CaddySaveConfigurationRequest and attempts to assign null to the Content property.
/// Expectation: The null assignment should not throw an exception, ensuring robust error handling in Caddy management operations where null assignments might occur due to programming errors or edge cases, maintaining system stability.
/// </summary>
[Fact]
public void Content_WithNullAssignment_DoesNotThrow()
{
// Act & Assert
var request = new CaddySaveConfigurationRequest
{
FileName = "test"
};
var act = () => request.Content = null!;
act.Should().NotThrow();
}
/// <summary>
/// Tests that CaddySaveConfigurationRequest correctly handles various realistic combinations of all properties.
/// Setup: Uses parameterized test data with different combinations of IsNew flags, file names, and content representing typical Caddy configuration scenarios including new configurations, updates, global configs, and empty content.
/// Expectation: All property combinations should be stored correctly, ensuring that the request model can handle the full range of Caddy configuration save scenarios from creating new site configs to updating existing ones with various content types.
/// </summary>
[Theory]
[InlineData(true, "new-config", "new content")]
[InlineData(false, "existing-config", "updated content")]
[InlineData(true, "Caddyfile", "global config content")]
[InlineData(false, "api-config", "")]
public void CompleteRequest_WithVariousCombinations_SetsAllPropertiesCorrectly(
bool isNew, string fileName, string content)
{
// Act
var request = new CaddySaveConfigurationRequest
{
IsNew = isNew,
FileName = fileName,
Content = content
};
// Assert
request.IsNew.Should().Be(isNew);
request.FileName.Should().Be(fileName);
request.Content.Should().Be(content);
}
}