blob: 8c2d1a33d8366d98ec4b880f4a52256b16521d63 [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.
#include "components/browsing_topics/annotator_impl.h"
#include "base/containers/flat_map.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_model_provider.h"
#include "components/optimization_guide/core/test_model_info_builder.h"
#include "components/optimization_guide/core/test_optimization_guide_model_provider.h"
#include "components/optimization_guide/proto/models.pb.h"
#include "components/optimization_guide/proto/page_topics_model_metadata.pb.h"
#include "components/optimization_guide/proto/page_topics_override_list.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/zlib/google/compression_utils.h"
namespace browsing_topics {
namespace {
const int kTaxonomyVersionV2 = 2;
const char kPageTopicsModelMetadataTypeUrl[] =
"type.googleapis.com/"
"google.internal.chrome.optimizationguide.v1.PageTopicsModelMetadata";
extern const int32_t kTopicsModelVersion = 2;
class ModelObserverTracker
: public optimization_guide::TestOptimizationGuideModelProvider {
public:
void AddObserverForOptimizationTargetModel(
optimization_guide::proto::OptimizationTarget target,
const std::optional<optimization_guide::proto::Any>& model_metadata,
optimization_guide::OptimizationTargetModelObserver* observer) override {
registered_model_metadata_.insert_or_assign(target, model_metadata);
}
bool DidRegisterForTarget(
optimization_guide::proto::OptimizationTarget target,
std::optional<optimization_guide::proto::Any>* out_model_metadata) const {
auto it = registered_model_metadata_.find(target);
if (it == registered_model_metadata_.end()) {
return false;
}
*out_model_metadata = registered_model_metadata_.at(target);
return true;
}
private:
base::flat_map<optimization_guide::proto::OptimizationTarget,
std::optional<optimization_guide::proto::Any>>
registered_model_metadata_;
};
class TestAnnotatorImpl : public AnnotatorImpl {
public:
TestAnnotatorImpl(
optimization_guide::OptimizationGuideModelProvider* model_provider,
scoped_refptr<base::SequencedTaskRunner> background_task_runner,
const std::optional<optimization_guide::proto::Any>& model_metadata)
: AnnotatorImpl(model_provider, background_task_runner, model_metadata) {}
~TestAnnotatorImpl() override = default;
void ExecuteModelWithInput(ExecutionCallback callback,
const std::string& input) override {
inputs_.push_back(input);
std::move(callback).Run(std::nullopt);
}
const std::vector<std::string>& inputs() const { return inputs_; }
private:
std::vector<std::string> inputs_;
};
class BrowsingTopicsAnnotatorImplTest : public testing::Test {
public:
BrowsingTopicsAnnotatorImplTest() {
scoped_feature_list_.InitWithFeatures(
/*enabled_features=*/{},
/*disabled_features=*/{
optimization_guide::features::kPreventLongRunningPredictionModels});
}
~BrowsingTopicsAnnotatorImplTest() override = default;
void SetUp() override {
model_observer_tracker_ = std::make_unique<ModelObserverTracker>();
annotator_ = std::make_unique<TestAnnotatorImpl>(
model_observer_tracker_.get(),
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}),
/*model_metadata=*/std::nullopt);
}
void TearDown() override {
annotator_.reset();
model_observer_tracker_.reset();
RunUntilIdle();
}
void SendModelToAnnotatorSkipWaiting(
const std::optional<optimization_guide::proto::Any>& model_metadata) {
base::FilePath source_root_dir;
base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &source_root_dir);
base::FilePath model_file_path =
source_root_dir.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
.AppendASCII("browsing_topics")
.AppendASCII("golden_data_model.tflite");
std::unique_ptr<optimization_guide::ModelInfo> model_info =
optimization_guide::TestModelInfoBuilder()
.SetModelFilePath(model_file_path)
.SetModelMetadata(model_metadata)
.Build();
annotator()->OnModelUpdated(
optimization_guide::proto::OPTIMIZATION_TARGET_PAGE_TOPICS_V2,
*model_info);
}
void SendModelToAnnotator(
const std::optional<optimization_guide::proto::Any>& model_metadata) {
SendModelToAnnotatorSkipWaiting(model_metadata);
base::RunLoop run_loop;
annotator()->NotifyWhenModelAvailable(run_loop.QuitClosure());
run_loop.Run();
}
ModelObserverTracker* model_observer_tracker() const {
return model_observer_tracker_.get();
}
TestAnnotatorImpl* annotator() const { return annotator_.get(); }
void RunUntilIdle() { task_environment_.RunUntilIdle(); }
protected:
base::test::TaskEnvironment task_environment_;
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<ModelObserverTracker> model_observer_tracker_;
std::unique_ptr<TestAnnotatorImpl> annotator_;
};
TEST_F(
BrowsingTopicsAnnotatorImplTest,
GetContentModelAnnotationsFromOutputNonNumericAndLowWeightCategoriesPruned) {
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
model_metadata.set_version(123);
model_metadata.set_taxonomy_version(kTaxonomyVersionV2);
auto* category_params = model_metadata.mutable_output_postprocessing_params()
->mutable_category_params();
category_params->set_max_categories(4);
category_params->set_min_none_weight(0.8);
category_params->set_min_category_weight(0.01);
category_params->set_min_normalized_weight_within_top_n(0.1);
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
model_metadata.SerializeToString(any_metadata.mutable_value());
SendModelToAnnotator(any_metadata);
std::vector<tflite::task::core::Category> model_output = {
{"0", 0.0001}, {"1", 0.1}, {"not an int", 0.9}, {"2", 0.2}, {"3", 0.3},
};
std::optional<std::vector<int32_t>> categories =
annotator()->ExtractCategoriesFromModelOutput(model_output);
ASSERT_TRUE(categories);
EXPECT_THAT(*categories, testing::UnorderedElementsAre(1, 2, 3));
}
TEST_F(BrowsingTopicsAnnotatorImplTest,
GetContentModelAnnotationsFromOutputNoneWeightTooStrong) {
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
model_metadata.set_version(123);
model_metadata.set_taxonomy_version(kTaxonomyVersionV2);
auto* category_params = model_metadata.mutable_output_postprocessing_params()
->mutable_category_params();
category_params->set_max_categories(4);
category_params->set_min_none_weight(0.1);
category_params->set_min_category_weight(0.01);
category_params->set_min_normalized_weight_within_top_n(0.1);
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
model_metadata.SerializeToString(any_metadata.mutable_value());
SendModelToAnnotator(any_metadata);
std::vector<tflite::task::core::Category> model_output = {
{"-2", 0.9999},
{"0", 0.3},
{"1", 0.2},
};
std::optional<std::vector<int32_t>> categories =
annotator()->ExtractCategoriesFromModelOutput(model_output);
EXPECT_FALSE(categories);
}
TEST_F(BrowsingTopicsAnnotatorImplTest,
GetContentModelAnnotationsFromOutputNoneInTopButNotStrongSoPruned) {
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
model_metadata.set_version(123);
model_metadata.set_taxonomy_version(kTaxonomyVersionV2);
auto* category_params = model_metadata.mutable_output_postprocessing_params()
->mutable_category_params();
category_params->set_max_categories(4);
category_params->set_min_none_weight(0.8);
category_params->set_min_category_weight(0.01);
category_params->set_min_normalized_weight_within_top_n(0.1);
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
model_metadata.SerializeToString(any_metadata.mutable_value());
SendModelToAnnotator(any_metadata);
std::vector<tflite::task::core::Category> model_output = {
{"-2", 0.1}, {"0", 0.3}, {"1", 0.2}, {"2", 0.4}, {"3", 0.05},
};
std::optional<std::vector<int32_t>> categories =
annotator()->ExtractCategoriesFromModelOutput(model_output);
ASSERT_TRUE(categories);
EXPECT_THAT(*categories, testing::UnorderedElementsAre(0, 1, 2));
}
TEST_F(BrowsingTopicsAnnotatorImplTest,
GetContentModelAnnotationsFromOutputPrunedAfterNormalization) {
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
model_metadata.set_version(123);
model_metadata.set_taxonomy_version(kTaxonomyVersionV2);
auto* category_params = model_metadata.mutable_output_postprocessing_params()
->mutable_category_params();
category_params->set_max_categories(4);
category_params->set_min_none_weight(0.8);
category_params->set_min_category_weight(0.01);
category_params->set_min_normalized_weight_within_top_n(0.25);
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
model_metadata.SerializeToString(any_metadata.mutable_value());
SendModelToAnnotator(any_metadata);
std::vector<tflite::task::core::Category> model_output = {
{"0", 0.3},
{"1", 0.25},
{"2", 0.4},
{"3", 0.05},
};
std::optional<std::vector<int32_t>> categories =
annotator()->ExtractCategoriesFromModelOutput(model_output);
ASSERT_TRUE(categories);
EXPECT_THAT(*categories, testing::UnorderedElementsAre(0, 1, 2));
}
// Regression test for crbug.com/1303304.
TEST_F(BrowsingTopicsAnnotatorImplTest, NoneCategoryBelowMinWeight) {
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
model_metadata.set_version(123);
model_metadata.set_taxonomy_version(kTaxonomyVersionV2);
auto* category_params = model_metadata.mutable_output_postprocessing_params()
->mutable_category_params();
category_params->set_max_categories(4);
category_params->set_min_none_weight(0.8);
category_params->set_min_category_weight(0.01);
category_params->set_min_normalized_weight_within_top_n(0.25);
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
model_metadata.SerializeToString(any_metadata.mutable_value());
SendModelToAnnotator(any_metadata);
std::vector<tflite::task::core::Category> model_output = {
{"-2", 0.001}, {"0", 0.001}, {"1", 0.25}, {"2", 0.4}, {"3", 0.05},
};
std::optional<std::vector<int32_t>> categories =
annotator()->ExtractCategoriesFromModelOutput(model_output);
ASSERT_TRUE(categories);
EXPECT_THAT(*categories, testing::UnorderedElementsAre(1, 2));
}
TEST_F(BrowsingTopicsAnnotatorImplTest, HostPreprocessingV1) {
std::vector<std::pair<std::string, std::string>> tests = {
{"www.chromium.org", "chromium org"},
{"foo-bar.com", "foo bar com"},
{"foo_bar.com", "foo bar com"},
{"cats.co.uk", "cats co uk"},
{"cats+dogs.com", "cats dogs com"},
{"www.foo-bar_.baz.com", "foo bar baz com"},
{"www.foo-bar-baz.com", "foo bar baz com"},
{"WwW.LOWER-CASE.com", "lower case com"},
{"m.foo.com", "m foo com"},
{"www2.foo.com", "www2 foo com"},
};
for (const auto& test : tests) {
std::string raw_host = test.first;
std::string processed_host = test.second;
std::string got_input;
// The callback is run synchronously in this test.
annotator()->BatchAnnotate(
base::BindOnce(
[](std::string* got_input_out,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
*got_input_out = annotations[0].input;
},
&got_input),
{raw_host});
EXPECT_EQ(raw_host, got_input);
EXPECT_EQ(processed_host, annotator()->inputs().back());
}
}
TEST_F(BrowsingTopicsAnnotatorImplTest, HostPreprocessingV2) {
std::vector<std::pair<std::string, std::string>> tests = {
{"www.chromium.org", "chromium org"},
{"foo-bar.com", "foo bar com"},
{"foo_bar.com", "foo bar com"},
{"cats.co.uk", "cats co uk"},
{"cats+dogs.com", "cats dogs com"},
{"www.foo-bar_.baz.com", "foo bar baz com"},
{"www.foo-bar-baz.com", "foo bar baz com"},
{"WwW.LOWER-CASE.com", "lower case com"},
{"m.foo.com", "foo com"},
{"web.foo.com", "foo com"},
{"ftp.foo.com", "foo com"},
{"www2.foo.com", "foo com"},
{"home.foo.com", "foo com"},
{"amp.foo.com", "foo com"},
{"mobile.foo.com", "foo com"},
{"wap.foo.com", "foo com"},
{"w.foo.com", "foo com"},
{"www-blaah.foo.com", "www blaah foo com"},
{"www123.foo.com", "foo com"},
{"www.com", "www com"},
{"m.com", "m com"},
{"WEB.foo.com", "foo com"},
};
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(kPageTopicsModelMetadataTypeUrl);
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
model_metadata.set_version(kTopicsModelVersion);
model_metadata.set_taxonomy_version(kTaxonomyVersionV2);
model_metadata.SerializeToString(any_metadata.mutable_value());
SendModelToAnnotator(any_metadata);
for (const auto& test : tests) {
std::string raw_host = test.first;
std::string processed_host = test.second;
std::string got_input;
// The callback is run synchronously in this test.
annotator()->BatchAnnotate(
base::BindOnce(
[](std::string* got_input_out,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
*got_input_out = annotations[0].input;
},
&got_input),
{raw_host});
EXPECT_EQ(raw_host, got_input);
EXPECT_EQ(processed_host, annotator()->inputs().back());
}
}
TEST_F(BrowsingTopicsAnnotatorImplTest, PreprocessingNewVersion) {
std::vector<std::pair<std::string, std::string>> tests = {
{"www.chromium.org", "chromium org"},
{"foo-bar.com", "foo bar com"},
{"foo_bar.com", "foo bar com"},
{"cats.co.uk", "cats co uk"},
{"cats+dogs.com", "cats dogs com"},
{"www.foo-bar_.baz.com", "foo bar baz com"},
{"www.foo-bar-baz.com", "foo bar baz com"},
{"WwW.LOWER-CASE.com", "lower case com"},
{"m.foo.com", "foo com"},
{"web.foo.com", "foo com"},
{"ftp.foo.com", "foo com"},
{"www2.foo.com", "foo com"},
{"home.foo.com", "foo com"},
{"amp.foo.com", "foo com"},
{"mobile.foo.com", "foo com"},
{"wap.foo.com", "foo com"},
{"w.foo.com", "foo com"},
{"www-blaah.foo.com", "www blaah foo com"},
{"www123.foo.com", "foo com"},
{"www.com", "www com"},
{"m.com", "m com"},
{"WEB.foo.com", "foo com"},
};
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(kPageTopicsModelMetadataTypeUrl);
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
model_metadata.set_version(kTopicsModelVersion + 1);
model_metadata.set_taxonomy_version(kTaxonomyVersionV2);
model_metadata.SerializeToString(any_metadata.mutable_value());
SendModelToAnnotator(any_metadata);
for (const auto& test : tests) {
std::string raw_host = test.first;
std::string processed_host = test.second;
std::string got_input;
// The callback is run synchronously in this test.
annotator()->BatchAnnotate(
base::BindOnce(
[](std::string* got_input_out,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
*got_input_out = annotations[0].input;
},
&got_input),
{raw_host});
EXPECT_EQ(raw_host, got_input);
EXPECT_EQ(processed_host, annotator()->inputs().back());
}
}
TEST_F(BrowsingTopicsAnnotatorImplTest,
SameTaxonomyVersions_ModelUpdateSuccess) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeaturesAndParameters(
/*enabled_features=*/
{{blink::features::kBrowsingTopicsParameters,
{{"taxonomy_version", "12345"}}}},
/*disabled_features=*/{
optimization_guide::features::kPreventLongRunningPredictionModels});
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
model_metadata.set_taxonomy_version(12345);
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
model_metadata.SerializeToString(any_metadata.mutable_value());
SendModelToAnnotatorSkipWaiting(any_metadata);
std::optional<optimization_guide::ModelInfo> model_info =
annotator()->GetBrowsingTopicsModelInfo();
EXPECT_TRUE(model_info);
}
TEST_F(BrowsingTopicsAnnotatorImplTest,
TaxonomyConfiguredVersion1ServerVersionEmpty_ModelUpdateSuccess) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeaturesAndParameters(
/*enabled_features=*/
{{blink::features::kBrowsingTopicsParameters,
{{"taxonomy_version", "1"}}}},
/*disabled_features=*/{
optimization_guide::features::kPreventLongRunningPredictionModels});
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
model_metadata.SerializeToString(any_metadata.mutable_value());
SendModelToAnnotatorSkipWaiting(any_metadata);
std::optional<optimization_guide::ModelInfo> model_info =
annotator()->GetBrowsingTopicsModelInfo();
EXPECT_TRUE(model_info);
}
class BrowsingTopicsAnnotatorOverrideListTest
: public BrowsingTopicsAnnotatorImplTest {
public:
BrowsingTopicsAnnotatorOverrideListTest() = default;
~BrowsingTopicsAnnotatorOverrideListTest() override = default;
void SetUp() override {
BrowsingTopicsAnnotatorImplTest::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
}
base::FilePath WriteToTempFile(const std::string& base_name,
const std::string& contents) {
base::FilePath abs_path = temp_dir_.GetPath().AppendASCII(base_name);
EXPECT_TRUE(base::WriteFile(abs_path, contents));
return abs_path;
}
std::string Compress(const std::string& data) {
std::string compressed;
EXPECT_TRUE(compression::GzipCompress(data, &compressed));
return compressed;
}
void SendModelWithAdditionalFilesToAnnotator(
const base::flat_set<base::FilePath>& additional_files) {
optimization_guide::proto::PageTopicsModelMetadata model_metadata;
model_metadata.set_version(123);
model_metadata.set_taxonomy_version(kTaxonomyVersionV2);
optimization_guide::proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
model_metadata.SerializeToString(any_metadata.mutable_value());
base::FilePath source_root_dir;
base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &source_root_dir);
base::FilePath model_file_path =
source_root_dir.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
.AppendASCII("browsing_topics")
// These tests don't need a valid model to execute as we don't care
// about the model output or execution.
.AppendASCII("model_doesnt_exist.tflite");
std::unique_ptr<optimization_guide::ModelInfo> model_info =
optimization_guide::TestModelInfoBuilder()
.SetModelFilePath(model_file_path)
.SetModelMetadata(any_metadata)
.SetAdditionalFiles(additional_files)
.Build();
annotator()->OnModelUpdated(
optimization_guide::proto::OPTIMIZATION_TARGET_PAGE_TOPICS_V2,
*model_info);
base::RunLoop run_loop;
annotator()->NotifyWhenModelAvailable(run_loop.QuitClosure());
run_loop.Run();
}
const base::FilePath& temp_file_path() const { return temp_dir_.GetPath(); }
private:
base::ScopedTempDir temp_dir_;
};
TEST_F(BrowsingTopicsAnnotatorOverrideListTest, FileDoesntExist) {
base::HistogramTester histogram_tester;
base::FilePath doesnt_exist = temp_file_path().Append(
base::FilePath(FILE_PATH_LITERAL("override_list.pb.gz")));
SendModelWithAdditionalFilesToAnnotator({doesnt_exist});
base::RunLoop run_loop;
annotator()->BatchAnnotate(
base::BindOnce(
[](base::RunLoop* run_loop,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
EXPECT_EQ(annotations[0].input, "input");
EXPECT_TRUE(annotations[0].topics.empty());
run_loop->Quit();
},
&run_loop),
{"input"});
run_loop.Run();
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.FileLoadResult",
/*OverrideListFileLoadResult::kCouldNotReadFile=*/2, 1);
histogram_tester.ExpectTotalCount("BrowsingTopics.OverrideList.UsedOverride",
0);
}
TEST_F(BrowsingTopicsAnnotatorOverrideListTest, BadGzip) {
base::HistogramTester histogram_tester;
base::FilePath add_file =
WriteToTempFile("override_list.pb.gz", std::string());
SendModelWithAdditionalFilesToAnnotator({add_file});
base::RunLoop run_loop;
annotator()->BatchAnnotate(
base::BindOnce(
[](base::RunLoop* run_loop,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
EXPECT_EQ(annotations[0].input, "input");
EXPECT_TRUE(annotations[0].topics.empty());
run_loop->Quit();
},
&run_loop),
{"input"});
run_loop.Run();
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.FileLoadResult",
/*OverrideListFileLoadResult::kCouldNotUncompressFile=*/3, 1);
histogram_tester.ExpectTotalCount("BrowsingTopics.OverrideList.UsedOverride",
0);
}
TEST_F(BrowsingTopicsAnnotatorOverrideListTest, BadProto) {
base::HistogramTester histogram_tester;
base::FilePath add_file =
WriteToTempFile("override_list.pb.gz", Compress("bad protobuf"));
SendModelWithAdditionalFilesToAnnotator({add_file});
base::RunLoop run_loop;
annotator()->BatchAnnotate(
base::BindOnce(
[](base::RunLoop* run_loop,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
EXPECT_EQ(annotations[0].input, "input");
EXPECT_TRUE(annotations[0].topics.empty());
run_loop->Quit();
},
&run_loop),
{"input"});
run_loop.Run();
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.FileLoadResult",
/*OverrideListFileLoadResult::kCouldNotUnmarshalProtobuf=*/4, 1);
histogram_tester.ExpectTotalCount("BrowsingTopics.OverrideList.UsedOverride",
0);
}
TEST_F(BrowsingTopicsAnnotatorOverrideListTest, SuccessCase) {
base::HistogramTester histogram_tester;
optimization_guide::proto::PageTopicsOverrideList override_list;
optimization_guide::proto::PageTopicsOverrideEntry* entry =
override_list.add_entries();
entry->set_domain("input com");
entry->mutable_topics()->add_topic_ids(1337);
std::string enc_pb;
ASSERT_TRUE(override_list.SerializeToString(&enc_pb));
base::FilePath add_file =
WriteToTempFile("override_list.pb.gz", Compress(enc_pb));
SendModelWithAdditionalFilesToAnnotator({add_file});
base::RunLoop run_loop;
annotator()->BatchAnnotate(
base::BindOnce(
[](base::RunLoop* run_loop,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
EXPECT_EQ(annotations[0].input, "www.input.com");
EXPECT_EQ(annotations[0].topics, std::vector<int32_t>{1337});
run_loop->Quit();
},
&run_loop),
{"www.input.com"});
run_loop.Run();
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.FileLoadResult",
/*OverrideListFileLoadResult::kSuccess=*/1, 1);
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.UsedOverride", true, 1);
}
TEST_F(BrowsingTopicsAnnotatorOverrideListTest, InputNotInOverride) {
base::HistogramTester histogram_tester;
optimization_guide::proto::PageTopicsOverrideList override_list;
optimization_guide::proto::PageTopicsOverrideEntry* entry =
override_list.add_entries();
entry->set_domain("other");
entry->mutable_topics()->add_topic_ids(1337);
std::string enc_pb;
ASSERT_TRUE(override_list.SerializeToString(&enc_pb));
base::FilePath add_file =
WriteToTempFile("override_list.pb.gz", Compress(enc_pb));
SendModelWithAdditionalFilesToAnnotator({add_file});
base::RunLoop run_loop;
annotator()->BatchAnnotate(
base::BindOnce(
[](base::RunLoop* run_loop,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
EXPECT_EQ(annotations[0].input, "input");
EXPECT_TRUE(annotations[0].topics.empty());
run_loop->Quit();
},
&run_loop),
{"input"});
run_loop.Run();
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.FileLoadResult",
/*OverrideListFileLoadResult::kSuccess=*/1, 1);
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.UsedOverride", false, 1);
}
TEST_F(BrowsingTopicsAnnotatorOverrideListTest, ModelUnloadsOverrideList) {
base::HistogramTester histogram_tester;
optimization_guide::proto::PageTopicsOverrideList override_list;
optimization_guide::proto::PageTopicsOverrideEntry* entry =
override_list.add_entries();
entry->set_domain("input");
entry->mutable_topics()->add_topic_ids(1337);
std::string enc_pb;
ASSERT_TRUE(override_list.SerializeToString(&enc_pb));
base::FilePath add_file =
WriteToTempFile("override_list.pb.gz", Compress(enc_pb));
SendModelWithAdditionalFilesToAnnotator({add_file});
{
base::RunLoop run_loop;
annotator()->BatchAnnotate(
base::BindOnce(
[](base::RunLoop* run_loop,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
EXPECT_EQ(annotations[0].input, "input");
EXPECT_EQ(annotations[0].topics, std::vector<int32_t>{1337});
run_loop->Quit();
},
&run_loop),
{"input"});
run_loop.Run();
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.UsedOverride", true, 1);
}
// Retry an execution and check that the UMA reports the override list being
// loaded twice.
{
base::RunLoop run_loop;
annotator()->BatchAnnotate(
base::BindOnce(
[](base::RunLoop* run_loop,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
EXPECT_EQ(annotations[0].input, "input");
EXPECT_EQ(annotations[0].topics, std::vector<int32_t>{1337});
run_loop->Quit();
},
&run_loop),
{"input"});
run_loop.Run();
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.UsedOverride", true, 2);
}
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.FileLoadResult",
/*OverrideListFileLoadResult::kSuccess=*/1, 2);
}
TEST_F(BrowsingTopicsAnnotatorOverrideListTest, NewModelUnloadsOverrideList) {
base::HistogramTester histogram_tester;
{
optimization_guide::proto::PageTopicsOverrideList override_list;
optimization_guide::proto::PageTopicsOverrideEntry* entry =
override_list.add_entries();
entry->set_domain("input");
entry->mutable_topics()->add_topic_ids(1337);
std::string enc_pb;
ASSERT_TRUE(override_list.SerializeToString(&enc_pb));
base::FilePath add_file =
WriteToTempFile("override_list.pb.gz", Compress(enc_pb));
SendModelWithAdditionalFilesToAnnotator({add_file});
base::RunLoop run_loop;
annotator()->BatchAnnotate(
base::BindOnce(
[](base::RunLoop* run_loop,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
EXPECT_EQ(annotations[0].input, "input");
EXPECT_EQ(annotations[0].topics, std::vector<int32_t>{1337});
run_loop->Quit();
},
&run_loop),
{"input"});
run_loop.Run();
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.UsedOverride", true, 1);
}
// Retry an execution and check that the UMA reports the override list being
// loaded twice, and that the topics are now different.
{
optimization_guide::proto::PageTopicsOverrideList override_list;
optimization_guide::proto::PageTopicsOverrideEntry* entry =
override_list.add_entries();
entry->set_domain("input");
entry->mutable_topics()->add_topic_ids(7331);
std::string enc_pb;
ASSERT_TRUE(override_list.SerializeToString(&enc_pb));
base::FilePath add_file =
WriteToTempFile("override_list.pb.gz", Compress(enc_pb));
SendModelWithAdditionalFilesToAnnotator({add_file});
base::RunLoop run_loop;
annotator()->BatchAnnotate(
base::BindOnce(
[](base::RunLoop* run_loop,
const std::vector<Annotation>& annotations) {
ASSERT_EQ(annotations.size(), 1U);
EXPECT_EQ(annotations[0].input, "input");
EXPECT_EQ(annotations[0].topics, std::vector<int32_t>{7331});
run_loop->Quit();
},
&run_loop),
{"input"});
run_loop.Run();
}
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.FileLoadResult",
/*OverrideListFileLoadResult::kSuccess=*/1, 2);
histogram_tester.ExpectUniqueSample(
"BrowsingTopics.OverrideList.UsedOverride", true, 2);
}
} // namespace
} // namespace browsing_topics