RCNThrottlingTests.m 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * Copyright 2019 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 "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
  19. #import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h"
  20. #import "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
  21. #import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
  22. #import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h"
  23. #import "FirebaseRemoteConfig/Tests/Unit/RCNTestUtilities.h"
  24. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  25. @import FirebaseRemoteConfigInterop;
  26. @interface RCNThrottlingTests : XCTestCase {
  27. RCNConfigContent *_configContentMock;
  28. RCNConfigSettings *_settings;
  29. RCNConfigExperiment *_experimentMock;
  30. RCNConfigFetch *_configFetch;
  31. NSString *_DBPath;
  32. }
  33. @end
  34. @implementation RCNThrottlingTests
  35. - (void)setUp {
  36. [super setUp];
  37. // Put setup code here. This method is called before the invocation of each test method in the
  38. // class.
  39. if (![FIRApp defaultApp]) {
  40. [FIRApp configure];
  41. }
  42. [[FIRConfiguration sharedInstance] setLoggerLevel:FIRLoggerLevelMax];
  43. // Get a test database.
  44. _DBPath = [RCNTestUtilities remoteConfigPathForTestDatabase];
  45. id classMock = OCMClassMock([RCNConfigDBManager class]);
  46. OCMStub([classMock remoteConfigPathForDatabase]).andReturn(_DBPath);
  47. RCNConfigDBManager *DBManager = [[RCNConfigDBManager alloc] init];
  48. _configContentMock = OCMClassMock([RCNConfigContent class]);
  49. _settings = [[RCNConfigSettings alloc]
  50. initWithDatabaseManager:DBManager
  51. namespace:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform
  52. app:[FIRApp defaultApp]];
  53. _experimentMock = OCMClassMock([RCNConfigExperiment class]);
  54. dispatch_queue_t _queue = dispatch_queue_create(
  55. "com.google.GoogleConfigService.FIRRemoteConfigTest", DISPATCH_QUEUE_SERIAL);
  56. _configFetch = [[RCNConfigFetch alloc]
  57. initWithContent:_configContentMock
  58. DBManager:DBManager
  59. settings:_settings
  60. experiment:_experimentMock
  61. queue:_queue
  62. namespace:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform
  63. app:[FIRApp defaultApp]];
  64. }
  65. - (void)mockFetchResponseWithStatusCode:(NSInteger)statusCode {
  66. // Mock successful network fetches with an empty config response.
  67. RCNConfigFetcherTestBlock testBlock = ^(RCNConfigFetcherCompletion completion) {
  68. NSURL *url = [[NSURL alloc] initWithString:@"https://google.com"];
  69. NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url
  70. statusCode:statusCode
  71. HTTPVersion:nil
  72. headerFields:@{@"etag" : @"etag1"}];
  73. NSData *data =
  74. [NSJSONSerialization dataWithJSONObject:@{@"key1" : @"val1", @"state" : @"UPDATE"}
  75. options:0
  76. error:nil];
  77. completion(data, response, nil);
  78. };
  79. [RCNConfigFetch setGlobalTestBlock:testBlock];
  80. }
  81. /// Regular case of calling fetch should succeed.
  82. - (void)testRegularFetchDoesNotGetThrottled {
  83. [self mockFetchResponseWithStatusCode:200];
  84. XCTestExpectation *expectation = [self expectationWithDescription:@"throttlingExpectation"];
  85. [_configFetch fetchAllConfigsWithExpirationDuration:0
  86. completionHandler:^(FIRRemoteConfigFetchStatus status,
  87. NSError *_Nullable error) {
  88. XCTAssertNil(error);
  89. XCTAssertEqual(FIRRemoteConfigFetchStatusSuccess, status);
  90. [expectation fulfill];
  91. }];
  92. // TODO(dmandar): Investigate using a smaller timeout. b/122674668
  93. [self waitForExpectationsWithTimeout:4.0 handler:nil];
  94. }
  95. - (void)testServerThrottleHTTP429ReturnsAThrottledError {
  96. [self mockFetchResponseWithStatusCode:429];
  97. XCTestExpectation *expectation = [self expectationWithDescription:@"throttlingExpectation"];
  98. [_configFetch
  99. fetchAllConfigsWithExpirationDuration:0
  100. completionHandler:^(FIRRemoteConfigFetchStatus status,
  101. NSError *_Nullable error) {
  102. XCTAssertNotNil(error);
  103. NSNumber *endTime = error.userInfo[@"error_throttled_end_time_seconds"];
  104. XCTAssertGreaterThanOrEqual([endTime doubleValue],
  105. [[NSDate date] timeIntervalSinceNow]);
  106. XCTAssertEqual(FIRRemoteConfigFetchStatusThrottled, status);
  107. [expectation fulfill];
  108. }];
  109. [self waitForExpectationsWithTimeout:4.0 handler:nil];
  110. }
  111. - (void)testServerInternalError500ReturnsAThrottledError {
  112. [self mockFetchResponseWithStatusCode:500];
  113. XCTestExpectation *expectation = [self expectationWithDescription:@"throttlingExpectation"];
  114. [_configFetch
  115. fetchAllConfigsWithExpirationDuration:0
  116. completionHandler:^(FIRRemoteConfigFetchStatus status,
  117. NSError *_Nullable error) {
  118. XCTAssertNotNil(error);
  119. NSNumber *endTime = error.userInfo[@"error_throttled_end_time_seconds"];
  120. XCTAssertGreaterThanOrEqual([endTime doubleValue],
  121. [[NSDate date] timeIntervalSinceNow]);
  122. XCTAssertEqual(FIRRemoteConfigFetchStatusThrottled, status);
  123. [expectation fulfill];
  124. }];
  125. [self waitForExpectationsWithTimeout:4.0 handler:nil];
  126. }
  127. - (void)testServerUnavailableError503ReturnsAThrottledError {
  128. [self mockFetchResponseWithStatusCode:503];
  129. XCTestExpectation *expectation = [self expectationWithDescription:@"throttlingExpectation"];
  130. [_configFetch
  131. fetchAllConfigsWithExpirationDuration:0
  132. completionHandler:^(FIRRemoteConfigFetchStatus status,
  133. NSError *_Nullable error) {
  134. XCTAssertNotNil(error);
  135. NSNumber *endTime = error.userInfo[@"error_throttled_end_time_seconds"];
  136. XCTAssertGreaterThanOrEqual([endTime doubleValue],
  137. [[NSDate date] timeIntervalSinceNow]);
  138. XCTAssertEqual(FIRRemoteConfigFetchStatusThrottled, status);
  139. [expectation fulfill];
  140. }];
  141. [self waitForExpectationsWithTimeout:4.0 handler:nil];
  142. }
  143. - (void)testThrottleReturnsAThrottledErrorAndThrottlesSubsequentRequests {
  144. [self mockFetchResponseWithStatusCode:429];
  145. XCTestExpectation *expectation = [self expectationWithDescription:@"throttlingExpectation"];
  146. XCTestExpectation *expectation2 = [self expectationWithDescription:@"throttlingExpectation2"];
  147. [_configFetch
  148. fetchAllConfigsWithExpirationDuration:0
  149. completionHandler:^(FIRRemoteConfigFetchStatus status,
  150. NSError *_Nullable error) {
  151. XCTAssertNotNil(error);
  152. NSNumber *endTime = error.userInfo[@"error_throttled_end_time_seconds"];
  153. XCTAssertGreaterThanOrEqual([endTime doubleValue],
  154. [[NSDate date] timeIntervalSinceNow]);
  155. XCTAssertEqual(FIRRemoteConfigFetchStatusThrottled, status);
  156. [expectation fulfill];
  157. // follow-up request.
  158. [_configFetch
  159. fetchAllConfigsWithExpirationDuration:0
  160. completionHandler:^(
  161. FIRRemoteConfigFetchStatus status,
  162. NSError *_Nullable error) {
  163. XCTAssertNotNil(error);
  164. NSNumber *endTime =
  165. error.userInfo
  166. [@"error_throttled_end_time_seconds"];
  167. XCTAssertGreaterThanOrEqual(
  168. [endTime doubleValue],
  169. [[NSDate date] timeIntervalSinceNow]);
  170. XCTAssertEqual(
  171. FIRRemoteConfigFetchStatusThrottled,
  172. status);
  173. [expectation2 fulfill];
  174. }];
  175. }];
  176. [self waitForExpectationsWithTimeout:4.0 handler:nil];
  177. }
  178. @end