build-flow.api/tests/BuildFlow.File.Tests/UploadFileCommandHandlerTests.cs
xiangning 3b13099378 refactor(domain): 重构领域实体结构并更新枚举命名
- 将通用 Entities 命名空间拆分为具体业务实体子目录
- 更新所有实体类型引用为具体的 Entity 后缀类型
- 将 ModelType、ModelProvider、GroupMemberRole 等枚举重命名为 Enum 后缀
- 重构 AiModel 相关配置和映射逻辑适配新的实体结构
- 更新测试代码中的实体类型引用和枚举使用
- 调整应用层处理器中的实体创建和查询逻辑
- 修改 appsettings.json 中的基础设施主机配置为动态占位符模式
2026-07-19 14:02:32 +08:00

112 lines
4.8 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.Common;
using File.Application.Features.Files.Commands;
using File.Application.Features.Files.Handlers;
using File.Domain.Entities.FileMeta;
using File.Domain.Entities.FileSetting;
using File.Domain.Entities.Folder;
using File.Domain.Entities.MultipartUploadSession;
using File.Domain.Entities.ShareLink;
using File.Domain.Values;
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 修复:直传完成后落 FileMetaEntity,使直传路径参与秒传。
/// </summary>
public class UploadFileCommandHandlerTests
{
private const string OwnerId = "user-001";
private const string Sha = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824";
/// <summary>测试用 bucket 解析器,固定返回 "files"。</summary>
private static IBucketResolver BucketResolver(string bucket = "files")
{
var mock = new Mock<IBucketResolver>();
mock.Setup(r => r.GetDefaultBucketAsync(It.IsAny<CancellationToken>())).ReturnsAsync(bucket);
return mock.Object;
}
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核心:直传必须落 FileMetaEntity,否则直传的文件永远无法被秒传
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, BucketResolver(), new Mock<MediatR.IMediator>().Object);
var result = await handler.Handle(
new UploadFileCommand("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);
// FileMetaEntity 应被创建,含 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, BucketResolver(), new Mock<MediatR.IMediator>().Object);
var act = () => handler.Handle(
new UploadFileCommand("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) 已有 FileMetaEntity,再次上传不重复 Add
var (db, s3, user) = CreateDeps(nameof(Upload_同对象已存在FileMeta_不重复落库));
db.Files.Add(new FileMetaEntity
{
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, BucketResolver(), new Mock<MediatR.IMediator>().Object);
await handler.Handle(
new UploadFileCommand("obj-key", new MemoryStream([1, 2, 3]), "application/octet-stream", 3, Sha),
CancellationToken.None);
// 仍只有一条记录
var count = await db.Files.CountAsync();
count.Should().Be(1);
}
}