Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ let package = Package(
),
.testTarget(
name: "UID2PrebidTests",
dependencies: ["UID2Prebid"]
dependencies: ["UID2Prebid", "TestHelpers"]
),
.target(
name: "TestHelpers",
Expand Down
3 changes: 3 additions & 0 deletions Sources/UID2/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ struct Environment: Hashable, Sendable {
/// API base URL
let endpoint: URL
let isProduction: Bool
let isEuid: Bool
}

extension Environment {
init(_ environment: UID2.Environment) {
endpoint = environment.endpoint
isProduction = (environment == .production)
isEuid = false
}

init(_ environment: EUID.Environment) {
endpoint = environment.endpoint
isProduction = (environment == .production)
isEuid = true
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/UID2/UID2Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Foundation
@available(iOS 13, tvOS 13, *)
internal final class UID2Client: Sendable {
private let clientVersion: String
private let environment: Environment
internal let environment: Environment
private let session: NetworkSession
private let log: OSLog
private var baseURL: URL { environment.endpoint }
Expand Down
8 changes: 6 additions & 2 deletions Sources/UID2/UID2Manager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ public final actor UID2Manager {

private let dateGenerator: DateGenerator

/// Returns `true` if this Manager is configured for the EUID environment. See also ``EUIDManager``.
public let isEuidEnvironment: Bool

// MARK: - Defaults

init(
Expand All @@ -118,7 +121,7 @@ public final actor UID2Manager {
if let apiUrlOverride = Bundle.main.object(forInfoDictionaryKey: "UID2ApiUrl") as? String,
!apiUrlOverride.isEmpty,
let apiUrl = URL(string: apiUrlOverride) {
clientEnvironment = Environment(endpoint: apiUrl, isProduction: false)
clientEnvironment = Environment(endpoint: apiUrl, isProduction: false, isEuid: false)
} else {
clientEnvironment = environment
}
Expand Down Expand Up @@ -155,7 +158,8 @@ public final actor UID2Manager {
self.sdkVersion = sdkVersion
self.log = log
self.dateGenerator = dateGenerator

self.isEuidEnvironment = uid2Client.environment.isEuid

// Try to load from Keychain if available
// Use case for app manually stopped and re-opened
Task {
Expand Down
12 changes: 6 additions & 6 deletions Sources/UID2Prebid/UID2Prebid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public actor UID2Prebid {
// https://github.com/InteractiveAdvertisingBureau/AdCOM/blob/main/AdCOM%20v1.0%20FINAL.md#list_agenttypes
// "A person-based ID, i.e., that is the same across devices."
private let agentType: NSNumber = 3
private let source = "uidapi.com"
private var task: Task<Void, Never>?

let stateStream: () async -> AsyncStream<UID2Manager.State?>
Expand Down Expand Up @@ -60,22 +59,23 @@ public actor UID2Prebid {
Task {
await manager.addInitializationListener { [weak self] in
guard let self else { return }
await self.updateExternalUserID(initialToken())
await self.observeIdentityChanges()
let source = await manager.isEuidEnvironment ? "euid.eu" : "uidapi.com"
await self.updateExternalUserID(initialToken(), source: source)
await self.observeIdentityChanges(source: source)
}
}
}

func observeIdentityChanges() {
func observeIdentityChanges(source: String) {
self.task = Task {
let identities = await stateStream()
for await advertisingToken in identities.map({ $0?.identity?.advertisingToken }) {
await updateExternalUserID(advertisingToken)
await updateExternalUserID(advertisingToken, source: source)
}
}
}

func updateExternalUserID(_ advertisingToken: String?) async {
func updateExternalUserID(_ advertisingToken: String?, source: String) async {
var userIDs = await self.thirdPartyUserIDs()
if let advertisingToken {
userIDs.append(ExternalUserId(
Expand Down
49 changes: 49 additions & 0 deletions Tests/UID2PrebidTests/UID2PrebidTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,55 @@ final class UID2PrebidTests: XCTestCase {
)
}

@MainActor
func testObservationOfEUIDSource() async throws {
let manager = UID2Manager(
uid2Client: UID2Client(
sdkVersion: "1.0",
environment: Environment(EUID.Environment.production)
),
storage: .null,
sdkVersion: (1, 0, 0),
log: .disabled
)
let updater = TestUserIDUpdater()

let (stream, continuation) = AsyncStream<UID2Manager.State?>.makeStream()

prebid = UID2Prebid(
manager: manager,
userIDUpdater: updater,
initialToken: {
"cat"
},
stateStream: {
stream
}
)
await observation(
of: [
ExternalUserId(source: "euid.eu", uids: [.init(id: "cat", aType: 3)])
],
by: updater
)

continuation.yield(.optout)
await observation(
of: [],
by: updater
)

continuation.yield(
.established(.established(advertisingToken: "turtle"))
)
await observation(
of: [
ExternalUserId(source: "euid.eu", uids: [.init(id: "turtle", aType: 3)])
],
by: updater
)
}

@MainActor
func observation(of expectedUserIds: [ExternalUserId], by updater: TestUserIDUpdater) async {
let expectation = XCTestExpectation(description: "Expected Test Updater to observe specific value")
Expand Down
16 changes: 12 additions & 4 deletions Tests/UID2Tests/Helpers/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@
import Foundation
@testable import UID2

extension Environment {
static func test() -> Environment {
.init(
endpoint: URL(string: "https://prod.uidapi.com")!,
isProduction: true,
isEuid: false,
)
}
}

extension UID2Client {
static func test(
sdkVersion: String = "TEST",
environment: Environment = .test(),
session: any NetworkSession = URLSession.shared,
cryptoUtil: CryptoUtil = .liveValue
) -> UID2Client {
.init(
sdkVersion: sdkVersion,
environment: .init(
endpoint: URL(string: "https://prod.uidapi.com")!,
isProduction: true
),
environment: environment,
session: session,
cryptoUtil: cryptoUtil
)
Expand Down
30 changes: 30 additions & 0 deletions Tests/UID2Tests/UID2ManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,36 @@ final class UID2ManagerTests: XCTestCase {
.failure(UnexpectedRequest(request: request))
}
}

func testNonEUIDEnvironment() async {
let manager = UID2Manager(
uid2Client: UID2Client.test(),
storage: .null,
sdkVersion: (1, 0, 0),
log: .disabled
)

let isEuidEnvironment = await manager.isEuidEnvironment
XCTAssertFalse(isEuidEnvironment)
}

func testEUIDEnvironment() async {
let manager = UID2Manager(
uid2Client: UID2Client.test(
environment: .init(
endpoint: URL(string: "https://prod.euid.eu/v2")!,
isProduction: true,
isEuid: true
)
),
storage: .null,
sdkVersion: (1, 0, 0),
log: .disabled
)

let isEuidEnvironment = await manager.isEuidEnvironment
XCTAssertTrue(isEuidEnvironment)
}

func testInitialState() async throws {
let manager = UID2Manager(
Expand Down
Loading