FIRAppDistributionTests.m 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. // Copyright 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import <Foundation/Foundation.h>
  15. #import <OCMock/OCMock.h>
  16. #import <XCTest/XCTest.h>
  17. #import "FirebaseAppDistribution/Sources/FIRAppDistributionMachO.h"
  18. #import "FirebaseAppDistribution/Sources/FIRAppDistributionUIService.h"
  19. #import "FirebaseAppDistribution/Sources/FIRFADApiService.h"
  20. #import "FirebaseAppDistribution/Sources/Private/FIRAppDistribution.h"
  21. #import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
  22. #import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h"
  23. #import "GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h"
  24. #import "GoogleUtilities/UserDefaults/Private/GULUserDefaults.h"
  25. @interface FIRAppDistributionTests : XCTestCase
  26. @property(nonatomic, strong) FIRAppDistribution *appDistribution;
  27. @end
  28. @interface FIRAppDistribution (PrivateUnitTesting)
  29. - (instancetype)initWithApp:(FIRApp *)app appInfo:(NSDictionary *)appInfo;
  30. - (void)fetchNewLatestRelease:(FIRAppDistributionUpdateCheckCompletion)completion;
  31. - (NSError *)mapFetchReleasesError:(NSError *)error;
  32. @end
  33. @implementation FIRAppDistributionTests {
  34. id _mockFIRAppClass;
  35. id _mockFIRFADApiService;
  36. id _mockFIRAppDistributionUIService;
  37. id _mockFIRInstallations;
  38. id _mockInstallationToken;
  39. id _mockMachO;
  40. NSString *_mockAuthToken;
  41. NSString *_mockInstallationId;
  42. NSArray *_mockReleases;
  43. NSString *_mockCodeHash;
  44. }
  45. - (void)setUp {
  46. [super setUp];
  47. _mockAuthToken = @"this-is-an-auth-token";
  48. _mockCodeHash = @"this-is-a-fake-code-hash";
  49. _mockFIRAppClass = OCMClassMock([FIRApp class]);
  50. _mockFIRFADApiService = OCMClassMock([FIRFADApiService class]);
  51. _mockFIRAppDistributionUIService = OCMPartialMock([FIRAppDistributionUIService sharedInstance]);
  52. _mockFIRInstallations = OCMClassMock([FIRInstallations class]);
  53. _mockInstallationToken = OCMClassMock([FIRInstallationsAuthTokenResult class]);
  54. _mockMachO = OCMClassMock([FIRAppDistributionMachO class]);
  55. id mockBundle = OCMClassMock([NSBundle class]);
  56. OCMStub([_mockFIRAppClass defaultApp]).andReturn(_mockFIRAppClass);
  57. OCMStub([_mockFIRAppDistributionUIService initializeUIState]);
  58. OCMStub([_mockFIRInstallations installations]).andReturn(_mockFIRInstallations);
  59. OCMStub([_mockInstallationToken authToken]).andReturn(_mockAuthToken);
  60. OCMStub([_mockMachO alloc]).andReturn(_mockMachO);
  61. OCMStub([_mockMachO initWithPath:OCMOCK_ANY]).andReturn(_mockMachO);
  62. OCMStub([mockBundle mainBundle]).andReturn(mockBundle);
  63. OCMStub([mockBundle executablePath]).andReturn(@"this-is-a-fake-executablePath");
  64. NSDictionary<NSString *, NSString *> *dict = [[NSDictionary<NSString *, NSString *> alloc] init];
  65. self.appDistribution = [[FIRAppDistribution alloc] initWithApp:_mockFIRAppClass appInfo:dict];
  66. _mockInstallationId = @"this-id-is-fake-ccccc";
  67. _mockReleases = @[
  68. @{
  69. @"codeHash" : @"this-is-another-code-hash",
  70. @"displayVersion" : @"1.0.0",
  71. @"buildVersion" : @"111",
  72. @"releaseNotes" : @"This is a release",
  73. @"downloadUrl" : @"http://faketyfakefake.download"
  74. },
  75. @{
  76. @"latest" : @YES,
  77. @"codeHash" : _mockCodeHash,
  78. @"displayVersion" : @"1.0.1",
  79. @"buildVersion" : @"112",
  80. @"releaseNotes" : @"This is a release too",
  81. @"downloadUrl" : @"http://faketyfakefake.download"
  82. }
  83. ];
  84. }
  85. - (void)tearDown {
  86. [super tearDown];
  87. [[GULUserDefaults standardUserDefaults] removeObjectForKey:@"FIRFADSignInState"];
  88. [_mockFIRAppClass stopMocking];
  89. [_mockFIRFADApiService stopMocking];
  90. [_mockFIRAppDistributionUIService stopMocking];
  91. [_mockFIRInstallations stopMocking];
  92. [_mockInstallationToken stopMocking];
  93. [_mockMachO stopMocking];
  94. }
  95. - (void)mockInstallationIdCompletion:(NSString *_Nullable)identifier
  96. error:(NSError *_Nullable)error {
  97. [OCMStub([_mockFIRInstallations installationIDWithCompletion:OCMOCK_ANY])
  98. andDo:^(NSInvocation *invocation) {
  99. __unsafe_unretained void (^handler)(NSString *identifier, NSError *_Nullable error);
  100. [invocation getArgument:&handler atIndex:2];
  101. handler(identifier, error);
  102. }];
  103. }
  104. - (void)verifyInstallationIdCompletion {
  105. OCMVerify([_mockFIRInstallations installationIDWithCompletion:OCMOCK_ANY]);
  106. }
  107. - (void)mockUIServiceRegistrationCompletion:(NSError *_Nullable)error {
  108. [OCMStub([_mockFIRAppDistributionUIService appDistributionRegistrationFlow:OCMOCK_ANY
  109. withCompletion:OCMOCK_ANY])
  110. andDo:^(NSInvocation *invocation) {
  111. __unsafe_unretained void (^handler)(NSError *_Nullable error);
  112. [invocation getArgument:&handler atIndex:3];
  113. handler(error);
  114. }];
  115. }
  116. - (void)verifyRegistrationCompletion {
  117. OCMVerify([_mockFIRAppDistributionUIService appDistributionRegistrationFlow:OCMOCK_ANY
  118. withCompletion:OCMOCK_ANY]);
  119. }
  120. - (void)rejectRegistrationCompletion {
  121. OCMReject([_mockFIRAppDistributionUIService appDistributionRegistrationFlow:OCMOCK_ANY
  122. withCompletion:OCMOCK_ANY]);
  123. }
  124. - (void)mockUIServiceShowUICompletion:(BOOL)continued {
  125. [OCMStub([_mockFIRAppDistributionUIService showUIAlertWithCompletion:OCMOCK_ANY])
  126. andDo:^(NSInvocation *invocation) {
  127. __unsafe_unretained void (^handler)(BOOL continued);
  128. [invocation getArgument:&handler atIndex:2];
  129. handler(continued);
  130. }];
  131. }
  132. - (void)verifyShowUICompletion {
  133. OCMVerify([_mockFIRAppDistributionUIService showUIAlertWithCompletion:OCMOCK_ANY]);
  134. }
  135. - (void)rejectShowUICompletion {
  136. OCMReject([_mockFIRAppDistributionUIService showUIAlertWithCompletion:OCMOCK_ANY]);
  137. }
  138. - (void)mockFetchReleasesCompletion:(NSArray *)releases error:(NSError *)error {
  139. [OCMStub([_mockFIRFADApiService fetchReleasesWithCompletion:OCMOCK_ANY])
  140. andDo:^(NSInvocation *invocation) {
  141. __unsafe_unretained void (^handler)(NSArray *releases, NSError *_Nullable error);
  142. [invocation getArgument:&handler atIndex:2];
  143. handler(releases, error);
  144. }];
  145. }
  146. - (void)verifyFetchReleasesCompletion {
  147. OCMVerify([_mockFIRFADApiService fetchReleasesWithCompletion:[OCMArg any]]);
  148. }
  149. - (void)rejectFetchReleasesCompletion {
  150. OCMReject([_mockFIRFADApiService fetchReleasesWithCompletion:[OCMArg any]]);
  151. }
  152. - (void)testInitWithApp {
  153. XCTAssertNotNil([self appDistribution]);
  154. }
  155. - (void)testSignInWithCompletionPersistSignInStateSuccess {
  156. [self mockInstallationIdCompletion:_mockInstallationId error:nil];
  157. [self mockUIServiceRegistrationCompletion:nil];
  158. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  159. XCTestExpectation *expectation =
  160. [self expectationWithDescription:@"Persist sign in state succeeds."];
  161. [[self appDistribution] signInTesterWithCompletion:^(NSError *_Nullable error) {
  162. XCTAssertNil(error);
  163. [expectation fulfill];
  164. }];
  165. [self waitForExpectations:@[ expectation ] timeout:5.0];
  166. XCTAssertTrue([[self appDistribution] isTesterSignedIn]);
  167. [self verifyInstallationIdCompletion];
  168. [self verifyRegistrationCompletion];
  169. [self verifyFetchReleasesCompletion];
  170. }
  171. - (void)testSignInWithCompletionInstallationIDNotFoundFailure {
  172. NSError *mockError =
  173. [NSError errorWithDomain:@"this.is.fake"
  174. code:3
  175. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  176. [self mockInstallationIdCompletion:_mockInstallationId error:mockError];
  177. [self mockUIServiceRegistrationCompletion:nil];
  178. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  179. XCTestExpectation *expectation =
  180. [self expectationWithDescription:@"Persist sign in state fails."];
  181. [[self appDistribution] signInTesterWithCompletion:^(NSError *_Nullable error) {
  182. XCTAssertNotNil(error);
  183. XCTAssertEqual([error code], FIRAppDistributionErrorUnknown);
  184. [expectation fulfill];
  185. }];
  186. [self waitForExpectations:@[ expectation ] timeout:5.0];
  187. XCTAssertFalse([[self appDistribution] isTesterSignedIn]);
  188. [self verifyInstallationIdCompletion];
  189. [self rejectRegistrationCompletion];
  190. [self rejectFetchReleasesCompletion];
  191. }
  192. - (void)testSignInWithCompletionDelegateFailureDoesNotPersist {
  193. NSError *mockError =
  194. [NSError errorWithDomain:@"fake.app.delegate.domain"
  195. code:4
  196. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  197. [self mockInstallationIdCompletion:_mockInstallationId error:nil];
  198. [self mockUIServiceRegistrationCompletion:mockError];
  199. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  200. XCTestExpectation *expectation =
  201. [self expectationWithDescription:
  202. @"Persist sign in state fails when the delegate recieves a failure."];
  203. [[self appDistribution] signInTesterWithCompletion:^(NSError *_Nullable error) {
  204. XCTAssertNotNil(error);
  205. XCTAssertEqual([error code], 4);
  206. [expectation fulfill];
  207. }];
  208. [self waitForExpectations:@[ expectation ] timeout:5.0];
  209. XCTAssertFalse([[self appDistribution] isTesterSignedIn]);
  210. [self verifyInstallationIdCompletion];
  211. [self verifyRegistrationCompletion];
  212. [self rejectFetchReleasesCompletion];
  213. }
  214. - (void)testSignInWithCompletionFetchReleasesFailureDoesNotPersist {
  215. NSError *mockError =
  216. [NSError errorWithDomain:kFIRFADApiErrorDomain
  217. code:FIRFADApiErrorUnauthenticated
  218. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  219. [self mockInstallationIdCompletion:_mockInstallationId error:nil];
  220. [self mockUIServiceRegistrationCompletion:nil];
  221. [self mockFetchReleasesCompletion:_mockReleases error:mockError];
  222. XCTestExpectation *expectation = [self
  223. expectationWithDescription:@"Persist sign in state fails when we fail to fetch releases."];
  224. [[self appDistribution] signInTesterWithCompletion:^(NSError *_Nullable error) {
  225. XCTAssertNotNil(error);
  226. XCTAssertEqual([error code], FIRAppDistributionErrorAuthenticationFailure);
  227. XCTAssertEqual([error domain], FIRAppDistributionErrorDomain);
  228. [expectation fulfill];
  229. }];
  230. [self waitForExpectations:@[ expectation ] timeout:5.0];
  231. XCTAssertFalse([[self appDistribution] isTesterSignedIn]);
  232. [self verifyInstallationIdCompletion];
  233. [self verifyRegistrationCompletion];
  234. [self verifyFetchReleasesCompletion];
  235. }
  236. - (void)testSignOutSuccess {
  237. [self mockInstallationIdCompletion:_mockInstallationId error:nil];
  238. [self mockUIServiceRegistrationCompletion:nil];
  239. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  240. XCTestExpectation *expectation =
  241. [self expectationWithDescription:@"Persist sign out state succeeds."];
  242. [[self appDistribution] signInTesterWithCompletion:^(NSError *_Nullable error) {
  243. XCTAssertTrue([[self appDistribution] isTesterSignedIn]);
  244. XCTAssertNil(error);
  245. [expectation fulfill];
  246. }];
  247. [self waitForExpectations:@[ expectation ] timeout:5.0];
  248. [[self appDistribution] signOutTester];
  249. XCTAssertFalse([[self appDistribution] isTesterSignedIn]);
  250. [self verifyInstallationIdCompletion];
  251. [self verifyRegistrationCompletion];
  252. [self verifyFetchReleasesCompletion];
  253. }
  254. - (void)testFetchNewLatestReleaseSuccess {
  255. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  256. OCMStub([_mockMachO codeHash]).andReturn(@"this-is-old");
  257. XCTestExpectation *expectation =
  258. [self expectationWithDescription:@"Fetch latest release succeeds."];
  259. [[self appDistribution] fetchNewLatestRelease:^(FIRAppDistributionRelease *_Nullable release,
  260. NSError *_Nullable error) {
  261. XCTAssertNotNil(release);
  262. XCTAssertNil(error);
  263. [expectation fulfill];
  264. }];
  265. [self waitForExpectations:@[ expectation ] timeout:5.0];
  266. [self verifyFetchReleasesCompletion];
  267. }
  268. - (void)testFetchNewLatestReleaseNoNewRelease {
  269. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  270. OCMStub([_mockMachO codeHash]).andReturn(_mockCodeHash);
  271. XCTestExpectation *expectation =
  272. [self expectationWithDescription:@"Fetch latest release with no new release succeeds."];
  273. [[self appDistribution] fetchNewLatestRelease:^(FIRAppDistributionRelease *_Nullable release,
  274. NSError *_Nullable error) {
  275. XCTAssertNil(release);
  276. XCTAssertNil(error);
  277. [expectation fulfill];
  278. }];
  279. [self waitForExpectations:@[ expectation ] timeout:5.0];
  280. [self verifyFetchReleasesCompletion];
  281. }
  282. - (void)testFetchNewLatestReleaseFailure {
  283. NSError *mockError =
  284. [NSError errorWithDomain:kFIRFADApiErrorDomain
  285. code:FIRFADApiErrorTimeout
  286. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  287. [self mockFetchReleasesCompletion:nil error:mockError];
  288. OCMStub([_mockMachO codeHash]).andReturn(@"this-is-old");
  289. XCTestExpectation *expectation = [self expectationWithDescription:@"Fetch latest release fails."];
  290. [[self appDistribution] fetchNewLatestRelease:^(FIRAppDistributionRelease *_Nullable release,
  291. NSError *_Nullable error) {
  292. XCTAssertNil(release);
  293. XCTAssertNotNil(error);
  294. XCTAssertEqual([error code], FIRAppDistributionErrorNetworkFailure);
  295. XCTAssertEqual([error domain], FIRAppDistributionErrorDomain);
  296. [expectation fulfill];
  297. }];
  298. [self waitForExpectations:@[ expectation ] timeout:5.0];
  299. [self verifyFetchReleasesCompletion];
  300. OCMReject([_mockMachO codeHash]);
  301. }
  302. - (void)testCheckForUpdateWithCompletionTesterSignedIn {
  303. [self mockInstallationIdCompletion:_mockInstallationId error:nil];
  304. [self mockUIServiceRegistrationCompletion:nil];
  305. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  306. [self mockUIServiceShowUICompletion:NO];
  307. // Sign in the tester
  308. XCTestExpectation *expectation =
  309. [self expectationWithDescription:@"Persist sign in state succeeds."];
  310. [[self appDistribution] signInTesterWithCompletion:^(NSError *_Nullable error) {
  311. XCTAssertNil(error);
  312. [expectation fulfill];
  313. }];
  314. [self waitForExpectations:@[ expectation ] timeout:5.0];
  315. XCTAssertTrue([[self appDistribution] isTesterSignedIn]);
  316. // Should Call check for update without calling the UIService
  317. XCTestExpectation *checkForUpdateExpectation =
  318. [self expectationWithDescription:@"Check for update does not prompt user"];
  319. [[self appDistribution]
  320. checkForUpdateWithCompletion:^(FIRAppDistributionRelease *_Nullable release,
  321. NSError *_Nullable error) {
  322. XCTAssertNil(error);
  323. XCTAssertNotNil(release);
  324. [checkForUpdateExpectation fulfill];
  325. }];
  326. [self waitForExpectations:@[ checkForUpdateExpectation ] timeout:5.0];
  327. [self rejectShowUICompletion];
  328. }
  329. - (void)testCheckForUpdateWithCompletionClicksYesSuccess {
  330. [self mockInstallationIdCompletion:_mockInstallationId error:nil];
  331. [self mockUIServiceRegistrationCompletion:nil];
  332. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  333. [self mockUIServiceShowUICompletion:YES];
  334. OCMStub([_mockMachO codeHash]).andReturn(@"this-is-old");
  335. XCTestExpectation *checkForUpdateExpectation =
  336. [self expectationWithDescription:@"Check for update does prompt user"];
  337. [[self appDistribution]
  338. checkForUpdateWithCompletion:^(FIRAppDistributionRelease *_Nullable release,
  339. NSError *_Nullable error) {
  340. XCTAssertNil(error);
  341. XCTAssertNotNil(release);
  342. [checkForUpdateExpectation fulfill];
  343. }];
  344. [self waitForExpectations:@[ checkForUpdateExpectation ] timeout:5.0];
  345. [self verifyShowUICompletion];
  346. OCMVerify([_mockMachO codeHash]);
  347. }
  348. - (void)testCheckForUpdateWithCompletionClicksYesFailure {
  349. NSError *mockError =
  350. [NSError errorWithDomain:@"this.is.fake"
  351. code:3
  352. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  353. [self mockInstallationIdCompletion:_mockInstallationId error:mockError];
  354. [self mockUIServiceRegistrationCompletion:nil];
  355. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  356. [self mockUIServiceShowUICompletion:YES];
  357. XCTestExpectation *checkForUpdateExpectation =
  358. [self expectationWithDescription:@"Check for update does prompt user"];
  359. [[self appDistribution]
  360. checkForUpdateWithCompletion:^(FIRAppDistributionRelease *_Nullable release,
  361. NSError *_Nullable error) {
  362. XCTAssertNotNil(error);
  363. XCTAssertNil(release);
  364. [checkForUpdateExpectation fulfill];
  365. }];
  366. [self waitForExpectations:@[ checkForUpdateExpectation ] timeout:5.0];
  367. [self verifyShowUICompletion];
  368. }
  369. - (void)testCheckForUpdateWithCompletionClicksNo {
  370. [self mockInstallationIdCompletion:_mockInstallationId error:nil];
  371. [self mockUIServiceRegistrationCompletion:nil];
  372. [self mockFetchReleasesCompletion:_mockReleases error:nil];
  373. [self mockUIServiceShowUICompletion:NO];
  374. XCTestExpectation *checkForUpdateExpectation =
  375. [self expectationWithDescription:@"Check for update does prompt user"];
  376. [[self appDistribution]
  377. checkForUpdateWithCompletion:^(FIRAppDistributionRelease *_Nullable release,
  378. NSError *_Nullable error) {
  379. XCTAssertNotNil(error);
  380. XCTAssertEqual([error code], FIRAppDistributionErrorAuthenticationCancelled);
  381. XCTAssertNil(release);
  382. [checkForUpdateExpectation fulfill];
  383. }];
  384. [self waitForExpectations:@[ checkForUpdateExpectation ] timeout:5.0];
  385. [self verifyShowUICompletion];
  386. }
  387. - (void)testHandleFetchReleasesErrorTimeout {
  388. NSError *mockError =
  389. [NSError errorWithDomain:kFIRFADApiErrorDomain
  390. code:FIRFADApiErrorTimeout
  391. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  392. NSError *handledError = [[self appDistribution] mapFetchReleasesError:mockError];
  393. XCTAssertNotNil(handledError);
  394. XCTAssertEqual([handledError code], FIRAppDistributionErrorNetworkFailure);
  395. XCTAssertEqual([handledError domain], FIRAppDistributionErrorDomain);
  396. }
  397. - (void)testHandleFetchReleasesErrorUnauthenticated {
  398. NSError *mockError =
  399. [NSError errorWithDomain:kFIRFADApiErrorDomain
  400. code:FIRFADApiErrorUnauthenticated
  401. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  402. NSError *handledError = [[self appDistribution] mapFetchReleasesError:mockError];
  403. XCTAssertNotNil(handledError);
  404. XCTAssertEqual([handledError code], FIRAppDistributionErrorAuthenticationFailure);
  405. XCTAssertEqual([handledError domain], FIRAppDistributionErrorDomain);
  406. }
  407. - (void)testHandleFetchReleasesErrorUnauthorized {
  408. NSError *mockError =
  409. [NSError errorWithDomain:kFIRFADApiErrorDomain
  410. code:FIRFADApiErrorUnauthorized
  411. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  412. NSError *handledError = [[self appDistribution] mapFetchReleasesError:mockError];
  413. XCTAssertNotNil(handledError);
  414. XCTAssertEqual([handledError code], FIRAppDistributionErrorAuthenticationFailure);
  415. XCTAssertEqual([handledError domain], FIRAppDistributionErrorDomain);
  416. }
  417. - (void)testHandleFetchReleasesErrorTokenGenerationFailure {
  418. NSError *mockError =
  419. [NSError errorWithDomain:kFIRFADApiErrorDomain
  420. code:FIRFADApiTokenGenerationFailure
  421. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  422. NSError *handledError = [[self appDistribution] mapFetchReleasesError:mockError];
  423. XCTAssertNotNil(handledError);
  424. XCTAssertEqual([handledError code], FIRAppDistributionErrorAuthenticationFailure);
  425. XCTAssertEqual([handledError domain], FIRAppDistributionErrorDomain);
  426. }
  427. - (void)testHandleFetchReleasesErrorInstallationIdentifierFailure {
  428. NSError *mockError =
  429. [NSError errorWithDomain:kFIRFADApiErrorDomain
  430. code:FIRFADApiInstallationIdentifierError
  431. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  432. NSError *handledError = [[self appDistribution] mapFetchReleasesError:mockError];
  433. XCTAssertNotNil(handledError);
  434. XCTAssertEqual([handledError code], FIRAppDistributionErrorAuthenticationFailure);
  435. XCTAssertEqual([handledError domain], FIRAppDistributionErrorDomain);
  436. }
  437. - (void)testHandleFetchReleasesErrorNotFound {
  438. NSError *mockError =
  439. [NSError errorWithDomain:kFIRFADApiErrorDomain
  440. code:FIRFADApiErrorNotFound
  441. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  442. NSError *handledError = [[self appDistribution] mapFetchReleasesError:mockError];
  443. XCTAssertNotNil(handledError);
  444. XCTAssertEqual([handledError code], FIRAppDistributionErrorAuthenticationFailure);
  445. XCTAssertEqual([handledError domain], FIRAppDistributionErrorDomain);
  446. }
  447. - (void)testHandleFetchReleasesErrorApiDomainErrorUnknown {
  448. NSError *mockError =
  449. [NSError errorWithDomain:kFIRFADApiErrorDomain
  450. code:209
  451. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  452. NSError *handledError = [[self appDistribution] mapFetchReleasesError:mockError];
  453. XCTAssertNotNil(handledError);
  454. XCTAssertEqual([handledError code], FIRAppDistributionErrorUnknown);
  455. XCTAssertEqual([handledError domain], FIRAppDistributionErrorDomain);
  456. }
  457. - (void)testHandleFetchReleasesErrorUnknownDomainError {
  458. NSError *mockError =
  459. [NSError errorWithDomain:@"this.is.not.an.api.failure"
  460. code:4
  461. userInfo:@{NSLocalizedDescriptionKey : @"This is unfortunate."}];
  462. NSError *handledError = [[self appDistribution] mapFetchReleasesError:mockError];
  463. XCTAssertNotNil(handledError);
  464. XCTAssertEqual([handledError code], FIRAppDistributionErrorUnknown);
  465. XCTAssertEqual([handledError domain], FIRAppDistributionErrorDomain);
  466. }
  467. @end