blob: 7d39bf4aa74e253a1fc489542abc2e65dc41b39e [file] [log] [blame] [edit]
// 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/omnibox/browser/autocomplete_controller_metrics.h"
#include <algorithm>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/memory/raw_ref.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/omnibox/browser/autocomplete_controller.h"
#include "components/omnibox/browser/autocomplete_enums.h"
#include "components/omnibox/browser/autocomplete_result.h"
#include "components/omnibox/browser/fake_autocomplete_controller.h"
#include "components/omnibox/browser/fake_autocomplete_provider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::ElementsAre;
using testing::ElementsAreArray;
namespace {
// A fake provider that will:
// a) Consume 1ms to run the sync pass.
// b) Can be configured whether to be done or not after the sync pass.
class FakeAutocompleteProviderDelayed : public FakeAutocompleteProvider {
public:
FakeAutocompleteProviderDelayed(
Type type,
raw_ptr<base::test::SingleThreadTaskEnvironment> task_environment,
bool done_after_sync_pass = false)
: FakeAutocompleteProvider(type),
task_environment_(task_environment),
done_after_sync_pass_(done_after_sync_pass) {}
void Start(const AutocompleteInput& input, bool minimal_changes) override {
done_ = done_after_sync_pass_;
task_environment_->FastForwardBy(base::Milliseconds(1));
FakeAutocompleteProvider::Start(input, minimal_changes);
}
// Used to simulate the sync pass consuming 1ms.
raw_ptr<base::test::SingleThreadTaskEnvironment> task_environment_ = nullptr;
// Whether the provider should be done after the sync pass.
bool done_after_sync_pass_;
protected:
~FakeAutocompleteProviderDelayed() override = default;
};
} // namespace
class AutocompleteControllerMetricsTest : public testing::Test {
public:
AutocompleteControllerMetricsTest()
: controller_(&task_environment_),
histogram_tester_(std::make_unique<base::HistogramTester>()) {
controller_.providers_ = {
base::MakeRefCounted<FakeAutocompleteProviderDelayed>(
AutocompleteProvider::Type::TYPE_BOOKMARK, &task_environment_)};
// Allow tests to simulate an initial update with no changes. Since the
// 0-matches cases is special handled, tests can't simply do
// `Simulate(true|false, {})` to simulate an initial update with no changes;
// this allows tests to instead do `Simulate(true|false, {CreateMatch(0)})`.
SimulateStart(true, {CreateMatch(0)});
ResetHistogramTester();
}
AutocompleteMatch CreateMatch(int i) {
const std::string name = base::NumberToString(i);
AutocompleteMatch match{nullptr, 1000, false,
AutocompleteMatchType::HISTORY_URL};
match.destination_url = GURL{"https://google.com/" + name};
return match;
}
// By default, the controller wants async matches. `SetInputSync()` will
// explicitly set this behavior.
void SetInputSync(bool sync) {
controller_.input_.set_omit_asynchronous_matches(sync);
}
// Mimics `AutocompleteController::Start()`'s behavior. `done` determines
// whether the controller should be done after the sync pass. `old_result` and
// `new_result` are passed to
// `AutocompleteControllerMetrics::OnUpdateResult()` to determine which
// matches changed.
void SimulateStart(bool done, std::vector<AutocompleteMatch> matches) {
controller_.GetFakeProvider().matches_ = matches;
controller_.GetFakeProvider().done_ = true;
controller_.GetFakeProvider<FakeAutocompleteProviderDelayed>()
.done_after_sync_pass_ = done;
controller_.Start(controller_.input_);
}
// Mimics `AutocompleteController::NotifyChanged()`'s behavior. `done`
// determines weather the controller should be done after this async update.
// `old_result` and `new_result` are passed to
// `AutocompleteControllerMetrics::OnUpdateResult()` to determine which
// matches changed.
void SimulateAsyncUpdate(bool done, std::vector<AutocompleteMatch> matches) {
controller_.GetFakeProvider().matches_ = matches;
controller_.GetFakeProvider().done_ = done;
task_environment_.FastForwardBy(base::Milliseconds(1));
controller_.OnProviderUpdate(true, &controller_.GetFakeProvider());
}
// Simulates `AutocompleteController::Stop()`.
void SimulateOnStop() {
task_environment_.FastForwardBy(base::Milliseconds(1));
controller_.Stop(AutocompleteStopReason::kInteraction);
}
// Convenience function to be called before/after EXPECT'ing histograms to
// avoid old logs converting new logs.
void ResetHistogramTester() {
histogram_tester_ = std::make_unique<base::HistogramTester>();
}
// Convenience function to call AutocompleteControllerMetrics::OnStop()` and
// expects it to not log any suggestion finalization metrics. Should be used
// to simulate the controller completing in which case metrics should have
// already been logged earlier during `::OnUpdateResult()`. Should not be used
// when the controller is interrupted in which case metrics are expected to be
// logged. Does not check provider or cross stability metrics.
void StopAndExpectNoSuggestionFinalizationMetrics() {
controller_.Stop(AutocompleteStopReason::kClobbered);
ExpectNoSuggestionFinalizationMetrics();
}
// Convenience method to check the buckets of a single metric.
void ExpectMetrics(const std::string metric_name,
std::optional<int> expected_time_ms) {
SCOPED_TRACE(metric_name);
const std::string full_name =
"Omnibox.AsyncAutocompletionTime2." + metric_name;
histogram_tester_->ExpectTotalCount(full_name,
expected_time_ms.has_value());
if (expected_time_ms) {
// Total sum is exact, whereas buckets aren't. E.g. we can't verify
// whether a metric recorded 300 or 301 if the containing bucket is [290,
// 310].
EXPECT_EQ(histogram_tester_->GetTotalSum(full_name), *expected_time_ms);
}
}
// Convenience method to check the buckets of 3 metrics:
// - '...<metric>' will be expected to have `buckets`.
// - '...<metric>.[Completed]' will be expected to either have
// `buckets` or be empty, depending on `completed`.
void ExpectSlicedMetrics(const std::string& metric,
std::optional<int> expected_time_ms,
bool completed) {
ExpectMetrics(metric, expected_time_ms);
ExpectMetrics(metric + ".Completed",
completed ? expected_time_ms : std::nullopt);
ExpectMetrics(metric + ".Interrupted",
!completed ? expected_time_ms : std::nullopt);
}
// Convenience method to check all 9 suggestion finalization metrics are
// empty. '...[Done|LastChange|LastDefaultChange][|.Completed]'
void ExpectNoSuggestionFinalizationMetrics() {
ExpectSlicedMetrics("Done", {}, false);
ExpectSlicedMetrics("LastChange", {}, false);
ExpectSlicedMetrics("LastDefaultChange", {}, false);
}
// Convince method to check all 9 suggestion finalization metrics have been
// logged exactly once with the correct bucket. This should be used if
// there's been a single controller request logged since the last
// `ResetHistogramTester()`. If there have been none,
// `ExpectNoSuggestionFinalizationMetrics()` should be used.
void ExpectSingleCountSuggestionFinalizationMetrics(
int done_bucket_min,
int last_change_bucket_min,
int last_default_change_bucket_min,
bool completed) {
ExpectSlicedMetrics("Done", done_bucket_min, completed);
ExpectSlicedMetrics("LastChange", last_change_bucket_min, completed);
ExpectSlicedMetrics("LastDefaultChange", last_default_change_bucket_min,
completed);
ResetHistogramTester();
}
// Convenience method to check the 3 metrics for a specific provider are
// empty. '...Provider.<Provider>[|.Completed]'
void ExpectNoProviderMetrics(const std::string& provider) {
ExpectSlicedMetrics("Provider." + provider, {}, false);
}
// Convenience method to check the 3 metrics for a specific provider have
// been logged exactly once with the correct bucket. This should be used if
// there's been a single log for the specified provider since the last
// `ResetHistogramTester()`. If there have been none,
// `ExpectNoProviderMetrics()` should be used.
void ExpectProviderMetrics(const std::string& provider,
int bucket_min,
bool completed) {
ExpectSlicedMetrics("Provider." + provider, bucket_min, completed);
}
// Used to control time passed between calls. Many metrics tested are timing
// metrics.
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
FakeAutocompleteController controller_;
std::unique_ptr<base::HistogramTester> histogram_tester_;
};
TEST_F(AutocompleteControllerMetricsTest, SuggestionFinalization_SyncInput) {
// Sync inputs should not log metrics.
SetInputSync(true);
SimulateStart(true, {CreateMatch(1)});
SimulateOnStop();
ExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest,
SuggestionFinalization_OnlySyncUpdate) {
// Sync updates should log metrics.
SimulateStart(true, {CreateMatch(1)});
ExpectSingleCountSuggestionFinalizationMetrics(1, 1, 1, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest,
SuggestionFinalization_OnlySyncUpdateWithNoChanges) {
// Sync updates without changes should log metrics.
SimulateStart(true, {CreateMatch(0)});
ExpectSingleCountSuggestionFinalizationMetrics(1, 0, 0, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest,
SuggestionFinalization_SyncAnd3AsyncUpdate) {
// This is the typical flow: 1 sync update followed by multiple async updates.
SimulateStart(false, {CreateMatch(1)});
// 1st async update.
SimulateAsyncUpdate(false, {CreateMatch(2)});
// 2nd async update.
SimulateAsyncUpdate(false, {CreateMatch(3)});
// Last async update.
SimulateAsyncUpdate(true, {CreateMatch(4)});
ExpectSingleCountSuggestionFinalizationMetrics(4, 4, 4, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest,
SuggestionFinalization_SyncAnd3AsyncUpdateWithNoChanges) {
// 1 sync and 3 async updates, none of the 4 has a change.
SimulateStart(false, {CreateMatch(0)});
// 1st async update.
SimulateAsyncUpdate(false, {CreateMatch(0)});
// 2nd async update.
SimulateAsyncUpdate(false, {CreateMatch(0)});
// Last async update.
SimulateAsyncUpdate(true, {CreateMatch(0)});
ExpectSingleCountSuggestionFinalizationMetrics(4, 0, 0, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(
AutocompleteControllerMetricsTest,
SuggestionFinalization_UnchangedSyncAnd2UnchangedAnd1ChangedAsyncUpdates) {
// 1 sync and 3 async updates, only the last of the 4 has a change.
SimulateStart(false, {CreateMatch(0)});
// 1st async update.
SimulateAsyncUpdate(false, {CreateMatch(0)});
// 2nd async update.
SimulateAsyncUpdate(false, {CreateMatch(0)});
// Last async update.
SimulateAsyncUpdate(true, {CreateMatch(1)});
ExpectSingleCountSuggestionFinalizationMetrics(4, 4, 4, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(
AutocompleteControllerMetricsTest,
SuggestionFinalization_UnchangedSyncAnd1ChangedAnd2UnchangedAsyncUpdates) {
// 1 sync and 3 async updates, only the 2nd of the 4 has a change. Because of
// debouncing, the change doesn't apply until the 4th update.
SimulateStart(false, {CreateMatch(0)});
// 1st async update.
SimulateAsyncUpdate(false, {CreateMatch(1)});
// 2nd async update.
SimulateAsyncUpdate(false, {CreateMatch(1)});
// Last async update.
SimulateAsyncUpdate(true, {CreateMatch(1)});
ExpectSingleCountSuggestionFinalizationMetrics(4, 4, 4, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(
AutocompleteControllerMetricsTest,
SuggestionFinalization_UnchangedSyncAnd1ChangedAnd2UnchangedAsyncUpdates_ChangeAppliedBeforeDone) {
// 1 sync and 3 async updates, only the 2nd of the 4 has a change. The
// debounced change applies before the last update.
SimulateStart(false, {CreateMatch(0)});
// 1st async update.
SimulateAsyncUpdate(false, {CreateMatch(1)});
task_environment_.FastForwardBy(base::Milliseconds(250));
// 2nd async update.
SimulateAsyncUpdate(false, {CreateMatch(1)});
// Last async update.
SimulateAsyncUpdate(true, {CreateMatch(1)});
ExpectSingleCountSuggestionFinalizationMetrics(254, 202, 202, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest,
SuggestionFinalization_ChangedSyncAnd3UnchangedAsyncUpdates) {
// 1 sync and 3 async updates, only the 1st of the 4 has a change.
SimulateStart(false, {CreateMatch(1)});
// 1st async update.
SimulateAsyncUpdate(false, {CreateMatch(1)});
// 2nd async update.
SimulateAsyncUpdate(false, {CreateMatch(1)});
// Last async update.
SimulateAsyncUpdate(true, {CreateMatch(1)});
ExpectSingleCountSuggestionFinalizationMetrics(4, 1, 1, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest,
SuggestionFinalization_StopTimerReached) {
// Simulates the case where the async updates take longer than the 1.5s stop
// timer. It's not possible for the sync update to take longer, as the stop
// timer only starts after the sync update. The logged times should however
// measure starting from before the sync update.
SimulateStart(false, {CreateMatch(1)});
// 1st async update.
SimulateAsyncUpdate(false, {CreateMatch(1)});
// Stop timer.
SimulateOnStop();
ExpectSingleCountSuggestionFinalizationMetrics(3, 1, 1, false);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest, SuggestionFinalization_Interrupted) {
// Start 1st input.
SimulateStart(false, {CreateMatch(1)});
// 1 async update for 1st input.
SimulateAsyncUpdate(false, {CreateMatch(2)});
// Wait for the debouncer.
task_environment_.FastForwardBy(base::Milliseconds(250));
ExpectNoSuggestionFinalizationMetrics();
// Interrupted by 2nd input. The log should include the time until
// interruption.
SimulateStart(false, {CreateMatch(3)});
ExpectSingleCountSuggestionFinalizationMetrics(252, 202, 202, false);
// Interrupted by 3rd input.
task_environment_.FastForwardBy(base::Milliseconds(1));
SimulateStart(false, {CreateMatch(4)});
ExpectSingleCountSuggestionFinalizationMetrics(2, 1, 1, false);
// 1st async update for 3rd input. Controller completes with the 2nd async
// update.
SimulateAsyncUpdate(false, {CreateMatch(5)});
ExpectNoSuggestionFinalizationMetrics();
// 2nd and last async update for 3rd input.
SimulateAsyncUpdate(true, {CreateMatch(6)});
ExpectSingleCountSuggestionFinalizationMetrics(3, 3, 3, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest, SuggestionFinalization_ExpireTimer) {
SimulateStart(true, {CreateMatch(0), CreateMatch(1)});
ResetHistogramTester();
// A sync update without matches. The transferred match should remain.
SimulateStart(false, {CreateMatch(2)});
// Wait for the expire timer.
task_environment_.FastForwardBy(base::Milliseconds(1000));
// Last update with no matches.
ExpectNoSuggestionFinalizationMetrics();
SimulateAsyncUpdate(true, {CreateMatch(2)});
// 500 expire timer + 200 debounce timer + 1 sync pass delay = 701.
ExpectSingleCountSuggestionFinalizationMetrics(1002, 701, 1, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest,
SuggestionFinalization_MatchDeletion) {
SimulateStart(true, {CreateMatch(0), CreateMatch(1)});
ResetHistogramTester();
auto match = CreateMatch(0);
match.provider = &controller_.GetFakeProvider();
match.deletable = true;
// Match deletion with changes. Since autocompletion is complete, finalization
// metrics aren't logged. Stability metrics are logged, but that's just
// arbitrary for consistency with historic behavior / code simplicity, and we
// could stop logging them for deletions if we chose.
controller_.DeleteMatch(match);
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition"),
testing::ElementsAre(base::Bucket(1, 1)));
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest,
SuggestionFinalization_DefaultUnchanged) {
// Sync update with a default match change.
SimulateStart(false, {CreateMatch(1)});
// 1st async update with non-default match changed.
SimulateAsyncUpdate(false, {CreateMatch(1), CreateMatch(2)});
// Wait for the debounce timer.
task_environment_.FastForwardBy(base::Milliseconds(200));
// 2nd async update with no matches changed.
SimulateAsyncUpdate(true, {CreateMatch(1), CreateMatch(2)});
ExpectSingleCountSuggestionFinalizationMetrics(203, 202, 1, true);
StopAndExpectNoSuggestionFinalizationMetrics();
}
TEST_F(AutocompleteControllerMetricsTest, Provider_SyncAndAsyncCompletion) {
controller_.providers_ = {
base::MakeRefCounted<FakeAutocompleteProviderDelayed>(
AutocompleteProvider::Type::TYPE_BOOKMARK, &task_environment_, true),
base::MakeRefCounted<FakeAutocompleteProviderDelayed>(
AutocompleteProvider::Type::TYPE_KEYWORD, &task_environment_),
base::MakeRefCounted<FakeAutocompleteProviderDelayed>(
AutocompleteProvider::Type::TYPE_BUILTIN, &task_environment_),
};
{
SCOPED_TRACE("Sync update with 1st provider completing.");
controller_.GetFakeProvider(0).matches_ = {CreateMatch(0)};
controller_.Start(controller_.input_);
ExpectNoProviderMetrics(controller_.GetFakeProvider(0).GetName());
ExpectNoProviderMetrics(controller_.GetFakeProvider(1).GetName());
ExpectNoProviderMetrics(controller_.GetFakeProvider(2).GetName());
ExpectNoSuggestionFinalizationMetrics();
ResetHistogramTester();
}
{
SCOPED_TRACE("1st async update with 2nd provider completing.");
task_environment_.FastForwardBy(base::Milliseconds(1));
controller_.GetFakeProvider(1).done_ = true;
controller_.OnProviderUpdate(true, &controller_.GetFakeProvider(1));
ExpectNoProviderMetrics(controller_.GetFakeProvider(0).GetName());
ExpectProviderMetrics(controller_.GetFakeProvider(1).GetName(), 4, true);
ExpectNoProviderMetrics(controller_.GetFakeProvider(2).GetName());
ExpectNoSuggestionFinalizationMetrics();
ResetHistogramTester();
}
{
SCOPED_TRACE("Last async update with 3rd provider completing.");
task_environment_.FastForwardBy(base::Milliseconds(1));
controller_.GetFakeProvider(2).done_ = true;
controller_.OnProviderUpdate(true, &controller_.GetFakeProvider(2));
ExpectNoProviderMetrics(controller_.GetFakeProvider(0).GetName());
ExpectNoProviderMetrics(controller_.GetFakeProvider(1).GetName());
ExpectProviderMetrics(controller_.GetFakeProvider(2).GetName(), 5, true);
ExpectSingleCountSuggestionFinalizationMetrics(5, 0, 0, true);
ResetHistogramTester();
}
{
SCOPED_TRACE("Stop.");
StopAndExpectNoSuggestionFinalizationMetrics();
ExpectNoProviderMetrics(controller_.GetFakeProvider(0).GetName());
ExpectNoProviderMetrics(controller_.GetFakeProvider(1).GetName());
ExpectNoProviderMetrics(controller_.GetFakeProvider(2).GetName());
ResetHistogramTester();
}
}
TEST_F(AutocompleteControllerMetricsTest,
Provider_1ProviderWithMultipleUpdates) {
// Sync update without completion.
controller_.GetFakeProvider().done_ = true;
SimulateStart(false, {CreateMatch(0)});
// 1st async update without completion.
SimulateAsyncUpdate(false, {CreateMatch(0)});
// Last async update with completion.
SimulateAsyncUpdate(true, {CreateMatch(0)});
ExpectProviderMetrics(controller_.GetFakeProvider().GetName(), 3, true);
ExpectSingleCountSuggestionFinalizationMetrics(3, 0, 0, true);
StopAndExpectNoSuggestionFinalizationMetrics();
ExpectNoProviderMetrics(controller_.GetFakeProvider().GetName());
}
TEST_F(AutocompleteControllerMetricsTest, Provider_Interrupted) {
controller_.providers_ = {
base::MakeRefCounted<FakeAutocompleteProviderDelayed>(
AutocompleteProvider::Type::TYPE_BOOKMARK, &task_environment_),
base::MakeRefCounted<FakeAutocompleteProviderDelayed>(
AutocompleteProvider::Type::TYPE_KEYWORD, &task_environment_),
};
// Sync update. 1st provider completes; 2nd provider does not.
controller_.GetFakeProvider(0).done_ = true;
controller_.GetFakeProvider(1).done_ = true;
controller_.GetFakeProvider<FakeAutocompleteProviderDelayed>(0)
.done_after_sync_pass_ = true;
controller_.GetFakeProvider<FakeAutocompleteProviderDelayed>(1)
.done_after_sync_pass_ = false;
controller_.Start(controller_.input_);
// 2nd provider is interrupted by stop.
SimulateOnStop();
ExpectNoProviderMetrics(controller_.GetFakeProvider(0).GetName());
ExpectProviderMetrics(controller_.GetFakeProvider(1).GetName(), 3, false);
ExpectSingleCountSuggestionFinalizationMetrics(3, 0, 0, false);
}
TEST_F(AutocompleteControllerMetricsTest, MatchStability) {
auto create_result = [&](std::vector<int> ids) {
std::vector<AutocompleteMatch> matches;
std::ranges::transform(ids, std::back_inserter(matches), [&](int id) {
auto match = CreateMatch(id);
match.relevance -= id;
return match;
});
return matches;
};
const auto first_result = create_result({10, 11, 12, 13, 14});
// Same as `first_result`, but with these changes:
// - Last two matches removed.
// - Default match updated to a new URL.
// - Third match updated to a new URL.
const auto second_result = create_result({0, 11, 20});
// Same as `second_result`, but with these changes:
// - 2 new matches appended to the bottom.
const auto third_result = create_result({0, 11, 20, 21, 22});
// Verify logging to the CrossInput* histograms.
SimulateStart(true, first_result);
ResetHistogramTester();
SimulateStart(true, second_result);
// Expect the default match, third match, and last two matches to be logged
// as changed, and nothing else.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex.CrossInput"),
testing::ElementsAre(base::Bucket(0, 1), base::Bucket(2, 1),
base::Bucket(3, 1), base::Bucket(4, 1)));
// Expect that we log that at least one of the matches has changed.
EXPECT_THAT(
histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition.CrossInput"),
testing::ElementsAre(base::Bucket(1, 1)));
// Expect that we don't log sync updates to the Async histograms.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex.Async"),
testing::ElementsAre());
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition.Async"),
testing::ElementsAre());
// Verify the unsliced histograms.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex"),
testing::ElementsAre(base::Bucket(0, 1), base::Bucket(2, 1),
base::Bucket(3, 1), base::Bucket(4, 1)));
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition"),
testing::ElementsAre(base::Bucket(1, 1)));
ResetHistogramTester();
// Verify logging to the Async* histograms.
SimulateStart(false, first_result);
ResetHistogramTester();
SimulateAsyncUpdate(true, second_result);
// Expect the default match, third match, and last two matches to be logged
// as changed, and nothing else.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex.Async"),
testing::ElementsAre(base::Bucket(0, 1), base::Bucket(2, 1),
base::Bucket(3, 1), base::Bucket(4, 1)));
// Expect that we log that at least one of the matches has changed.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition.Async"),
testing::ElementsAre(base::Bucket(1, 1)));
// Expect that we don't log sync updates to the CrossInput histograms.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex.CrossInput"),
testing::ElementsAre());
EXPECT_THAT(
histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition.CrossInput"),
testing::ElementsAre());
// Verify the unsliced histograms.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex"),
testing::ElementsAre(base::Bucket(0, 1), base::Bucket(2, 1),
base::Bucket(3, 1), base::Bucket(4, 1)));
// Expect that we log that at least one of the matches has changed.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition"),
testing::ElementsAre(base::Bucket(1, 1)));
ResetHistogramTester();
// Verify no logging when appending matches for sync updates.
SimulateStart(true, second_result);
ResetHistogramTester();
SimulateStart(true, third_result);
// Expect no changes logged; expect 1 false logged to each
// MatchChangeInAnyPosition.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex.CrossInput"),
testing::ElementsAre());
EXPECT_THAT(
histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition.CrossInput"),
testing::ElementsAre(base::Bucket(0, 1)));
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex.Async"),
testing::ElementsAre());
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition.Async"),
testing::ElementsAre());
// Verify the unsliced histograms.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex"),
testing::ElementsAre());
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition"),
testing::ElementsAre(base::Bucket(0, 1)));
ResetHistogramTester();
// Verify no logging when appending matches for async updates.
SimulateStart(false, second_result);
ResetHistogramTester();
SimulateAsyncUpdate(true, third_result);
// Expect no changes logged; expect 1 false logged to each
// MatchChangeInAnyPosition.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex.CrossInput"),
testing::ElementsAre());
EXPECT_THAT(
histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition.CrossInput"),
testing::ElementsAre());
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex.Async"),
testing::ElementsAre());
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition.Async"),
testing::ElementsAre(base::Bucket(0, 1)));
// Verify the unsliced histograms.
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeIndex"),
testing::ElementsAre());
EXPECT_THAT(histogram_tester_->GetAllSamples(
"Omnibox.MatchStability2.MatchChangeInAnyPosition"),
testing::ElementsAre(base::Bucket(0, 1)));
ResetHistogramTester();
}