From e8a36b8ddb92a9b915ad9fcadfacb0bfb99add27 Mon Sep 17 00:00:00 2001 From: Daniel <95646168+daniel-statsig@users.noreply.github.com> Date: Fri, 15 Dec 2023 16:02:51 -0800 Subject: [PATCH] Event Logging Override (#231) * Event Logging Override * Update StatsigOptions.swift --- Sources/Statsig/NetworkService.swift | 18 ++++-- Sources/Statsig/StatsigOptions.swift | 36 +++++++++--- Tests/StatsigTests/ApiOverrideSpec.swift | 56 +++++++++++++++++-- Tests/StatsigTests/AppLifecycleSpec.swift | 2 +- Tests/StatsigTests/CodableSpec.swift | 2 +- Tests/StatsigTests/ExposureLoggingSpec.swift | 2 +- Tests/StatsigTests/ManualFlushSpec.swift | 2 +- .../NotAwaitingInitCallsSpec.swift | 2 +- Tests/StatsigTests/PerformanceSpec.swift | 2 +- Tests/StatsigTests/StatsigSpec.swift | 4 +- Tests/StatsigTests/TestUtils.swift | 4 +- 11 files changed, 104 insertions(+), 26 deletions(-) diff --git a/Sources/Statsig/NetworkService.swift b/Sources/Statsig/NetworkService.swift index 06049dc..d9f8408 100644 --- a/Sources/Statsig/NetworkService.swift +++ b/Sources/Statsig/NetworkService.swift @@ -214,10 +214,12 @@ class NetworkService { urlComponents.host = ApiHost urlComponents.path = endpoint.rawValue - if let override = self.statsigOptions.overrideURL { - urlComponents.scheme = override.scheme - urlComponents.host = override.host - urlComponents.port = override.port + if let override = self.statsigOptions.mainApiUrl { + urlComponents.applyOverride(override) + } + + if endpoint == .logEvent, let loggingApiOverride = self.statsigOptions.logEventApiUrl { + urlComponents.applyOverride(loggingApiOverride) } guard let requestURL = urlComponents.url else { @@ -287,3 +289,11 @@ class NetworkService { } } } + +extension URLComponents { + mutating func applyOverride(_ url: URL) { + scheme = url.scheme + host = url.host + port = url.port + } +} diff --git a/Sources/Statsig/StatsigOptions.swift b/Sources/Statsig/StatsigOptions.swift index 130827b..ac0363e 100644 --- a/Sources/Statsig/StatsigOptions.swift +++ b/Sources/Statsig/StatsigOptions.swift @@ -61,11 +61,25 @@ public class StatsigOptions { public var shutdownOnBackground = true; /** - The endpoint to use for all SDK network requests. You should not need to override this (unless you have another API that implements the Statsig API endpoints) + The API to use for all SDK network requests. You should not need to override this (unless you have another API that implements the Statsig API endpoints) */ - public var api = "https://\(ApiHost)"; + public var api = "https://\(ApiHost)" { + didSet { + mainApiUrl = URL(string: api) ?? mainApiUrl + } + } + + /** + The API to use for log_event network requests. You should not need to override this (unless you have another API that implements the Statsig /v1/log_event endpoint) + */ + public var eventLoggingApi = "https://\(ApiHost)" { + didSet { + logEventApiUrl = URL(string: eventLoggingApi) ?? logEventApiUrl + } + } - internal var overrideURL: URL? + internal var mainApiUrl: URL? + internal var logEventApiUrl: URL? var environment: [String: String] = [:] public init(initTimeout: Double? = 3.0, @@ -79,7 +93,8 @@ public class StatsigOptions { disableDiagnostics: Bool? = false, disableHashing: Bool? = false, shutdownOnBackground: Bool? = true, - api: String? = nil + api: String? = nil, + eventLoggingApi: String? = nil ) { if let initTimeout = initTimeout, initTimeout >= 0 { @@ -122,10 +137,15 @@ public class StatsigOptions { self.autoValueUpdateIntervalSec = internval } - if let api = api, let url = URL(string: api) { - self.overrideURL = url - } else { - self.overrideURL = nil + + if let api = api { + self.api = api + self.mainApiUrl = URL(string: api) + } + + if let eventLoggingApi = eventLoggingApi { + self.eventLoggingApi = eventLoggingApi + self.logEventApiUrl = URL(string: eventLoggingApi) } self.overrideStableID = overrideStableID diff --git a/Tests/StatsigTests/ApiOverrideSpec.swift b/Tests/StatsigTests/ApiOverrideSpec.swift index 5bb6898..613b61c 100644 --- a/Tests/StatsigTests/ApiOverrideSpec.swift +++ b/Tests/StatsigTests/ApiOverrideSpec.swift @@ -17,7 +17,7 @@ final class ApiOverrideSpec: BaseSpec { var request: URLRequest? - describe("When Overriden") { + describe("When Main API Overridden") { func start() { let opts = StatsigOptions(api: "http://api.override.com") request = TestUtils.startWithStatusAndWait(options: opts) @@ -28,7 +28,7 @@ final class ApiOverrideSpec: BaseSpec { expect(request?.url?.absoluteString).to(equal("http://api.override.com/v1/initialize")) } - it("calls initialize on the overridden api") { + it("calls log_event on the overridden api") { start() var hitLog = false TestUtils.captureLogs(host: "api.override.com") { logs in @@ -41,7 +41,7 @@ final class ApiOverrideSpec: BaseSpec { } } - describe("When Not Overriden") { + describe("When Not Overridden") { func start() { request = TestUtils.startWithStatusAndWait() } @@ -51,7 +51,7 @@ final class ApiOverrideSpec: BaseSpec { expect(request?.url?.absoluteString).to(equal("https://api.statsig.com/v1/initialize")) } - it("calls initialize on the statsig api") { + it("calls log_event on the statsig api") { start() var hitLog = false TestUtils.captureLogs(host: "api.statsig.com") { logs in @@ -64,5 +64,53 @@ final class ApiOverrideSpec: BaseSpec { } } + describe("When Logging API Overridden") { + func start() { + let opts = StatsigOptions(eventLoggingApi: "http://api.log.co.nz/") + request = TestUtils.startWithStatusAndWait(options: opts) + } + + it("calls initialize on the statsig api") { + start() + expect(request?.url?.absoluteString).to(equal("https://api.statsig.com/v1/initialize")) + } + + it("calls log_event on the overridden api.log.co.nz api") { + start() + var hitLog = false + TestUtils.captureLogs(host: "api.log.co.nz") { logs in + hitLog = true + } + + Statsig.logEvent("test_event") + Statsig.shutdown() + expect(hitLog).toEventually(beTrue()) + } + } + + describe("When Main and Logging API Overridden") { + func start() { + let opts = StatsigOptions(api: "http://main.api", eventLoggingApi: "http://api.log.co.nz") + request = TestUtils.startWithStatusAndWait(options: opts) + } + + it("calls initialize on the overridden api") { + start() + expect(request?.url?.absoluteString).to(equal("http://main.api/v1/initialize")) + } + + it("calls log_event on the overridden api.log.co.nz api") { + start() + var hitLog = false + TestUtils.captureLogs(host: "api.log.co.nz") { logs in + hitLog = true + } + + Statsig.logEvent("test_event") + Statsig.shutdown() + expect(hitLog).toEventually(beTrue()) + } + } + } } diff --git a/Tests/StatsigTests/AppLifecycleSpec.swift b/Tests/StatsigTests/AppLifecycleSpec.swift index 3b47021..97c22ed 100644 --- a/Tests/StatsigTests/AppLifecycleSpec.swift +++ b/Tests/StatsigTests/AppLifecycleSpec.swift @@ -18,7 +18,7 @@ final class AppLifecycleSpec: BaseSpec { func startAndLog(shutdownOnBackground: Bool, tag: String) { let opts = StatsigOptions(shutdownOnBackground: shutdownOnBackground) - opts.overrideURL = URL(string: "http://AppLifecycleSpec::\(tag)") + opts.mainApiUrl = URL(string: "http://AppLifecycleSpec::\(tag)") _ = TestUtils.startWithStatusAndWait(options: opts) diff --git a/Tests/StatsigTests/CodableSpec.swift b/Tests/StatsigTests/CodableSpec.swift index 61fc0f7..29f9842 100644 --- a/Tests/StatsigTests/CodableSpec.swift +++ b/Tests/StatsigTests/CodableSpec.swift @@ -18,7 +18,7 @@ class CodableSpec: BaseSpec { describe("Codable") { let opts = StatsigOptions(disableDiagnostics: true) - opts.overrideURL = URL(string: "http://CodableSpec") + opts.mainApiUrl = URL(string: "http://CodableSpec") beforeEach { _ = TestUtils.startWithResponseAndWait([ diff --git a/Tests/StatsigTests/ExposureLoggingSpec.swift b/Tests/StatsigTests/ExposureLoggingSpec.swift index 774ecb2..39ecd6e 100644 --- a/Tests/StatsigTests/ExposureLoggingSpec.swift +++ b/Tests/StatsigTests/ExposureLoggingSpec.swift @@ -15,7 +15,7 @@ class ExposureLoggingSpec: BaseSpec { describe("ExposureLogging") { let opts = StatsigOptions(disableDiagnostics: true) - opts.overrideURL = URL(string: "http://ExposureLoggingSpec") + opts.mainApiUrl = URL(string: "http://ExposureLoggingSpec") var logs: [[String: Any]] = [] beforeEach { diff --git a/Tests/StatsigTests/ManualFlushSpec.swift b/Tests/StatsigTests/ManualFlushSpec.swift index 43f71ba..58a1c32 100644 --- a/Tests/StatsigTests/ManualFlushSpec.swift +++ b/Tests/StatsigTests/ManualFlushSpec.swift @@ -17,7 +17,7 @@ final class ManualFlushSpec: BaseSpec { it("flushes the logger") { let opts = StatsigOptions() - opts.overrideURL = URL(string: "http://ManualFlushSpec") + opts.mainApiUrl = URL(string: "http://ManualFlushSpec") _ = TestUtils.startWithResponseAndWait([:], options: opts) Statsig.logEvent("my_event") diff --git a/Tests/StatsigTests/NotAwaitingInitCallsSpec.swift b/Tests/StatsigTests/NotAwaitingInitCallsSpec.swift index b4aedab..d5efdef 100644 --- a/Tests/StatsigTests/NotAwaitingInitCallsSpec.swift +++ b/Tests/StatsigTests/NotAwaitingInitCallsSpec.swift @@ -20,7 +20,7 @@ class NotAwaitingInitCallsSpec: BaseSpec { describe("Not Awaiting Init Calls") { beforeEach { - options.overrideURL = URL(string: "http://NotAwaitingInitCallsSpec") + options.mainApiUrl = URL(string: "http://NotAwaitingInitCallsSpec") TestUtils.clearStorage() diff --git a/Tests/StatsigTests/PerformanceSpec.swift b/Tests/StatsigTests/PerformanceSpec.swift index dbebdb8..dcc232f 100644 --- a/Tests/StatsigTests/PerformanceSpec.swift +++ b/Tests/StatsigTests/PerformanceSpec.swift @@ -14,7 +14,7 @@ final class PerformanceSpec: XCTestCase { override func setUpWithError() throws { let opts = StatsigOptions(disableDiagnostics: true) - opts.overrideURL = URL(string: "http://PerformanceSpec") + opts.mainApiUrl = URL(string: "http://PerformanceSpec") _ = TestUtils.startWithResponseAndWait([ "feature_gates": [ diff --git a/Tests/StatsigTests/StatsigSpec.swift b/Tests/StatsigTests/StatsigSpec.swift index eb4a95d..ebae15e 100644 --- a/Tests/StatsigTests/StatsigSpec.swift +++ b/Tests/StatsigTests/StatsigSpec.swift @@ -96,7 +96,7 @@ class StatsigSpec: BaseSpec { autoValueUpdateIntervalSec: 0.1, disableDiagnostics: true ) - opts.overrideURL = URL(string: "http://api.statsig.enableAutoValueUpdateTest") + opts.mainApiUrl = URL(string: "http://api.statsig.enableAutoValueUpdateTest") Statsig.start(sdkKey: "client-api-key", options: opts) // first request, "lastSyncTimeForUser" field should not be present in the request body @@ -114,7 +114,7 @@ class StatsigSpec: BaseSpec { autoValueUpdateIntervalSec: 0.1, disableDiagnostics: true ) - opts.overrideURL = URL(string: "http://StatsigSpec.enableAutoValueUpdateEQtrue") + opts.mainApiUrl = URL(string: "http://StatsigSpec.enableAutoValueUpdateEQtrue") var requestExpectation = self.expectation(description: "Request Made Once") stub(condition: isHost("StatsigSpec.enableAutoValueUpdateEQtrue")) { request in diff --git a/Tests/StatsigTests/TestUtils.swift b/Tests/StatsigTests/TestUtils.swift index b75b245..5d62a54 100644 --- a/Tests/StatsigTests/TestUtils.swift +++ b/Tests/StatsigTests/TestUtils.swift @@ -51,7 +51,7 @@ class TestUtils { static func startWithResponseAndWait(_ response: [String: Any], _ key: String = "client-api-key", _ user: StatsigUser? = nil, _ statusCode: Int32 = 200, options: StatsigOptions? = nil) -> URLRequest? { var result: URLRequest? = nil - let host = options?.overrideURL?.host ?? "api.statsig.com" + let host = options?.mainApiUrl?.host ?? "api.statsig.com" let handle = stub(condition: isHost(host)) { req in result = req return HTTPStubsResponse(jsonObject: response, statusCode: statusCode, headers: nil) @@ -68,7 +68,7 @@ class TestUtils { static func startWithStatusAndWait(_ statusCode: Int32 = 200, _ key: String = "client-api-key", _ user: StatsigUser? = nil, options: StatsigOptions? = nil) -> URLRequest? { var result: URLRequest? = nil - stub(condition: isHost(options?.overrideURL?.host ?? "api.statsig.com")) { req in + stub(condition: isHost(options?.mainApiUrl?.host ?? "api.statsig.com")) { req in result = req return HTTPStubsResponse(data: Data(), statusCode: statusCode, headers: nil) }