1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <string>
11 #include <vector>
12 
13 #include "base/base64.h"
14 #include "base/command_line.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/run_loop.h"
17 #include "base/stl_util.h"
18 #include "base/test/bind.h"
19 #include "base/test/metrics/histogram_tester.h"
20 #include "base/test/mock_entropy_provider.h"
21 #include "base/test/scoped_feature_list.h"
22 #include "base/test/task_environment.h"
23 #include "base/time/default_clock.h"
24 #include "base/time/time.h"
25 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h"
26 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
27 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
28 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
29 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
30 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
31 #include "components/data_reduction_proxy/proto/client_config.pb.h"
32 #include "components/prefs/pref_registry_simple.h"
33 #include "net/base/network_change_notifier.h"
34 #include "net/base/proxy_server.h"
35 #include "net/http/http_request_headers.h"
36 #include "net/http/http_response_headers.h"
37 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
38 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
39 #include "services/network/test/test_url_loader_factory.h"
40 #include "services/network/test/test_utils.h"
41 #include "testing/gmock/include/gmock/gmock.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43 #include "url/gurl.h"
44 
45 namespace {
46 
47 // The following values should match those in
48 // DataReductionProxyConfigServiceClientTest.config_:
49 const char kSuccessSessionKey[] = "SecretSessionKey";
50 
51 // The following values should match those in
52 // DataReductionProxyConfigServiceClientTest.previous_config_:
53 const char kOldSuccessSessionKey[] = "OldSecretSessionKey";
54 
55 // The following values should match those in
56 // DataReductionProxyConfigServiceClientTest.loaded_config_:
57 const char kPersistedSessionKey[] = "PersistedSessionKey";
58 
59 // Duration (in seconds) after which the config should be refreshed.
60 const int kConfigRefreshDurationSeconds = 600;
61 
62 #if defined(OS_ANDROID)
63 // Maximum duration  to wait before fetching the config, while the application
64 // is in background.
65 const uint32_t kMaxBackgroundFetchIntervalSeconds = 6 * 60 * 60;  // 6 hours.
66 #endif
67 
68 }  // namespace
69 
70 namespace data_reduction_proxy {
71 
72 class DataReductionProxyConfigServiceClientTest : public testing::Test {
73  protected:
DataReductionProxyConfigServiceClientTest(bool enable_aggressive_config_fetch_feature=false)74   DataReductionProxyConfigServiceClientTest(
75       bool enable_aggressive_config_fetch_feature = false)
76       : test_shared_url_loader_factory_(
77             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
78                 &test_url_loader_factory_)) {
79     if (enable_aggressive_config_fetch_feature) {
80       scoped_feature_list_.InitAndEnableFeature(
81           features::kDataReductionProxyAggressiveConfigFetch);
82     } else {
83       scoped_feature_list_.InitAndDisableFeature(
84           features::kDataReductionProxyAggressiveConfigFetch);
85     }
86   }
87 
SetUp()88   void SetUp() override {
89     testing::Test::SetUp();
90 
91     // Install an interceptor here to process the queue of responses
92     // (fed by calls to AddMock{Success,PreviousSuccess,Failure}.
93     test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
94         [&](const network::ResourceRequest& request) {
95           // Some tests trigger loading, without having an respective
96           // mock response set. Ignore such cases.
97           if (mock_responses_.size() <= curr_mock_response_index_) {
98             test_url_loader_factory_.pending_requests()->clear();
99             return;
100           }
101           test_url_loader_factory_.ClearResponses();
102           test_url_loader_factory_.AddResponse(
103               request.url.spec(),
104               mock_responses_[curr_mock_response_index_].response,
105               mock_responses_[curr_mock_response_index_].http_code);
106           curr_mock_response_index_++;
107           RunUntilIdle();
108         }));
109   }
110 
Init()111   void Init() {
112     test_context_ = DataReductionProxyTestContext::Builder()
113                         .WithURLLoaderFactory(test_shared_url_loader_factory_)
114                         .WithMockRequestOptions()
115                         .WithTestConfigClient()
116                         .SkipSettingsInitialization()
117                         .Build();
118 
119     test_context_->InitSettings();
120     ResetBackoffEntryReleaseTime();
121     test_context_->test_config_client()->SetNow(base::Time::UnixEpoch());
122     test_context_->test_config_client()->SetEnabled(true);
123     test_context_->test_config_client()->SetConfigServiceURL(
124         GURL("http://configservice.com"));
125 
126     // Set up the various test ClientConfigs.
127     ClientConfig config = CreateClientConfig(kSuccessSessionKey,
128                                              kConfigRefreshDurationSeconds, 0);
129     config.SerializeToString(&config_);
130     encoded_config_ = EncodeConfig(config);
131 
132     ClientConfig previous_config = CreateClientConfig(
133         kOldSuccessSessionKey, kConfigRefreshDurationSeconds, 0);
134     previous_config.SerializeToString(&previous_config_);
135 
136     ClientConfig persisted = CreateClientConfig(
137         kPersistedSessionKey, kConfigRefreshDurationSeconds, 0);
138     loaded_config_ = EncodeConfig(persisted);
139 
140     ClientConfig ignore_block_list_config = CreateClientConfig(
141         kSuccessSessionKey, kConfigRefreshDurationSeconds, 0);
142     ignore_block_list_encoded_config_ = EncodeConfig(ignore_block_list_config);
143 
144     ClientConfig no_proxies_config;
145     no_proxies_config.set_session_key(kSuccessSessionKey);
146     no_proxies_config.mutable_refresh_duration()->set_seconds(
147         kConfigRefreshDurationSeconds);
148     no_proxies_config.mutable_refresh_duration()->set_nanos(0);
149     no_proxies_config_ = EncodeConfig(no_proxies_config);
150   }
151 
ResetBackoffEntryReleaseTime()152   void ResetBackoffEntryReleaseTime() {
153     config_client()->SetCustomReleaseTime(base::TimeTicks::UnixEpoch());
154   }
155 
VerifyRemoteSuccess(bool expect_secure_proxies)156   void VerifyRemoteSuccess(bool expect_secure_proxies) {
157     EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
158               config_client()->GetDelay());
159     EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession());
160     // The config should be persisted on the pref.
161     EXPECT_EQ(encoded_config(), persisted_config());
162   }
163 
VerifyRemoteSuccessWithOldConfig()164   void VerifyRemoteSuccessWithOldConfig() {
165     EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
166               config_client()->GetDelay());
167     EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession());
168   }
169 
VerifySuccessWithLoadedConfig(bool expect_secure_proxies)170   void VerifySuccessWithLoadedConfig(bool expect_secure_proxies) {
171     EXPECT_EQ(kPersistedSessionKey, request_options()->GetSecureSession());
172   }
173 
config_client()174   TestDataReductionProxyConfigServiceClient* config_client() {
175     return test_context_->test_config_client();
176   }
177 
request_options()178   MockDataReductionProxyRequestOptions* request_options() {
179     return test_context_->mock_request_options();
180   }
181 
RunUntilIdle()182   void RunUntilIdle() { test_context_->RunUntilIdle(); }
183 
AddMockSuccess()184   void AddMockSuccess() {
185     mock_responses_.push_back({success_response(), net::HTTP_OK});
186   }
187 
AddMockPreviousSuccess()188   void AddMockPreviousSuccess() {
189     mock_responses_.push_back({previous_success_response(), net::HTTP_OK});
190   }
191 
AddMockFailure()192   void AddMockFailure() {
193     mock_responses_.push_back({std::string(), net::HTTP_NOT_FOUND});
194   }
195 
persisted_config() const196   std::string persisted_config() const {
197     return test_context_->pref_service()->GetString(
198         prefs::kDataReductionProxyConfig);
199   }
200 
persisted_config_retrieval_time() const201   base::Time persisted_config_retrieval_time() const {
202     return base::Time() +
203            base::TimeDelta::FromMicroseconds(
204                test_context_->pref_service()->GetInt64(
205                    prefs::kDataReductionProxyLastConfigRetrievalTime));
206   }
207 
success_response() const208   const std::string& success_response() const { return config_; }
209 
encoded_config() const210   const std::string& encoded_config() const { return encoded_config_; }
211 
previous_success_response() const212   const std::string& previous_success_response() const {
213     return previous_config_;
214   }
ignore_block_list_encoded_config() const215   const std::string& ignore_block_list_encoded_config() const {
216     return ignore_block_list_encoded_config_;
217   }
no_proxies_config() const218   const std::string& no_proxies_config() const { return no_proxies_config_; }
219 
loaded_config() const220   const std::string& loaded_config() const { return loaded_config_; }
221 
222  private:
223   base::test::ScopedFeatureList scoped_feature_list_;
224   base::test::SingleThreadTaskEnvironment task_environment_;
225 
226   network::TestURLLoaderFactory test_url_loader_factory_;
227   scoped_refptr<network::SharedURLLoaderFactory>
228       test_shared_url_loader_factory_;
229 
230  protected:
231   std::unique_ptr<DataReductionProxyTestContext> test_context_;
232 
233  private:
234   std::unique_ptr<DataReductionProxyRequestOptions> request_options_;
235 
236   // A configuration from the current remote request. The encoded version is
237   // also stored.
238   std::string config_;
239   std::string encoded_config_;
240 
241   // A configuration from a previous remote request.
242   std::string previous_config_;
243 
244   // An encoded config that represents a previously saved configuration.
245   std::string loaded_config_;
246 
247   // A configuration where the block list rules are ignored.
248   std::string ignore_block_list_encoded_config_;
249 
250   // A configuration where no proxies are configured.
251   std::string no_proxies_config_;
252 
253   struct MockResponse {
254     std::string response;
255     net::HttpStatusCode http_code;
256   };
257   std::vector<MockResponse> mock_responses_;
258   size_t curr_mock_response_index_ = 0;
259 
260   DISALLOW_COPY_AND_ASSIGN(DataReductionProxyConfigServiceClientTest);
261 };
262 
263 // Tests that backoff values increases with every time config cannot be fetched.
TEST_F(DataReductionProxyConfigServiceClientTest,EnsureBackoff)264 TEST_F(DataReductionProxyConfigServiceClientTest, EnsureBackoff) {
265   Init();
266   // Use a local/static config.
267   base::HistogramTester histogram_tester;
268   AddMockFailure();
269   AddMockFailure();
270   AddMockSuccess();
271 
272   EXPECT_EQ(0, config_client()->failed_attempts_before_success());
273 
274   // First attempt should be unsuccessful.
275   config_client()->RetrieveConfig();
276   RunUntilIdle();
277   EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
278 
279 #if defined(OS_ANDROID)
280   EXPECT_FALSE(config_client()->foreground_fetch_pending());
281 #endif
282 
283   // Second attempt should be unsuccessful and backoff time should increase.
284   config_client()->RetrieveConfig();
285   RunUntilIdle();
286   EXPECT_EQ(base::TimeDelta::FromSeconds(90), config_client()->GetDelay());
287   EXPECT_TRUE(persisted_config().empty());
288   EXPECT_TRUE(persisted_config_retrieval_time().is_null());
289 
290 #if defined(OS_ANDROID)
291   EXPECT_FALSE(config_client()->foreground_fetch_pending());
292 #endif
293 
294   EXPECT_EQ(2, config_client()->failed_attempts_before_success());
295   histogram_tester.ExpectTotalCount(
296       "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 0);
297 }
298 
299 // Tests that the config is read successfully on the first attempt.
TEST_F(DataReductionProxyConfigServiceClientTest,RemoteConfigSuccess)300 TEST_F(DataReductionProxyConfigServiceClientTest, RemoteConfigSuccess) {
301   Init();
302   base::HistogramTester histogram_tester;
303 
304   AddMockSuccess();
305   config_client()->RetrieveConfig();
306   RunUntilIdle();
307   VerifyRemoteSuccess(true);
308   histogram_tester.ExpectTotalCount(
309       "DataReductionProxy.ConfigService.HttpRequestRTT", 1);
310 #if defined(OS_ANDROID)
311   EXPECT_FALSE(config_client()->foreground_fetch_pending());
312 #endif
313 }
314 
315 // Tests that the config is read successfully on the first attempt, and secure
316 // proxies are not used if the secure check failed.
TEST_F(DataReductionProxyConfigServiceClientTest,RemoteConfigSuccessWithSecureCheckFail)317 TEST_F(DataReductionProxyConfigServiceClientTest,
318        RemoteConfigSuccessWithSecureCheckFail) {
319   Init();
320   AddMockSuccess();
321   config_client()->RetrieveConfig();
322   RunUntilIdle();
323   VerifyRemoteSuccess(false);
324 #if defined(OS_ANDROID)
325   EXPECT_FALSE(config_client()->foreground_fetch_pending());
326 #endif
327 }
328 
329 
330 // Tests that the config is read successfully on the second attempt.
TEST_F(DataReductionProxyConfigServiceClientTest,RemoteConfigSuccessAfterFailure)331 TEST_F(DataReductionProxyConfigServiceClientTest,
332        RemoteConfigSuccessAfterFailure) {
333   Init();
334   base::HistogramTester histogram_tester;
335 
336   AddMockFailure();
337   AddMockSuccess();
338 
339   EXPECT_EQ(0, config_client()->failed_attempts_before_success());
340 
341   // First attempt should be unsuccessful.
342   config_client()->RetrieveConfig();
343   RunUntilIdle();
344   EXPECT_EQ(1, config_client()->failed_attempts_before_success());
345   EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
346   EXPECT_TRUE(request_options()->GetSecureSession().empty());
347 
348   // Second attempt should be successful.
349   config_client()->RetrieveConfig();
350   RunUntilIdle();
351   VerifyRemoteSuccess(true);
352   EXPECT_EQ(0, config_client()->failed_attempts_before_success());
353 
354   histogram_tester.ExpectUniqueSample(
355       "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 1,
356       1);
357   histogram_tester.ExpectTotalCount(
358       "DataReductionProxy.ConfigService.HttpRequestRTT", 1);
359 }
360 
361 // Verifies that the config is fetched successfully after IP address changes.
TEST_F(DataReductionProxyConfigServiceClientTest,OnIPAddressChange)362 TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChange) {
363   Init();
364   const struct {
365     bool secure_proxies_allowed;
366   } tests[] = {
367       {
368           true,
369       },
370       {
371           false,
372       },
373   };
374 
375   for (size_t i = 0; i < base::size(tests); ++i) {
376     config_client()->RetrieveConfig();
377 
378     const int kFailureCount = 5;
379 
380     for (int i = 0; i < kFailureCount; ++i) {
381       AddMockFailure();
382       config_client()->RetrieveConfig();
383       RunUntilIdle();
384     }
385 
386     // Verify that the backoff increased exponentially.
387     EXPECT_EQ(base::TimeDelta::FromSeconds(2430),
388               config_client()->GetDelay());  // 2430 = 30 * 3^(5-1)
389     EXPECT_EQ(kFailureCount, config_client()->GetBackoffErrorCount());
390 
391     // IP address change should reset.
392     config_client()->OnConnectionChanged(
393         network::mojom::ConnectionType::CONNECTION_WIFI);
394     EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
395     EXPECT_EQ(i == 0, persisted_config().empty());
396     EXPECT_EQ(i == 0, persisted_config_retrieval_time().is_null());
397     ResetBackoffEntryReleaseTime();
398 
399     // Fetching the config should be successful.
400     AddMockSuccess();
401     config_client()->RetrieveConfig();
402     RunUntilIdle();
403     VerifyRemoteSuccess(tests[i].secure_proxies_allowed);
404   }
405 }
406 
407 // Verifies that the config is fetched successfully after IP address changes,
408 // and secure proxies are not used if the secure proxy check fails later after
409 // some time.
TEST_F(DataReductionProxyConfigServiceClientTest,OnIPAddressChangeDelayedSecureProxyCheckFail)410 TEST_F(DataReductionProxyConfigServiceClientTest,
411        OnIPAddressChangeDelayedSecureProxyCheckFail) {
412   Init();
413 
414   config_client()->RetrieveConfig();
415 
416   const int kFailureCount = 5;
417 
418   for (int i = 0; i < kFailureCount; ++i) {
419     AddMockFailure();
420     config_client()->RetrieveConfig();
421     RunUntilIdle();
422   }
423 
424   // Verify that the backoff increased exponentially.
425   EXPECT_EQ(base::TimeDelta::FromSeconds(2430),
426             config_client()->GetDelay());  // 2430 = 30 * 3^(5-1)
427   EXPECT_EQ(kFailureCount, config_client()->GetBackoffErrorCount());
428 
429   // IP address change should reset.
430   config_client()->OnConnectionChanged(
431       network::mojom::ConnectionType::CONNECTION_WIFI);
432   EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
433   EXPECT_TRUE(persisted_config().empty());
434   EXPECT_TRUE(persisted_config_retrieval_time().is_null());
435   ResetBackoffEntryReleaseTime();
436 
437   // Fetching the config should be successful.
438   AddMockSuccess();
439   config_client()->RetrieveConfig();
440   RunUntilIdle();
441   VerifyRemoteSuccess(true);
442 
443 }
444 
445 // Verifies that fetching the remote config has no effect if the config client
446 // is disabled.
TEST_F(DataReductionProxyConfigServiceClientTest,OnIPAddressChangeDisabled)447 TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChangeDisabled) {
448   Init();
449   config_client()->SetEnabled(false);
450   config_client()->RetrieveConfig();
451   EXPECT_TRUE(request_options()->GetSecureSession().empty());
452 
453   enum : int { kFailureCount = 5 };
454 
455   for (int i = 0; i < kFailureCount; ++i) {
456     config_client()->RetrieveConfig();
457     RunUntilIdle();
458     EXPECT_TRUE(request_options()->GetSecureSession().empty());
459   }
460 
461   EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
462   config_client()->OnConnectionChanged(
463       network::mojom::ConnectionType::CONNECTION_WIFI);
464   EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
465 
466   config_client()->RetrieveConfig();
467   RunUntilIdle();
468 
469   EXPECT_TRUE(request_options()->GetSecureSession().empty());
470 }
471 
472 // Verifies that the persisted client config is fetched from the disk at
473 // startup, and that the persisted client config is used only if it is less
474 // than 24 hours old.
TEST_F(DataReductionProxyConfigServiceClientTest,ValidatePersistedClientConfig)475 TEST_F(DataReductionProxyConfigServiceClientTest,
476        ValidatePersistedClientConfig) {
477   Init();
478 
479   const struct {
480     base::Optional<base::TimeDelta> staleness;
481     bool expect_valid_config;
482   } tests[] = {
483       {
484           base::nullopt,
485           true,
486       },
487       {
488           base::TimeDelta::FromHours(25),
489           false,
490       },
491       {
492           base::TimeDelta::FromHours(1),
493           true,
494       },
495   };
496 
497   for (const auto& test : tests) {
498     base::HistogramTester histogram_tester;
499     // Reset the state.
500     request_options()->Invalidate();
501     test_context_->pref_service()->ClearPref(
502         prefs::kDataReductionProxyLastConfigRetrievalTime);
503     RunUntilIdle();
504     EXPECT_TRUE(request_options()->GetSecureSession().empty());
505 
506     // Apply a valid config. This should be stored on the disk.
507     AddMockSuccess();
508     config_client()->RetrieveConfig();
509 
510     RunUntilIdle();
511     EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession());
512 
513     if (test.staleness) {
514       base::TimeDelta last_config_retrieval_time =
515           base::Time::Now() - base::Time() - test.staleness.value();
516 
517       test_context_->pref_service()->SetInt64(
518           prefs::kDataReductionProxyLastConfigRetrievalTime,
519           last_config_retrieval_time.InMicroseconds());
520       test_context_->pref_service()->SchedulePendingLossyWrites();
521       test_context_->pref_service()->CommitPendingWrite();
522     }
523 
524     RunUntilIdle();
525     EXPECT_FALSE(persisted_config().empty());
526     EXPECT_FALSE(persisted_config_retrieval_time().is_null());
527 
528     // Simulate startup which should cause the empty persisted client config to
529     // be read from the disk.
530     config_client()->SetRemoteConfigApplied(false);
531     request_options()->Invalidate();
532     test_context_->data_reduction_proxy_service()->ReadPersistedClientConfig();
533     RunUntilIdle();
534     EXPECT_NE(test.expect_valid_config,
535               request_options()->GetSecureSession().empty());
536     if (test.expect_valid_config) {
537       EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession());
538     }
539   }
540 }
541 
542 // Tests that the config is overriden by kDataReductionProxyServerClientConfig.
TEST_F(DataReductionProxyConfigServiceClientTest,ApplyClientConfigOverride)543 TEST_F(DataReductionProxyConfigServiceClientTest, ApplyClientConfigOverride) {
544   const std::string override_key = "OverrideSecureSession";
545   std::string encoded_config;
546   ClientConfig config =
547       CreateClientConfig(override_key, kConfigRefreshDurationSeconds, 0);
548   config.SerializeToString(&encoded_config);
549   base::Base64Encode(encoded_config, &encoded_config);
550 
551   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
552       data_reduction_proxy::switches::kDataReductionProxyServerClientConfig,
553       encoded_config);
554   Init();
555 
556   AddMockSuccess();
557   config_client()->RetrieveConfig();
558   RunUntilIdle();
559   // Make sure repeated fetches won't change the overridden config.
560   config_client()->RetrieveConfig();
561   RunUntilIdle();
562   EXPECT_EQ(request_options()->GetSecureSession(), override_key);
563 }
564 
565 // Tests that remote config can be applied after the serialized config has
566 // been applied.
TEST_F(DataReductionProxyConfigServiceClientTest,ApplySerializedConfig)567 TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfig) {
568   Init();
569   AddMockSuccess();
570 
571   config_client()->ApplySerializedConfig(loaded_config());
572   VerifySuccessWithLoadedConfig(true);
573   EXPECT_TRUE(persisted_config().empty());
574 
575   config_client()->RetrieveConfig();
576   RunUntilIdle();
577   VerifyRemoteSuccess(true);
578 }
579 
580 // Tests that remote config can be applied after the serialized config has
581 // been applied. Verifies that if the secure transport is restricted, then the
582 // secure proxies are not used.
TEST_F(DataReductionProxyConfigServiceClientTest,ApplySerializedConfigWithSecureTransportRestricted)583 TEST_F(DataReductionProxyConfigServiceClientTest,
584        ApplySerializedConfigWithSecureTransportRestricted) {
585   Init();
586 
587   AddMockSuccess();
588 
589   config_client()->ApplySerializedConfig(loaded_config());
590   VerifySuccessWithLoadedConfig(false);
591   EXPECT_TRUE(persisted_config().empty());
592 
593   config_client()->RetrieveConfig();
594   RunUntilIdle();
595   VerifyRemoteSuccess(false);
596 }
597 
598 // Tests that serialized config has no effect after the config has been
599 // retrieved successfully.
TEST_F(DataReductionProxyConfigServiceClientTest,ApplySerializedConfigAfterReceipt)600 TEST_F(DataReductionProxyConfigServiceClientTest,
601        ApplySerializedConfigAfterReceipt) {
602   Init();
603   AddMockSuccess();
604 
605   EXPECT_TRUE(request_options()->GetSecureSession().empty());
606 
607   // Retrieve the remote config.
608   config_client()->RetrieveConfig();
609   RunUntilIdle();
610   VerifyRemoteSuccess(true);
611 
612   // ApplySerializedConfig should not have any effect since the remote config
613   // is already applied.
614   config_client()->ApplySerializedConfig(encoded_config());
615   VerifyRemoteSuccess(true);
616 }
617 
618 // Tests that a local serialized config can be applied successfully if remote
619 // config has not been fetched so far.
TEST_F(DataReductionProxyConfigServiceClientTest,ApplySerializedConfigLocal)620 TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfigLocal) {
621   Init();
622   EXPECT_TRUE(request_options()->GetSecureSession().empty());
623   EXPECT_TRUE(persisted_config_retrieval_time().is_null());
624 
625   // ApplySerializedConfig should apply the encoded config.
626   config_client()->ApplySerializedConfig(encoded_config());
627   EXPECT_TRUE(persisted_config().empty());
628   EXPECT_TRUE(persisted_config_retrieval_time().is_null());
629   EXPECT_FALSE(request_options()->GetSecureSession().empty());
630 }
631 
TEST_F(DataReductionProxyConfigServiceClientTest,EmptyConfigDisablesDRP)632 TEST_F(DataReductionProxyConfigServiceClientTest, EmptyConfigDisablesDRP) {
633   Init();
634 
635   config_client()->ApplySerializedConfig(no_proxies_config());
636 }
637 
638 #if defined(OS_ANDROID)
639 // Verifies the correctness of fetching config when Chromium is in background
640 // and foreground.
TEST_F(DataReductionProxyConfigServiceClientTest,FetchConfigOnForeground)641 TEST_F(DataReductionProxyConfigServiceClientTest, FetchConfigOnForeground) {
642   Init();
643 
644   {
645     // Tests that successful config fetches while Chromium is in background,
646     // does not trigger refetches when Chromium comes to foreground.
647     base::HistogramTester histogram_tester;
648     AddMockSuccess();
649     config_client()->set_application_state_background(true);
650     config_client()->RetrieveConfig();
651     RunUntilIdle();
652     VerifyRemoteSuccess(true);
653     EXPECT_FALSE(config_client()->foreground_fetch_pending());
654     histogram_tester.ExpectTotalCount(
655         "DataReductionProxy.ConfigService.FetchLatency", 1);
656     EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
657               config_client()->GetDelay());
658     config_client()->set_application_state_background(false);
659     config_client()->TriggerApplicationStatusToForeground();
660     RunUntilIdle();
661     EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
662               config_client()->GetDelay());
663     histogram_tester.ExpectTotalCount(
664         "DataReductionProxy.ConfigService.FetchLatency", 1);
665   }
666 
667   {
668     // Tests that config fetch failures while Chromium is in foreground does not
669     // trigger refetches when Chromium comes to foreground again.
670     base::HistogramTester histogram_tester;
671     AddMockFailure();
672     config_client()->set_application_state_background(false);
673     config_client()->RetrieveConfig();
674     RunUntilIdle();
675     EXPECT_FALSE(config_client()->foreground_fetch_pending());
676     histogram_tester.ExpectTotalCount(
677         "DataReductionProxy.ConfigService.FetchLatency", 0);
678     EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
679     config_client()->TriggerApplicationStatusToForeground();
680     RunUntilIdle();
681     histogram_tester.ExpectTotalCount(
682         "DataReductionProxy.ConfigService.FetchLatency", 0);
683     EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
684   }
685 
686   {
687     // Tests that config fetch failures while Chromium is in background, trigger
688     // a refetch when Chromium comes to foreground.
689     base::HistogramTester histogram_tester;
690     AddMockFailure();
691     AddMockSuccess();
692     config_client()->set_application_state_background(true);
693     config_client()->RetrieveConfig();
694     RunUntilIdle();
695     EXPECT_TRUE(config_client()->foreground_fetch_pending());
696     histogram_tester.ExpectTotalCount(
697         "DataReductionProxy.ConfigService.FetchLatency", 0);
698     EXPECT_EQ(base::TimeDelta::FromSeconds(kMaxBackgroundFetchIntervalSeconds),
699               config_client()->GetDelay());
700     config_client()->set_application_state_background(false);
701     config_client()->TriggerApplicationStatusToForeground();
702     RunUntilIdle();
703     EXPECT_FALSE(config_client()->foreground_fetch_pending());
704     histogram_tester.ExpectTotalCount(
705         "DataReductionProxy.ConfigService.FetchLatency", 1);
706     EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
707               config_client()->GetDelay());
708     VerifyRemoteSuccess(true);
709   }
710 }
711 
712 class DataReductionProxyAggressiveConfigServiceClientTest
713     : public DataReductionProxyConfigServiceClientTest {
714  public:
DataReductionProxyAggressiveConfigServiceClientTest()715   DataReductionProxyAggressiveConfigServiceClientTest()
716       : DataReductionProxyConfigServiceClientTest(true) {}
717 };
718 
TEST_F(DataReductionProxyAggressiveConfigServiceClientTest,AggressiveFetchConfigOnBackground)719 TEST_F(DataReductionProxyAggressiveConfigServiceClientTest,
720        AggressiveFetchConfigOnBackground) {
721   Init();
722 
723   // Tests that config fetch failures while Chromium is in background, trigger
724   // refetches while still in background, and no refetch happens Chromium
725   // comes to foreground, when the aggressive client config fetch feature is
726   // enabled.
727   base::HistogramTester histogram_tester;
728   AddMockFailure();
729   AddMockFailure();
730   AddMockSuccess();
731   config_client()->set_application_state_background(true);
732   config_client()->RetrieveConfig();
733   RunUntilIdle();
734   // Three fetches are triggered in background without any backoff. First two
735   // fail, while the third succeeds.
736   EXPECT_EQ(base::TimeDelta::FromSeconds(0),
737             config_client()->GetBackoffTimeUntilRelease());
738   EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
739             config_client()->GetDelay());
740   EXPECT_FALSE(config_client()->foreground_fetch_pending());
741   histogram_tester.ExpectTotalCount(
742       "DataReductionProxy.ConfigService.FetchLatency", 1);
743   histogram_tester.ExpectBucketCount(
744       "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 2,
745       1);
746 
747   // No new fetch should happen when Chromium comes to foreground.
748   config_client()->set_application_state_background(false);
749   config_client()->TriggerApplicationStatusToForeground();
750   RunUntilIdle();
751   EXPECT_FALSE(config_client()->foreground_fetch_pending());
752   histogram_tester.ExpectTotalCount(
753       "DataReductionProxy.ConfigService.FetchLatency", 1);
754   EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
755             config_client()->GetDelay());
756   VerifyRemoteSuccess(true);
757 }
758 
759 #endif
760 
761 }  // namespace data_reduction_proxy
762