#include <memory>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/task_environment.h"
#include "media/learning/impl/learning_task_controller_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
namespace learning {
class LearningTaskControllerHelperTest : public testing::Test {
public:
class FakeFeatureProvider : public FeatureProvider {
public:
FakeFeatureProvider(FeatureVector* features_out,
FeatureProvider::FeatureVectorCB* cb_out)
: features_out_(features_out), cb_out_(cb_out) {}
void AddFeatures(FeatureVector features,
FeatureProvider::FeatureVectorCB cb) override {
*features_out_ = std::move(features);
*cb_out_ = std::move(cb);
}
raw_ptr<FeatureVector> features_out_;
raw_ptr<FeatureProvider::FeatureVectorCB> cb_out_;
};
LearningTaskControllerHelperTest() {
task_runner_ = base::SequencedTaskRunner::GetCurrentDefault();
task_.name = "example_task";
example_.features.push_back(FeatureValue(1));
example_.features.push_back(FeatureValue(2));
example_.features.push_back(FeatureValue(3));
example_.target_value = TargetValue(123);
example_.weight = 100u;
id_ = base::UnguessableToken::Create();
}
~LearningTaskControllerHelperTest() override {
helper_.reset();
task_environment_.RunUntilIdle();
}
void CreateClient(bool include_fp) {
base::SequenceBound<FakeFeatureProvider> sb_fp;
if (include_fp) {
sb_fp = base::SequenceBound<FakeFeatureProvider>(task_runner_,
&fp_features_, &fp_cb_);
task_environment_.RunUntilIdle();
}
helper_ = std::make_unique<LearningTaskControllerHelper>(
task_,
base::BindRepeating(
&LearningTaskControllerHelperTest::OnLabelledExample,
base::Unretained(this)),
std::move(sb_fp));
}
void OnLabelledExample(LabelledExample example, ukm::SourceId source_id) {
most_recent_example_ = std::move(example);
most_recent_source_id_ = source_id;
}
size_t pending_example_count() const {
return helper_->pending_example_count_for_testing();
}
base::test::TaskEnvironment task_environment_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
std::unique_ptr<LearningTaskControllerHelper> helper_;
FeatureVector fp_features_;
FeatureProvider::FeatureVectorCB fp_cb_;
absl::optional<LabelledExample> most_recent_example_;
ukm::SourceId most_recent_source_id_;
LearningTask task_;
base::UnguessableToken id_;
LabelledExample example_;
};
TEST_F(LearningTaskControllerHelperTest, AddingAnExampleWithoutFPWorks) {
CreateClient(false);
ukm::SourceId source_id = 2;
helper_->BeginObservation(id_, example_.features, source_id);
EXPECT_EQ(pending_example_count(), 1u);
helper_->CompleteObservation(
id_, ObservationCompletion(example_.target_value, example_.weight));
EXPECT_TRUE(most_recent_example_);
EXPECT_EQ(*most_recent_example_, example_);
EXPECT_EQ(most_recent_example_->weight, example_.weight);
EXPECT_EQ(most_recent_source_id_, source_id);
EXPECT_EQ(pending_example_count(), 0u);
}
TEST_F(LearningTaskControllerHelperTest, DropTargetValueWithoutFPWorks) {
CreateClient(false);
helper_->BeginObservation(id_, example_.features, absl::nullopt);
EXPECT_EQ(pending_example_count(), 1u);
helper_->CancelObservation(id_);
task_environment_.RunUntilIdle();
EXPECT_FALSE(most_recent_example_);
EXPECT_EQ(pending_example_count(), 0u);
}
TEST_F(LearningTaskControllerHelperTest, AddTargetValueBeforeFP) {
CreateClient(true);
helper_->BeginObservation(id_, example_.features, absl::nullopt);
EXPECT_EQ(pending_example_count(), 1u);
task_environment_.RunUntilIdle();
EXPECT_EQ(fp_features_, example_.features);
helper_->CompleteObservation(
id_, ObservationCompletion(example_.target_value, example_.weight));
EXPECT_FALSE(most_recent_example_);
EXPECT_EQ(pending_example_count(), 1u);
example_.features[0] = FeatureValue(456);
std::move(fp_cb_).Run(example_.features);
task_environment_.RunUntilIdle();
EXPECT_EQ(pending_example_count(), 0u);
EXPECT_TRUE(most_recent_example_);
EXPECT_EQ(*most_recent_example_, example_);
EXPECT_EQ(most_recent_example_->weight, example_.weight);
}
TEST_F(LearningTaskControllerHelperTest, DropTargetValueBeforeFP) {
CreateClient(true);
helper_->BeginObservation(id_, example_.features, absl::nullopt);
EXPECT_EQ(pending_example_count(), 1u);
task_environment_.RunUntilIdle();
EXPECT_EQ(fp_features_, example_.features);
helper_->CancelObservation(id_);
example_.features[0] = FeatureValue(456);
std::move(fp_cb_).Run(example_.features);
task_environment_.RunUntilIdle();
EXPECT_EQ(pending_example_count(), 0u);
EXPECT_FALSE(most_recent_example_);
}
TEST_F(LearningTaskControllerHelperTest, AddTargetValueAfterFP) {
CreateClient(true);
helper_->BeginObservation(id_, example_.features, absl::nullopt);
EXPECT_EQ(pending_example_count(), 1u);
task_environment_.RunUntilIdle();
EXPECT_EQ(fp_features_, example_.features);
EXPECT_EQ(pending_example_count(), 1u);
example_.features[0] = FeatureValue(456);
std::move(fp_cb_).Run(example_.features);
task_environment_.RunUntilIdle();
EXPECT_FALSE(most_recent_example_);
EXPECT_EQ(pending_example_count(), 1u);
helper_->CompleteObservation(
id_, ObservationCompletion(example_.target_value, example_.weight));
EXPECT_TRUE(most_recent_example_);
EXPECT_EQ(*most_recent_example_, example_);
EXPECT_EQ(most_recent_example_->weight, example_.weight);
EXPECT_EQ(pending_example_count(), 0u);
}
TEST_F(LearningTaskControllerHelperTest, DropTargetValueAfterFP) {
CreateClient(true);
helper_->BeginObservation(id_, example_.features, absl::nullopt);
EXPECT_EQ(pending_example_count(), 1u);
task_environment_.RunUntilIdle();
EXPECT_EQ(fp_features_, example_.features);
EXPECT_EQ(pending_example_count(), 1u);
example_.features[0] = FeatureValue(456);
std::move(fp_cb_).Run(example_.features);
task_environment_.RunUntilIdle();
EXPECT_FALSE(most_recent_example_);
EXPECT_EQ(pending_example_count(), 1u);
helper_->CancelObservation(id_);
task_environment_.RunUntilIdle();
EXPECT_FALSE(most_recent_example_);
EXPECT_EQ(pending_example_count(), 0u);
}
}
}