blob: e673edbc2eea626a4e1fc719bcf96e7d5ba7b121 [file] [log] [blame]
// 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 <memory>
#include "base/metrics/metrics_hashes.h"
#include "base/metrics/statistics_recorder.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/segmentation_platform/segmentation_platform_service_factory.h"
#include "chrome/browser/segmentation_platform/ukm_data_manager_test_utils.h"
#include "chrome/browser/segmentation_platform/ukm_database_client.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "components/optimization_guide/core/model_info.h"
#include "components/optimization_guide/core/test_model_info_builder.h"
#include "components/optimization_guide/proto/models.pb.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_observer.h"
#include "components/prefs/pref_service.h"
#include "components/segmentation_platform/embedder/default_model/database_api_clients.h"
#include "components/segmentation_platform/embedder/default_model/optimization_target_segmentation_dummy.h"
#include "components/segmentation_platform/internal/constants.h"
#include "components/segmentation_platform/internal/database/client_result_prefs.h"
#include "components/segmentation_platform/internal/database/ukm_database.h"
#include "components/segmentation_platform/internal/execution/mock_model_provider.h"
#include "components/segmentation_platform/internal/metadata/metadata_writer.h"
#include "components/segmentation_platform/internal/segmentation_platform_service_impl.h"
#include "components/segmentation_platform/internal/stats.h"
#include "components/segmentation_platform/internal/ukm_data_manager.h"
#include "components/segmentation_platform/public/constants.h"
#include "components/segmentation_platform/public/database_client.h"
#include "components/segmentation_platform/public/features.h"
#include "components/segmentation_platform/public/model_provider.h"
#include "components/segmentation_platform/public/proto/aggregation.pb.h"
#include "components/segmentation_platform/public/proto/model_metadata.pb.h"
#include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
#include "components/segmentation_platform/public/result.h"
#include "components/segmentation_platform/public/segmentation_platform_service.h"
#include "components/ukm/ukm_service.h"
#include "content/public/test/browser_test.h"
#include "services/metrics/public/cpp/ukm_builders.h"
namespace segmentation_platform {
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SaveArg;
constexpr SegmentId kSegmentId1 =
SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT;
constexpr SegmentId kSegmentId2 =
SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_DUMMY;
constexpr SegmentId kSegmentId3 =
SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER;
constexpr char kFeatureProcessingHistogram[] =
"SegmentationPlatform.FeatureProcessing.Error.";
constexpr char kSqlFeatureQuery[] = "SELECT COUNT(*) from metrics";
class SegmentationPlatformTest : public PlatformBrowserTest {
public:
explicit SegmentationPlatformTest(bool setup_feature_list = true) {
if (!setup_feature_list) {
return;
}
// Low Engagement Segment is used to test segmentation service without multi
// output. Search User Segment supports multi output path.
feature_list_.InitWithFeaturesAndParameters(
{base::test::FeatureRefAndParams(features::kSegmentationPlatformFeature,
{}),
base::test::FeatureRefAndParams(
features::kSegmentationPlatformUkmEngine, {}),
base::test::FeatureRefAndParams(
features::kSegmentationPlatformLowEngagementFeature,
{{"enable_default_model", "true"}}),
base::test::FeatureRefAndParams(
features::kSegmentationPlatformSearchUser,
{{"enable_default_model", "true"}}),
base::test::FeatureRefAndParams(
kSegmentationPlatformOptimizationTargetSegmentationDummy, {})},
{});
}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch("segmentation-platform-refresh-results");
command_line->AppendSwitch(
"segmentation-platform-disable-model-execution-delay");
}
SegmentationPlatformService* GetService() {
return segmentation_platform::SegmentationPlatformServiceFactory::
GetForProfile(chrome_test_utils::GetProfile(this));
}
bool HasClientResultPref(const std::string& segmentation_key) {
PrefService* pref_service = chrome_test_utils::GetProfile(this)->GetPrefs();
std::unique_ptr<ClientResultPrefs> result_prefs_ =
std::make_unique<ClientResultPrefs>(pref_service);
return result_prefs_->ReadClientResultFromPrefs(segmentation_key) !=
nullptr;
}
void OnClientResultPrefUpdated() {
if (!wait_for_pref_callback_.is_null() &&
HasClientResultPref(kSearchUserKey)) {
std::move(wait_for_pref_callback_).Run();
}
}
void WaitForClientResultPrefUpdate() {
if (HasClientResultPref(kSearchUserKey)) {
return;
}
base::RunLoop wait_for_pref;
wait_for_pref_callback_ = wait_for_pref.QuitClosure();
pref_registrar_.Init(chrome_test_utils::GetProfile(this)->GetPrefs());
pref_registrar_.Add(
kSegmentationClientResultPrefs,
base::BindRepeating(
&SegmentationPlatformTest::OnClientResultPrefUpdated,
weak_ptr_factory_.GetWeakPtr()));
wait_for_pref.Run();
pref_registrar_.RemoveAll();
}
void WaitForPlatformInit() {
base::RunLoop wait_for_init;
SegmentationPlatformService* service = GetService();
while (!service->IsPlatformInitialized()) {
wait_for_init.RunUntilIdle();
}
}
void ExpectDatabaseQuery(const std::vector<std::string>& metrics,
const ModelProvider::Request& result) {
DatabaseClient* client = GetService()->GetDatabaseClient();
ASSERT_TRUE(client);
proto::SegmentationModelMetadata metadata;
MetadataWriter writer(&metadata);
writer.SetDefaultSegmentationMetadataConfig();
for (const std::string& metric : metrics) {
DatabaseApiClients::AddSumQuery(writer, metric, /*days=*/1);
}
base::RunLoop wait;
client->ProcessFeatures(
metadata, base::Time::Now() + base::Minutes(1),
base::BindOnce(
[](base::OnceClosure quit,
const ModelProvider::Request& expected_result,
DatabaseClient::ResultStatus status,
const ModelProvider::Request& result) {
EXPECT_EQ(status, DatabaseClient::ResultStatus::kSuccess);
EXPECT_EQ(expected_result, result);
std::move(quit).Run();
},
wait.QuitClosure(), result));
wait.Run();
}
void RunProcessFeaturesAndCallback(
const proto::SegmentationModelMetadata& metadata,
DatabaseClient::FeaturesCallback callback) {
DatabaseClient* client = GetService()->GetDatabaseClient();
ASSERT_TRUE(client);
base::RunLoop wait;
client->ProcessFeatures(metadata, base::Time::Now() + base::Minutes(1),
base::BindOnce(
[](base::OnceClosure quit,
DatabaseClient::FeaturesCallback callback,
DatabaseClient::ResultStatus status,
const ModelProvider::Request& result) {
std::move(callback).Run(status, result);
std::move(quit).Run();
},
wait.QuitClosure(), std::move(callback)));
wait.Run();
}
void WaitForSegmentInfoDatabaseUpdate(
SegmentId segment_id,
const base::HistogramTester& histogram_tester) {
std::string database_update_histogram =
"SegmentationPlatform.SegmentInfoDatabase.ProtoDBUpdateResult." +
SegmentIdToHistogramVariant(segment_id);
// Wait for model update to be written to disk.
WaitForHistogram(database_update_histogram, histogram_tester);
int success_count =
histogram_tester.GetBucketCount(database_update_histogram, 1);
ASSERT_GE(success_count, 1);
}
void ExpectClassificationResult(const std::string& segmentation_key,
PredictionStatus expected_prediction_status) {
SegmentationPlatformService* service = GetService();
PredictionOptions options;
options.on_demand_execution = false;
base::RunLoop wait_for_segment;
service->GetClassificationResult(
segmentation_key, options, nullptr,
base::BindOnce(&SegmentationPlatformTest::OnGetClassificationResult,
weak_ptr_factory_.GetWeakPtr(),
wait_for_segment.QuitClosure(),
expected_prediction_status));
wait_for_segment.Run();
}
void OnGetClassificationResult(base::RepeatingClosure closure,
PredictionStatus expected_prediction_status,
const ClassificationResult& actual) {
EXPECT_EQ(expected_prediction_status, actual.status);
EXPECT_TRUE(actual.ordered_labels.size() > 0);
std::move(closure).Run();
}
base::HistogramTester& histogram_tester() { return histogram_tester_; }
std::unique_ptr<optimization_guide::ModelInfo>
CreateOptimizationGuideModelInfo(
std::optional<proto::SegmentationModelMetadata>
segmentation_model_metadata) {
auto model_info_builder = optimization_guide::TestModelInfoBuilder();
if (segmentation_model_metadata.has_value()) {
std::string serialized_metadata;
segmentation_model_metadata.value().SerializeToString(
&serialized_metadata);
optimization_guide::proto::Any any_proto;
auto any = std::make_optional(any_proto);
any->set_value(serialized_metadata);
any->set_type_url(
"type.googleapis.com/"
"segmentation_platform.proto.SegmentationModelMetadata");
model_info_builder.SetModelMetadata(any);
}
return model_info_builder.Build();
}
proto::SegmentationModelMetadata GetSegmentationModelMetadataWithSignals() {
std::array<MetadataWriter::UMAFeature, 5> uma_features = {
MetadataWriter::UMAFeature::FromUserAction("Action.Foo", 7),
MetadataWriter::UMAFeature::FromUserAction("Action.Bar", 7),
MetadataWriter::UMAFeature::FromUserAction("Action.Baz", 7),
MetadataWriter::UMAFeature::FromValueHistogram("Histogram.Foo", 7,
proto::Aggregation::SUM),
MetadataWriter::UMAFeature::FromValueHistogram("Histogram.Bar", 7,
proto::Aggregation::SUM),
};
proto::SegmentationModelMetadata search_user_metadata;
MetadataWriter writer = MetadataWriter(&search_user_metadata);
writer.SetSegmentationMetadataConfig(proto::TimeUnit::DAY, 1, 7, 7, 7);
writer.AddUmaFeatures(uma_features.data(), uma_features.size());
return search_user_metadata;
}
void WaitForHistogram(const std::string& histogram_name,
const base::HistogramTester& histogram_tester) {
// Continue if histogram was already recorded.
if (histogram_tester.GetAllSamples(histogram_name).size() > 0) {
return;
}
// Else, wait until the histogram is recorded.
base::RunLoop run_loop;
auto histogram_observer = std::make_unique<
base::StatisticsRecorder::ScopedHistogramSampleObserver>(
histogram_name,
base::BindLambdaForTesting(
[&](const char* histogram_name, uint64_t name_hash,
base::HistogramBase::Sample sample) { run_loop.Quit(); }));
run_loop.Run();
}
protected:
base::HistogramTester histogram_tester_;
base::test::ScopedFeatureList feature_list_;
PrefChangeRegistrar pref_registrar_;
base::OnceClosure wait_for_pref_callback_;
base::WeakPtrFactory<SegmentationPlatformTest> weak_ptr_factory_{this};
};
// https://crbug.com/1257820 -- Tests using "PRE_" don't work on Android.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_PRE_CachedClassificationModel \
DISABLED_PRE_CachedClassificationModel
#define MAYBE_CachedClassificationModel DISABLED_CachedClassificationModel
#else
#define MAYBE_PRE_CachedClassificationModel PRE_CachedClassificationModel
#define MAYBE_CachedClassificationModel CachedClassificationModel
#endif
IN_PROC_BROWSER_TEST_F(SegmentationPlatformTest,
MAYBE_PRE_CachedClassificationModel) {
WaitForPlatformInit();
WaitForClientResultPrefUpdate();
}
IN_PROC_BROWSER_TEST_F(SegmentationPlatformTest,
MAYBE_CachedClassificationModel) {
WaitForPlatformInit();
// Result is available from previous session's prefs.
ExpectClassificationResult(
kSearchUserKey,
/*expected_prediction_status=*/PredictionStatus::kSucceeded);
}
IN_PROC_BROWSER_TEST_F(SegmentationPlatformTest, RunCachedModelsOnly) {
WaitForPlatformInit();
WaitForClientResultPrefUpdate();
// Feature processing isn't called for ondemand models.
// Note: There is no definite way to check if on-demand models do not get
// executed. So we wait until the a default model runs and make sure the
// on-demand model is not executed.
histogram_tester().ExpectUniqueSample(
kFeatureProcessingHistogram + SegmentIdToHistogramVariant(kSegmentId3),
stats::FeatureProcessingError::kSuccess, 1);
histogram_tester().ExpectUniqueSample(
kFeatureProcessingHistogram + SegmentIdToHistogramVariant(kSegmentId2),
stats::FeatureProcessingError::kSuccess, 0);
}
IN_PROC_BROWSER_TEST_F(SegmentationPlatformTest,
ReceiveModelUpdateFromOptimizationGuide) {
WaitForPlatformInit();
auto user_actions_tracked_before_model = histogram_tester().GetTotalSum(
"SegmentationPlatform.Signals.ListeningCount.UserAction");
auto value_histograms_tracked_before_model = histogram_tester().GetTotalSum(
"SegmentationPlatform.Signals.ListeningCount.HistogramValue");
base::HistogramTester histogram_tester_1;
// Create a model metadata with 5 signals, 3 user actions and 2 histograms.
proto::SegmentationModelMetadata search_user_metadata =
GetSegmentationModelMetadataWithSignals();
OptimizationGuideKeyedServiceFactory::GetForProfile(
chrome_test_utils::GetProfile(this))
->OverrideTargetModelForTesting(
optimization_guide::proto::
OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER,
CreateOptimizationGuideModelInfo(search_user_metadata));
// Wait for model update to be written to disk.
WaitForSegmentInfoDatabaseUpdate(
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER, histogram_tester_1);
// Get the number of signals tracked after receiving the new model. Updating
// signals happens synchronously, so there's no need to wait for these
// histograms.
auto user_actions_tracked_after_model = histogram_tester_1.GetTotalSum(
"SegmentationPlatform.Signals.ListeningCount.UserAction");
auto value_histograms_tracked_after_model = histogram_tester_1.GetTotalSum(
"SegmentationPlatform.Signals.ListeningCount.HistogramValue");
EXPECT_EQ(
user_actions_tracked_after_model - user_actions_tracked_before_model, 3);
EXPECT_EQ(value_histograms_tracked_after_model -
value_histograms_tracked_before_model,
2);
// OptimizationGuideSegmentationModelHandler should have recorded that it
// received a model with valid SegmentationModelMetadata.
histogram_tester_1.ExpectUniqueSample(
"SegmentationPlatform.ModelDelivery.HasMetadata." +
SegmentIdToHistogramVariant(
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER),
1, 1);
// OptimizationGuideSegmentationModelHandler should have recorded that it
// received a model with valid metadata.
histogram_tester_1.ExpectUniqueSample(
"SegmentationPlatform.ModelAvailability." +
SegmentIdToHistogramVariant(
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER),
stats::SegmentationModelAvailability::kModelAvailable, 1);
// ModelManagerImpl should have recorded that it received an updated model.
histogram_tester_1.ExpectUniqueSample(
"SegmentationPlatform.ModelDelivery.Received",
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER, 1);
// ModelManagerImpl should have stored the SegmentInfo.
histogram_tester_1.ExpectBucketCount(
"SegmentationPlatform.ModelDelivery.SaveResult." +
SegmentIdToHistogramVariant(
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER),
1, 1);
}
IN_PROC_BROWSER_TEST_F(SegmentationPlatformTest,
ReceiveNullModelUpdateFromOptimizationGuide) {
WaitForPlatformInit();
base::HistogramTester histogram_tester_1;
// Create a model metadata with 5 signals, 3 user actions and 2 histograms.
proto::SegmentationModelMetadata search_user_metadata =
GetSegmentationModelMetadataWithSignals();
// Send a model update event from Optimization Guide to segmentation platform.
OptimizationGuideKeyedServiceFactory::GetForProfile(
chrome_test_utils::GetProfile(this))
->OverrideTargetModelForTesting(
optimization_guide::proto::
OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER,
CreateOptimizationGuideModelInfo(search_user_metadata));
// Count how many user actions and histograms are tracked with this new model,
// updating signals happens synchronously, so there's no need to wait for
// these histograms.
auto user_actions_tracked_before_model_deletion =
histogram_tester_1.GetTotalSum(
"SegmentationPlatform.Signals.ListeningCount.UserAction");
auto value_histograms_tracked_before_model_deletion =
histogram_tester_1.GetTotalSum(
"SegmentationPlatform.Signals.ListeningCount.HistogramValue");
// Wait for model update to be written to disk.
WaitForSegmentInfoDatabaseUpdate(
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER, histogram_tester_1);
// Create a new HistogramTester to only count histograms recorded after
// removing the model.
base::HistogramTester histogram_tester_2;
// Send another model update, this time indicating the model is no longer
// being served.
OptimizationGuideKeyedServiceFactory::GetForProfile(
chrome_test_utils::GetProfile(this))
->OverrideTargetModelForTesting(
optimization_guide::proto::
OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER,
nullptr);
// Count how many user actions and histgrams are tracked after removing this
// model. Updating signals happens synchronously, so there's no need to wait
// for these histograms.
auto user_actions_tracked_after_model_deletion =
histogram_tester_2.GetTotalSum(
"SegmentationPlatform.Signals.ListeningCount.UserAction");
auto value_histograms_tracked_after_model_deletion =
histogram_tester_2.GetTotalSum(
"SegmentationPlatform.Signals.ListeningCount.HistogramValue");
// Wait for model to be removed to disk.
WaitForSegmentInfoDatabaseUpdate(
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER, histogram_tester_2);
// OptimizationGuideSegmentationModelHandler should not record the HasMetadata
// histogram, as it only applies to the SegmentationModelMetadata inside
// ModelInfo.
histogram_tester_2.ExpectUniqueSample(
"SegmentationPlatform.ModelDelivery.HasMetadata." +
SegmentIdToHistogramVariant(
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER),
1, 0);
// OptimizationGuideSegmentationModelHandler should have recorded that the
// optimization target has no model available.
histogram_tester_2.ExpectUniqueSample(
"SegmentationPlatform.ModelAvailability." +
SegmentIdToHistogramVariant(
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER),
stats::SegmentationModelAvailability::kNoModelAvailable, 1);
// ModelManagerImpl should have recorded that it received an updated model.
histogram_tester_2.ExpectUniqueSample(
"SegmentationPlatform.ModelDelivery.Received",
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER, 1);
// ModelManagerImpl should have deleted the previous SegmentInfo.
histogram_tester_2.ExpectUniqueSample(
"SegmentationPlatform.ModelDelivery.DeleteResult." +
SegmentIdToHistogramVariant(
proto::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER),
1, 1);
// SignalFilterProcessor should be tracking 3 fewer user actions after
// removing this model.
EXPECT_EQ(user_actions_tracked_before_model_deletion -
user_actions_tracked_after_model_deletion,
3);
// SignalFilterProcessor should be tracking 2 fewer value histograms after
// removing this model.
EXPECT_EQ(value_histograms_tracked_before_model_deletion -
value_histograms_tracked_after_model_deletion,
2);
// DatabaseMaintenanceImpl should have started a cleanup process, wait for it
// to complete.
WaitForHistogram("SegmentationPlatform.Maintenance.CleanupSignalSuccessCount",
histogram_tester_2);
// DatabaseMaintenanceImpl should have cleaned 5 signals from the database.
histogram_tester_2.ExpectUniqueSample(
"SegmentationPlatform.Maintenance.CleanupSignalSuccessCount", 5, 1);
}
IN_PROC_BROWSER_TEST_F(SegmentationPlatformTest,
NullModelUpdateForUnknownModelShouldBeNoOp) {
WaitForPlatformInit();
// Create a new HistogramTester to only count histograms recorded after
// removing the model.
base::HistogramTester histogram_tester_2;
// Send a model update for an optimization target that wasn't registered.
OptimizationGuideKeyedServiceFactory::GetForProfile(
chrome_test_utils::GetProfile(this))
->OverrideTargetModelForTesting(
optimization_guide::proto::
OPTIMIZATION_TARGET_SEGMENTATION_ADAPTIVE_TOOLBAR,
nullptr);
histogram_tester_2.ExpectUniqueSample(
"SegmentationPlatform.ModelDelivery.HasMetadata." +
SegmentIdToHistogramVariant(
proto::OPTIMIZATION_TARGET_SEGMENTATION_ADAPTIVE_TOOLBAR),
1, 0);
}
class SegmentationPlatformUkmModelTest : public SegmentationPlatformTest {
public:
SegmentationPlatformUkmModelTest()
: utils_(&ukm_recorder_, /*owned_db_client=*/false) {}
void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
PlatformBrowserTest::CreatedBrowserMainParts(parts);
utils_.PreProfileInit(
{{kSegmentId1, utils_.GetSamplePageLoadMetadata(kSqlFeatureQuery)}});
MockDefaultModelProvider* provider = utils_.GetDefaultOverride(kSegmentId1);
EXPECT_CALL(*provider, ExecuteModelWithInput(_, _))
.WillRepeatedly(Invoke([&](const ModelProvider::Request& inputs,
ModelProvider::ExecutionCallback callback) {
input_feature_in_last_execution_ = inputs;
std::move(callback).Run(ModelProvider::Response(1, 0.5));
}));
}
void PreRunTestOnMainThread() override {
SegmentationPlatformTest::PreRunTestOnMainThread();
utils_.set_history_service(HistoryServiceFactory::GetForProfile(
chrome_test_utils::GetProfile(this),
ServiceAccessType::IMPLICIT_ACCESS));
}
protected:
ukm::TestUkmRecorder ukm_recorder_;
UkmDataManagerTestUtils utils_;
std::optional<ModelProvider::Request> input_feature_in_last_execution_;
};
// This test is disabled in CrOS because CrOS creates a signin profile that uses
// incognito mode. This disables the segmentation platform data collection.
// TODO(ssid): Fix this test for CrOS by waiting for signin profile to be
// deleted at startup before adding metrics.
// https://crbug.com/1467530 -- Flaky on Mac
// https://crbug.com/1257820 -- Tests using "PRE_" don't work on Android.
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
#define MAYBE_PRE_RunUkmBasedModel DISABLED_PRE_RunUkmBasedModel
#define MAYBE_RunUkmBasedModel DISABLED_RunUkmBasedModel
#else
#define MAYBE_PRE_RunUkmBasedModel PRE_RunUkmBasedModel
#define MAYBE_RunUkmBasedModel RunUkmBasedModel
#endif
IN_PROC_BROWSER_TEST_F(SegmentationPlatformUkmModelTest,
MAYBE_PRE_RunUkmBasedModel) {
const GURL kUrl1("https://www.url1.com");
WaitForPlatformInit();
utils_.WaitForUkmObserverRegistration();
// Wait for the default model to run and save results to prefs.
WaitForClientResultPrefUpdate();
// Record page load UKM that should be recorded in the database, persisted
// across sessions.
utils_.RecordPageLoadUkm(kUrl1, base::Time::Now());
while (!utils_.IsUrlInDatabase(kUrl1)) {
base::RunLoop().RunUntilIdle();
}
UkmDatabaseClientHolder::GetClientInstance(
chrome_test_utils::GetProfile(this))
.GetUkmDataManager()
->GetUkmDatabase()
->CommitTransactionForTesting();
// There are no UKM metrics written to the database, count = 0.
EXPECT_EQ(ModelProvider::Request({0}), input_feature_in_last_execution_);
}
IN_PROC_BROWSER_TEST_F(SegmentationPlatformUkmModelTest,
MAYBE_RunUkmBasedModel) {
const GURL kUrl1("https://www.url1.com");
WaitForPlatformInit();
// Verify that the URL recorded in last session is still in database.
EXPECT_TRUE(utils_.IsUrlInDatabase(kUrl1));
// Result is available from previous session's selection.
ExpectClassificationResult(
kChromeLowUserEngagementSegmentationKey,
/*expected_prediction_status=*/PredictionStatus::kSucceeded);
utils_.WaitForUkmObserverRegistration();
WaitForClientResultPrefUpdate();
// There are 2 UKM metrics written to the database, count = 2.
EXPECT_EQ(ModelProvider::Request({2}), input_feature_in_last_execution_);
}
IN_PROC_BROWSER_TEST_F(SegmentationPlatformUkmModelTest, DatabaseApi) {
WaitForPlatformInit();
ExpectDatabaseQuery({}, {});
ExpectDatabaseQuery({"test1"}, {0});
DatabaseClient::StructuredEvent e1("TestEvent", {{"test1", 1}, {"test2", 2}});
DatabaseClient::StructuredEvent e2("TestEvent",
{{"test1", 10}, {"test2", 20}});
SegmentationPlatformService* service = GetService();
DatabaseClient* client = service->GetDatabaseClient();
client->AddEvent(e1);
client->AddEvent(e2);
ExpectDatabaseQuery({}, {});
ExpectDatabaseQuery({"test1"}, {11});
ExpectDatabaseQuery({"test1", "test2"}, {11, 22});
}
IN_PROC_BROWSER_TEST_F(SegmentationPlatformUkmModelTest, SumGroupDatabaseApi) {
WaitForPlatformInit();
constexpr char kSampleEventName[] = "TestEvent";
constexpr char kSampleTestMetric1[] = "test1";
constexpr char kSampleTestMetric2[] = "test2";
SegmentationPlatformService* service = GetService();
DatabaseClient* client = service->GetDatabaseClient();
client->AddEvent(
{kSampleEventName, {{kSampleTestMetric1, 1}, {kSampleTestMetric2, 2}}});
client->AddEvent(
{kSampleEventName, {{kSampleTestMetric1, 10}, {kSampleTestMetric2, 20}}});
constexpr char kSampleTestMetric0[] = "test0";
proto::SegmentationModelMetadata metadata;
MetadataWriter writer(&metadata);
writer.SetDefaultSegmentationMetadataConfig();
DatabaseApiClients::AddSumGroupQuery(
writer, kSampleEventName,
{kSampleTestMetric0, kSampleTestMetric1, kSampleTestMetric2},
/*days=*/1);
RunProcessFeaturesAndCallback(
metadata, base::BindOnce([](DatabaseClient::ResultStatus status,
const ModelProvider::Request& result) {
EXPECT_EQ(status, DatabaseClient::ResultStatus::kSuccess);
const std::vector<float> kExpectedResults = {0, 11, 22};
EXPECT_EQ(result, kExpectedResults);
}));
}
class SegmentationPlatformUkmDisabledTest : public SegmentationPlatformTest {
public:
SegmentationPlatformUkmDisabledTest()
: SegmentationPlatformTest(/*setup_feature_list=*/false) {
feature_list_.InitWithFeaturesAndParameters(
{base::test::FeatureRefAndParams(features::kSegmentationPlatformFeature,
{}),
base::test::FeatureRefAndParams(
kSegmentationPlatformOptimizationTargetSegmentationDummy, {})},
/*disabled_features=*/{
features::kSegmentationPlatformUkmEngine,
});
}
};
// On Android tests are failing because of unrelated browser tests failures.
// TODO(ssid): Once the issue is resolved, enable the test on Android.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_DatabaseApi DISABLED_DatabaseApi
#else
#define MAYBE_DatabaseApi DatabaseApi
#endif
IN_PROC_BROWSER_TEST_F(SegmentationPlatformUkmDisabledTest, MAYBE_DatabaseApi) {
WaitForPlatformInit();
SegmentationPlatformService* service = GetService();
DatabaseClient* client = service->GetDatabaseClient();
EXPECT_FALSE(client);
}
} // namespace segmentation_platform