123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/feedback/feedback_uploader.h"
- #include <string>
- #include "base/files/scoped_temp_dir.h"
- #include "base/metrics/field_trial.h"
- #include "base/run_loop.h"
- #include "base/task/task_traits.h"
- #include "base/test/bind.h"
- #include "base/test/task_environment.h"
- #include "components/variations/net/variations_http_headers.h"
- #include "components/variations/scoped_variations_ids_provider.h"
- #include "components/variations/variations_associated_data.h"
- #include "components/variations/variations_ids_provider.h"
- #include "net/http/http_util.h"
- #include "services/network/public/cpp/shared_url_loader_factory.h"
- #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
- #include "services/network/public/mojom/url_response_head.mojom.h"
- #include "services/network/test/test_url_loader_factory.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace feedback {
- namespace {
- constexpr base::TimeDelta kTestRetryDelay = base::Milliseconds(1);
- constexpr char kFeedbackPostUrl[] =
- "https://www.google.com/tools/feedback/chrome/__submit";
- void QueueReport(FeedbackUploader* uploader,
- const std::string& report_data,
- bool has_email = true) {
- uploader->QueueReport(std::make_unique<std::string>(report_data), has_email);
- }
- // Stand-in for the FeedbackUploaderChrome class that adds a fake bearer token
- // to the request.
- class MockFeedbackUploaderChrome : public FeedbackUploader {
- public:
- MockFeedbackUploaderChrome(
- bool is_off_the_record,
- const base::FilePath& state_path,
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
- : FeedbackUploader(is_off_the_record, state_path, url_loader_factory) {}
- void AppendExtraHeadersToUploadRequest(
- network::ResourceRequest* resource_request) override {
- resource_request->headers.SetHeader(net::HttpRequestHeaders::kAuthorization,
- "Bearer abcdefg");
- }
- };
- } // namespace
- class FeedbackUploaderDispatchTest : public ::testing::Test {
- protected:
- FeedbackUploaderDispatchTest()
- : shared_url_loader_factory_(
- base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
- &test_url_loader_factory_)) {
- EXPECT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
- }
- FeedbackUploaderDispatchTest(const FeedbackUploaderDispatchTest&) = delete;
- FeedbackUploaderDispatchTest& operator=(const FeedbackUploaderDispatchTest&) =
- delete;
- ~FeedbackUploaderDispatchTest() override {
- // Clean up registered ids.
- variations::testing::ClearAllVariationIDs();
- }
- // Registers a field trial with the specified name and group and an associated
- // google web property variation id.
- void CreateFieldTrialWithId(const std::string& trial_name,
- const std::string& group_name,
- int variation_id) {
- variations::AssociateGoogleVariationID(
- variations::GOOGLE_WEB_PROPERTIES_ANY_CONTEXT, trial_name, group_name,
- static_cast<variations::VariationID>(variation_id));
- base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group();
- }
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory() {
- return shared_url_loader_factory_;
- }
- network::TestURLLoaderFactory* test_url_loader_factory() {
- return &test_url_loader_factory_;
- }
- const base::FilePath& state_path() { return scoped_temp_dir_.GetPath(); }
- private:
- base::test::TaskEnvironment task_environment_;
- base::ScopedTempDir scoped_temp_dir_;
- variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
- variations::VariationsIdsProvider::Mode::kUseSignedInState};
- network::TestURLLoaderFactory test_url_loader_factory_;
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
- };
- TEST_F(FeedbackUploaderDispatchTest, VariationHeaders) {
- // Register a trial and variation id, so that there is data in variations
- // headers.
- CreateFieldTrialWithId("Test", "Group1", 123);
- FeedbackUploader uploader(/*is_off_the_record=*/false, state_path(),
- shared_url_loader_factory());
- net::HttpRequestHeaders headers;
- test_url_loader_factory()->SetInterceptor(
- base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
- EXPECT_TRUE(variations::HasVariationsHeader(request));
- }));
- QueueReport(&uploader, "test");
- base::RunLoop().RunUntilIdle();
- }
- // Test that the bearer token is present if there is an email address present in
- // the report.
- TEST_F(FeedbackUploaderDispatchTest, BearerTokenWithEmail) {
- MockFeedbackUploaderChrome uploader(/*is_off_the_record=*/false, state_path(),
- shared_url_loader_factory());
- test_url_loader_factory()->SetInterceptor(
- base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
- EXPECT_TRUE(request.headers.HasHeader("Authorization"));
- }));
- QueueReport(&uploader, "test", /*has_email=*/true);
- base::RunLoop().RunUntilIdle();
- }
- TEST_F(FeedbackUploaderDispatchTest, BearerTokenNoEmail) {
- MockFeedbackUploaderChrome uploader(/*is_off_the_record=*/false, state_path(),
- shared_url_loader_factory());
- test_url_loader_factory()->SetInterceptor(
- base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
- EXPECT_FALSE(request.headers.HasHeader("Authorization"));
- }));
- QueueReport(&uploader, "test", /*has_email=*/false);
- base::RunLoop().RunUntilIdle();
- }
- TEST_F(FeedbackUploaderDispatchTest, 204Response) {
- FeedbackUploader::SetMinimumRetryDelayForTesting(kTestRetryDelay);
- FeedbackUploader uploader(/*is_off_the_record=*/false, state_path(),
- shared_url_loader_factory());
- EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
- // Successful reports should not introduce any retries, and should not
- // increase the backoff delay.
- auto head = network::mojom::URLResponseHead::New();
- std::string headers("HTTP/1.1 204 No Content\n\n");
- head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
- net::HttpUtil::AssembleRawHeaders(headers));
- network::URLLoaderCompletionStatus status;
- test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl),
- std::move(head), "", status);
- QueueReport(&uploader, "Successful report");
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
- EXPECT_TRUE(uploader.QueueEmpty());
- }
- TEST_F(FeedbackUploaderDispatchTest, 400Response) {
- FeedbackUploader::SetMinimumRetryDelayForTesting(kTestRetryDelay);
- FeedbackUploader uploader(/*is_off_the_record=*/false, state_path(),
- shared_url_loader_factory());
- EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
- // Failed reports due to client errors are not retried. No backoff delay
- // should be doubled.
- auto head = network::mojom::URLResponseHead::New();
- std::string headers("HTTP/1.1 400 Bad Request\n\n");
- head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
- net::HttpUtil::AssembleRawHeaders(headers));
- network::URLLoaderCompletionStatus status;
- test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl),
- std::move(head), "", status);
- QueueReport(&uploader, "Client error failed report");
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
- EXPECT_TRUE(uploader.QueueEmpty());
- }
- TEST_F(FeedbackUploaderDispatchTest, 500Response) {
- FeedbackUploader::SetMinimumRetryDelayForTesting(kTestRetryDelay);
- FeedbackUploader uploader(/*is_off_the_record=*/false, state_path(),
- shared_url_loader_factory());
- EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
- // Failed reports due to server errors are retried.
- auto head = network::mojom::URLResponseHead::New();
- std::string headers("HTTP/1.1 500 Server Error\n\n");
- head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
- net::HttpUtil::AssembleRawHeaders(headers));
- network::URLLoaderCompletionStatus status;
- test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl),
- std::move(head), "", status);
- QueueReport(&uploader, "Server error failed report");
- base::RunLoop().RunUntilIdle();
- EXPECT_LT(kTestRetryDelay, uploader.retry_delay());
- EXPECT_FALSE(uploader.QueueEmpty());
- }
- } // namespace feedback
|