SessionStartEventTests.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. //
  2. // Copyright 2022 Google LLC
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. import XCTest
  16. #if SWIFT_PACKAGE
  17. import FirebaseSessionsObjC
  18. #endif // SWIFT_PACKAGE
  19. #if SWIFT_PACKAGE
  20. @_implementationOnly import GoogleUtilities_Environment
  21. #else
  22. @_implementationOnly import GoogleUtilities
  23. #endif // SWIFT_PACKAGE
  24. @testable import FirebaseSessions
  25. class SessionStartEventTests: XCTestCase {
  26. var time: MockTimeProvider!
  27. var appInfo: MockApplicationInfo!
  28. override func setUp() {
  29. super.setUp()
  30. time = MockTimeProvider()
  31. appInfo = MockApplicationInfo()
  32. }
  33. var defaultSessionInfo: SessionInfo {
  34. return SessionInfo(
  35. sessionId: "test_session_id",
  36. firstSessionId: "test_first_session_id",
  37. dispatchEvents: true,
  38. sessionIndex: 0
  39. )
  40. }
  41. var thirdSessionInfo: SessionInfo {
  42. return SessionInfo(
  43. sessionId: "test_third_session_id",
  44. firstSessionId: "test_first_session_id",
  45. dispatchEvents: true,
  46. sessionIndex: 2
  47. )
  48. }
  49. /// This function runs the `testCase` twice, once for the proto object stored in
  50. /// the event, and once after encoding and decoding the proto. This is useful for
  51. /// testing cases where the proto hasn't been encoded correctly.
  52. func testProtoAndDecodedProto(sessionEvent: SessionStartEvent,
  53. testCase: (firebase_appquality_sessions_SessionEvent) -> Void) {
  54. let proto = sessionEvent.proto
  55. testCase(proto)
  56. /// If you are getting failures in this test case, and not the one above, the
  57. /// problem likely lies in encoding the proto
  58. let decodedProto = sessionEvent.encodeDecodeEvent()
  59. testCase(decodedProto)
  60. }
  61. func test_init_setsSessionData() {
  62. let event = SessionStartEvent(sessionInfo: thirdSessionInfo, appInfo: appInfo, time: time)
  63. testProtoAndDecodedProto(sessionEvent: event) { proto in
  64. assertEqualProtoString(
  65. proto.session_data.session_id,
  66. expected: "test_third_session_id",
  67. fieldName: "session_id"
  68. )
  69. assertEqualProtoString(
  70. proto.session_data.first_session_id,
  71. expected: "test_first_session_id",
  72. fieldName: "first_session_id"
  73. )
  74. XCTAssertEqual(proto.session_data.session_index, 2)
  75. XCTAssertEqual(proto.session_data.event_timestamp_us, 123)
  76. }
  77. }
  78. func test_init_setsApplicationInfo() {
  79. let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
  80. testProtoAndDecodedProto(sessionEvent: event) { proto in
  81. assertEqualProtoString(
  82. proto.application_info.app_id,
  83. expected: MockApplicationInfo.testAppID,
  84. fieldName: "app_id"
  85. )
  86. assertEqualProtoString(
  87. proto.application_info.session_sdk_version,
  88. expected: MockApplicationInfo.testSDKVersion,
  89. fieldName: "session_sdk_version"
  90. )
  91. assertEqualProtoString(
  92. proto.application_info.apple_app_info.bundle_short_version,
  93. expected: MockApplicationInfo.testAppDisplayVersion,
  94. fieldName: "bundle_short_version"
  95. )
  96. assertEqualProtoString(
  97. proto.application_info.device_model,
  98. expected: MockApplicationInfo.testDeviceModel,
  99. fieldName: "device_model"
  100. )
  101. // Ensure we convert the test OS name into the enum.
  102. XCTAssertEqual(
  103. proto.application_info.apple_app_info.os_name,
  104. firebase_appquality_sessions_OsName_IOS
  105. )
  106. }
  107. }
  108. func test_setInstallationID_setsInstallationID() {
  109. let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
  110. event.setInstallationID(installationId: "testInstallationID")
  111. testProtoAndDecodedProto(sessionEvent: event) { proto in
  112. assertEqualProtoString(
  113. proto.session_data.firebase_installation_id,
  114. expected: "testInstallationID",
  115. fieldName: "firebase_installation_id"
  116. )
  117. }
  118. }
  119. func test_convertOSName_convertsCorrectly() {
  120. let expectations: [(given: String, expected: firebase_appquality_sessions_OsName)] = [
  121. ("macos", firebase_appquality_sessions_OsName_MACOS),
  122. ("maccatalyst", firebase_appquality_sessions_OsName_MACCATALYST),
  123. ("ios_on_mac", firebase_appquality_sessions_OsName_IOS_ON_MAC),
  124. ("ios", firebase_appquality_sessions_OsName_IOS),
  125. ("tvos", firebase_appquality_sessions_OsName_TVOS),
  126. ("watchos", firebase_appquality_sessions_OsName_WATCHOS),
  127. ("ipados", firebase_appquality_sessions_OsName_IPADOS),
  128. ("something unknown", firebase_appquality_sessions_OsName_UNKNOWN_OSNAME),
  129. ]
  130. expectations.forEach { (given: String, expected: firebase_appquality_sessions_OsName) in
  131. appInfo.osName = given
  132. let event = SessionStartEvent(
  133. sessionInfo: self.defaultSessionInfo,
  134. appInfo: appInfo,
  135. time: time
  136. )
  137. testProtoAndDecodedProto(sessionEvent: event) { proto in
  138. XCTAssertEqual(event.proto.application_info.apple_app_info.os_name, expected)
  139. }
  140. }
  141. }
  142. func test_convertLogEnvironment_convertsCorrectly() {
  143. let expectations: [(given: DevEnvironment,
  144. expected: firebase_appquality_sessions_LogEnvironment)] = [
  145. (.prod, firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_PROD),
  146. (
  147. .staging,
  148. firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_STAGING
  149. ),
  150. (
  151. .autopush,
  152. firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_AUTOPUSH
  153. ),
  154. ]
  155. expectations.forEach { (given: DevEnvironment,
  156. expected: firebase_appquality_sessions_LogEnvironment) in
  157. appInfo.environment = given
  158. let event = SessionStartEvent(
  159. sessionInfo: self.defaultSessionInfo,
  160. appInfo: appInfo,
  161. time: time
  162. )
  163. XCTAssertEqual(event.proto.application_info.log_environment, expected)
  164. }
  165. }
  166. func test_dataCollectionState_defaultIsUnknown() {
  167. let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
  168. testProtoAndDecodedProto(sessionEvent: event) { proto in
  169. XCTAssertEqual(
  170. proto.session_data.data_collection_status.performance,
  171. firebase_appquality_sessions_DataCollectionState_COLLECTION_SDK_NOT_INSTALLED
  172. )
  173. XCTAssertEqual(
  174. proto.session_data.data_collection_status.crashlytics,
  175. firebase_appquality_sessions_DataCollectionState_COLLECTION_SDK_NOT_INSTALLED
  176. )
  177. }
  178. }
  179. func test_newtworkInfo_onlyPresentWhenPerformanceInstalled() {
  180. let mockNetworkInfo = MockNetworkInfo()
  181. mockNetworkInfo.networkType = .mobile
  182. // Mobile Subtypes are always empty on non-iOS platforms, and
  183. // Performance doesn't support those platforms anyways
  184. #if os(iOS) && !targetEnvironment(macCatalyst)
  185. mockNetworkInfo.mobileSubtype = CTRadioAccessTechnologyHSUPA
  186. #else
  187. mockNetworkInfo.mobileSubtype = ""
  188. #endif
  189. appInfo.networkInfo = mockNetworkInfo
  190. let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
  191. // These fields will not be filled in when Crashlytics is installed
  192. event.set(subscriber: .Crashlytics, isDataCollectionEnabled: true, appInfo: appInfo)
  193. // They should also not be filled in when Performance data collection is disabled
  194. event.set(subscriber: .Performance, isDataCollectionEnabled: false, appInfo: appInfo)
  195. // Expect empty because Crashlytics is installed, but not Perf
  196. testProtoAndDecodedProto(sessionEvent: event) { proto in
  197. XCTAssertEqual(
  198. event.proto.application_info.apple_app_info.network_connection_info.network_type,
  199. firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_DUMMY
  200. )
  201. XCTAssertEqual(
  202. event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
  203. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
  204. )
  205. assertEqualProtoString(
  206. proto.application_info.apple_app_info.mcc_mnc,
  207. expected: "",
  208. fieldName: "mcc_mnc"
  209. )
  210. }
  211. // These fields will only be filled in when the Perf SDK is installed
  212. event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
  213. // Now the field should be set with the real thing
  214. testProtoAndDecodedProto(sessionEvent: event) { proto in
  215. XCTAssertEqual(
  216. event.proto.application_info.apple_app_info.network_connection_info.network_type,
  217. firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE
  218. )
  219. // Mobile Subtypes are always empty on non-iOS platforms, and
  220. // Performance doesn't support those platforms anyways
  221. #if os(iOS) && !targetEnvironment(macCatalyst)
  222. XCTAssertEqual(
  223. event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
  224. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
  225. )
  226. #else
  227. XCTAssertEqual(
  228. event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
  229. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
  230. )
  231. #endif
  232. assertEqualProtoString(
  233. proto.application_info.apple_app_info.mcc_mnc,
  234. expected: MockApplicationInfo.testMCCMNC,
  235. fieldName: "mcc_mnc"
  236. )
  237. }
  238. }
  239. func test_convertNetworkType_convertsCorrectly() {
  240. let expectations: [(
  241. given: GULNetworkType,
  242. expected: firebase_appquality_sessions_NetworkConnectionInfo_NetworkType
  243. )] = [
  244. (
  245. .WIFI,
  246. firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_WIFI
  247. ),
  248. (
  249. .mobile,
  250. firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE
  251. ),
  252. (
  253. .none,
  254. firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_DUMMY
  255. ),
  256. ]
  257. expectations.forEach { (
  258. given: GULNetworkType,
  259. expected: firebase_appquality_sessions_NetworkConnectionInfo_NetworkType
  260. ) in
  261. let mockNetworkInfo = MockNetworkInfo()
  262. mockNetworkInfo.networkType = given
  263. appInfo.networkInfo = mockNetworkInfo
  264. let event = SessionStartEvent(
  265. sessionInfo: self.defaultSessionInfo,
  266. appInfo: appInfo,
  267. time: time
  268. )
  269. // These fields will only be filled in when the Perf SDK is installed
  270. event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
  271. testProtoAndDecodedProto(sessionEvent: event) { proto in
  272. XCTAssertEqual(
  273. event.proto.application_info.apple_app_info.network_connection_info.network_type,
  274. expected
  275. )
  276. }
  277. }
  278. }
  279. /// Following tests can be run only in iOS environment
  280. #if os(iOS) && !targetEnvironment(macCatalyst)
  281. func test_convertMobileSubtype_convertsCorrectlyPreOS14() {
  282. let expectations: [(
  283. given: String,
  284. expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
  285. )] = [
  286. (
  287. CTRadioAccessTechnologyGPRS,
  288. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
  289. ),
  290. (
  291. CTRadioAccessTechnologyEdge,
  292. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
  293. ),
  294. (
  295. CTRadioAccessTechnologyWCDMA,
  296. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
  297. ),
  298. (
  299. CTRadioAccessTechnologyCDMA1x,
  300. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
  301. ),
  302. (
  303. CTRadioAccessTechnologyHSDPA,
  304. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
  305. ),
  306. (
  307. CTRadioAccessTechnologyHSUPA,
  308. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
  309. ),
  310. (
  311. CTRadioAccessTechnologyCDMAEVDORev0,
  312. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
  313. ),
  314. (
  315. CTRadioAccessTechnologyCDMAEVDORevA,
  316. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
  317. ),
  318. (
  319. CTRadioAccessTechnologyCDMAEVDORevB,
  320. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
  321. ),
  322. (
  323. CTRadioAccessTechnologyeHRPD,
  324. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
  325. ),
  326. (
  327. CTRadioAccessTechnologyLTE,
  328. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
  329. ),
  330. (
  331. "random",
  332. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
  333. ),
  334. ]
  335. expectations
  336. .forEach { (
  337. given: String,
  338. expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
  339. ) in
  340. let mockNetworkInfo = MockNetworkInfo()
  341. mockNetworkInfo.mobileSubtype = given
  342. appInfo.networkInfo = mockNetworkInfo
  343. let event = SessionStartEvent(
  344. sessionInfo: self.defaultSessionInfo,
  345. appInfo: appInfo,
  346. time: time
  347. )
  348. // These fields will only be filled in when the Perf SDK is installed
  349. event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
  350. testProtoAndDecodedProto(sessionEvent: event) { proto in
  351. XCTAssertEqual(
  352. event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
  353. expected
  354. )
  355. }
  356. }
  357. }
  358. #endif
  359. #if os(iOS) && !targetEnvironment(macCatalyst)
  360. @available(iOS 14.1, *)
  361. func test_convertMobileSubtype_convertsCorrectlyPostOS14() {
  362. let expectations: [(
  363. given: String,
  364. expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
  365. )] = [
  366. (
  367. CTRadioAccessTechnologyGPRS,
  368. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
  369. ),
  370. (
  371. CTRadioAccessTechnologyEdge,
  372. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
  373. ),
  374. (
  375. CTRadioAccessTechnologyWCDMA,
  376. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
  377. ),
  378. (
  379. CTRadioAccessTechnologyCDMA1x,
  380. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
  381. ),
  382. (
  383. CTRadioAccessTechnologyHSDPA,
  384. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
  385. ),
  386. (
  387. CTRadioAccessTechnologyHSUPA,
  388. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
  389. ),
  390. (
  391. CTRadioAccessTechnologyCDMAEVDORev0,
  392. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
  393. ),
  394. (
  395. CTRadioAccessTechnologyCDMAEVDORevA,
  396. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
  397. ),
  398. (
  399. CTRadioAccessTechnologyCDMAEVDORevB,
  400. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
  401. ),
  402. (
  403. CTRadioAccessTechnologyeHRPD,
  404. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
  405. ),
  406. (
  407. CTRadioAccessTechnologyLTE,
  408. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
  409. ),
  410. (
  411. CTRadioAccessTechnologyNRNSA,
  412. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
  413. ),
  414. (
  415. CTRadioAccessTechnologyNR,
  416. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
  417. ),
  418. (
  419. "random",
  420. firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
  421. ),
  422. ]
  423. expectations
  424. .forEach { (
  425. given: String,
  426. expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
  427. ) in
  428. let mockNetworkInfo = MockNetworkInfo()
  429. mockNetworkInfo.mobileSubtype = given
  430. appInfo.networkInfo = mockNetworkInfo
  431. let event = SessionStartEvent(
  432. sessionInfo: self.defaultSessionInfo,
  433. appInfo: appInfo,
  434. time: time
  435. )
  436. // These fields will only be filled in when the Perf SDK is installed
  437. event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
  438. testProtoAndDecodedProto(sessionEvent: event) { proto in
  439. XCTAssertEqual(
  440. event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
  441. expected
  442. )
  443. }
  444. }
  445. }
  446. #endif
  447. }