307 lines
12 KiB
C#
307 lines
12 KiB
C#
using System.Net;
|
|
using System.Net.Http.Headers;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using Microsoft.AspNetCore.Authentication;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.AspNetCore.Mvc.Testing;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using NSubstitute;
|
|
using Xunit;
|
|
using XiangYi.AppApi;
|
|
using XiangYi.Application.DTOs.Responses;
|
|
using XiangYi.Infrastructure.Storage;
|
|
|
|
namespace XiangYi.Api.Tests.AppApi;
|
|
|
|
/// <summary>
|
|
/// 文件上传控制器集成测试
|
|
/// </summary>
|
|
public class UploadControllerIntegrationTests : IClassFixture<WebApplicationFactory<IAppApiMarker>>
|
|
{
|
|
private readonly WebApplicationFactory<IAppApiMarker> _factory;
|
|
private readonly IStorageProvider _mockStorageProvider;
|
|
|
|
public UploadControllerIntegrationTests(WebApplicationFactory<IAppApiMarker> factory)
|
|
{
|
|
_mockStorageProvider = Substitute.For<IStorageProvider>();
|
|
|
|
_factory = factory.WithWebHostBuilder(builder =>
|
|
{
|
|
builder.UseEnvironment("Testing");
|
|
builder.ConfigureServices(services =>
|
|
{
|
|
services.RemoveAll<IStorageProvider>();
|
|
services.AddSingleton(_mockStorageProvider);
|
|
|
|
services.AddAuthentication(options =>
|
|
{
|
|
options.DefaultAuthenticateScheme = TestAuthHandler.AuthenticationScheme;
|
|
options.DefaultChallengeScheme = TestAuthHandler.AuthenticationScheme;
|
|
})
|
|
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
|
|
TestAuthHandler.AuthenticationScheme, options => { });
|
|
});
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试上传语音文件 - 成功
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task UploadVoice_ValidMp3File_ReturnsSuccess()
|
|
{
|
|
// Arrange
|
|
var expectedFileKey = "voice/test.mp3";
|
|
var expectedUrl = "https://example.com/voice/test.mp3";
|
|
_mockStorageProvider.UploadAsync(Arg.Any<Stream>(), Arg.Any<string>(), "voice")
|
|
.Returns(Task.FromResult(expectedFileKey));
|
|
_mockStorageProvider.GetAccessUrl(expectedFileKey, Arg.Any<int>())
|
|
.Returns(expectedUrl);
|
|
|
|
var client = _factory.CreateClient();
|
|
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
|
|
|
|
// 创建模拟的 MP3 文件
|
|
var content = new MultipartFormDataContent();
|
|
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake mp3 content"));
|
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue("audio/mpeg");
|
|
content.Add(fileContent, "file", "test.mp3");
|
|
|
|
// Act
|
|
var response = await client.PostAsync("/api/app/upload/voice", content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
|
|
var responseContent = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
|
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal(0, result.Code);
|
|
Assert.NotNull(result.Data);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试上传语音文件 - 不支持的格式
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task UploadVoice_InvalidFormat_ReturnsError()
|
|
{
|
|
// Arrange
|
|
var client = _factory.CreateClient();
|
|
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
|
|
|
|
// 创建不支持的文件格式
|
|
var content = new MultipartFormDataContent();
|
|
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
|
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
|
|
content.Add(fileContent, "file", "test.pdf");
|
|
|
|
// Act
|
|
var response = await client.PostAsync("/api/app/upload/voice", content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
|
|
var responseContent = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
|
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
|
|
Assert.NotNull(result);
|
|
Assert.NotEqual(0, result.Code); // 应返回错误码
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试上传语音文件 - 文件为空
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task UploadVoice_EmptyFile_ReturnsError()
|
|
{
|
|
// Arrange
|
|
var client = _factory.CreateClient();
|
|
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
|
|
|
|
var content = new MultipartFormDataContent();
|
|
|
|
// Act
|
|
var response = await client.PostAsync("/api/app/upload/voice", content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试上传图片文件 - 成功
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task UploadImage_ValidJpgFile_ReturnsSuccess()
|
|
{
|
|
// Arrange
|
|
var expectedFileKey = "images/test.jpg";
|
|
var expectedUrl = "https://example.com/images/test.jpg";
|
|
_mockStorageProvider.UploadAsync(Arg.Any<Stream>(), Arg.Any<string>(), "images")
|
|
.Returns(Task.FromResult(expectedFileKey));
|
|
_mockStorageProvider.GetAccessUrl(expectedFileKey, Arg.Any<int>())
|
|
.Returns(expectedUrl);
|
|
|
|
var client = _factory.CreateClient();
|
|
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
|
|
|
|
// 创建模拟的 JPG 文件
|
|
var content = new MultipartFormDataContent();
|
|
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake jpg content"));
|
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
|
|
content.Add(fileContent, "file", "test.jpg");
|
|
|
|
// Act
|
|
var response = await client.PostAsync("/api/app/upload/image", content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
|
|
var responseContent = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
|
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal(0, result.Code);
|
|
Assert.NotNull(result.Data);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试上传图片文件 - 不支持的格式
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task UploadImage_InvalidFormat_ReturnsError()
|
|
{
|
|
// Arrange
|
|
var client = _factory.CreateClient();
|
|
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
|
|
|
|
// 创建不支持的文件格式
|
|
var content = new MultipartFormDataContent();
|
|
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
|
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
|
|
content.Add(fileContent, "file", "test.pdf");
|
|
|
|
// Act
|
|
var response = await client.PostAsync("/api/app/upload/image", content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
|
|
var responseContent = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
|
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
|
|
Assert.NotNull(result);
|
|
Assert.NotEqual(0, result.Code); // 应返回错误码
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试上传语音文件 - 支持的所有格式
|
|
/// </summary>
|
|
[Theory]
|
|
[InlineData("test.mp3", "audio/mpeg")]
|
|
[InlineData("test.wav", "audio/wav")]
|
|
[InlineData("test.m4a", "audio/mp4")]
|
|
[InlineData("test.amr", "audio/amr")]
|
|
public async Task UploadVoice_SupportedFormats_ReturnsSuccess(string fileName, string contentType)
|
|
{
|
|
// Arrange
|
|
var expectedFileKey = $"voice/{fileName}";
|
|
var expectedUrl = $"https://example.com/voice/{fileName}";
|
|
_mockStorageProvider.UploadAsync(Arg.Any<Stream>(), Arg.Any<string>(), "voice")
|
|
.Returns(Task.FromResult(expectedFileKey));
|
|
_mockStorageProvider.GetAccessUrl(Arg.Any<string>(), Arg.Any<int>())
|
|
.Returns(expectedUrl);
|
|
|
|
var client = _factory.CreateClient();
|
|
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
|
|
|
|
var content = new MultipartFormDataContent();
|
|
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
|
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
|
|
content.Add(fileContent, "file", fileName);
|
|
|
|
// Act
|
|
var response = await client.PostAsync("/api/app/upload/voice", content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
|
|
var responseContent = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
|
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal(0, result.Code);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试上传图片文件 - 支持的所有格式
|
|
/// </summary>
|
|
[Theory]
|
|
[InlineData("test.jpg", "image/jpeg")]
|
|
[InlineData("test.jpeg", "image/jpeg")]
|
|
[InlineData("test.png", "image/png")]
|
|
[InlineData("test.gif", "image/gif")]
|
|
[InlineData("test.webp", "image/webp")]
|
|
public async Task UploadImage_SupportedFormats_ReturnsSuccess(string fileName, string contentType)
|
|
{
|
|
// Arrange
|
|
var expectedFileKey = $"images/{fileName}";
|
|
var expectedUrl = $"https://example.com/images/{fileName}";
|
|
_mockStorageProvider.UploadAsync(Arg.Any<Stream>(), Arg.Any<string>(), "images")
|
|
.Returns(Task.FromResult(expectedFileKey));
|
|
_mockStorageProvider.GetAccessUrl(Arg.Any<string>(), Arg.Any<int>())
|
|
.Returns(expectedUrl);
|
|
|
|
var client = _factory.CreateClient();
|
|
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
|
|
|
|
var content = new MultipartFormDataContent();
|
|
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
|
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
|
|
content.Add(fileContent, "file", fileName);
|
|
|
|
// Act
|
|
var response = await client.PostAsync("/api/app/upload/image", content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
|
|
var responseContent = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
|
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal(0, result.Code);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试上传文件 - 未授权
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task UploadVoice_NoAuth_ReturnsUnauthorized()
|
|
{
|
|
// Arrange
|
|
var client = _factory.CreateClient();
|
|
// 不添加 Authorization 头
|
|
|
|
var content = new MultipartFormDataContent();
|
|
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
|
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue("audio/mpeg");
|
|
content.Add(fileContent, "file", "test.mp3");
|
|
|
|
// Act
|
|
var response = await client.PostAsync("/api/app/upload/voice", content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
|
}
|
|
}
|