Buckets:
localhost1978/localhost / LOCALHOST1978 /Modules /SSK_Providers /Tests /SSK_ProvidersTests /HTTP3AudioArtifactTests.swift
| import CryptoKit | |
| import Foundation | |
| import SSK_Abstractions | |
| @testable import SSK_Providers | |
| import XCTest | |
| @available(macOS 27.0, iOS 27.0, *) | |
| final class HTTP3AudioArtifactTests: XCTestCase { | |
| func testClientUsesHTTPSHTTP3AndValidatedPUTRoute() async throws { | |
| let payload = Data("audio-fixture".utf8) | |
| let hash = sha256(payload) | |
| let jobID = AudioIngestionJobID(rawValue: UUID()) | |
| let uri = makeURI(jobID: jobID, kind: .sourceRecord, hash: hash) | |
| let recorder = RequestRecorder() | |
| let receiptData = try JSONEncoder().encode( | |
| RemoteAudioArtifactReceipt(uri: uri, contentHash: hash, byteCount: payload.count) | |
| ) | |
| let client = HTTP3AudioArtifactClient { request, limit in | |
| await recorder.record(request, limit: limit) | |
| return ( | |
| receiptData, | |
| HTTPURLResponse( | |
| url: request.url!, | |
| statusCode: 201, | |
| httpVersion: "HTTP/3", | |
| headerFields: nil | |
| )! | |
| ) | |
| } | |
| let receipt = try await client.putAudioArtifact( | |
| endpoint: URL(string: "https://storage.example/ssk")!, | |
| jobID: jobID, | |
| kind: .sourceRecord, | |
| contentHash: hash, | |
| payload: payload | |
| ) | |
| XCTAssertEqual(receipt, RemoteAudioArtifactReceipt(uri: uri, contentHash: hash, byteCount: payload.count)) | |
| let lastRequest = await recorder.last() | |
| let recorded = try XCTUnwrap(lastRequest) | |
| XCTAssertEqual(recorded.request.httpMethod, "PUT") | |
| XCTAssertTrue(recorded.request.assumesHTTP3Capable) | |
| XCTAssertEqual( | |
| recorded.request.url?.path, | |
| "/ssk/audio-artifacts/\(jobID.rawValue.uuidString.lowercased())/sourceRecord/\(hash)" | |
| ) | |
| XCTAssertEqual(recorded.request.value(forHTTPHeaderField: "X-SSK-Content-SHA256"), hash) | |
| XCTAssertEqual(recorded.request.httpBody, payload) | |
| XCTAssertEqual(recorded.limit, 65_536) | |
| } | |
| func testClientRejectsInsecureEndpointAndNoncanonicalHashWithoutNetwork() async { | |
| let recorder = RequestRecorder() | |
| let client = HTTP3AudioArtifactClient { request, limit in | |
| await recorder.record(request, limit: limit) | |
| throw RemoteAudioArtifactTransportError.invalidResponse | |
| } | |
| do { | |
| _ = try await client.putAudioArtifact( | |
| endpoint: URL(string: "http://storage.example")!, | |
| jobID: AudioIngestionJobID(rawValue: UUID()), | |
| kind: .sourceRecord, | |
| contentHash: "bad/hash", | |
| payload: Data() | |
| ) | |
| XCTFail("Expected a secure endpoint failure") | |
| } catch { | |
| XCTAssertEqual(error as? RemoteAudioArtifactTransportError, .secureEndpointRequired) | |
| } | |
| let lastRequest = await recorder.last() | |
| XCTAssertNil(lastRequest) | |
| } | |
| func testClientRejectsOversizedOrHashMismatchedGETResponse() async throws { | |
| let uri = makeURI( | |
| jobID: AudioIngestionJobID(rawValue: UUID()), | |
| kind: .metadata, | |
| hash: String(repeating: "a", count: 64) | |
| ) | |
| let oversized = Data(repeating: 0, count: 5) | |
| let oversizedClient = HTTP3AudioArtifactClient(maximumArtifactByteCount: 4) { request, _ in | |
| ( | |
| oversized, | |
| HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "HTTP/3", headerFields: nil)! | |
| ) | |
| } | |
| do { | |
| _ = try await oversizedClient.getAudioArtifact( | |
| endpoint: URL(string: "https://storage.example")!, | |
| uri: uri, | |
| expectedContentHash: String(repeating: "a", count: 64) | |
| ) | |
| XCTFail("Expected an oversized response failure") | |
| } catch { | |
| XCTAssertEqual(error as? RemoteAudioArtifactTransportError, .responseTooLarge) | |
| } | |
| let mismatchClient = HTTP3AudioArtifactClient { request, _ in | |
| ( | |
| Data("wrong".utf8), | |
| HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "HTTP/3", headerFields: nil)! | |
| ) | |
| } | |
| do { | |
| _ = try await mismatchClient.getAudioArtifact( | |
| endpoint: URL(string: "https://storage.example")!, | |
| uri: uri, | |
| expectedContentHash: String(repeating: "a", count: 64) | |
| ) | |
| XCTFail("Expected a content hash failure") | |
| } catch { | |
| XCTAssertEqual(error as? RemoteAudioArtifactTransportError, .contentHashMismatch) | |
| } | |
| } | |
| func testServerPUTGETDELETELifecycle() async throws { | |
| let fixture = try makeServerFixture(maximumByteCount: 64) | |
| defer { try? FileManager.default.removeItem(at: fixture.root) } | |
| let payload = Data("audio-fixture".utf8) | |
| let hash = sha256(payload) | |
| let jobID = AudioIngestionJobID(rawValue: UUID()) | |
| let put = await fixture.server.handle( | |
| HTTP3AudioArtifactRequest( | |
| method: "PUT", | |
| path: "/audio-artifacts/\(jobID.rawValue.uuidString.lowercased())/metadata/\(hash)", | |
| headers: [ | |
| "content-type": "application/octet-stream", | |
| "content-length": String(payload.count), | |
| "x-ssk-content-sha256": hash, | |
| ], | |
| body: payload | |
| ) | |
| ) | |
| XCTAssertEqual(put.statusCode, 201) | |
| let receipt = try JSONDecoder().decode(RemoteAudioArtifactReceipt.self, from: put.body) | |
| XCTAssertEqual(receipt.contentHash, hash) | |
| let get = await fixture.server.handle( | |
| HTTP3AudioArtifactRequest( | |
| method: "GET", | |
| path: "/audio-artifacts/by-hash/\(hash)", | |
| headers: ["x-ssk-artifact-uri": receipt.uri.stringValue], | |
| body: Data() | |
| ) | |
| ) | |
| XCTAssertEqual(get.statusCode, 200) | |
| XCTAssertEqual(get.body, payload) | |
| let encodedURI = base64URL(Data(receipt.uri.stringValue.utf8)) | |
| let delete = await fixture.server.handle( | |
| HTTP3AudioArtifactRequest( | |
| method: "DELETE", | |
| path: "/audio-artifacts/by-uri/\(encodedURI)", | |
| headers: [:], | |
| body: Data() | |
| ) | |
| ) | |
| XCTAssertEqual(delete.statusCode, 204) | |
| let missing = await fixture.server.handle( | |
| HTTP3AudioArtifactRequest( | |
| method: "GET", | |
| path: "/audio-artifacts/by-hash/\(hash)", | |
| headers: ["x-ssk-artifact-uri": receipt.uri.stringValue], | |
| body: Data() | |
| ) | |
| ) | |
| XCTAssertEqual(missing.statusCode, 404) | |
| } | |
| func testServerFailsClosedForLargeMismatchAndTraversalRequests() async throws { | |
| let fixture = try makeServerFixture(maximumByteCount: 4) | |
| defer { try? FileManager.default.removeItem(at: fixture.root) } | |
| let job = UUID().uuidString.lowercased() | |
| let hash = String(repeating: "a", count: 64) | |
| let tooLarge = await fixture.server.handle( | |
| HTTP3AudioArtifactRequest( | |
| method: "PUT", | |
| path: "/audio-artifacts/\(job)/metadata/\(hash)", | |
| headers: [ | |
| "content-type": "application/octet-stream", | |
| "content-length": "5", | |
| "x-ssk-content-sha256": hash, | |
| ], | |
| body: Data(repeating: 0, count: 5) | |
| ) | |
| ) | |
| XCTAssertEqual(tooLarge.statusCode, 413) | |
| let mismatch = await fixture.server.handle( | |
| HTTP3AudioArtifactRequest( | |
| method: "PUT", | |
| path: "/audio-artifacts/\(job)/metadata/\(hash)", | |
| headers: [ | |
| "content-type": "application/octet-stream", | |
| "content-length": "1", | |
| "x-ssk-content-sha256": hash, | |
| ], | |
| body: Data([0]) | |
| ) | |
| ) | |
| XCTAssertEqual(mismatch.statusCode, 422) | |
| let traversal = await fixture.server.handle( | |
| HTTP3AudioArtifactRequest( | |
| method: "GET", | |
| path: "/audio-artifacts/by-hash/%2E%2E", | |
| headers: ["x-ssk-artifact-uri": "ssk://cas:\(hash)/media/audio-artifact/\(job)/metadata"], | |
| body: Data() | |
| ) | |
| ) | |
| XCTAssertEqual(traversal.statusCode, 400) | |
| } | |
| func testStoreRejectsSymlinkEscapeBeforeWrite() async throws { | |
| let root = FileManager.default.temporaryDirectory | |
| .appendingPathComponent("ssk-http3-root-\(UUID().uuidString)", isDirectory: true) | |
| let outside = FileManager.default.temporaryDirectory | |
| .appendingPathComponent("ssk-http3-outside-\(UUID().uuidString)", isDirectory: true) | |
| defer { | |
| try? FileManager.default.removeItem(at: root) | |
| try? FileManager.default.removeItem(at: outside) | |
| } | |
| try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) | |
| try FileManager.default.createDirectory(at: outside, withIntermediateDirectories: true) | |
| let jobID = AudioIngestionJobID(rawValue: UUID()) | |
| try FileManager.default.createSymbolicLink( | |
| at: root.appendingPathComponent(jobID.rawValue.uuidString.lowercased()), | |
| withDestinationURL: outside | |
| ) | |
| let store = try HTTP3AudioArtifactStore(rootURL: root, maximumArtifactByteCount: 64) | |
| let payload = Data("fixture".utf8) | |
| do { | |
| _ = try await store.put( | |
| jobID: jobID, | |
| kind: .metadata, | |
| contentHash: sha256(payload), | |
| payload: payload | |
| ) | |
| XCTFail("Expected containment failure") | |
| } catch { | |
| XCTAssertEqual(error as? HTTP3AudioArtifactServerError, .pathOutsideStore) | |
| } | |
| XCTAssertEqual(try FileManager.default.contentsOfDirectory(atPath: outside.path), []) | |
| } | |
| private func makeServerFixture( | |
| maximumByteCount: Int | |
| ) throws -> (root: URL, server: HTTP3AudioArtifactServer) { | |
| let root = FileManager.default.temporaryDirectory | |
| .appendingPathComponent("ssk-http3-artifacts-\(UUID().uuidString)", isDirectory: true) | |
| let store = try HTTP3AudioArtifactStore( | |
| rootURL: root, | |
| maximumArtifactByteCount: maximumByteCount | |
| ) | |
| return ( | |
| root, | |
| HTTP3AudioArtifactServer( | |
| store: store, | |
| maximumArtifactByteCount: maximumByteCount | |
| ) | |
| ) | |
| } | |
| private func makeURI( | |
| jobID: AudioIngestionJobID, | |
| kind: AudioArtifactKind, | |
| hash: String | |
| ) -> SSKURI { | |
| SSKURI( | |
| authority: .cas(hash: .init(rawValue: hash)), | |
| domain: .media, | |
| subdomain: "audio-artifact", | |
| pathComponents: [ | |
| .init(rawValue: jobID.rawValue.uuidString.lowercased()), | |
| .init(rawValue: kind.rawValue), | |
| ] | |
| ) | |
| } | |
| private func sha256(_ data: Data) -> String { | |
| SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() | |
| } | |
| private func base64URL(_ data: Data) -> String { | |
| data.base64EncodedString() | |
| .replacingOccurrences(of: "/", with: "_") | |
| .replacingOccurrences(of: "+", with: "-") | |
| .replacingOccurrences(of: "=", with: "") | |
| } | |
| } | |
| @available(macOS 27.0, iOS 27.0, *) | |
| private actor RequestRecorder { | |
| struct Entry: Sendable { | |
| let request: URLRequest | |
| let limit: Int | |
| } | |
| private var entry: Entry? | |
| func record(_ request: URLRequest, limit: Int) { | |
| entry = Entry(request: request, limit: limit) | |
| } | |
| func last() -> Entry? { | |
| entry | |
| } | |
| } | |
Xet Storage Details
- Size:
- 12 kB
- Xet hash:
- 3b91a69fbba2dfd64a1f47eef33ee43b73c8505af60e82aedd3f04167e2d8def
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.