diff --git a/PostHogTests/PostHogCaptureV1Test.swift b/PostHogTests/PostHogCaptureV1Test.swift index ee1bd6625..632d8abf0 100644 --- a/PostHogTests/PostHogCaptureV1Test.swift +++ b/PostHogTests/PostHogCaptureV1Test.swift @@ -798,6 +798,30 @@ final class PostHogCaptureV1QueueTest { #expect(queue.depth == 0) #expect(server.batchRequests.map { server.parsePostHogEvents($0).count } == [2, 1]) } + + @Test("flushes analytics once a batch's worth of bytes is queued, before flushAt") + func flushesAtByteLimit() async throws { + let config = PostHogConfig(projectToken: "phc_bytes_\(UUID().uuidString)", host: "http://localhost:9001") + config.flushAt = 100 + let storage = PostHogStorage(config) + // Not started, so no timer: only the byte threshold can trigger a send. + let queue = PostHogQueue(config, storage, .batch(api: PostHogApi(config)), nil) + server.batchProjectToken = config.projectToken + defer { + queue.stop() + queue.clear() + deleteSafely(storage.appFolderUrl) + } + + let blob = String(repeating: "a", count: 2 * 1024 * 1024) + for _ in 0 ..< 3 { + queue.add(PostHogEvent(event: "large", distinctId: "user", properties: ["blob": blob])) + } + await waitUntil(timeout: 10) { queue.depth == 0 } + + #expect(queue.depth == 0) + #expect(!server.batchRequests.isEmpty) + } } @Suite("Capture V1 AI lane", .serialized, .resetsGlobalState) diff --git a/PostHogTests/PostHogFileBackedQueueAlignmentTest.swift b/PostHogTests/PostHogFileBackedQueueAlignmentTest.swift index 07ec910c6..01a12fc68 100644 --- a/PostHogTests/PostHogFileBackedQueueAlignmentTest.swift +++ b/PostHogTests/PostHogFileBackedQueueAlignmentTest.swift @@ -105,6 +105,23 @@ struct PostHogFileBackedQueueAlignmentTest { #expect(decode(queue.peek(10)) == ["CCCC", "DDDD"]) } + @Test("tracks the byte count without a byte limit and evicts nothing") + func tracksBytesWithoutLimit() throws { + let dir = FileManager.default.temporaryDirectory + .appendingPathComponent("ph-queue-bytes-\(UUID().uuidString)") + defer { try? FileManager.default.removeItem(at: dir) } + let queue = PostHogFileBackedQueue(queue: dir, trackBytes: true) + + #expect(queue.add(Data("AAAA".utf8)).evicted.isEmpty) + #expect(queue.add(Data("BBBBBB".utf8)).evicted.isEmpty) + #expect(queue.byteCount == 10) + #expect(PostHogFileBackedQueue(queue: dir, trackBytes: true).byteCount == 10) + + queue.pop(1) + #expect(queue.byteCount == 6) + #expect(decode(queue.peek(10)) == ["BBBBBB"]) + } + @Test("keeps the newest record even when it is over the byte limit alone") func keepsOversizedNewestRecord() throws { let dir = FileManager.default.temporaryDirectory