build-flow.api/tests/BuildFlow.File.Tests/UploadFileCommandHandlerTests.cs

98 lines
4.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using BuildFlow.Shared.Domain.Common;
using BuildFlow.Shared.Infrastructure;
using File.Application.Features.Files.Commands;
using File.Application.Features.Files.Handlers;
using File.Domain.Entities;
using File.Domain.Exceptions;
using File.Infrastructure.Persistence;
using File.Infrastructure.Storage;
using FluentAssertions;
using Microsoft.EntityFrameworkCore;
using Moq;
using Xunit;
namespace BuildFlow.File.Tests;
/// <summary>
/// 直传上传处理器测试。验证缺陷 C 修复:直传完成后落 FileMeta,使直传路径参与秒传。
/// </summary>
public class UploadFileCommandHandlerTests
{
private const string OwnerId = "user-001";
private const string Sha = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824";
private static (FileDbContext db, Mock<IS3StorageService> s3, Mock<ICurrentUserContext> user) CreateDeps(string dbName)
{
var user = new Mock<ICurrentUserContext>();
user.SetupGet(u => u.UserId).Returns(OwnerId);
user.SetupGet(u => u.IPAddress).Returns("127.0.0.1");
var s3 = new Mock<IS3StorageService>();
var options = new DbContextOptionsBuilder<FileDbContext>()
.UseInMemoryDatabase(dbName)
.AddInterceptors(new AuditInterceptor(user.Object))
.Options;
return (new FileDbContext(options), s3, user);
}
[Fact]
public async Task Upload_成功后落FileMeta_含ContentHash_使直传参与秒传()
{
// 缺陷C核心:直传必须落 FileMeta,否则直传的文件永远无法被秒传
var (db, s3, user) = CreateDeps(nameof(Upload_成功后落FileMeta_含ContentHash_使直传参与秒传));
var data = new MemoryStream([1, 2, 3]);
var handler = new UploadFileCommandHandler(s3.Object, db, user.Object, new Mock<MediatR.IMediator>().Object);
var result = await handler.Handle(
new UploadFileCommand("files", "obj-key", data, "application/octet-stream", 3, Sha),
CancellationToken.None);
result.ObjectKey.Should().Be("obj-key");
s3.Verify(x => x.UploadFileAsync("files", "obj-key", It.IsAny<Stream>(), "application/octet-stream", It.IsAny<CancellationToken>()), Times.Once);
// FileMeta 应被创建,含 ContentHash,FolderId=null(根目录散落)
var meta = await db.Files.SingleAsync();
meta.S3Key.Should().Be("obj-key");
meta.S3Bucket.Should().Be("files");
meta.Size.Should().Be(3);
meta.ContentHash.Should().Be(Sha);
meta.FolderId.Should().BeNull();
meta.OwnerId.Should().Be(OwnerId);
}
[Fact]
public async Task Upload_超过500MiB_抛TooLarge()
{
var (db, s3, user) = CreateDeps(nameof(Upload_超过500MiB_抛TooLarge));
var handler = new UploadFileCommandHandler(s3.Object, db, user.Object, new Mock<MediatR.IMediator>().Object);
var act = () => handler.Handle(
new UploadFileCommand("files", "big", new MemoryStream(), "application/octet-stream", 501 * 1024 * 1024),
CancellationToken.None);
await act.Should().ThrowAsync<TooLargeException>();
s3.Verify(x => x.UploadFileAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Stream>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
}
[Fact]
public async Task Upload_同对象已存在FileMeta_不重复落库()
{
// 幂等:同一 (bucket, key) 已有 FileMeta,再次上传不重复 Add
var (db, s3, user) = CreateDeps(nameof(Upload_同对象已存在FileMeta_不重复落库));
db.Files.Add(new FileMeta
{
Name = "obj-key", S3Key = "obj-key", S3Bucket = "files",
Size = 3, ContentType = "application/octet-stream", ContentHash = Sha, OwnerId = OwnerId,
});
await db.SaveChangesAsync();
var handler = new UploadFileCommandHandler(s3.Object, db, user.Object, new Mock<MediatR.IMediator>().Object);
await handler.Handle(
new UploadFileCommand("files", "obj-key", new MemoryStream([1, 2, 3]), "application/octet-stream", 3, Sha),
CancellationToken.None);
// 仍只有一条记录
var count = await db.Files.CountAsync();
count.Should().Be(1);
}
}