// Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/supervised_user/core/browser/proto_fetcher.h" #include <memory> #include <optional> #include <string> #include <string_view> #include "base/functional/bind.h" #include "base/functional/callback_forward.h" #include "base/strings/strcat.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "base/types/expected.h" #include "base/version_info/channel.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h" #include "components/supervised_user/core/browser/fetcher_config.h" #include "components/supervised_user/core/browser/kids_management_api_fetcher.h" #include "components/supervised_user/core/browser/proto/test.pb.h" #include "components/supervised_user/test_support/kids_management_api_server_mock.h" #include "google_apis/common/api_key_request_test_util.h" #include "google_apis/gaia/google_service_auth_error.h" #include "net/base/backoff_entry.h" #include "net/base/net_errors.h" #include "net/http/http_request_headers.h" #include "net/http/http_status_code.h" #include "services/network/public/cpp/data_element.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" #include "services/network/test/test_utils.h" #include "stddef.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace supervised_user { bool operator==(const ProtoFetcherStatus& a, const ProtoFetcherStatus& b) { … } namespace { BindOnce; Time; ClassifyUrlRequest; ClassifyUrlResponse; CreatePermissionRequestResponse; FamilyRole; PermissionRequest; GetUploadData; TestURLLoaderFactory; ConsentLevel; IdentityTestEnvironment; constexpr FetcherConfig kTestGetConfig{ … }; constexpr FetcherConfig kTestGetConfigWithoutMetrics{ … }; constexpr FetcherConfig kTestPostConfig{ … }; constexpr FetcherConfig kTestRetryConfig{ … }; constexpr FetcherConfig kTestGetConfigBestEffortAccessToken{ … }; // Receiver is an artificial consumer of the fetch process. Typically, calling // an RPC has the purpose of writing the data somewhere. Instances of this class // serve as a general-purpose destination for fetched data. class Receiver { … }; // Base of the test fixture for proto fetcher. // Defines required runtime environment, and a collection of helper methods // which are used to build initial test state and define behaviours. // // Simulate* methods are short-hands to put response with specific property in // test url environmnent's queue; // // FastForward is important for retrying feature tests: make sure that the time // skipped is greater than possible retry timeouts. class ProtoFetcherTestBase { … }; class ProtoFetcherTest : public ProtoFetcherTestBase, public ::testing::TestWithParam<FetcherConfig> { … }; // Test whether the outgoing request has correctly set endpoint and method. TEST_P(ProtoFetcherTest, ConfiguresEndpoint) { … } // Test whether the outgoing request has the HTTP payload, only for those HTTP // verbs that support it. TEST_P(ProtoFetcherTest, AddsPayload) { … } // Tests a default flow, where an empty (default) proto is received. TEST_P(ProtoFetcherTest, AcceptsRequests) { … } // Tests a flow where the caller is denied access token. There should be // response consumed, that indicated auth error and contains details about the // reason for denying access. TEST_P(ProtoFetcherTest, NoAccessTokenStrict) { … } // Tests a flow where incoming data from RPC can't be deserialized to a valid // proto. TEST_P(ProtoFetcherTest, HandlesMalformedResponse) { … } // Tests whether access token information is added to the request in a right // header. TEST_P(ProtoFetcherTest, CreatesToken) { … } // Tests a flow where the request couldn't be completed due to network // infrastructure errors. The result must contain details about the error. TEST_P(ProtoFetcherTest, HandlesNetworkError) { … } // Tests a flow where the remote server couldn't process the request and // responded with an error. TEST_P(ProtoFetcherTest, HandlesServerError) { … } // The fetchers are recording various metrics for the basic flow with default // empty proto response. This test is checking whether all metrics receive right // values. TEST_P(ProtoFetcherTest, RecordsMetrics) { … } // When retrying is configured, the fetch process is re-launched until a // decisive status is received (OK or permanent error, see // RetryingFetcherImpl::ShouldRetry for details). This tests checks that the // compound fetch process eventually terminates and that related metrics are // also recorded. TEST_P(ProtoFetcherTest, RetryingFetcherTerminatesOnOkStatusAndRecordsMetrics) { … } // When retrying is configured, the fetch process is re-launched until a // decisive status is received (OK or permanent error, see // RetryingFetcherImpl::ShouldRetry for details). This tests checks that the // compound fetch process eventually terminates and that related metrics are // also recorded. TEST_P(ProtoFetcherTest, RetryingFetcherTerminatesOnPersistentErrorAndRecordsMetrics) { … } // When retrying is configured, the fetch process is re-launched until a // decisive status is received (OK or permanent error, see // RetryingFetcherImpl::ShouldRetry for details). This tests assumes only // transient error responses from the server (eg. those that are expect to go // away on their own soon). This means that no response will be received, and no // extra retrying metrics recording, because the process is still not finished. TEST_P(ProtoFetcherTest, RetryingFetcherContinuesOnTransientError) { … } // Test whether fetcher forbids being started twice. TEST_P(ProtoFetcherTest, MustBeStoppedBeforeRestarting) { … } class StatusFetcherTest : public ProtoFetcherTest { … }; // Tests a default flow, where an empty (default) proto is received. TEST_P(StatusFetcherTest, StatusFetcherReportsSuccess) { … } // Tests an error flow. TEST_P(StatusFetcherTest, StatusFetcherReportsFailure) { … } // Instead of /0, /1... print human-readable description of the test: status of // the retrying feature followed by http method. std::string PrettyPrintFetcherTestCaseName( const ::testing::TestParamInfo<FetcherConfig>& info) { … } INSTANTIATE_TEST_SUITE_P(…); INSTANTIATE_TEST_SUITE_P(…); class BestEffortProtoFetcherTest : public ProtoFetcherTestBase, public testing::Test { … }; // Tests a flow where the caller is denied access token. // // Since the fetcher config specifies best effort as the credentials // requirement, the request proceeds. TEST_F(BestEffortProtoFetcherTest, NoAccessToken) { … } class FetchManagerTest : public testing::Test { … }; // Tests whether two requests can be handled "in parallel" from the observer's // point of view. TEST_F(FetchManagerTest, HandlesMultipleRequests) { … } // Tests whether destroying the fetch manager will also terminate all pending // network operations. TEST_F(FetchManagerTest, CancelsRequestsUponDestruction) { … } class DeferredFetcherTest : public ::testing::Test { … }; // This test demonstrates possible misusage of proto fetchers (antipattern) and // its behavior. A fetcher bound to its own callback will be executed even when // all *visible* references will be gone (because the one remaining reference is // inside the callback). Such usage strips the caller from any control over the // fetch process and makes cancel or termination impossible. Use // ParallelFetchManager instead. TEST_F(DeferredFetcherTest, IsCreatedAndStarted) { … } } // namespace } // namespace supervised_user