FIRIAMMsgFetcherUsingRestfulTests.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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 "FIRIAMFetchFlow.h"
  19. #import "FIRIAMMessageDefinition.h"
  20. #import "FIRIAMMsgFetcherUsingRestful.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 *iidValue = @"my iid";
  68. NSString *iidToken = @"my iid token";
  69. OCMStub([self.mockclientInfoFetcher
  70. fetchFirebaseIIDDataWithProjectNumber:[OCMArg any]
  71. withCompletion:([OCMArg invokeBlockWithArgs:iidValue, iidToken,
  72. [NSNull null], nil])]);
  73. NSString *osVersion = @"OS Version";
  74. OCMStub([self.mockclientInfoFetcher getOSVersion]).andReturn(osVersion);
  75. NSString *appVersion = @"App Version";
  76. OCMStub([self.mockclientInfoFetcher getAppVersion]).andReturn(appVersion);
  77. NSString *deviceLanguage = @"Language";
  78. OCMStub([self.mockclientInfoFetcher getDeviceLanguageCode]).andReturn(deviceLanguage);
  79. NSString *timezone = @"time zone";
  80. OCMStub([self.mockclientInfoFetcher getTimezone]).andReturn(timezone);
  81. [self.fetcher
  82. fetchMessagesWithImpressionList:@[]
  83. withCompletion:^(NSArray<FIRIAMMessageDefinition *> *_Nullable messages,
  84. NSNumber *nextFetchWaitTime, NSInteger discardCount,
  85. NSError *_Nullable error){
  86. // blank on purpose: it won't get triggered
  87. }];
  88. // verify that the dataTaskWithRequest:completionHandler: is triggered for NSURLSession object
  89. OCMVerify([self.mockedNSURLSession dataTaskWithRequest:[OCMArg any]
  90. completionHandler:[OCMArg any]]);
  91. XCTAssertEqualObjects(@"POST", capturedNSURLRequest.HTTPMethod);
  92. NSDictionary<NSString *, NSString *> *requestHeaders = capturedNSURLRequest.allHTTPHeaderFields;
  93. // verifying some request header fields
  94. XCTAssertEqualObjects([NSBundle mainBundle].bundleIdentifier,
  95. requestHeaders[@"X-Ios-Bundle-Identifier"]);
  96. XCTAssertEqualObjects(@"application/json", requestHeaders[@"Content-Type"]);
  97. XCTAssertEqualObjects(@"application/json", requestHeaders[@"Accept"]);
  98. // verify that the request contains the desired api key
  99. NSString *s = [NSString stringWithFormat:@"key=%@", apiKey];
  100. XCTAssertTrue([capturedNSURLRequest.URL.absoluteString containsString:s]);
  101. XCTAssertTrue([capturedNSURLRequest.URL.absoluteString containsString:projectNumber]);
  102. // verify that we the request body contains desired iid data
  103. NSError *errorJson = nil;
  104. NSDictionary *requestBodyDict =
  105. [NSJSONSerialization JSONObjectWithData:capturedNSURLRequest.HTTPBody
  106. options:kNilOptions
  107. error:&errorJson];
  108. XCTAssertEqualObjects(appId, requestBodyDict[@"requesting_client_app"][@"gmp_app_id"]);
  109. XCTAssertEqualObjects(iidValue, requestBodyDict[@"requesting_client_app"][@"app_instance_id"]);
  110. XCTAssertEqualObjects(iidToken,
  111. requestBodyDict[@"requesting_client_app"][@"app_instance_id_token"]);
  112. XCTAssertEqualObjects(osVersion, requestBodyDict[@"client_signals"][@"platform_version"]);
  113. XCTAssertEqualObjects(appVersion, requestBodyDict[@"client_signals"][@"app_version"]);
  114. XCTAssertEqualObjects(deviceLanguage, requestBodyDict[@"client_signals"][@"language_code"]);
  115. XCTAssertEqualObjects(timezone, requestBodyDict[@"client_signals"][@"time_zone"]);
  116. }
  117. - (void)testRequestConstructionWithImpressionData {
  118. __block NSURLRequest *capturedNSURLRequest;
  119. OCMStub([self.mockedNSURLSession
  120. dataTaskWithRequest:[OCMArg checkWithBlock:^BOOL(NSURLRequest *request) {
  121. capturedNSURLRequest = request;
  122. return YES;
  123. }]
  124. completionHandler:[OCMArg any] // second parameter is the callback which we don't care in
  125. // this unit testing
  126. ]);
  127. NSString *iidValue = @"my iid";
  128. NSString *iidToken = @"my iid token";
  129. OCMStub([self.mockclientInfoFetcher
  130. fetchFirebaseIIDDataWithProjectNumber:[OCMArg any]
  131. withCompletion:([OCMArg invokeBlockWithArgs:iidValue, iidToken,
  132. [NSNull null], nil])]);
  133. // this is to test the case that only partial client signal fields are available
  134. NSString *osVersion = @"OS Version";
  135. OCMStub([self.mockclientInfoFetcher getOSVersion]).andReturn(osVersion);
  136. NSString *appVersion = @"App Version";
  137. OCMStub([self.mockclientInfoFetcher getAppVersion]).andReturn(appVersion);
  138. long impression1Timestamp = 12345;
  139. FIRIAMImpressionRecord *impression1 =
  140. [[FIRIAMImpressionRecord alloc] initWithMessageID:@"impression 1"
  141. impressionTimeInSeconds:impression1Timestamp];
  142. long impression2Timestamp = 45678;
  143. FIRIAMImpressionRecord *impression2 =
  144. [[FIRIAMImpressionRecord alloc] initWithMessageID:@"impression 2"
  145. impressionTimeInSeconds:impression2Timestamp];
  146. [self.fetcher
  147. fetchMessagesWithImpressionList:@[ impression1, impression2 ]
  148. withCompletion:^(NSArray<FIRIAMMessageDefinition *> *_Nullable messages,
  149. NSNumber *_Nullable nextFetchWaitTime,
  150. NSInteger discardCount, NSError *_Nullable error){
  151. // blank on purpose: it won't get triggered
  152. }];
  153. // verify that the captured nsurl request has expected body
  154. NSError *errorJson = nil;
  155. NSDictionary *requestBodyDict =
  156. [NSJSONSerialization JSONObjectWithData:capturedNSURLRequest.HTTPBody
  157. options:kNilOptions
  158. error:&errorJson];
  159. XCTAssertEqualObjects(impression1.messageID,
  160. requestBodyDict[@"already_seen_campaigns"][0][@"campaign_id"]);
  161. XCTAssertEqualWithAccuracy(
  162. impression1Timestamp * 1000,
  163. ((NSNumber *)requestBodyDict[@"already_seen_campaigns"][0][@"impression_timestamp_millis"])
  164. .longValue,
  165. 0.1);
  166. XCTAssertEqualObjects(impression2.messageID,
  167. requestBodyDict[@"already_seen_campaigns"][1][@"campaign_id"]);
  168. XCTAssertEqualWithAccuracy(
  169. impression2Timestamp * 1000,
  170. ((NSNumber *)requestBodyDict[@"already_seen_campaigns"][1][@"impression_timestamp_millis"])
  171. .longValue,
  172. 0.1);
  173. XCTAssertEqualObjects(osVersion, requestBodyDict[@"client_signals"][@"platform_version"]);
  174. XCTAssertEqualObjects(appVersion, requestBodyDict[@"client_signals"][@"app_version"]);
  175. // not expexting language siganl since it's not mocked on mockclientInfoFetcher
  176. XCTAssertNil(requestBodyDict[@"client_signals"][@"language_code"]);
  177. }
  178. - (void)testBailoutOnIIDError {
  179. // in this test, the attempt to fetch iid data failed and as a result, we expect the whole
  180. // fetch operation attempt to fail with that error
  181. NSError *iidError = [[NSError alloc] initWithDomain:@"Error Domain" code:100 userInfo:nil];
  182. OCMStub([self.mockclientInfoFetcher
  183. fetchFirebaseIIDDataWithProjectNumber:[OCMArg any]
  184. withCompletion:([OCMArg invokeBlockWithArgs:[NSNull null],
  185. [NSNull null], iidError,
  186. nil])]);
  187. XCTestExpectation *expectation =
  188. [self expectationWithDescription:@"fetch callback block triggered."];
  189. [self.fetcher
  190. fetchMessagesWithImpressionList:@[]
  191. withCompletion:^(NSArray<FIRIAMMessageDefinition *> *_Nullable messages,
  192. NSNumber *_Nullable nextFetchWaitTime,
  193. NSInteger discardCount, NSError *_Nullable error) {
  194. // expecting triggering the completion callback with error
  195. XCTAssertNil(messages);
  196. XCTAssertEqualObjects(iidError, error);
  197. [expectation fulfill];
  198. }];
  199. [self waitForExpectationsWithTimeout:5.0 handler:nil];
  200. }
  201. @end