feedback_uploader_dispatch_unittest.cc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright 2017 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/feedback/feedback_uploader.h"
  5. #include <string>
  6. #include "base/files/scoped_temp_dir.h"
  7. #include "base/metrics/field_trial.h"
  8. #include "base/run_loop.h"
  9. #include "base/task/task_traits.h"
  10. #include "base/test/bind.h"
  11. #include "base/test/task_environment.h"
  12. #include "components/variations/net/variations_http_headers.h"
  13. #include "components/variations/scoped_variations_ids_provider.h"
  14. #include "components/variations/variations_associated_data.h"
  15. #include "components/variations/variations_ids_provider.h"
  16. #include "net/http/http_util.h"
  17. #include "services/network/public/cpp/shared_url_loader_factory.h"
  18. #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  19. #include "services/network/public/mojom/url_response_head.mojom.h"
  20. #include "services/network/test/test_url_loader_factory.h"
  21. #include "testing/gtest/include/gtest/gtest.h"
  22. namespace feedback {
  23. namespace {
  24. constexpr base::TimeDelta kTestRetryDelay = base::Milliseconds(1);
  25. constexpr char kFeedbackPostUrl[] =
  26. "https://www.google.com/tools/feedback/chrome/__submit";
  27. void QueueReport(FeedbackUploader* uploader,
  28. const std::string& report_data,
  29. bool has_email = true) {
  30. uploader->QueueReport(std::make_unique<std::string>(report_data), has_email);
  31. }
  32. // Stand-in for the FeedbackUploaderChrome class that adds a fake bearer token
  33. // to the request.
  34. class MockFeedbackUploaderChrome : public FeedbackUploader {
  35. public:
  36. MockFeedbackUploaderChrome(
  37. bool is_off_the_record,
  38. const base::FilePath& state_path,
  39. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
  40. : FeedbackUploader(is_off_the_record, state_path, url_loader_factory) {}
  41. void AppendExtraHeadersToUploadRequest(
  42. network::ResourceRequest* resource_request) override {
  43. resource_request->headers.SetHeader(net::HttpRequestHeaders::kAuthorization,
  44. "Bearer abcdefg");
  45. }
  46. };
  47. } // namespace
  48. class FeedbackUploaderDispatchTest : public ::testing::Test {
  49. protected:
  50. FeedbackUploaderDispatchTest()
  51. : shared_url_loader_factory_(
  52. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  53. &test_url_loader_factory_)) {
  54. EXPECT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
  55. }
  56. FeedbackUploaderDispatchTest(const FeedbackUploaderDispatchTest&) = delete;
  57. FeedbackUploaderDispatchTest& operator=(const FeedbackUploaderDispatchTest&) =
  58. delete;
  59. ~FeedbackUploaderDispatchTest() override {
  60. // Clean up registered ids.
  61. variations::testing::ClearAllVariationIDs();
  62. }
  63. // Registers a field trial with the specified name and group and an associated
  64. // google web property variation id.
  65. void CreateFieldTrialWithId(const std::string& trial_name,
  66. const std::string& group_name,
  67. int variation_id) {
  68. variations::AssociateGoogleVariationID(
  69. variations::GOOGLE_WEB_PROPERTIES_ANY_CONTEXT, trial_name, group_name,
  70. static_cast<variations::VariationID>(variation_id));
  71. base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group();
  72. }
  73. scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory() {
  74. return shared_url_loader_factory_;
  75. }
  76. network::TestURLLoaderFactory* test_url_loader_factory() {
  77. return &test_url_loader_factory_;
  78. }
  79. const base::FilePath& state_path() { return scoped_temp_dir_.GetPath(); }
  80. private:
  81. base::test::TaskEnvironment task_environment_;
  82. base::ScopedTempDir scoped_temp_dir_;
  83. variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
  84. variations::VariationsIdsProvider::Mode::kUseSignedInState};
  85. network::TestURLLoaderFactory test_url_loader_factory_;
  86. scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
  87. };
  88. TEST_F(FeedbackUploaderDispatchTest, VariationHeaders) {
  89. // Register a trial and variation id, so that there is data in variations
  90. // headers.
  91. CreateFieldTrialWithId("Test", "Group1", 123);
  92. FeedbackUploader uploader(/*is_off_the_record=*/false, state_path(),
  93. shared_url_loader_factory());
  94. net::HttpRequestHeaders headers;
  95. test_url_loader_factory()->SetInterceptor(
  96. base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
  97. EXPECT_TRUE(variations::HasVariationsHeader(request));
  98. }));
  99. QueueReport(&uploader, "test");
  100. base::RunLoop().RunUntilIdle();
  101. }
  102. // Test that the bearer token is present if there is an email address present in
  103. // the report.
  104. TEST_F(FeedbackUploaderDispatchTest, BearerTokenWithEmail) {
  105. MockFeedbackUploaderChrome uploader(/*is_off_the_record=*/false, state_path(),
  106. shared_url_loader_factory());
  107. test_url_loader_factory()->SetInterceptor(
  108. base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
  109. EXPECT_TRUE(request.headers.HasHeader("Authorization"));
  110. }));
  111. QueueReport(&uploader, "test", /*has_email=*/true);
  112. base::RunLoop().RunUntilIdle();
  113. }
  114. TEST_F(FeedbackUploaderDispatchTest, BearerTokenNoEmail) {
  115. MockFeedbackUploaderChrome uploader(/*is_off_the_record=*/false, state_path(),
  116. shared_url_loader_factory());
  117. test_url_loader_factory()->SetInterceptor(
  118. base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
  119. EXPECT_FALSE(request.headers.HasHeader("Authorization"));
  120. }));
  121. QueueReport(&uploader, "test", /*has_email=*/false);
  122. base::RunLoop().RunUntilIdle();
  123. }
  124. TEST_F(FeedbackUploaderDispatchTest, 204Response) {
  125. FeedbackUploader::SetMinimumRetryDelayForTesting(kTestRetryDelay);
  126. FeedbackUploader uploader(/*is_off_the_record=*/false, state_path(),
  127. shared_url_loader_factory());
  128. EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
  129. // Successful reports should not introduce any retries, and should not
  130. // increase the backoff delay.
  131. auto head = network::mojom::URLResponseHead::New();
  132. std::string headers("HTTP/1.1 204 No Content\n\n");
  133. head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
  134. net::HttpUtil::AssembleRawHeaders(headers));
  135. network::URLLoaderCompletionStatus status;
  136. test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl),
  137. std::move(head), "", status);
  138. QueueReport(&uploader, "Successful report");
  139. base::RunLoop().RunUntilIdle();
  140. EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
  141. EXPECT_TRUE(uploader.QueueEmpty());
  142. }
  143. TEST_F(FeedbackUploaderDispatchTest, 400Response) {
  144. FeedbackUploader::SetMinimumRetryDelayForTesting(kTestRetryDelay);
  145. FeedbackUploader uploader(/*is_off_the_record=*/false, state_path(),
  146. shared_url_loader_factory());
  147. EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
  148. // Failed reports due to client errors are not retried. No backoff delay
  149. // should be doubled.
  150. auto head = network::mojom::URLResponseHead::New();
  151. std::string headers("HTTP/1.1 400 Bad Request\n\n");
  152. head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
  153. net::HttpUtil::AssembleRawHeaders(headers));
  154. network::URLLoaderCompletionStatus status;
  155. test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl),
  156. std::move(head), "", status);
  157. QueueReport(&uploader, "Client error failed report");
  158. base::RunLoop().RunUntilIdle();
  159. EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
  160. EXPECT_TRUE(uploader.QueueEmpty());
  161. }
  162. TEST_F(FeedbackUploaderDispatchTest, 500Response) {
  163. FeedbackUploader::SetMinimumRetryDelayForTesting(kTestRetryDelay);
  164. FeedbackUploader uploader(/*is_off_the_record=*/false, state_path(),
  165. shared_url_loader_factory());
  166. EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
  167. // Failed reports due to server errors are retried.
  168. auto head = network::mojom::URLResponseHead::New();
  169. std::string headers("HTTP/1.1 500 Server Error\n\n");
  170. head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
  171. net::HttpUtil::AssembleRawHeaders(headers));
  172. network::URLLoaderCompletionStatus status;
  173. test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl),
  174. std::move(head), "", status);
  175. QueueReport(&uploader, "Server error failed report");
  176. base::RunLoop().RunUntilIdle();
  177. EXPECT_LT(kTestRetryDelay, uploader.retry_delay());
  178. EXPECT_FALSE(uploader.QueueEmpty());
  179. }
  180. } // namespace feedback