FIRIAMMsgFetcherUsingRestfulTests.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright 2017 Google
  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. */
  16. #import <OCMock/OCMock.h>
  17. #import <XCTest/XCTest.h>
  18. #import "FirebaseInAppMessaging/Sources/Private/Data/FIRIAMMessageDefinition.h"
  19. #import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMMsgFetcherUsingRestful.h"
  20. #import "FirebaseInAppMessaging/Sources/Private/Runtime/FIRIAMFetchFlow.h"
  21. static NSString *serverHost = @"myhost";
  22. static NSString *projectNumber = @"My-project-number";
  23. static NSString *appId = @"My-app-id";
  24. static NSString *apiKey = @"Api-key";
  25. @interface FIRIAMMsgFetcherUsingRestfulTests : XCTestCase
  26. @property NSURLSession *mockedNSURLSession;
  27. @property FIRIAMClientInfoFetcher *mockclientInfoFetcher;
  28. @property FIRIAMMsgFetcherUsingRestful *fetcher;
  29. @end
  30. @implementation FIRIAMMsgFetcherUsingRestfulTests
  31. - (void)setUp {
  32. [super setUp];
  33. // Put setup code here. This method is called before the invocation of each test method in the
  34. // class.
  35. self.mockedNSURLSession = OCMClassMock([NSURLSession class]);
  36. self.mockclientInfoFetcher = OCMClassMock([FIRIAMClientInfoFetcher class]);
  37. FIRIAMFetchResponseParser *parser =
  38. [[FIRIAMFetchResponseParser alloc] initWithTimeFetcher:[[FIRIAMTimerWithNSDate alloc] init]];
  39. self.fetcher =
  40. [[FIRIAMMsgFetcherUsingRestful alloc] initWithHost:serverHost
  41. HTTPProtocol:@"https"
  42. project:projectNumber
  43. firebaseApp:appId
  44. APIKey:apiKey
  45. fetchStorage:[[FIRIAMServerMsgFetchStorage alloc] init]
  46. instanceIDFetcher:_mockclientInfoFetcher
  47. usingURLSession:_mockedNSURLSession
  48. responseParser:parser];
  49. }
  50. - (void)tearDown {
  51. // Put teardown code here. This method is called after the invocation of each test method in the
  52. // class.
  53. [super tearDown];
  54. }
  55. - (void)testRequestConstructionWithoutImpressionData {
  56. // This is an example of a functional test case.
  57. // Use XCTAssert and related functions to verify your tests produce the correct results.
  58. __block NSURLRequest *capturedNSURLRequest;
  59. OCMStub([self.mockedNSURLSession
  60. dataTaskWithRequest:[OCMArg checkWithBlock:^BOOL(NSURLRequest *request) {
  61. capturedNSURLRequest = request;
  62. return YES;
  63. }]
  64. completionHandler:[OCMArg any] // second parameter is the callback which we don't care in
  65. // this unit testing
  66. ]);
  67. NSString *FIDValue = @"my FID";
  68. NSString *FISToken = @"my FIS token";
  69. OCMStub([self.mockclientInfoFetcher
  70. fetchFirebaseInstallationDataWithProjectNumber:[OCMArg any]
  71. withCompletion:([OCMArg
  72. invokeBlockWithArgs:FIDValue, FISToken,
  73. [NSNull null], nil])]);
  74. NSString *osVersion = @"OS Version";
  75. OCMStub([self.mockclientInfoFetcher getOSVersion]).andReturn(osVersion);
  76. NSString *appVersion = @"App Version";
  77. OCMStub([self.mockclientInfoFetcher getAppVersion]).andReturn(appVersion);
  78. NSString *deviceLanguage = @"Language";
  79. OCMStub([self.mockclientInfoFetcher getDeviceLanguageCode]).andReturn(deviceLanguage);
  80. NSString *timezone = @"time zone";
  81. OCMStub([self.mockclientInfoFetcher getTimezone]).andReturn(timezone);
  82. [self.fetcher
  83. fetchMessagesWithImpressionList:@[]
  84. withCompletion:^(NSArray<FIRIAMMessageDefinition *> *_Nullable messages,
  85. NSNumber *nextFetchWaitTime, NSInteger discardCount,
  86. NSError *_Nullable error){
  87. // blank on purpose: it won't get triggered
  88. }];
  89. // verify that the dataTaskWithRequest:completionHandler: is triggered for NSURLSession object
  90. OCMVerify([self.mockedNSURLSession dataTaskWithRequest:[OCMArg any]
  91. completionHandler:[OCMArg any]]);
  92. XCTAssertEqualObjects(@"POST", capturedNSURLRequest.HTTPMethod);
  93. NSDictionary<NSString *, NSString *> *requestHeaders = capturedNSURLRequest.allHTTPHeaderFields;
  94. // verifying some request header fields
  95. XCTAssertEqualObjects([NSBundle mainBundle].bundleIdentifier,
  96. requestHeaders[@"X-Ios-Bundle-Identifier"]);
  97. XCTAssertEqualObjects(@"application/json", requestHeaders[@"Content-Type"]);
  98. XCTAssertEqualObjects(@"application/json", requestHeaders[@"Accept"]);
  99. // verify that the request contains the desired api key
  100. NSString *s = [NSString stringWithFormat:@"key=%@", apiKey];
  101. XCTAssertTrue([capturedNSURLRequest.URL.absoluteString containsString:s]);
  102. XCTAssertTrue([capturedNSURLRequest.URL.absoluteString containsString:projectNumber]);
  103. // verify that we the request body contains desired iid data
  104. NSError *errorJson = nil;
  105. NSDictionary *requestBodyDict =
  106. [NSJSONSerialization JSONObjectWithData:capturedNSURLRequest.HTTPBody
  107. options:kNilOptions
  108. error:&errorJson];
  109. XCTAssertEqualObjects(appId, requestBodyDict[@"requesting_client_app"][@"gmp_app_id"]);
  110. XCTAssertEqualObjects(FIDValue, requestBodyDict[@"requesting_client_app"][@"app_instance_id"]);
  111. XCTAssertEqualObjects(FISToken,
  112. requestBodyDict[@"requesting_client_app"][@"app_instance_id_token"]);
  113. XCTAssertEqualObjects(osVersion, requestBodyDict[@"client_signals"][@"platform_version"]);
  114. XCTAssertEqualObjects(appVersion, requestBodyDict[@"client_signals"][@"app_version"]);
  115. XCTAssertEqualObjects(deviceLanguage, requestBodyDict[@"client_signals"][@"language_code"]);
  116. XCTAssertEqualObjects(timezone, requestBodyDict[@"client_signals"][@"time_zone"]);
  117. }
  118. - (void)testRequestConstructionWithImpressionData {
  119. __block NSURLRequest *capturedNSURLRequest;
  120. OCMStub([self.mockedNSURLSession
  121. dataTaskWithRequest:[OCMArg checkWithBlock:^BOOL(NSURLRequest *request) {
  122. capturedNSURLRequest = request;
  123. return YES;
  124. }]
  125. completionHandler:[OCMArg any] // second parameter is the callback which we don't care in
  126. // this unit testing
  127. ]);
  128. NSString *FIDValue = @"my FID";
  129. NSString *FISToken = @"my FIS token";
  130. OCMStub([self.mockclientInfoFetcher
  131. fetchFirebaseInstallationDataWithProjectNumber:[OCMArg any]
  132. withCompletion:([OCMArg
  133. invokeBlockWithArgs:FIDValue, FISToken,
  134. [NSNull null], nil])]);
  135. // this is to test the case that only partial client signal fields are available
  136. NSString *osVersion = @"OS Version";
  137. OCMStub([self.mockclientInfoFetcher getOSVersion]).andReturn(osVersion);
  138. NSString *appVersion = @"App Version";
  139. OCMStub([self.mockclientInfoFetcher getAppVersion]).andReturn(appVersion);
  140. long impression1Timestamp = 12345;
  141. FIRIAMImpressionRecord *impression1 =
  142. [[FIRIAMImpressionRecord alloc] initWithMessageID:@"impression 1"
  143. impressionTimeInSeconds:impression1Timestamp];
  144. long impression2Timestamp = 45678;
  145. FIRIAMImpressionRecord *impression2 =
  146. [[FIRIAMImpressionRecord alloc] initWithMessageID:@"impression 2"
  147. impressionTimeInSeconds:impression2Timestamp];
  148. [self.fetcher
  149. fetchMessagesWithImpressionList:@[ impression1, impression2 ]
  150. withCompletion:^(NSArray<FIRIAMMessageDefinition *> *_Nullable messages,
  151. NSNumber *_Nullable nextFetchWaitTime,
  152. NSInteger discardCount, NSError *_Nullable error){
  153. // blank on purpose: it won't get triggered
  154. }];
  155. // verify that the captured nsurl request has expected body
  156. NSError *errorJson = nil;
  157. NSDictionary *requestBodyDict =
  158. [NSJSONSerialization JSONObjectWithData:capturedNSURLRequest.HTTPBody
  159. options:kNilOptions
  160. error:&errorJson];
  161. XCTAssertEqualObjects(impression1.messageID,
  162. requestBodyDict[@"already_seen_campaigns"][0][@"campaign_id"]);
  163. XCTAssertEqualWithAccuracy(
  164. impression1Timestamp * 1000,
  165. ((NSNumber *)requestBodyDict[@"already_seen_campaigns"][0][@"impression_timestamp_millis"])
  166. .longValue,
  167. 0.1);
  168. XCTAssertEqualObjects(impression2.messageID,
  169. requestBodyDict[@"already_seen_campaigns"][1][@"campaign_id"]);
  170. XCTAssertEqualWithAccuracy(
  171. impression2Timestamp * 1000,
  172. ((NSNumber *)requestBodyDict[@"already_seen_campaigns"][1][@"impression_timestamp_millis"])
  173. .longValue,
  174. 0.1);
  175. XCTAssertEqualObjects(osVersion, requestBodyDict[@"client_signals"][@"platform_version"]);
  176. XCTAssertEqualObjects(appVersion, requestBodyDict[@"client_signals"][@"app_version"]);
  177. // not expecting language signal since it's not mocked on mockclientInfoFetcher
  178. XCTAssertNil(requestBodyDict[@"client_signals"][@"language_code"]);
  179. }
  180. - (void)testBailoutOnFIDError {
  181. // in this test, the attempt to fetch iid data failed and as a result, we expect the whole
  182. // fetch operation attempt to fail with that error
  183. NSError *FIDError = [[NSError alloc] initWithDomain:@"Error Domain" code:100 userInfo:nil];
  184. OCMStub([self.mockclientInfoFetcher
  185. fetchFirebaseInstallationDataWithProjectNumber:[OCMArg any]
  186. withCompletion:([OCMArg invokeBlockWithArgs:[NSNull null],
  187. [NSNull null],
  188. FIDError, nil])]);
  189. XCTestExpectation *expectation =
  190. [self expectationWithDescription:@"fetch callback block triggered."];
  191. [self.fetcher
  192. fetchMessagesWithImpressionList:@[]
  193. withCompletion:^(NSArray<FIRIAMMessageDefinition *> *_Nullable messages,
  194. NSNumber *_Nullable nextFetchWaitTime,
  195. NSInteger discardCount, NSError *_Nullable error) {
  196. // expecting triggering the completion callback with error
  197. XCTAssertNil(messages);
  198. XCTAssertEqualObjects(FIDError, error);
  199. [expectation fulfill];
  200. }];
  201. [self waitForExpectationsWithTimeout:5.0 handler:nil];
  202. }
  203. @end