Files
suixinkan_ios_new/suixinkanTests/Live/LiveAPITests.swift
汉秋 fcb692b56a 新增直播模块,包含推流管理与相册流程
将直播推流管理与直播相册从首页占位页迁移为完整实现,包含 alive album OSS 上传、首页路由与单元测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 14:38:52 +08:00

169 lines
8.1 KiB
Swift
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.

//
// LiveAPITests.swift
// suixinkanTests
//
// Created by Codex on 2026/6/25.
//
import XCTest
@testable import suixinkan
@MainActor
/// API
final class LiveAPITests: XCTestCase {
func testLiveListAndDetailDecodeFixturesAndUseExpectedQueries() async throws {
let listSession = LiveRecordingURLSession(data: try TestFixture.data(named: "alive_list_success"))
let listAPI = LiveAPI(client: APIClient(session: listSession))
let list = try await listAPI.liveList(scenicId: 88, page: 0, pageSize: 0)
XCTAssertEqual(list.total, 2)
XCTAssertEqual(list.page, 1)
XCTAssertEqual(list.pageSize, 1)
XCTAssertEqual(list.items.first?.id, 8101)
XCTAssertEqual(list.items.first?.manualPushMode, 2)
let listRequest = try XCTUnwrap(listSession.requests.first)
XCTAssertEqual(listRequest.httpMethod, "GET")
XCTAssertEqual(listRequest.url?.path, "/api/app/manual-live/list")
XCTAssertEqual(liveQueryItems(from: listRequest)["scenic_id"], "88")
XCTAssertEqual(liveQueryItems(from: listRequest)["page"], "1")
XCTAssertEqual(liveQueryItems(from: listRequest)["page_size"], "1")
let detailSession = LiveRecordingURLSession(data: try TestFixture.data(named: "alive_detail_success"))
let detailAPI = LiveAPI(client: APIClient(session: detailSession))
let detail = try await detailAPI.liveDetail(liveId: 8101)
XCTAssertEqual(detail.id, 8101)
XCTAssertEqual(detail.pushUrl, "rtmp://push.example.com/live/8101")
XCTAssertEqual(detail.status, 2)
XCTAssertEqual(detail.duration, 3600)
let detailRequest = try XCTUnwrap(detailSession.requests.first)
XCTAssertEqual(detailRequest.url?.path, "/api/app/manual-live/detail")
XCTAssertEqual(liveQueryItems(from: detailRequest)["live_id"], "8101")
}
func testLiveCreateAndControlsUseExpectedBodies() async throws {
let createSession = LiveRecordingURLSession(responses: Array(repeating: try TestFixture.data(named: "empty_success"), count: 5))
let api = LiveAPI(client: APIClient(session: createSession))
try await api.liveCreate(LiveCreateRequest(scenicId: "88", title: "景区晨间直播", coverImg: "https://cdn.example.com/cover.jpg"))
var request = try XCTUnwrap(createSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/manual-live/create")
var json = try liveJSONBody(from: request)
XCTAssertEqual(json["scenic_id"] as? String, "88")
XCTAssertEqual(json["title"] as? String, "景区晨间直播")
XCTAssertEqual(json["cover_img"] as? String, "https://cdn.example.com/cover.jpg")
try await api.liveStart(liveId: 8101)
request = try XCTUnwrap(createSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/manual-live/start")
XCTAssertEqual(try liveJSONBody(from: request)["live_id"] as? Int, 8101)
try await api.liveStop(liveId: 8101)
request = try XCTUnwrap(createSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/manual-live/stop")
XCTAssertEqual(try liveJSONBody(from: request)["live_id"] as? Int, 8101)
try await api.liveFinish(liveId: 8101)
request = try XCTUnwrap(createSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/manual-live/finish")
XCTAssertEqual(try liveJSONBody(from: request)["live_id"] as? Int, 8101)
try await api.liveSetPushMode(liveId: 8101, mode: 2)
request = try XCTUnwrap(createSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/manual-live/set-push-mode")
json = try liveJSONBody(from: request)
XCTAssertEqual(json["live_id"] as? Int, 8101)
XCTAssertEqual(json["manual_push_mode"] as? Int, 2)
}
func testLiveAlbumAPIsUseExpectedRequests() async throws {
let listSession = LiveRecordingURLSession(data: try TestFixture.data(named: "alive_album_list_success"))
let api = LiveAPI(client: APIClient(session: listSession))
let response = try await api.liveAlbumList(scenicId: 88, startTime: "2026-05-01", endTime: "2026-05-23", page: 0, pageSize: 0)
XCTAssertEqual(response.total, 2)
XCTAssertEqual(response.items.first?.id, 6101)
XCTAssertEqual(response.items.first?.items.last?.previewURL, "https://cdn.example.com/alive/video-cover.jpg")
var request = try XCTUnwrap(listSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/view-album/folders")
var query = liveQueryItems(from: request)
XCTAssertEqual(query["scenic_id"], "88")
XCTAssertEqual(query["start_time"], "2026-05-01")
XCTAssertEqual(query["end_time"], "2026-05-23")
XCTAssertEqual(query["page"], "1")
XCTAssertEqual(query["page_size"], "1")
let mutationSession = LiveRecordingURLSession(data: try TestFixture.data(named: "empty_success"))
let mutationAPI = LiveAPI(client: APIClient(session: mutationSession))
try await mutationAPI.liveAlbumCreateFolder(
LiveAlbumCreateFolderRequest(
scenicId: "88",
name: "五一直播相册",
items: [LiveAlbumCreateFileItem(url: "https://cdn.example.com/a.jpg", type: 1, size: 12, coverImg: nil)]
)
)
request = try XCTUnwrap(mutationSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/view-album/create-folder")
var json = try liveJSONBody(from: request)
XCTAssertEqual(json["scenic_id"] as? String, "88")
XCTAssertEqual((json["items"] as? [[String: Any]])?.first?["url"] as? String, "https://cdn.example.com/a.jpg")
try await mutationAPI.liveAlbumDeleteFolder(folderId: 6101)
request = try XCTUnwrap(mutationSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/view-album/delete-folder")
XCTAssertEqual(try liveJSONBody(from: request)["folder_id"] as? Int, 6101)
let detailSession = LiveRecordingURLSession(data: try TestFixture.data(named: "alive_album_folder_detail_success"))
let detailAPI = LiveAPI(client: APIClient(session: detailSession))
let folder = try await detailAPI.liveAlbumFolderDetail(folderId: 6101)
XCTAssertEqual(folder.items.count, 2)
request = try XCTUnwrap(detailSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/view-album/folder-detail")
XCTAssertEqual(liveQueryItems(from: request)["folder_id"], "6101")
try await mutationAPI.liveAlbumDeleteFiles(folderId: 6101, fileIds: [7101, 7102])
request = try XCTUnwrap(mutationSession.requests.last)
XCTAssertEqual(request.url?.path, "/api/app/view-album/delete-files")
json = try liveJSONBody(from: request)
XCTAssertEqual(json["folder_id"] as? Int, 6101)
XCTAssertEqual(json["file_ids"] as? [Int], [7101, 7102])
}
}
private final class LiveRecordingURLSession: URLSessionProtocol {
private var responses: [Data]
private(set) var requests: [URLRequest] = []
init(data: Data) {
responses = [data]
}
init(responses: [Data]) {
self.responses = responses
}
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
requests.append(request)
let data = responses.isEmpty ? try TestFixture.data(named: "empty_success") : responses.removeFirst()
return (data, HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!)
}
}
private func liveQueryItems(from request: URLRequest) -> [String: String] {
guard let url = request.url,
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
else { return [:] }
return Dictionary(uniqueKeysWithValues: (components.queryItems ?? []).compactMap { item in
item.value.map { (item.name, $0) }
})
}
private func liveJSONBody(from request: URLRequest) throws -> [String: Any] {
let body = try XCTUnwrap(request.httpBody)
return try XCTUnwrap(JSONSerialization.jsonObject(with: body) as? [String: Any])
}