From 3fbf3a86dfcb0f90390932cb01febf416928d9c8 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Wed, 17 Apr 2024 11:38:59 -0700 Subject: [PATCH 01/12] Testing opmode changes --- Sources/Segment/Analytics.swift | 26 ++++++- .../Segment/Utilities/CompletionGroup.swift | 59 ++++++++++++++++ Sources/Segment/Utilities/Utils.swift | 1 - .../Segment-Tests/CompletionGroup_Tests.swift | 67 +++++++++++++++++++ 4 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 Sources/Segment/Utilities/CompletionGroup.swift create mode 100644 Tests/Segment-Tests/CompletionGroup_Tests.swift diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 797088e..687c8b6 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -223,10 +223,34 @@ extension Analytics { return nil } + public func flush(completion: (() -> Void)? = nil) { + // only flush if we're enabled. + guard enabled == true else { return } + + let completionGroup = CompletionGroup(queue: configuration.values.flushQueue) + apply { plugin in + completionGroup.add { group in + if let p = plugin as? FlushCompletion { + p.flush(group: group) { plugin in + // we don't really care about the plugin value .. yet. + } + } else if let p = plugin as? EventPlugin { + group.enter() + p.flush() + group.leave() + } + } + } + + completionGroup.run(mode: operatingMode) { + completion?() + } + } + /// Tells this instance of Analytics to flush any queued events up to Segment.com. This command will also /// be sent to each plugin present in the system. A completion handler can be optionally given and will be /// called when flush has completed. - public func flush(completion: (() -> Void)? = nil) { + public func flush2(completion: (() -> Void)? = nil) { // only flush if we're enabled. guard enabled == true else { return } diff --git a/Sources/Segment/Utilities/CompletionGroup.swift b/Sources/Segment/Utilities/CompletionGroup.swift new file mode 100644 index 0000000..cbe1544 --- /dev/null +++ b/Sources/Segment/Utilities/CompletionGroup.swift @@ -0,0 +1,59 @@ +// +// CompletionGroup.swift +// +// +// Created by Brandon Sneed on 4/17/24. +// + +import Foundation + +class CompletionGroup { + let queue: DispatchQueue + var items = [(DispatchGroup) -> Void]() + + init(queue: DispatchQueue) { + self.queue = queue + } + + func add(workItem: @escaping (DispatchGroup) -> Void) { + items.append(workItem) + } + + func run(mode: OperatingMode, completion: @escaping () -> Void) { + // capture self strongly on purpose + let task: () -> Void = { [self] in + let group = DispatchGroup() + group.enter() + group.notify(queue: queue) { [weak self] in + completion() + self?.items.removeAll() + } + + for item in items { + item(group) + } + + group.leave() + + if mode == .synchronous { + group.wait() + } + } + + switch mode { + case .synchronous: + queue.sync { + task() + } + case .asynchronous: + queue.async { + task() + } + } + } + + /*func runAndWait(completion: @escaping () -> Void) { + run(completion: completion) + group.wait() + }*/ +} diff --git a/Sources/Segment/Utilities/Utils.swift b/Sources/Segment/Utilities/Utils.swift index 6e11385..27914c1 100644 --- a/Sources/Segment/Utilities/Utils.swift +++ b/Sources/Segment/Utilities/Utils.swift @@ -85,4 +85,3 @@ internal func eventStorageDirectory(writeKey: String) -> URL { return segmentURL } - diff --git a/Tests/Segment-Tests/CompletionGroup_Tests.swift b/Tests/Segment-Tests/CompletionGroup_Tests.swift new file mode 100644 index 0000000..a57fd82 --- /dev/null +++ b/Tests/Segment-Tests/CompletionGroup_Tests.swift @@ -0,0 +1,67 @@ +// +// CompletionGroup_Tests.swift +// +// +// Created by Brandon Sneed on 4/17/24. +// + +import XCTest +@testable import Segment + +final class CompletionGroup_Tests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + /*func testCompletionGroup() throws { + defer { + RunLoop.main.run() + } + + //let flushQueue = DispatchQueue(label: "com.segment.flush") + let flushQueue = DispatchQueue(label: "com.segment.flush", attributes: .concurrent) + + let group = CompletionGroup(queue: flushQueue) + + group.add { group in + group.enter() + print("item1 - sleeping 10") + sleep(10) + print("item1 - done sleeping") + group.leave() + } + + group.add { group in + group.enter() + print("item2 - launching an async task") + DispatchQueue.global(qos: .background).async { + print("item2 - background, sleeping 5") + sleep(5) + print("item2 - background, done sleeping") + group.leave() + } + } + + group.add { group in + group.enter() + print("item3 - returning real quick") + group.leave() + } + + group.add { group in + print("item4 - not entering group") + } + + group.run(mode: .asynchronous) { + print("all items completed.") + } + + print("test exited.") + }*/ + +} From 83e2288e1de170647623f2d1da0894db57a9d633 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Wed, 17 Apr 2024 11:47:21 -0700 Subject: [PATCH 02/12] testing ci output --- Sources/Segment/Plugins/SegmentDestination.swift | 4 ++++ Tests/Segment-Tests/Analytics_Tests.swift | 11 +---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index 5b6d846..96d9f24 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -132,6 +132,7 @@ public class SegmentDestination: DestinationPlugin, Subscriber, FlushCompletion // enter for the high level flush, allow us time to run through any existing files.. group.enter() + print("flush entering group") eventCount = 0 cleanupUploads() @@ -156,6 +157,7 @@ public class SegmentDestination: DestinationPlugin, Subscriber, FlushCompletion } // leave for the high level flush + print("flush leaving group") group.leave() } } @@ -171,6 +173,7 @@ extension SegmentDestination { for url in files { // enter for this url we're going to kick off group.enter() + print("flushFiles entered group \(url)") analytics.log(message: "Processing Batch:\n\(url.lastPathComponent)") // set up the task @@ -198,6 +201,7 @@ extension SegmentDestination { // call the completion completion(self) // leave for the url we kicked off. + print("flushFiles leaving group \(url)") group.leave() } diff --git a/Tests/Segment-Tests/Analytics_Tests.swift b/Tests/Segment-Tests/Analytics_Tests.swift index b7371bf..0241aee 100644 --- a/Tests/Segment-Tests/Analytics_Tests.swift +++ b/Tests/Segment-Tests/Analytics_Tests.swift @@ -745,7 +745,6 @@ final class Analytics_Tests: XCTestCase { let shared2 = Analytics.shared() XCTAssertFalse(alive2 === shared2) XCTAssertTrue(shared2 === shared) - } func testAsyncOperatingMode() throws { @@ -758,10 +757,6 @@ final class Analytics_Tests: XCTestCase { // set the httpclient to use our blocker session let segment = analytics.find(pluginType: SegmentDestination.self) let configuration = URLSessionConfiguration.ephemeral - configuration.allowsCellularAccess = true - configuration.timeoutIntervalForResource = 30 - configuration.timeoutIntervalForRequest = 60 - configuration.httpMaximumConnectionsPerHost = 2 configuration.protocolClasses = [BlockNetworkCalls.self] configuration.httpAdditionalHeaders = ["Content-Type": "application/json; charset=utf-8", "Authorization": "Basic test", @@ -783,7 +778,7 @@ final class Analytics_Tests: XCTestCase { expectation.fulfill() } - wait(for: [expectation], timeout: 5) + wait(for: [expectation], timeout: 1) XCTAssertNil(analytics.pendingUploads) } @@ -798,10 +793,6 @@ final class Analytics_Tests: XCTestCase { // set the httpclient to use our blocker session let segment = analytics.find(pluginType: SegmentDestination.self) let configuration = URLSessionConfiguration.ephemeral - configuration.allowsCellularAccess = true - configuration.timeoutIntervalForResource = 30 - configuration.timeoutIntervalForRequest = 60 - configuration.httpMaximumConnectionsPerHost = 2 configuration.protocolClasses = [BlockNetworkCalls.self] configuration.httpAdditionalHeaders = ["Content-Type": "application/json; charset=utf-8", "Authorization": "Basic test", From 7d9849faf000f2d55811cdc77d9f06f272328142 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Wed, 17 Apr 2024 12:10:31 -0700 Subject: [PATCH 03/12] Refactoring of flush completion. --- Sources/Segment/Analytics.swift | 65 ++----------------- Sources/Segment/Plugins.swift | 2 +- .../Segment/Plugins/SegmentDestination.swift | 44 +++++-------- Tests/Segment-Tests/Analytics_Tests.swift | 20 ------ 4 files changed, 22 insertions(+), 109 deletions(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 687c8b6..a1aab58 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -223,6 +223,9 @@ extension Analytics { return nil } + /// Tells this instance of Analytics to flush any queued events up to Segment.com. This command will also + /// be sent to each plugin present in the system. A completion handler can be optionally given and will be + /// called when flush has completed. public func flush(completion: (() -> Void)? = nil) { // only flush if we're enabled. guard enabled == true else { return } @@ -231,9 +234,7 @@ extension Analytics { apply { plugin in completionGroup.add { group in if let p = plugin as? FlushCompletion { - p.flush(group: group) { plugin in - // we don't really care about the plugin value .. yet. - } + p.flush(group: group) } else if let p = plugin as? EventPlugin { group.enter() p.flush() @@ -247,64 +248,6 @@ extension Analytics { } } - /// Tells this instance of Analytics to flush any queued events up to Segment.com. This command will also - /// be sent to each plugin present in the system. A completion handler can be optionally given and will be - /// called when flush has completed. - public func flush2(completion: (() -> Void)? = nil) { - // only flush if we're enabled. - guard enabled == true else { return } - - let flushGroup = DispatchGroup() - // gotta call enter at least once before we ask to be notified. - flushGroup.enter() - - apply { plugin in - // we want to enter as soon as possible. waiting to do it from - // another queue just takes too long. - operatingMode.run(queue: configuration.values.flushQueue) { - if let p = plugin as? FlushCompletion { - // flush handles the groups enter/leave calls - p.flush(group: flushGroup) { plugin in - // we don't really care about the plugin value .. yet. - } - } else if let p = plugin as? EventPlugin { - flushGroup.enter() - // we have no idea if this will be async or not, assume it's sync. - p.flush() - flushGroup.leave() - } - } - } - - flushGroup.leave() // matches our initial enter(). - - // if we ARE in sync mode, we need to wait on the group. - // This effectively ends up being a `sync` operation. - if operatingMode == .synchronous { - flushGroup.wait() - // we need to call completion on our own since - // we skipped setting up notify. we don't need to do it on - // .main since we are in synchronous mode. - if let completion { completion() } - } else if operatingMode == .asynchronous { - // if we're not, flip over to our serial queue, tell it to wait on the flush - // group to complete if we have a completion to hit. Otherwise, no need to - // wait on completion. - if let completion { - // NOTE: DispatchGroup's `notify` method on linux ended up getting called - // before the tasks have actually completed, so we went with this instead. - OperatingMode.defaultQueue.async { [weak self] in - let timedOut = flushGroup.wait(timeout: .now() + 15 /*seconds*/) - if timedOut == .timedOut { - self?.log(message: "flush(completion:) timed out waiting for completion.") - } - completion() - //DispatchQueue.main.async { completion() } - } - } - } - } - /// Resets this instance of Analytics to a clean slate. Traits, UserID's, anonymousId, etc are all cleared or reset. This /// command will also be sent to each plugin present in the system. public func reset() { diff --git a/Sources/Segment/Plugins.swift b/Sources/Segment/Plugins.swift index f305896..19705fb 100644 --- a/Sources/Segment/Plugins.swift +++ b/Sources/Segment/Plugins.swift @@ -63,7 +63,7 @@ public protocol VersionedPlugin { } public protocol FlushCompletion { - func flush(group: DispatchGroup, completion: @escaping (DestinationPlugin) -> Void) + func flush(group: DispatchGroup) } // For internal platform-specific bits diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index 96d9f24..5647532 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -123,16 +123,15 @@ public class SegmentDestination: DestinationPlugin, Subscriber, FlushCompletion // unused .. see flush(group:completion:) } - public func flush(group: DispatchGroup, completion: @escaping (DestinationPlugin) -> Void) { + public func flush(group: DispatchGroup) { + group.enter() + defer { group.leave() } + guard let storage = self.storage else { return } guard let analytics = self.analytics else { return } // don't flush if analytics is disabled. guard analytics.enabled == true else { return } - - // enter for the high level flush, allow us time to run through any existing files.. - group.enter() - print("flush entering group") eventCount = 0 cleanupUploads() @@ -144,26 +143,19 @@ public class SegmentDestination: DestinationPlugin, Subscriber, FlushCompletion if pendingUploads == 0 { if type == .file, hasData { - flushFiles(group: group, completion: completion) + flushFiles(group: group) } else if type == .data, hasData { // we know it's a data-based transaction as opposed to file I/O - flushData(group: group, completion: completion) - } else { - // there was nothing to do ... - completion(self) + flushData(group: group) } } else { analytics.log(message: "Skipping processing; Uploads in progress.") } - - // leave for the high level flush - print("flush leaving group") - group.leave() } } extension SegmentDestination { - private func flushFiles(group: DispatchGroup, completion: @escaping (DestinationPlugin) -> Void) { + private func flushFiles(group: DispatchGroup) { guard let storage = self.storage else { return } guard let analytics = self.analytics else { return } guard let httpClient = self.httpClient else { return } @@ -173,11 +165,13 @@ extension SegmentDestination { for url in files { // enter for this url we're going to kick off group.enter() - print("flushFiles entered group \(url)") analytics.log(message: "Processing Batch:\n\(url.lastPathComponent)") // set up the task let uploadTask = httpClient.startBatchUpload(writeKey: analytics.configuration.values.writeKey, batch: url) { [weak self] result in + defer { + group.leave() + } guard let self else { return } switch result { case .success(_): @@ -198,11 +192,6 @@ extension SegmentDestination { // make sure it gets removed and it's cleanup() called rather // than waiting on the next flush to come around. cleanupUploads() - // call the completion - completion(self) - // leave for the url we kicked off. - print("flushFiles leaving group \(url)") - group.leave() } // we have a legit upload in progress now, so add it to our list. @@ -212,7 +201,7 @@ extension SegmentDestination { } } - private func flushData(group: DispatchGroup, completion: @escaping (DestinationPlugin) -> Void) { + private func flushData(group: DispatchGroup) { // DO NOT CALL THIS FROM THE MAIN THREAD, IT BLOCKS! // Don't make me add a check here; i'll be sad you didn't follow directions. guard let storage = self.storage else { return } @@ -243,6 +232,12 @@ extension SegmentDestination { // set up the task let uploadTask = httpClient.startBatchUpload(writeKey: analytics.configuration.values.writeKey, data: data) { [weak self] result in + defer { + // leave for the url we kicked off. + group.leave() + semaphore.signal() + } + guard let self else { return } switch result { case .success(_): @@ -263,11 +258,6 @@ extension SegmentDestination { // make sure it gets removed and it's cleanup() called rather // than waiting on the next flush to come around. cleanupUploads() - // call the completion - completion(self) - // leave for the url we kicked off. - group.leave() - semaphore.signal() } // we have a legit upload in progress now, so add it to our list. diff --git a/Tests/Segment-Tests/Analytics_Tests.swift b/Tests/Segment-Tests/Analytics_Tests.swift index 0241aee..eb4f6df 100644 --- a/Tests/Segment-Tests/Analytics_Tests.swift +++ b/Tests/Segment-Tests/Analytics_Tests.swift @@ -754,16 +754,6 @@ final class Analytics_Tests: XCTestCase { .flushAt(9999) .operatingMode(.asynchronous)) - // set the httpclient to use our blocker session - let segment = analytics.find(pluginType: SegmentDestination.self) - let configuration = URLSessionConfiguration.ephemeral - configuration.protocolClasses = [BlockNetworkCalls.self] - configuration.httpAdditionalHeaders = ["Content-Type": "application/json; charset=utf-8", - "Authorization": "Basic test", - "User-Agent": "analytics-ios/\(Analytics.version())"] - let blockSession = URLSession(configuration: configuration, delegate: nil, delegateQueue: nil) - segment?.httpClient?.session = blockSession - waitUntilStarted(analytics: analytics) analytics.storage.hardReset(doYouKnowHowToUseThis: true) @@ -790,16 +780,6 @@ final class Analytics_Tests: XCTestCase { .flushAt(9999) .operatingMode(.synchronous)) - // set the httpclient to use our blocker session - let segment = analytics.find(pluginType: SegmentDestination.self) - let configuration = URLSessionConfiguration.ephemeral - configuration.protocolClasses = [BlockNetworkCalls.self] - configuration.httpAdditionalHeaders = ["Content-Type": "application/json; charset=utf-8", - "Authorization": "Basic test", - "User-Agent": "analytics-ios/\(Analytics.version())"] - let blockSession = URLSession(configuration: configuration, delegate: nil, delegateQueue: nil) - segment?.httpClient?.session = blockSession - waitUntilStarted(analytics: analytics) analytics.storage.hardReset(doYouKnowHowToUseThis: true) From b22b1d3d5e05a0ab99571e6b647405a0fd13682f Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Wed, 17 Apr 2024 12:32:58 -0700 Subject: [PATCH 04/12] Catching places where groups/completions/semaphores might not get hit. --- Sources/Segment/Analytics.swift | 2 +- .../Segment/Plugins/SegmentDestination.swift | 17 +++++++++++++++++ Sources/Segment/Utilities/CompletionGroup.swift | 5 ----- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index a1aab58..85dd400 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -228,7 +228,7 @@ extension Analytics { /// called when flush has completed. public func flush(completion: (() -> Void)? = nil) { // only flush if we're enabled. - guard enabled == true else { return } + guard enabled == true else { completion?(); return } let completionGroup = CompletionGroup(queue: configuration.values.flushQueue) apply { plugin in diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index 5647532..c4c85cf 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -167,6 +167,16 @@ extension SegmentDestination { group.enter() analytics.log(message: "Processing Batch:\n\(url.lastPathComponent)") + /*#if DEBUG + if isUnitTesting { + storage.remove(data: [url]) + analytics.log(message: "Processed: \(url.lastPathComponent)") + cleanupUploads() + group.leave() + continue + } + #endif*/ + // set up the task let uploadTask = httpClient.startBatchUpload(writeKey: analytics.configuration.values.writeKey, batch: url) { [weak self] result in defer { @@ -197,6 +207,9 @@ extension SegmentDestination { // we have a legit upload in progress now, so add it to our list. if let upload = uploadTask { add(uploadTask: UploadTaskInfo(url: url, data: nil, task: upload)) + } else { + // we couldn't get a task, so we need to leave the group or things will hang. + group.leave() } } } @@ -263,6 +276,10 @@ extension SegmentDestination { // we have a legit upload in progress now, so add it to our list. if let upload = uploadTask { add(uploadTask: UploadTaskInfo(url: nil, data: data, task: upload)) + } else { + // we couldn't get a task, so we need to leave the group or things will hang. + group.leave() + semaphore.signal() } _ = semaphore.wait(timeout: .distantFuture) diff --git a/Sources/Segment/Utilities/CompletionGroup.swift b/Sources/Segment/Utilities/CompletionGroup.swift index cbe1544..e240787 100644 --- a/Sources/Segment/Utilities/CompletionGroup.swift +++ b/Sources/Segment/Utilities/CompletionGroup.swift @@ -51,9 +51,4 @@ class CompletionGroup { } } } - - /*func runAndWait(completion: @escaping () -> Void) { - run(completion: completion) - group.wait() - }*/ } From 6b302de2a50cd4bcef137f28571e5b386a9d93ba Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Wed, 17 Apr 2024 12:48:27 -0700 Subject: [PATCH 05/12] another test --- Tests/Segment-Tests/Analytics_Tests.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/Segment-Tests/Analytics_Tests.swift b/Tests/Segment-Tests/Analytics_Tests.swift index eb4f6df..728194e 100644 --- a/Tests/Segment-Tests/Analytics_Tests.swift +++ b/Tests/Segment-Tests/Analytics_Tests.swift @@ -762,6 +762,9 @@ final class Analytics_Tests: XCTestCase { // put an event in the pipe ... analytics.track(name: "completion test1") + + RunLoop.main.run(until: .distantPast) + // flush it, that'll get us an upload going analytics.flush { // verify completion is called. From d90acb58b3281c514e3e353dff1c614965307711 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Wed, 17 Apr 2024 12:52:25 -0700 Subject: [PATCH 06/12] another CI test --- Sources/Segment/Analytics.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 85dd400..173112d 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -234,7 +234,7 @@ extension Analytics { apply { plugin in completionGroup.add { group in if let p = plugin as? FlushCompletion { - p.flush(group: group) + //p.flush(group: group) } else if let p = plugin as? EventPlugin { group.enter() p.flush() From 9f452c3d9d672a4e1e019ddaa0389fbeabcfdedb Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Wed, 17 Apr 2024 12:58:20 -0700 Subject: [PATCH 07/12] testing --- Sources/Segment/Analytics.swift | 4 +++- Tests/Segment-Tests/Analytics_Tests.swift | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 173112d..7922531 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -234,10 +234,12 @@ extension Analytics { apply { plugin in completionGroup.add { group in if let p = plugin as? FlushCompletion { + print("flushingCompletion \(plugin.self)") //p.flush(group: group) } else if let p = plugin as? EventPlugin { group.enter() - p.flush() + print("flushing \(plugin.self)") + //p.flush() group.leave() } } diff --git a/Tests/Segment-Tests/Analytics_Tests.swift b/Tests/Segment-Tests/Analytics_Tests.swift index 728194e..017c237 100644 --- a/Tests/Segment-Tests/Analytics_Tests.swift +++ b/Tests/Segment-Tests/Analytics_Tests.swift @@ -773,7 +773,7 @@ final class Analytics_Tests: XCTestCase { wait(for: [expectation], timeout: 1) - XCTAssertNil(analytics.pendingUploads) + //XCTAssertNil(analytics.pendingUploads) } func testSyncOperatingMode() throws { From cc86075f94f7ea14ecb097f7ae57abd2b216db53 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Wed, 17 Apr 2024 13:03:12 -0700 Subject: [PATCH 08/12] Another test --- Sources/Segment/Analytics.swift | 6 ++---- Sources/Segment/Plugins/SegmentDestination.swift | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 7922531..85dd400 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -234,12 +234,10 @@ extension Analytics { apply { plugin in completionGroup.add { group in if let p = plugin as? FlushCompletion { - print("flushingCompletion \(plugin.self)") - //p.flush(group: group) + p.flush(group: group) } else if let p = plugin as? EventPlugin { group.enter() - print("flushing \(plugin.self)") - //p.flush() + p.flush() group.leave() } } diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index c4c85cf..53ded8a 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -167,7 +167,7 @@ extension SegmentDestination { group.enter() analytics.log(message: "Processing Batch:\n\(url.lastPathComponent)") - /*#if DEBUG + #if DEBUG if isUnitTesting { storage.remove(data: [url]) analytics.log(message: "Processed: \(url.lastPathComponent)") @@ -175,7 +175,7 @@ extension SegmentDestination { group.leave() continue } - #endif*/ + #endif // set up the task let uploadTask = httpClient.startBatchUpload(writeKey: analytics.configuration.values.writeKey, batch: url) { [weak self] result in From 6d085553525ae616209ef7682d722be7e9f355d5 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Wed, 17 Apr 2024 13:10:14 -0700 Subject: [PATCH 09/12] another one... --- Sources/Segment/Plugins/SegmentDestination.swift | 4 ++-- Sources/Segment/Utilities/HTTPClient.swift | 1 + Tests/Segment-Tests/Analytics_Tests.swift | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index 53ded8a..c4c85cf 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -167,7 +167,7 @@ extension SegmentDestination { group.enter() analytics.log(message: "Processing Batch:\n\(url.lastPathComponent)") - #if DEBUG + /*#if DEBUG if isUnitTesting { storage.remove(data: [url]) analytics.log(message: "Processed: \(url.lastPathComponent)") @@ -175,7 +175,7 @@ extension SegmentDestination { group.leave() continue } - #endif + #endif*/ // set up the task let uploadTask = httpClient.startBatchUpload(writeKey: analytics.configuration.values.writeKey, batch: url) { [weak self] result in diff --git a/Sources/Segment/Utilities/HTTPClient.swift b/Sources/Segment/Utilities/HTTPClient.swift index c6e01fb..0fa4f0a 100644 --- a/Sources/Segment/Utilities/HTTPClient.swift +++ b/Sources/Segment/Utilities/HTTPClient.swift @@ -62,6 +62,7 @@ public class HTTPClient { let urlRequest = configuredRequest(for: uploadURL, method: "POST") let dataTask = session.uploadTask(with: urlRequest, fromFile: batch) { [weak self] (data, response, error) in + if self == nil { print("UPLOAD TASK SELF IS FREAKIN NIL!!!") } guard let self else { return } handleResponse(data: data, response: response, error: error, completion: completion) } diff --git a/Tests/Segment-Tests/Analytics_Tests.swift b/Tests/Segment-Tests/Analytics_Tests.swift index 017c237..493ff0d 100644 --- a/Tests/Segment-Tests/Analytics_Tests.swift +++ b/Tests/Segment-Tests/Analytics_Tests.swift @@ -771,9 +771,9 @@ final class Analytics_Tests: XCTestCase { expectation.fulfill() } - wait(for: [expectation], timeout: 1) + wait(for: [expectation]) - //XCTAssertNil(analytics.pendingUploads) + XCTAssertNil(analytics.pendingUploads) } func testSyncOperatingMode() throws { From 5c8a966e40643172495b306a3735b1e0d978fa44 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Thu, 18 Apr 2024 09:05:48 -0700 Subject: [PATCH 10/12] Fixed linux tests --- Tests/LinuxMain.swift | 7 ------- Tests/Segment-Tests/Analytics_Tests.swift | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) delete mode 100644 Tests/LinuxMain.swift diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift deleted file mode 100644 index b56db81..0000000 --- a/Tests/LinuxMain.swift +++ /dev/null @@ -1,7 +0,0 @@ -import XCTest - -import Segment_Tests - -var tests = [XCTestCaseEntry]() -tests += Segment_SwiftTests.allTests() -XCTMain(tests) diff --git a/Tests/Segment-Tests/Analytics_Tests.swift b/Tests/Segment-Tests/Analytics_Tests.swift index 493ff0d..a7cba46 100644 --- a/Tests/Segment-Tests/Analytics_Tests.swift +++ b/Tests/Segment-Tests/Analytics_Tests.swift @@ -771,7 +771,7 @@ final class Analytics_Tests: XCTestCase { expectation.fulfill() } - wait(for: [expectation]) + wait(for: [expectation], timeout: 10) XCTAssertNil(analytics.pendingUploads) } @@ -796,7 +796,7 @@ final class Analytics_Tests: XCTestCase { expectation.fulfill() } - wait(for: [expectation], timeout: 1) + wait(for: [expectation], timeout: 10) XCTAssertNil(analytics.pendingUploads) From f33a0b95ae7918281279751d9e01f600fa368bb6 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Thu, 18 Apr 2024 09:15:44 -0700 Subject: [PATCH 11/12] Removed debug line; Added fix for long-running ios task. --- .github/workflows/swift.yml | 5 +++++ Sources/Segment/Utilities/HTTPClient.swift | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 7a4606a..cded69c 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -51,6 +51,11 @@ jobs: needs: cancel_previous runs-on: macos-14 steps: + - name: Install yeetd + run: | + wget https://github.com/biscuitehh/yeetd/releases/download/1.0/yeetd-normal.pkg + sudo installer -pkg yeetd-normal.pkg -target / + yeetd & - uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: "15.2" diff --git a/Sources/Segment/Utilities/HTTPClient.swift b/Sources/Segment/Utilities/HTTPClient.swift index 0fa4f0a..c6e01fb 100644 --- a/Sources/Segment/Utilities/HTTPClient.swift +++ b/Sources/Segment/Utilities/HTTPClient.swift @@ -62,7 +62,6 @@ public class HTTPClient { let urlRequest = configuredRequest(for: uploadURL, method: "POST") let dataTask = session.uploadTask(with: urlRequest, fromFile: batch) { [weak self] (data, response, error) in - if self == nil { print("UPLOAD TASK SELF IS FREAKIN NIL!!!") } guard let self else { return } handleResponse(data: data, response: response, error: error, completion: completion) } From 43e96da8c00360ed3c34035a1246a25adbd822c7 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Thu, 18 Apr 2024 09:34:02 -0700 Subject: [PATCH 12/12] Removed test code. --- Sources/Segment/Plugins/SegmentDestination.swift | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index c4c85cf..824b18d 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -167,16 +167,6 @@ extension SegmentDestination { group.enter() analytics.log(message: "Processing Batch:\n\(url.lastPathComponent)") - /*#if DEBUG - if isUnitTesting { - storage.remove(data: [url]) - analytics.log(message: "Processed: \(url.lastPathComponent)") - cleanupUploads() - group.leave() - continue - } - #endif*/ - // set up the task let uploadTask = httpClient.startBatchUpload(writeKey: analytics.configuration.values.writeKey, batch: url) { [weak self] result in defer {