126 lines
5.7 KiB
Swift
126 lines
5.7 KiB
Swift
//
|
||
// UploadTests.swift
|
||
// suixinkanTests
|
||
//
|
||
// Created by Codex on 2026/6/22.
|
||
//
|
||
|
||
import XCTest
|
||
@testable import suixinkan_ios
|
||
|
||
@MainActor
|
||
/// 上传模块测试,覆盖 OSS 上传策略和 STS 配置接口。
|
||
final class UploadTests: XCTestCase {
|
||
/// 测试文件校验能识别空文件、超大文件和不支持扩展名。
|
||
func testOSSUploadPolicyValidatesFileConstraints() {
|
||
XCTAssertThrowsError(try OSSUploadPolicy.validate(dataSize: 0, fileName: "avatar.jpg")) { error in
|
||
XCTAssertEqual(error as? OSSUploadError, .emptyFile)
|
||
}
|
||
XCTAssertThrowsError(try OSSUploadPolicy.validate(dataSize: OSSUploadPolicy.maxFileSize + 1, fileName: "avatar.jpg")) { error in
|
||
XCTAssertEqual(error as? OSSUploadError, .fileTooLarge)
|
||
}
|
||
XCTAssertThrowsError(try OSSUploadPolicy.validate(dataSize: 12, fileName: "avatar.txt")) { error in
|
||
XCTAssertEqual(error as? OSSUploadError, .unsupportedFileType)
|
||
}
|
||
XCTAssertNoThrow(try OSSUploadPolicy.validate(dataSize: 12, fileName: "avatar.heic"))
|
||
}
|
||
|
||
/// 测试 objectKey 按业务模块生成稳定路径并清洗文件名。
|
||
func testOSSUploadPolicyBuildsObjectKeys() {
|
||
let date = Date(timeIntervalSince1970: 1_767_225_600)
|
||
let uuid = UUID(uuidString: "12345678-1234-1234-1234-1234567890ab")!
|
||
let timeZone = TimeZone(secondsFromGMT: 0)!
|
||
|
||
XCTAssertEqual(
|
||
OSSUploadPolicy.objectKey(fileName: "a/b.jpg", scenicId: 9, moduleType: "user_avatar", date: date, uuid: uuid, timeZone: timeZone),
|
||
"avatar/20260101/9/123456781234123412341234567890AB_a_b.jpg"
|
||
)
|
||
XCTAssertEqual(
|
||
OSSUploadPolicy.objectKey(fileName: "id.jpg", scenicId: 9, moduleType: "real_name", date: date, uuid: uuid, timeZone: timeZone),
|
||
"real_name/20260101/9/123456781234123412341234567890AB_id.jpg"
|
||
)
|
||
XCTAssertEqual(
|
||
OSSUploadPolicy.objectKey(fileName: "video.mp4", scenicId: 9, moduleType: "task_upload", date: date, uuid: uuid, timeZone: timeZone),
|
||
"task_upload/20260101/9/123456781234123412341234567890AB_video.mp4"
|
||
)
|
||
XCTAssertEqual(
|
||
OSSUploadPolicy.objectKey(fileName: "bank.jpg", scenicId: 9, moduleType: "bank_card", date: date, uuid: uuid, timeZone: timeZone),
|
||
"bank_card/20260101/9/123456781234123412341234567890AB_bank.jpg"
|
||
)
|
||
XCTAssertEqual(
|
||
OSSUploadPolicy.objectKey(fileName: "cover.jpg", scenicId: 9, moduleType: "project", date: date, uuid: uuid, timeZone: timeZone),
|
||
"project/20260101/9/123456781234123412341234567890AB_cover.jpg"
|
||
)
|
||
XCTAssertEqual(
|
||
OSSUploadPolicy.objectKey(fileName: "live.mp4", scenicId: 9, moduleType: "alive_album", date: date, uuid: uuid, timeZone: timeZone),
|
||
"live_albums/20260101/9/123456781234123412341234567890AB_live.mp4"
|
||
)
|
||
}
|
||
|
||
/// 测试 MIME 类型推断和 URL 拼接规则。
|
||
func testOSSUploadPolicyContentTypeAndURLJoin() {
|
||
XCTAssertEqual(OSSUploadPolicy.contentType(for: "a.jpg", fileType: 2), "image/jpeg")
|
||
XCTAssertEqual(OSSUploadPolicy.contentType(for: "a.png", fileType: 2), "image/png")
|
||
XCTAssertEqual(OSSUploadPolicy.contentType(for: "a.mp4", fileType: 1), "video/mp4")
|
||
XCTAssertEqual(OSSUploadPolicy.contentType(for: "a.unknown", fileType: 1), "video/mp4")
|
||
XCTAssertEqual(OSSUploadPolicy.contentType(for: "a.unknown", fileType: 2), "image/jpeg")
|
||
XCTAssertEqual(OSSUploadPolicy.joinURL(baseURL: "https://cdn.example.com", objectKey: "a/b.jpg"), "https://cdn.example.com/a/b.jpg")
|
||
XCTAssertEqual(OSSUploadPolicy.joinURL(baseURL: "https://cdn.example.com/", objectKey: "a/b.jpg"), "https://cdn.example.com/a/b.jpg")
|
||
}
|
||
|
||
/// 测试 STS token 接口使用正确路径、bucket 参数并兼容宽松字段类型。
|
||
func testUploadAPIRequestsSTSConfig() async throws {
|
||
let response = """
|
||
{
|
||
"code": 100000,
|
||
"msg": "success",
|
||
"data": {
|
||
"base_url": 123,
|
||
"endpoint": "oss-cn-hangzhou.aliyuncs.com",
|
||
"region": "cn-hangzhou",
|
||
"bucket": "vipsky",
|
||
"expire_seconds": "900",
|
||
"credentials": {
|
||
"access_key_id": 456,
|
||
"access_key_secret": "secret",
|
||
"security_token": "token"
|
||
}
|
||
}
|
||
}
|
||
""".data(using: .utf8)!
|
||
let session = UploadURLSession(responses: [response])
|
||
let api = UploadAPI(client: APIClient(session: session))
|
||
|
||
let config = try await api.aliyunOSSBucket()
|
||
|
||
XCTAssertEqual(config.baseUrl, "123")
|
||
XCTAssertEqual(config.expireSeconds, 900)
|
||
XCTAssertEqual(config.credentials.accessKeyId, "456")
|
||
let request = try XCTUnwrap(session.requests.first)
|
||
XCTAssertEqual(request.httpMethod, "GET")
|
||
XCTAssertEqual(request.url?.path, "/api/app/config/get-sts-token")
|
||
XCTAssertEqual(URLComponents(url: request.url!, resolvingAgainstBaseURL: false)?.queryItems?.first?.value, "vipsky")
|
||
}
|
||
}
|
||
|
||
/// 上传测试用 URLSession 替身,按顺序返回预设响应。
|
||
private final class UploadURLSession: URLSessionProtocol {
|
||
private var responses: [Data]
|
||
private(set) var requests: [URLRequest] = []
|
||
|
||
/// 初始化顺序响应。
|
||
init(responses: [Data]) {
|
||
self.responses = responses
|
||
}
|
||
|
||
/// 记录请求并返回下一份响应。
|
||
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
|
||
requests.append(request)
|
||
let data = responses.isEmpty ? Data() : responses.removeFirst()
|
||
return (
|
||
data,
|
||
HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!
|
||
)
|
||
}
|
||
}
|