Skip to content

Commit

Permalink
feat: client identification headers
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew committed Jan 21, 2025
1 parent 59b2127 commit 03f869c
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class UnleashClientBase {
var timer: Timer?
var poller: Poller
var metrics: Metrics
var connectionId: UUID

public init(
unleashUrl: String,
Expand All @@ -26,6 +27,7 @@ public class UnleashClientBase {
fatalError("Invalid Unleash URL: \(unleashUrl)")
}

self.connectionId = UUID()
self.timer = nil
if let poller = poller {
self.poller = poller
Expand All @@ -35,7 +37,9 @@ public class UnleashClientBase {
unleashUrl: url,
apiKey: clientKey,
customHeaders: customHeaders,
bootstrap: bootstrap
bootstrap: bootstrap,
appName: appName,
connectionId: connectionId
)
}
if let metrics = metrics {
Expand All @@ -51,7 +55,7 @@ public class UnleashClientBase {
}
task.resume()
}
self.metrics = Metrics(appName: appName, metricsInterval: Double(metricsInterval), clock: { return Date() }, disableMetrics: disableMetrics, poster: urlSessionPoster, url: url, clientKey: clientKey, customHeaders: customHeaders)
self.metrics = Metrics(appName: appName, metricsInterval: Double(metricsInterval), clock: { return Date() }, disableMetrics: disableMetrics, poster: urlSessionPoster, url: url, clientKey: clientKey, customHeaders: customHeaders, connectionId: connectionId)
}

self.context = Context(appName: appName, environment: environment)
Expand Down
8 changes: 7 additions & 1 deletion Sources/UnleashProxyClientSwift/Metrics/Metrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class Metrics {
var bucket: Bucket
let url: URL
let customHeaders: [String: String]
let connectionId: UUID

init(appName: String,
metricsInterval: TimeInterval,
Expand All @@ -21,7 +22,8 @@ public class Metrics {
poster: @escaping PosterHandler,
url: URL,
clientKey: String,
customHeaders: [String: String] = [:]) {
customHeaders: [String: String] = [:],
connectionId: UUID) {
self.appName = appName
self.metricsInterval = metricsInterval
self.clock = clock
Expand All @@ -31,6 +33,7 @@ public class Metrics {
self.clientKey = clientKey
self.bucket = Bucket(clock: clock)
self.customHeaders = customHeaders
self.connectionId = connectionId
}

func start() {
Expand Down Expand Up @@ -105,6 +108,9 @@ public class Metrics {
request.addValue("no-cache", forHTTPHeaderField: "Cache")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue(clientKey, forHTTPHeaderField: "Authorization")
request.addValue(appName, forHTTPHeaderField: "x-unleash-appname")
request.addValue(connectionId.uuidString, forHTTPHeaderField: "x-unleash-connection-id")
request.setValue("unleash-client-swift:development", forHTTPHeaderField: "x-unleash-sdk")
if !self.customHeaders.isEmpty {
for (key, value) in self.customHeaders {
request.setValue(value, forHTTPHeaderField: key)
Expand Down
13 changes: 11 additions & 2 deletions Sources/UnleashProxyClientSwift/Poller/Poller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ public class Poller {
var ready: Bool
var apiKey: String;
var etag: String;

var appName: String;
var connectionId: UUID;

private let session: PollerSession
var storageProvider: StorageProvider
let customHeaders: [String: String]
Expand All @@ -21,11 +23,15 @@ public class Poller {
session: PollerSession = URLSession.shared,
storageProvider: StorageProvider = DictionaryStorageProvider(),
customHeaders: [String: String] = [:],
bootstrap: Bootstrap = .toggles([])
bootstrap: Bootstrap = .toggles([]),
appName: String,
connectionId: UUID
) {
self.refreshInterval = refreshInterval
self.unleashUrl = unleashUrl
self.apiKey = apiKey
self.appName = appName
self.connectionId = connectionId
self.timer = nil
self.ready = false
self.etag = ""
Expand Down Expand Up @@ -102,6 +108,9 @@ public class Poller {
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(self.apiKey, forHTTPHeaderField: "Authorization")
request.setValue(self.etag, forHTTPHeaderField: "If-None-Match")
request.setValue(self.appName, forHTTPHeaderField: "x-unleash-appname")
request.setValue(self.connectionId.uuidString, forHTTPHeaderField: "x-unleash-connection-id")
request.setValue("unleash-client-swift:development", forHTTPHeaderField: "x-unleash-sdk")
if !self.customHeaders.isEmpty {
for (key, value) in self.customHeaders {
request.setValue(value, forHTTPHeaderField: key)
Expand Down
9 changes: 6 additions & 3 deletions Tests/UnleashProxyClientSwiftTests/MetricsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ final class MetricsTests: XCTestCase {
clock: fixedClock,
poster: poster,
url: URL(string: "https://unleashinstance.com")!,
clientKey: "testKey")
clientKey: "testKey",
connectionId: UUID())
metrics.start()

metrics.count(name: "testToggle", enabled: true)
Expand Down Expand Up @@ -84,7 +85,8 @@ final class MetricsTests: XCTestCase {
clock: fixedClock,
poster: poster,
url: URL(string: "https://unleashinstance.com")!,
clientKey: "testKey")
clientKey: "testKey",
connectionId: UUID())
metrics.start()

metrics.count(name: "irrelevant", enabled: true)
Expand All @@ -105,7 +107,8 @@ final class MetricsTests: XCTestCase {
disableMetrics: true,
poster: poster,
url: URL(string: "https://unleashinstance.com")!,
clientKey: "testKey")
clientKey: "testKey",
connectionId: UUID())
metrics.start()

metrics.count(name: "irrelevant", enabled: true)
Expand Down
2 changes: 1 addition & 1 deletion Tests/UnleashProxyClientSwiftTests/MockMetrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ class MockMetrics: Metrics {
let response = HTTPURLResponse(url: URL(string: "https://irrelevant.com")!, statusCode: 200, httpVersion: nil, headerFields: nil)
completionHandler(.success((Data(), response!)))
}
super.init(appName: appName, metricsInterval: Double(15), clock: { return Date() }, disableMetrics: false, poster: noOpPoster, url: URL(string: "https://irrelevant.com")!, clientKey: "irrelevant")
super.init(appName: appName, metricsInterval: Double(15), clock: { return Date() }, disableMetrics: false, poster: noOpPoster, url: URL(string: "https://irrelevant.com")!, clientKey: "irrelevant", connectionId: UUID())
}
}
4 changes: 2 additions & 2 deletions Tests/UnleashProxyClientSwiftTests/MockPoller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ class MockPoller: Poller {
var dataGenerator: () -> [String: Toggle];
var stubCompletionError: PollerError?

init(callback: @escaping () -> [String: Toggle], unleashUrl: URL, apiKey: String, session: PollerSession) {
init(callback: @escaping () -> [String: Toggle], unleashUrl: URL, apiKey: String, session: PollerSession, appName: String, connectionId: UUID) {
self.dataGenerator = callback
super.init(refreshInterval: 15, unleashUrl: unleashUrl, apiKey: apiKey, session: session)
super.init(refreshInterval: 15, unleashUrl: unleashUrl, apiKey: apiKey, session: session, appName: appName, connectionId: connectionId)
}

override func getFeatures(context: Context, completionHandler: ((PollerError?) -> Void)? = nil) -> Void {
Expand Down
11 changes: 9 additions & 2 deletions Tests/UnleashProxyClientSwiftTests/PollerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ final class PollerTests: XCTestCase {

private let unleashUrl = URL(string: "https://app.unleash-hosted.com/hosted/api/proxy")!
private let apiKey = "SECRET"
private let appName = "APPNAME"
private let connectionId = UUID(uuidString: "123E4567-E89B-12d3-A456-426614174000")!
private let timeout = 1.0

func testWhenInitWithBootstrapTogglesThenAddToStore() {
Expand Down Expand Up @@ -190,13 +192,16 @@ final class PollerTests: XCTestCase {
let response = mockResponse()
let data = stubData()
let session = MockPollerSession(data: data, response: response)
let poller = Poller(refreshInterval: nil, unleashUrl: unleashUrl, apiKey: apiKey, session: session, customHeaders: customHeaders)
let poller = Poller(refreshInterval: nil, unleashUrl: unleashUrl, apiKey: apiKey, session: session, customHeaders: customHeaders, appName: appName, connectionId: connectionId)

let expectation = XCTestExpectation(description: "Expect custom headers to be set in the request.")

session.performRequestHandler = { request in
XCTAssertEqual(request.value(forHTTPHeaderField: "X-Custom-Header"), "CustomValue")
XCTAssertEqual(request.value(forHTTPHeaderField: "X-Another-Header"), "AnotherValue")
XCTAssertEqual(request.value(forHTTPHeaderField: "x-unleash-appname"), "APPNAME")
XCTAssertEqual(request.value(forHTTPHeaderField: "x-unleash-connection-id"), "123E4567-E89B-12D3-A456-426614174000")
XCTAssertEqual(request.value(forHTTPHeaderField: "x-unleash-sdk"), "unleash-client-swift:development")
expectation.fulfill()
}

Expand Down Expand Up @@ -240,7 +245,9 @@ final class PollerTests: XCTestCase {
unleashUrl: url ?? unleashUrl,
apiKey: apiKey,
session: session,
bootstrap: bootstrap
bootstrap: bootstrap,
appName: appName,
connectionId: connectionId
)
}

Expand Down
12 changes: 9 additions & 3 deletions Tests/UnleashProxyClientSwiftTests/testUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ func setup(
callback: dataGenerator,
unleashUrl: URL(string: "https://app.unleash-hosted.com/hosted/api/proxy")!,
apiKey: "SECRET",
session: session
session: session,
appName: "APPNAME",
connectionId: UUID()
)
let metrics = MockMetrics(appName: "test")

Expand Down Expand Up @@ -80,7 +82,9 @@ func setup(
callback: dataGenerator,
unleashUrl: URL(string: "https://app.unleash-hosted.com/hosted/api/proxy")!,
apiKey: "SECRET",
session: session
session: session,
appName: "APPNAME",
connectionId: UUID()
)
let metrics = MockMetrics(appName: "test")

Expand All @@ -107,7 +111,9 @@ func setupBase(
callback: dataGenerator,
unleashUrl: URL(string: "https://app.unleash-hosted.com/hosted/api/proxy")!,
apiKey: "SECRET",
session: session
session: session,
appName: "APPNAME",
connectionId: UUID()
)
let metrics = MockMetrics(appName: "test")

Expand Down

0 comments on commit 03f869c

Please sign in to comment.