Skip to content

Commit 569344f

Browse files
authored
Always include traits in event payload, even if empty. (#384)
* Traits can no longer be nil. Pass empty object if no traits desired. * Remove linux/windows tests. * Attempt to fix Apple TV test runner. * Update test runners. * fix watchOS test runner
1 parent 59ae167 commit 569344f

File tree

6 files changed

+38
-77
lines changed

6 files changed

+38
-77
lines changed

.github/workflows/swift.yml

+16-50
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ jobs:
1616

1717
generate_code_coverage:
1818
needs: cancel_previous
19-
runs-on: macos-14
19+
runs-on: macos-15
2020
steps:
2121
- uses: maxim-lobanov/setup-xcode@v1
2222
with:
23-
xcode-version: "15.2"
23+
xcode-version: "16.2"
2424
- uses: actions/checkout@v2
2525
- uses: webfactory/[email protected]
2626
with:
@@ -37,55 +37,21 @@ jobs:
3737

3838
build_and_test_spm_mac:
3939
needs: cancel_previous
40-
runs-on: macos-14
40+
runs-on: macos-15
4141
steps:
4242
- uses: maxim-lobanov/setup-xcode@v1
4343
with:
44-
xcode-version: "15.2"
44+
xcode-version: "16.2"
4545
- uses: actions/checkout@v2
4646
- uses: webfactory/[email protected]
4747
with:
4848
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
4949
- name: Build & Run tests
5050
run: swift test
5151

52-
build_and_test_spm_linux:
53-
needs: cancel_previous
54-
runs-on: ubuntu-latest
55-
steps:
56-
- uses: sersoft-gmbh/swifty-linux-action@v3
57-
with:
58-
release-version: "5.9.2"
59-
github-token: ${{secrets.GITHUB_TOKEN}}
60-
- uses: actions/checkout@v2
61-
- uses: webfactory/[email protected]
62-
with:
63-
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
64-
- name: Build & Run tests
65-
run: swift test --enable-test-discovery
66-
67-
build_and_test_spm_windows:
68-
needs: cancel_previous
69-
runs-on: windows-latest
70-
steps:
71-
- uses: SwiftyLab/setup-swift@latest
72-
with:
73-
swift-version: "5.10"
74-
- uses: actions/checkout@v2
75-
- name: Build
76-
run: swift build
77-
#
78-
# Disable tests right now. There's an SPM issue where link errors generate
79-
# a bad exit code even though the tests run/work properly.
80-
#
81-
# See: https://forums.swift.org/t/linker-warnings-on-windows-with-swift-argument-parser/71443/2
82-
#
83-
# - name: Run tests
84-
# run: swift test --enable-test-discovery
85-
8652
build_and_test_ios:
8753
needs: cancel_previous
88-
runs-on: macos-14
54+
runs-on: macos-15
8955
steps:
9056
- name: Install yeetd
9157
run: |
@@ -94,20 +60,20 @@ jobs:
9460
yeetd &
9561
- uses: maxim-lobanov/setup-xcode@v1
9662
with:
97-
xcode-version: "15.2"
63+
xcode-version: "16.2"
9864
- uses: actions/checkout@v2
9965
- uses: webfactory/[email protected]
10066
with:
10167
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
102-
- run: xcodebuild -scheme Segment test -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15'
68+
- run: xcodebuild -scheme Segment test -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 16'
10369

10470
build_and_test_tvos:
10571
needs: cancel_previous
106-
runs-on: macos-14
72+
runs-on: macos-15
10773
steps:
10874
- uses: maxim-lobanov/setup-xcode@v1
10975
with:
110-
xcode-version: "15.2"
76+
xcode-version: "16.2"
11177
- uses: actions/checkout@v2
11278
- uses: webfactory/[email protected]
11379
with:
@@ -116,24 +82,24 @@ jobs:
11682

11783
build_and_test_watchos:
11884
needs: cancel_previous
119-
runs-on: macos-14
85+
runs-on: macos-15
12086
steps:
12187
- uses: maxim-lobanov/setup-xcode@v1
12288
with:
123-
xcode-version: "15.2"
89+
xcode-version: "16.2"
12490
- uses: actions/checkout@v2
12591
- uses: webfactory/[email protected]
12692
with:
12793
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
128-
- run: xcodebuild -scheme Segment test -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch Series 9 (45mm)'
94+
- run: xcodebuild -scheme Segment test -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch Series 10 (42mm)'
12995

13096
build_and_test_visionos:
13197
needs: cancel_previous
132-
runs-on: macos-14
98+
runs-on: macos-15
13399
steps:
134100
- uses: maxim-lobanov/setup-xcode@v1
135101
with:
136-
xcode-version: "15.2"
102+
xcode-version: "16.2"
137103
- uses: actions/checkout@v2
138104
- uses: webfactory/[email protected]
139105
with:
@@ -146,11 +112,11 @@ jobs:
146112

147113
build_and_test_examples:
148114
needs: cancel_previous
149-
runs-on: macos-14
115+
runs-on: macos-15
150116
steps:
151117
- uses: maxim-lobanov/setup-xcode@v1
152118
with:
153-
xcode-version: "15.2"
119+
xcode-version: "16.2"
154120
- uses: actions/checkout@v2
155121
- uses: webfactory/[email protected]
156122
with:

Package.resolved

-18
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
11
{
22
"pins" : [
3-
{
4-
"identity" : "analytics-swift-mixpanel",
5-
"kind" : "remoteSourceControl",
6-
"location" : "https://github.com/segment-integrations/analytics-swift-mixpanel",
7-
"state" : {
8-
"revision" : "bc6a9628af225e679a581cc9ac2316eaf42f23a8",
9-
"version" : "1.1.7"
10-
}
11-
},
123
{
134
"identity" : "jsonsafeencoding-swift",
145
"kind" : "remoteSourceControl",
@@ -18,15 +9,6 @@
189
"version" : "2.0.0"
1910
}
2011
},
21-
{
22-
"identity" : "mixpanel-swift",
23-
"kind" : "remoteSourceControl",
24-
"location" : "https://github.com/mixpanel/mixpanel-swift",
25-
"state" : {
26-
"revision" : "48d6668ceaaefc338f94e2b084c3cf77b90182f8",
27-
"version" : "4.3.0"
28-
}
29-
},
3012
{
3113
"identity" : "sovran-swift",
3214
"kind" : "remoteSourceControl",

Sources/Segment/Analytics.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -241,15 +241,15 @@ extension Analytics {
241241
/// Returns the traits that were specified in the last identify call.
242242
public func traits<T: Codable>() -> T? {
243243
if let userInfo: UserInfo = store.currentState() {
244-
return userInfo.traits?.codableValue()
244+
return userInfo.traits.codableValue()
245245
}
246246
return nil
247247
}
248248

249249
/// Returns the traits that were specified in the last identify call, as a dictionary.
250250
public func traits() -> [String: Any]? {
251251
if let userInfo: UserInfo = store.currentState() {
252-
return userInfo.traits?.dictionaryValue
252+
return userInfo.traits.dictionaryValue
253253
}
254254
return nil
255255
}

Sources/Segment/State.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ struct System: State {
108108
struct UserInfo: Codable, State {
109109
let anonymousId: String
110110
let userId: String?
111-
let traits: JSON?
111+
let traits: JSON
112112
let referrer: URL?
113113

114114
@Noncodable var anonIdGenerator: AnonymousIdGenerator?
@@ -121,7 +121,7 @@ struct UserInfo: Codable, State {
121121
} else {
122122
anonId = UUID().uuidString
123123
}
124-
return UserInfo(anonymousId: anonId, userId: nil, traits: nil, referrer: nil, anonIdGenerator: state.anonIdGenerator)
124+
return UserInfo(anonymousId: anonId, userId: nil, traits: .object([:]), referrer: nil, anonIdGenerator: state.anonIdGenerator)
125125
}
126126
}
127127

@@ -137,7 +137,7 @@ struct UserInfo: Codable, State {
137137
let traits: JSON?
138138

139139
func reduce(state: UserInfo) -> UserInfo {
140-
return UserInfo(anonymousId: state.anonymousId, userId: state.userId, traits: traits, referrer: state.referrer, anonIdGenerator: state.anonIdGenerator)
140+
return UserInfo(anonymousId: state.anonymousId, userId: state.userId, traits: traits ?? .object([:]), referrer: state.referrer, anonIdGenerator: state.anonIdGenerator)
141141
}
142142
}
143143

@@ -146,7 +146,7 @@ struct UserInfo: Codable, State {
146146
let traits: JSON?
147147

148148
func reduce(state: UserInfo) -> UserInfo {
149-
return UserInfo(anonymousId: state.anonymousId, userId: userId, traits: traits, referrer: state.referrer, anonIdGenerator: state.anonIdGenerator)
149+
return UserInfo(anonymousId: state.anonymousId, userId: userId, traits: traits ?? .object([:]), referrer: state.referrer, anonIdGenerator: state.anonIdGenerator)
150150
}
151151
}
152152

@@ -178,7 +178,7 @@ extension System {
178178
extension UserInfo {
179179
static func defaultState(from storage: Storage, anonIdGenerator: AnonymousIdGenerator) -> UserInfo {
180180
let userId: String? = storage.read(.userId)
181-
let traits: JSON? = storage.read(.traits)
181+
let traits: JSON = storage.read(.traits) ?? .object([:])
182182
var anonymousId: String
183183
if let existingId: String = storage.read(.anonymousId) {
184184
anonymousId = existingId

Tests/Segment-Tests/Analytics_Tests.swift

+14-1
Original file line numberDiff line numberDiff line change
@@ -347,21 +347,34 @@ final class Analytics_Tests: XCTestCase {
347347
}
348348

349349
func testIdentify() {
350+
Storage.hardSettingsReset(writeKey: "test")
350351
let analytics = Analytics(configuration: Configuration(writeKey: "test"))
351352
let outputReader = OutputReaderPlugin()
352353
analytics.add(plugin: outputReader)
353354

354355
waitUntilStarted(analytics: analytics)
356+
357+
// traits should be an empty object.
358+
let currentTraits = analytics.traits()
359+
XCTAssertNotNil(currentTraits)
360+
XCTAssertTrue(currentTraits!.isEmpty == true)
355361

356362
analytics.identify(userId: "brandon", traits: MyTraits(email: "[email protected]"))
357363

358364
let identifyEvent: IdentifyEvent? = outputReader.lastEvent as? IdentifyEvent
359365
XCTAssertTrue(identifyEvent?.userId == "brandon")
360366
let traits = identifyEvent?.traits?.dictionaryValue
361367
XCTAssertTrue(traits?["email"] as? String == "[email protected]")
368+
369+
analytics.reset()
370+
371+
let emptyTraits = analytics.traits()
372+
XCTAssertNotNil(emptyTraits)
373+
XCTAssertTrue(emptyTraits!.isEmpty == true)
362374
}
363375

364376
func testUserIdAndTraitsPersistCorrectly() {
377+
Storage.hardSettingsReset(writeKey: "test")
365378
let analytics = Analytics(configuration: Configuration(writeKey: "test"))
366379
let outputReader = OutputReaderPlugin()
367380
analytics.add(plugin: outputReader)
@@ -693,7 +706,7 @@ final class Analytics_Tests: XCTestCase {
693706
return request
694707
}.errorHandler { error in
695708
switch error {
696-
case AnalyticsError.networkServerRejected(_):
709+
case AnalyticsError.networkServerRejected(_, _):
697710
// we expect this one; it's a bogus writekey
698711
break;
699712
default:

Tests/Segment-Tests/JSON_Tests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class JSONTests: XCTestCase {
3838
}
3939

4040
func testJSONBasic() throws {
41-
let traits = try? JSON(["email": "[email protected]"])
41+
let traits = try! JSON(["email": "[email protected]"])
4242
let userInfo = UserInfo(anonymousId: "1234", userId: "brandon", traits: traits, referrer: nil)
4343

4444
let encoder = JSONSafeEncoder.default

0 commit comments

Comments
 (0)