93 lines
3.8 KiB
C#
93 lines
3.8 KiB
C#
using System.Text;
|
|
using File.Infrastructure.Storage;
|
|
using FluentAssertions;
|
|
using Microsoft.Extensions.Options;
|
|
using Moq;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace BuildFlow.File.Tests;
|
|
|
|
/// <summary>真实 S3 兼容存储往返测试,供隔离 MinIO SOP 阶段执行。</summary>
|
|
public sealed class S3StorageServiceIntegrationTests(ITestOutputHelper output)
|
|
{
|
|
[Fact]
|
|
[Trait("Category", "External")]
|
|
public async Task UploadDownloadAndZeroByteObjectsRoundTrip()
|
|
{
|
|
var endpoint = GetRequiredVariable("BUILDFLOW_FILE_S3_TEST_ENDPOINT");
|
|
var accessKey = GetRequiredVariable("BUILDFLOW_FILE_S3_TEST_ACCESS_KEY");
|
|
var secretKey = GetRequiredVariable("BUILDFLOW_FILE_S3_TEST_SECRET_KEY");
|
|
var options = new Mock<IOptionsMonitor<S3Options>>();
|
|
options.SetupGet(x => x.CurrentValue).Returns(new S3Options
|
|
{
|
|
Endpoint = endpoint,
|
|
AccessKey = accessKey,
|
|
SecretKey = secretKey,
|
|
Region = "us-east-1",
|
|
});
|
|
var storage = new S3StorageService(options.Object);
|
|
var bucket = $"buildflow-sop-{Guid.NewGuid():N}";
|
|
var payloadKey = "payload.bin";
|
|
var zeroByteKey = "empty.bin";
|
|
var bucketCreated = false;
|
|
|
|
try
|
|
{
|
|
await storage.CreateBucketAsync(bucket, CancellationToken.None);
|
|
bucketCreated = true;
|
|
|
|
var payload = Encoding.UTF8.GetBytes("BuildFlow isolated MinIO round trip");
|
|
await using (var payloadStream = new MemoryStream(payload, writable: false))
|
|
{
|
|
await storage.UploadFileAsync(
|
|
bucket,
|
|
payloadKey,
|
|
payloadStream,
|
|
"application/octet-stream",
|
|
CancellationToken.None);
|
|
}
|
|
|
|
var download = await storage.DownloadFileAsync(bucket, payloadKey, CancellationToken.None);
|
|
await using (download.Stream)
|
|
await using (var downloaded = new MemoryStream())
|
|
{
|
|
await download.Stream.CopyToAsync(downloaded, CancellationToken.None);
|
|
downloaded.ToArray().Should().Equal(payload);
|
|
}
|
|
download.ContentType.Should().Be("application/octet-stream");
|
|
|
|
await using (var emptyStream = new MemoryStream(Array.Empty<byte>(), writable: false))
|
|
{
|
|
await storage.UploadFileAsync(
|
|
bucket,
|
|
zeroByteKey,
|
|
emptyStream,
|
|
"application/octet-stream",
|
|
CancellationToken.None);
|
|
}
|
|
|
|
(await storage.ObjectExistsAsync(bucket, zeroByteKey, CancellationToken.None)).Should().BeTrue();
|
|
(await storage.GetObjectSizeAsync(bucket, zeroByteKey, CancellationToken.None)).Should().Be(0);
|
|
var listed = await storage.ListObjectsAsync(bucket, null, 100, null, CancellationToken.None);
|
|
listed.Files.Select(x => x.Key).Should().BeEquivalentTo(payloadKey, zeroByteKey);
|
|
|
|
output.WriteLine($"SOP_METRIC s3_object_count={listed.Files.Count}");
|
|
output.WriteLine($"SOP_METRIC s3_object_bytes={payload.Length}");
|
|
}
|
|
finally
|
|
{
|
|
if (bucketCreated)
|
|
{
|
|
await storage.DeleteFileAsync(bucket, payloadKey, CancellationToken.None);
|
|
await storage.DeleteFileAsync(bucket, zeroByteKey, CancellationToken.None);
|
|
await storage.DeleteBucketAsync(bucket, CancellationToken.None);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string GetRequiredVariable(string name)
|
|
=> Environment.GetEnvironmentVariable(name)
|
|
?? throw new InvalidOperationException($"必须设置环境变量 {name} 才能运行真实 S3 集成测试。");
|
|
}
|