Skip to content

Commit 35b6ec8

Browse files
authored
fix: add check to drop events that return a 400 response from Segment (#296)
* fix: add check to drop events that return a 400 response from Segment * add test * add fix for linux in test * fix tests * remove redundant log
1 parent 28ab076 commit 35b6ec8

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

Sources/Segment/Plugins/SegmentDestination.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ public class SegmentDestination: DestinationPlugin, Subscriber, FlushCompletion
146146
case .success(_):
147147
storage.remove(file: url)
148148
self.cleanupUploads()
149+
150+
// we don't want to retry events in a given batch when a 400
151+
// response for malformed JSON is returned
152+
case .failure(Segment.HTTPClientErrors.statusCode(code: 400)):
153+
storage.remove(file: url)
154+
self.cleanupUploads()
149155
default:
150156
break
151157
}

Tests/Segment-Tests/Analytics_Tests.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,4 +865,56 @@ final class Analytics_Tests: XCTestCase {
865865
let d: Double? = trackEvent?.properties?.value(forKeyPath: "TestNaN")
866866
XCTAssertNil(d)
867867
}
868+
869+
// Linux doesn't know what URLProtocol is and on watchOS it somehow works differently and isn't hit.
870+
#if !os(Linux) && !os(watchOS)
871+
func testFailedSegmentResponse() throws {
872+
//register our network blocker (returns 400 response)
873+
guard URLProtocol.registerClass(FailedNetworkCalls.self) else {
874+
XCTFail(); return }
875+
876+
let analytics = Analytics(configuration: Configuration(writeKey: "networkTest"))
877+
878+
waitUntilStarted(analytics: analytics)
879+
880+
//set the httpClient to use our blocker session
881+
let segment = analytics.find(pluginType: SegmentDestination.self)
882+
let configuration = URLSessionConfiguration.ephemeral
883+
configuration.allowsCellularAccess = true
884+
configuration.timeoutIntervalForRequest = 30
885+
configuration.timeoutIntervalForRequest = 60
886+
configuration.httpMaximumConnectionsPerHost = 2
887+
configuration.protocolClasses = [FailedNetworkCalls.self]
888+
configuration.httpAdditionalHeaders = [
889+
"Content-Type": "application/json; charset=utf-8",
890+
"Authorization": "Basic test",
891+
"User-Agent": "analytics-ios/\(Analytics.version())"
892+
]
893+
894+
let blockSession = URLSession(configuration: configuration, delegate: nil, delegateQueue: nil)
895+
896+
segment?.httpClient?.session = blockSession
897+
898+
analytics.track(name: "test track", properties: ["Malformed Paylod": "My Failed Prop"])
899+
900+
//get fileUrl from track call
901+
let storedEvents: [URL]? = analytics.storage.read(.events)
902+
let fileURL = storedEvents![0]
903+
904+
905+
let expectation = XCTestExpectation()
906+
907+
analytics.flush {
908+
expectation.fulfill()
909+
}
910+
911+
wait(for: [expectation], timeout: 1.0)
912+
913+
let newStoredEvents: [URL]? = analytics.storage.read(.events)
914+
915+
XCTAssert(!(newStoredEvents?.contains(fileURL))!)
916+
917+
XCTAssertFalse(FileManager.default.fileExists(atPath: fileURL.path))
918+
}
919+
#endif
868920
}

Tests/Segment-Tests/Support/TestUtilities.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,27 @@ class BlockNetworkCalls: URLProtocol {
179179
}
180180
}
181181

182+
class FailedNetworkCalls: URLProtocol {
183+
var initialURL: URL? = nil
184+
override class func canInit(with request: URLRequest) -> Bool {
185+
186+
return true
187+
}
188+
189+
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
190+
return request
191+
}
192+
193+
override var cachedResponse: CachedURLResponse? { return nil }
194+
195+
override func startLoading() {
196+
client?.urlProtocol(self, didReceive: HTTPURLResponse(url: URL(string: "http://api.segment.com")!, statusCode: 400, httpVersion: nil, headerFields: ["blocked": "true"])!, cacheStoragePolicy: .notAllowed)
197+
client?.urlProtocolDidFinishLoading(self)
198+
}
199+
200+
override func stopLoading() {
201+
202+
}
203+
}
204+
182205
#endif

0 commit comments

Comments
 (0)