Files
ghostgram/submodules/Postbox/Tests/MediaBoxFileContextV2ReopenTests.swift
ichmagmaus111andClaude Opus 5.5 0622057a4f Ghostgram: open-source release
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 17:57:09 +01:00

117 lines
4.4 KiB
Swift

import Foundation
import XCTest
import SwiftSignalKit
import RangeSet
@testable import Postbox
/// The file map (`<id>_partial.meta`) is the context's record of which bytes of the
/// partial file are present. It must never claim more than the partial file holds, and a
/// write that cannot be performed must fail the fetch rather than leave requests pending.
final class MediaBoxFileContextV2ReopenTests: XCTestCase {
private var queue: Queue!
private var basePath: String!
private var manager: MediaBoxFileManager!
private var fullPath: String { return self.basePath + "/resource" }
private var partialPath: String { return self.basePath + "/resource_partial" }
private var metaPath: String { return self.basePath + "/resource_partial.meta" }
override func setUp() {
super.setUp()
self.queue = Queue(name: "MediaBoxFileContextV2ReopenTests")
self.basePath = NSTemporaryDirectory() + "MediaBoxFileContextV2ReopenTests-" + UUID().uuidString
try? FileManager.default.createDirectory(atPath: self.basePath, withIntermediateDirectories: true)
self.manager = MediaBoxFileManager(queue: self.queue)
}
override func tearDown() {
self.manager = nil
let _ = try? FileManager.default.removeItem(atPath: self.basePath)
super.tearDown()
}
// MARK: - Helpers
private func makeContext() -> MediaBoxFileContextV2Impl {
var context: MediaBoxFileContextV2Impl?
self.queue.sync {
context = MediaBoxFileContextV2Impl(
queue: self.queue,
manager: self.manager,
storageBox: nil,
resourceId: "resource".data(using: .utf8)!,
path: self.fullPath,
partialPath: self.partialPath,
metaPath: self.metaPath
)
}
return context!
}
private func writeMeta(claiming range: Range<Int64>) {
self.queue.sync {
let map = MediaBoxFileMap()
map.fill(range)
map.serialize(manager: self.manager, to: self.metaPath)
}
}
private func reportedRanges(of context: MediaBoxFileContextV2Impl) -> RangeSet<Int64>? {
var reported: RangeSet<Int64>?
self.queue.sync {
let _ = context.rangeStatus(next: { ranges in
reported = ranges
}, completed: {})
}
return reported
}
// MARK: - Tests
func testMapClaimingMoreThanThePartialFileHoldsIsDiscardedOnReopen() {
XCTAssertTrue(FileManager.default.createFile(atPath: self.partialPath, contents: Data(repeating: 0x7A, count: 10)))
self.writeMeta(claiming: 0 ..< 100)
let context = self.makeContext()
XCTAssertEqual(self.reportedRanges(of: context), RangeSet<Int64>(), "a map that claims bytes the partial file does not hold must be reset")
}
func testMapConsistentWithThePartialFileIsKeptOnReopen() {
XCTAssertTrue(FileManager.default.createFile(atPath: self.partialPath, contents: Data(repeating: 0x7A, count: 100)))
self.writeMeta(claiming: 0 ..< 40)
let context = self.makeContext()
XCTAssertEqual(self.reportedRanges(of: context), RangeSet<Int64>(0 ..< 40))
}
func testUnwritablePartialFileFailsTheFetchInsteadOfHanging() {
// A read-only partial file cannot be opened read-write, so every write fails.
XCTAssertTrue(FileManager.default.createFile(atPath: self.partialPath, contents: Data(), attributes: [.posixPermissions: 0o444]))
let context = self.makeContext()
let finished = self.expectation(description: "fetch finished")
var failed = false
self.queue.sync {
let _ = context.fetched(range: 0 ..< 8, priority: .default, fetch: { _ in
return Signal { subscriber in
subscriber.putNext(.dataPart(resourceOffset: 0, data: Data(repeating: 0x01, count: 8), range: 0 ..< 8, complete: true))
subscriber.putCompletion()
return EmptyDisposable
}
}, error: { _ in
failed = true
finished.fulfill()
}, completed: {
XCTFail("a fetch whose bytes could not be written must not complete")
finished.fulfill()
})
}
self.wait(for: [finished], timeout: 5.0)
XCTAssertTrue(failed)
XCTAssertFalse(FileManager.default.fileExists(atPath: self.fullPath))
}
}