blob: 144da2f447fa60bb1ff03065d6328da940615b36 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_PUBLIC_TEST_KEEP_ALIVE_URL_LOADER_UTILS_H_
#define CONTENT_PUBLIC_TEST_KEEP_ALIVE_URL_LOADER_UTILS_H_
#include <stdint.h>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/browser/keep_alive_request_tracker.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
namespace content {
class BrowserContext;
class KeepAliveURLLoadersTestObserverImpl;
// Observes behaviors of all `KeepAliveURLLoader` instances in synchronous way.
//
// KeepAliveURLLoader itself is running in browser UI thread, but there can be
// multiple instances created and triggered by different renderers.
// For example:
// - Renderer A triggers `KeepAliveURLLoader::OnReceiveRedirectForwarded()`
// and then `KeepAliveURLLoader::OnReceiveResponseProcessed()
// - Renderer B triggers `KeepAliveURLLoader::OnReceiveRedirectForwarded()`
// twice.
// - Users can call `WaitForTotalOnReceiveRedirectForwarded()` to wait until
// all 3 triggerings of `KeepAliveURLLoader::OnReceiveRedirectForwarded()`
// completed.
//
// The methods provided by this class can also be used to assert that
// KeepAliveURLLoader has entered certain state, e.g.
// `WaitForTotalOnReceiveRedirectProcessed()` indicates the loader handles the
// redirect itself rather than handing over to renderer as renderer is gone.
class KeepAliveURLLoadersTestObserver {
public:
// Begins observing the internal states of all instances of KeepAliveURLLoader
// created under the given `browser_context` immediately.
explicit KeepAliveURLLoadersTestObserver(BrowserContext* browser_context);
~KeepAliveURLLoadersTestObserver();
// Not Copyable.
KeepAliveURLLoadersTestObserver(const KeepAliveURLLoadersTestObserver&) =
delete;
KeepAliveURLLoadersTestObserver& operator=(
const KeepAliveURLLoadersTestObserver&) = delete;
// Waits for `KeepAliveURLLoader::OnReceiveRedirectForwarded()` to be called
// `total` times.
void WaitForTotalOnReceiveRedirectForwarded(size_t total);
// Waits for `KeepAliveURLLoader::OnReceiveRedirectProcessed()` to be called
// `total` times.
void WaitForTotalOnReceiveRedirectProcessed(size_t total);
// Waits for `KeepAliveURLLoader::OnReceiveResponse()` to be called `total`
// times.
void WaitForTotalOnReceiveResponse(size_t total);
// Waits for `KeepAliveURLLoader::OnReceiveResponseForwarded()` to be called
// `total` times.
void WaitForTotalOnReceiveResponseForwarded(size_t total);
// Waits for `KeepAliveURLLoader::OnReceiveResponseProcessed()` to be called
// `total` times.
void WaitForTotalOnReceiveResponseProcessed(size_t total);
// Waits for `KeepAliveURLLoader::OnComplete()` to be called
// `error_codes.size()` times, and the error codes from all previous calls to
// that method should match `error_codes`.
void WaitForTotalOnComplete(const std::vector<int>& error_codes);
// Waits for `KeepAliveURLLoader::OnCompleteForwarded()` to be called
// `error_codes.size()` times, and the error codes from all previous calls to
// that method should match `error_codes`.
void WaitForTotalOnCompleteForwarded(const std::vector<int>& error_codes);
// Waits for `KeepAliveURLLoader::OnCompleteProcessed()` to be called
// `error_codes.size()` times, and the error codes from all previous calls to
// that method should match `error_codes`.
void WaitForTotalOnCompleteProcessed(const std::vector<int>& error_codes);
private:
std::unique_ptr<KeepAliveURLLoadersTestObserverImpl> impl_;
};
// `KeepAliveRequestUkmMatcher` provides common matchers and expectations to
// help make test assertions on fetch keepalive request-related UKM metrics.
class KeepAliveRequestUkmMatcher {
protected:
using UkmEvent = ukm::builders::FetchKeepAliveRequest_WithCategory;
static constexpr std::string_view kUkmName =
"FetchKeepAliveRequest.WithCategory";
virtual ukm::TestAutoSetUkmRecorder& ukm_recorder() = 0;
// Returns the last recorded UKM event.
// This assumes that only a single UKM event is recorded.
const ukm::mojom::UkmEntry* GetUkmEntry();
// Verifies no UKM event logged.
void ExpectNoUkm();
struct CommonUkm {
KeepAliveRequestTracker::RequestType request_type;
size_t category_id;
size_t num_redirects;
size_t num_retries;
bool is_context_detached;
KeepAliveRequestTracker::RequestStageType end_stage;
std::optional<KeepAliveRequestTracker::RequestStageType> previous_stage =
std::nullopt;
std::optional<base::UnguessableToken> keepalive_token = std::nullopt;
std::optional<int64_t> failed_error_code = std::nullopt;
std::optional<int64_t> failed_extended_error_code = std::nullopt;
std::optional<int64_t> completed_error_code = std::nullopt;
std::optional<int64_t> completed_extended_error_code = std::nullopt;
std::optional<int64_t> retried_error_code = std::nullopt;
std::optional<int64_t> retried_extended_error_code = std::nullopt;
CommonUkm(
KeepAliveRequestTracker::RequestType request_type,
size_t category_id,
size_t num_redirects,
size_t num_retries,
bool is_context_detached,
KeepAliveRequestTracker::RequestStageType end_stage,
std::optional<KeepAliveRequestTracker::RequestStageType>
previous_stage = std::nullopt,
const std::optional<base::UnguessableToken>& keepalive_token =
std::nullopt,
std::optional<int64_t> failed_error_code = std::nullopt,
std::optional<int64_t> failed_extended_error_code = std::nullopt,
std::optional<int64_t> completed_error_code = std::nullopt,
std::optional<int64_t> completed_extended_error_code = std::nullopt,
std::optional<int64_t> retried_error_code = std::nullopt,
std::optional<int64_t> retried_extended_error_code = std::nullopt);
CommonUkm(const CommonUkm& other);
};
// Verifies all the common UKM metrics.
//
// `keepalive_token` is optional. If not provided, this method will just
// assert the existence of Id.Low and Id.High metrics.
void ExpectCommonUkm(
KeepAliveRequestTracker::RequestType request_type,
size_t category_id,
size_t num_redirects,
size_t num_retries,
bool is_context_detached,
KeepAliveRequestTracker::RequestStageType end_stage,
std::optional<KeepAliveRequestTracker::RequestStageType> previous_stage =
std::nullopt,
const std::optional<base::UnguessableToken>& keepalive_token =
std::nullopt,
std::optional<int64_t> failed_error_code = std::nullopt,
std::optional<int64_t> failed_extended_error_code = std::nullopt,
std::optional<int64_t> completed_error_code = std::nullopt,
std::optional<int64_t> completed_extended_error_code = std::nullopt,
std::optional<int64_t> retried_error_code = std::nullopt,
std::optional<int64_t> retried_extended_error_code = std::nullopt);
void ExpectCommonUkms(const std::vector<CommonUkm>& ukms);
// Verifies that UKM TimeDelta.* listed in `time_sorted_metric_names` are all
// non-null and have their values in the given order. All the other
// TimeDelta.* metrics must be null.
//
// For example, if `time_sorted_metric_names` is
// {"TimeDelta.RequestStarted", "TimeDelta.RequestFailed"}, this method will
// check that the logged value for "TimeDelta.RequestStarted" <=
// "TimeDelta.RequestFailed".
void ExpectTimeSortedTimeDeltaUkm(
const std::vector<std::string>& time_sorted_metric_names);
private:
void ExpectCommonUkm(
const ukm::mojom::UkmEntry* entry,
KeepAliveRequestTracker::RequestType request_type,
size_t category_id,
size_t num_redirects,
size_t num_retries,
bool is_context_detached,
KeepAliveRequestTracker::RequestStageType end_stage,
std::optional<KeepAliveRequestTracker::RequestStageType> previous_stage =
std::nullopt,
const std::optional<base::UnguessableToken>& keepalive_token =
std::nullopt,
std::optional<int64_t> failed_error_code = std::nullopt,
std::optional<int64_t> failed_extended_error_code = std::nullopt,
std::optional<int64_t> completed_error_code = std::nullopt,
std::optional<int64_t> completed_extended_error_code = std::nullopt,
std::optional<int64_t> retried_error_code = std::nullopt,
std::optional<int64_t> retried_extended_error_code = std::nullopt);
};
// `NavigationKeepAliveRequestUkmMatcher` provides common matchers and
// expectations to help make test assertions on navigation-fetch keepalive
// request-related UKM metrics.
class NavigationKeepAliveRequestUkmMatcher {
protected:
using UkmEvent = ukm::builders::FetchKeepAliveRequest_WithCategory_Navigation;
static constexpr std::string_view kUkmName =
"FetchKeepAliveRequest.WithCategory.Navigation";
virtual ukm::TestAutoSetUkmRecorder& ukm_recorder() = 0;
// Returns the last recorded UKM event.
// This assumes that only a single UKM event is recorded.
const ukm::mojom::UkmEntry* GetUkmEntry();
// Verifies no UKM event logged.
void ExpectNoUkm();
struct NavigationUkm {
size_t category_id;
std::optional<int64_t> navigation_id = std::nullopt;
std::optional<base::UnguessableToken> keepalive_token = std::nullopt;
};
// Verifies all the navigation-related UKM metrics.
//
// `navigation_id` is optional. If not provided, this method will just
// assert the existence of it.
// `keepalive_token` is optional. If not provided, this method will just
// assert the existence of Id.Low and Id.High metrics.
void ExpectNavigationUkm(size_t category_id,
std::optional<int64_t> navigation_id,
const std::optional<base::UnguessableToken>&
keepalive_token = std::nullopt);
void ExpectNavigationUkms(const std::vector<NavigationUkm>& ukms);
private:
void ExpectNavigationUkm(const ukm::mojom::UkmEntry* entry,
size_t category_id,
std::optional<int64_t> navigation_id,
const std::optional<base::UnguessableToken>&
keepalive_token = std::nullopt);
};
} // namespace content
#endif // CONTENT_PUBLIC_TEST_KEEP_ALIVE_URL_LOADER_UTILS_H_