prediction_model_fetcher_unittest.cc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Copyright 2019 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. #include "components/optimization_guide/core/prediction_model_fetcher_impl.h"
  5. #include <memory>
  6. #include <string>
  7. #include <vector>
  8. #include "base/callback.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/memory/scoped_refptr.h"
  11. #include "base/run_loop.h"
  12. #include "base/strings/string_number_conversions.h"
  13. #include "base/test/metrics/histogram_tester.h"
  14. #include "base/test/task_environment.h"
  15. #include "components/optimization_guide/core/optimization_guide_features.h"
  16. #include "components/optimization_guide/proto/models.pb.h"
  17. #include "components/variations/scoped_variations_ids_provider.h"
  18. #include "net/base/url_util.h"
  19. #include "services/network/public/cpp/shared_url_loader_factory.h"
  20. #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  21. #include "services/network/test/test_url_loader_factory.h"
  22. #include "testing/gtest/include/gtest/gtest.h"
  23. #include "third_party/abseil-cpp/absl/types/optional.h"
  24. namespace optimization_guide {
  25. constexpr char optimization_guide_service_url[] =
  26. "https://optimizationguideservice.com/";
  27. class PredictionModelFetcherTest : public testing::Test {
  28. public:
  29. PredictionModelFetcherTest()
  30. : task_environment_(base::test::TaskEnvironment::MainThreadType::UI),
  31. shared_url_loader_factory_(
  32. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  33. &test_url_loader_factory_)) {
  34. prediction_model_fetcher_ = std::make_unique<PredictionModelFetcherImpl>(
  35. shared_url_loader_factory_, GURL(optimization_guide_service_url));
  36. }
  37. PredictionModelFetcherTest(const PredictionModelFetcherTest&) = delete;
  38. PredictionModelFetcherTest& operator=(const PredictionModelFetcherTest&) =
  39. delete;
  40. ~PredictionModelFetcherTest() override {}
  41. void OnModelsFetched(absl::optional<std::unique_ptr<proto::GetModelsResponse>>
  42. get_models_response) {
  43. if (get_models_response)
  44. models_fetched_ = true;
  45. }
  46. bool models_fetched() { return models_fetched_; }
  47. protected:
  48. bool FetchModels(const std::vector<proto::ModelInfo> models_request_info,
  49. proto::RequestContext request_context,
  50. const std::string& locale) {
  51. bool status =
  52. prediction_model_fetcher_->FetchOptimizationGuideServiceModels(
  53. models_request_info, request_context, locale,
  54. base::BindOnce(&PredictionModelFetcherTest::OnModelsFetched,
  55. base::Unretained(this)));
  56. RunUntilIdle();
  57. return status;
  58. }
  59. // Return a 200 response with provided content to any pending requests.
  60. bool SimulateResponse(const std::string& content,
  61. net::HttpStatusCode http_status) {
  62. return test_url_loader_factory_.SimulateResponseForPendingRequest(
  63. optimization_guide_service_url, content, http_status,
  64. network::TestURLLoaderFactory::kUrlMatchPrefix);
  65. }
  66. void VerifyHasPendingFetchRequests() {
  67. EXPECT_GE(test_url_loader_factory_.NumPending(), 1);
  68. std::string key_value;
  69. for (const auto& pending_request :
  70. *test_url_loader_factory_.pending_requests()) {
  71. EXPECT_EQ(pending_request.request.method, "POST");
  72. EXPECT_TRUE(net::GetValueForKeyInQuery(pending_request.request.url, "key",
  73. &key_value));
  74. }
  75. }
  76. private:
  77. void RunUntilIdle() {
  78. task_environment_.RunUntilIdle();
  79. base::RunLoop().RunUntilIdle();
  80. }
  81. bool models_fetched_ = false;
  82. base::test::TaskEnvironment task_environment_;
  83. variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
  84. variations::VariationsIdsProvider::Mode::kUseSignedInState};
  85. std::unique_ptr<PredictionModelFetcherImpl> prediction_model_fetcher_;
  86. scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
  87. network::TestURLLoaderFactory test_url_loader_factory_;
  88. };
  89. TEST_F(PredictionModelFetcherTest, FetchOptimizationGuideServiceModels) {
  90. std::string response_content;
  91. proto::ModelInfo model_info;
  92. model_info.set_optimization_target(
  93. proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
  94. EXPECT_TRUE(FetchModels({model_info},
  95. proto::RequestContext::CONTEXT_BATCH_UPDATE_MODELS,
  96. "en-US"));
  97. VerifyHasPendingFetchRequests();
  98. EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
  99. EXPECT_TRUE(models_fetched());
  100. }
  101. // Tests 404 response from request.
  102. TEST_F(PredictionModelFetcherTest, FetchReturned404) {
  103. base::HistogramTester histogram_tester;
  104. std::string response_content;
  105. proto::ModelInfo model_info;
  106. model_info.set_optimization_target(
  107. proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
  108. EXPECT_TRUE(FetchModels({model_info},
  109. proto::RequestContext::CONTEXT_BATCH_UPDATE_MODELS,
  110. "en-US"));
  111. // Send a 404 to HintsFetcher.
  112. SimulateResponse(response_content, net::HTTP_NOT_FOUND);
  113. EXPECT_FALSE(models_fetched());
  114. histogram_tester.ExpectUniqueSample(
  115. "OptimizationGuide.PredictionModelFetcher."
  116. "GetModelsResponse.Status",
  117. net::HTTP_NOT_FOUND, 1);
  118. histogram_tester.ExpectUniqueSample(
  119. "OptimizationGuide.PredictionModelFetcher."
  120. "GetModelsResponse.Status.PainfulPageLoad",
  121. net::HTTP_NOT_FOUND, 1);
  122. // Net error codes are negative but UMA histograms require positive values.
  123. histogram_tester.ExpectUniqueSample(
  124. "OptimizationGuide.PredictionModelFetcher."
  125. "GetModelsResponse.NetErrorCode",
  126. -net::ERR_HTTP_RESPONSE_CODE_FAILURE, 1);
  127. histogram_tester.ExpectUniqueSample(
  128. "OptimizationGuide.PredictionModelFetcher."
  129. "GetModelsResponse.NetErrorCode.PainfulPageLoad",
  130. -net::ERR_HTTP_RESPONSE_CODE_FAILURE, 1);
  131. }
  132. TEST_F(PredictionModelFetcherTest, FetchReturnBadResponse) {
  133. std::string response_content = "not proto";
  134. proto::ModelInfo model_info;
  135. model_info.set_optimization_target(
  136. proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
  137. EXPECT_TRUE(FetchModels({model_info},
  138. proto::RequestContext::CONTEXT_BATCH_UPDATE_MODELS,
  139. "en-US"));
  140. VerifyHasPendingFetchRequests();
  141. EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
  142. EXPECT_FALSE(models_fetched());
  143. }
  144. TEST_F(PredictionModelFetcherTest, EmptyModelInfo) {
  145. base::HistogramTester histogram_tester;
  146. std::string response_content;
  147. EXPECT_FALSE(FetchModels(/*models_request_info=*/{},
  148. proto::RequestContext::CONTEXT_BATCH_UPDATE_MODELS,
  149. "en-US"));
  150. EXPECT_FALSE(models_fetched());
  151. }
  152. } // namespace optimization_guide