[merchant trust] Add survey config for evaluation surveys

Add features and survey configs for evaluation surveys. They will be attempted to be shown on NTP open if the conditions apply: since feature interaction between [min, max] minutes has passed (will be added in a separate CL).

Bug: 378854311
Change-Id: Ib552295434c42b65f44016d110044e4b310545c4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6185361
Reviewed-by: Martin Šrámek <[email protected]>
Reviewed-by: Nicola Tommasi <[email protected]>
Code-Coverage: [email protected] <[email protected]>
Reviewed-by: Elly FJ <[email protected]>
Commit-Queue: Olesia Marukhno <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1409967}
diff --git a/components/page_info/core/features.cc b/components/page_info/core/features.cc
index e84c198f..856842d 100644
--- a/components/page_info/core/features.cc
+++ b/components/page_info/core/features.cc
@@ -83,4 +83,12 @@
          base::ToLowerASCII(locale) == kMerchantTrustEnabledForLocale;
 }
 
+BASE_FEATURE(kMerchantTrustEvaluationControlSurvey,
+             "MerchantTrustEvaluationControlSurvey",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kMerchantTrustEvaluationExperimentSurvey,
+             "MerchantTrustEvaluationExperimentSurvey",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 }  // namespace page_info
diff --git a/components/page_info/core/features.h b/components/page_info/core/features.h
index f55976c..be807ee 100644
--- a/components/page_info/core/features.h
+++ b/components/page_info/core/features.h
@@ -49,6 +49,19 @@
 extern bool IsMerchantTrustFeatureEnabled(const std::string& country_code,
                                           const std::string& locale);
 
+// Enables the 'Merchant trust' sentiment survey for control group. Used for
+// feature evaluation. This should be set in the fieldtrial config along with
+// the trigger ID for the corresponding survey (as en_site_id) and probability
+// (as probability).
+BASE_DECLARE_FEATURE(kMerchantTrustEvaluationControlSurvey);
+
+// Enables the 'Merchant trust' sentiment survey for experiment group. Used for
+// feature evaluation. The survey will be attempted to be shown on a new tab
+// when all the conditions apply. This should be set in the fieldtrial config
+// along with the trigger ID for the corresponding survey (as en_site_id) and
+// probability (as probability).
+BASE_DECLARE_FEATURE(kMerchantTrustEvaluationExperimentSurvey);
+
 }  // namespace page_info
 
 #endif  // COMPONENTS_PAGE_INFO_CORE_FEATURES_H_
diff --git a/components/page_info/core/merchant_trust_service.cc b/components/page_info/core/merchant_trust_service.cc
index 41317fb75..60c1d57b 100644
--- a/components/page_info/core/merchant_trust_service.cc
+++ b/components/page_info/core/merchant_trust_service.cc
@@ -40,10 +40,12 @@
 }  // namespace
 
 MerchantTrustService::MerchantTrustService(
+    std::unique_ptr<Delegate> delegate,
     optimization_guide::OptimizationGuideDecider* optimization_guide_decider,
     bool is_off_the_record,
     PrefService* prefs)
-    : optimization_guide_decider_(optimization_guide_decider),
+    : delegate_(std::move(delegate)),
+      optimization_guide_decider_(optimization_guide_decider),
       is_off_the_record_(is_off_the_record),
       prefs_(prefs),
       weak_ptr_factory_(this) {
@@ -72,6 +74,12 @@
                      weak_ptr_factory_.GetWeakPtr(), url, std::move(callback)));
 }
 
+void MerchantTrustService::MaybeShowEvaluationSurvey() {
+  if (CanShowEvaluationSurvey()) {
+    delegate_->ShowEvaluationSurvey();
+  }
+}
+
 void MerchantTrustService::OnCanApplyOptimizationComplete(
     const GURL& url,
     MerchantDataCallback callback,
@@ -139,4 +147,20 @@
   return merchant_data;
 }
 
+bool MerchantTrustService::CanShowEvaluationSurvey() {
+  if (base::FeatureList::IsEnabled(
+          page_info::kMerchantTrustEvaluationControlSurvey)) {
+    // TODO(crbug.com/378854311): Check when the feature was used.
+    return true;
+  }
+
+  if (base::FeatureList::IsEnabled(
+          page_info::kMerchantTrustEvaluationExperimentSurvey)) {
+    // TODO(crbug.com/378854311): Check when the feature was used.
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace page_info
diff --git a/components/page_info/core/merchant_trust_service.h b/components/page_info/core/merchant_trust_service.h
index f4cb4b052..07c35e73 100644
--- a/components/page_info/core/merchant_trust_service.h
+++ b/components/page_info/core/merchant_trust_service.h
@@ -29,11 +29,20 @@
 // Provides merchant information for a web site.
 class MerchantTrustService : public KeyedService {
  public:
+  class Delegate {
+   public:
+    // Launches the evaluation survey based on the experiment state.
+    virtual void ShowEvaluationSurvey() = 0;
+
+    virtual ~Delegate() = default;
+  };
+
   using DecisionAndMetadata =
       std::pair<optimization_guide::OptimizationGuideDecision,
                 std::optional<commerce::MerchantTrustSignalsV2>>;
 
-  explicit MerchantTrustService(
+  MerchantTrustService(
+      std::unique_ptr<Delegate> delegate,
       optimization_guide::OptimizationGuideDecider* optimization_guide_decider,
       bool is_off_the_record,
       PrefService* prefs);
@@ -46,7 +55,12 @@
   virtual void GetMerchantTrustInfo(const GURL& url,
                             MerchantDataCallback callback) const;
 
+  // Attempt to show an evaluation survey if the conditions apply. It will show
+  // either a control or an experiment survey depending on the feature state.
+  virtual void MaybeShowEvaluationSurvey();
+
  private:
+  std::unique_ptr<Delegate> delegate_;
   const raw_ptr<optimization_guide::OptimizationGuideDecider>
       optimization_guide_decider_;
   const bool is_off_the_record_;
@@ -66,6 +80,10 @@
 
   std::optional<page_info::MerchantData> GetMerchantDataFromProto(
       const std::optional<commerce::MerchantTrustSignalsV2>& metadata) const;
+
+  // Whether the evaluation survey should be shown based on how long ago user
+  // interacted with the feature.
+  bool CanShowEvaluationSurvey();
 };
 
 }  // namespace page_info
diff --git a/components/page_info/core/merchant_trust_service_unittest.cc b/components/page_info/core/merchant_trust_service_unittest.cc
index 5286bfa7..f94c39f8 100644
--- a/components/page_info/core/merchant_trust_service_unittest.cc
+++ b/components/page_info/core/merchant_trust_service_unittest.cc
@@ -60,11 +60,18 @@
 
 }  // namespace
 
+class MockMerchantTrustServiceDelegate : public MerchantTrustService::Delegate {
+ public:
+  MOCK_METHOD(void, ShowEvaluationSurvey, (), (override));
+};
+
 class MockMerchantTrustService : public MerchantTrustService {
  public:
   explicit MockMerchantTrustService(
-      optimization_guide::OptimizationGuideDecider* optimization_guide_decider)
-      : MerchantTrustService(optimization_guide_decider,
+      optimization_guide::OptimizationGuideDecider* optimization_guide_decider,
+      std::unique_ptr<MockMerchantTrustServiceDelegate> delegate)
+      : MerchantTrustService(std::move(delegate),
+                             optimization_guide_decider,
                              /*is_off_the_record=*/false,
                              nullptr) {}
 
@@ -74,7 +81,10 @@
 class MerchantTrustServiceTest : public ::testing::Test {
  public:
   void SetUp() override {
-    service_ = std::make_unique<MockMerchantTrustService>(&opt_guide());
+    auto delegate = std::make_unique<MockMerchantTrustServiceDelegate>();
+    delegate_ = delegate.get();
+    service_ = std::make_unique<MockMerchantTrustService>(&opt_guide(),
+                                                          std::move(delegate));
     SetOptimizationGuideAllowed(true);
     SetResponse(GURL("https://foo.com"), OptimizationGuideDecision::kUnknown,
                 BuildMerchantTrustResponse());
@@ -107,6 +117,7 @@
   optimization_guide::MockOptimizationGuideDecider& opt_guide() {
     return opt_guide_;
   }
+  MockMerchantTrustServiceDelegate* delegate() { return delegate_; }
 
  private:
   base::test::TaskEnvironment task_environment_{
@@ -114,6 +125,7 @@
   testing::NiceMock<optimization_guide::MockOptimizationGuideDecider>
       opt_guide_;
   std::unique_ptr<MockMerchantTrustService> service_;
+  raw_ptr<MockMerchantTrustServiceDelegate> delegate_;
 };
 
 // Tests that proto are returned correctly when optimization guide decision is
@@ -225,4 +237,45 @@
   t.ExpectUniqueSample("Security.PageInfo.MerchantTrustStatus",
                        MerchantTrustStatus::kMissingReviewsSummary, 1);
 }
+
+// Test for control evaluation survey.
+TEST_F(MerchantTrustServiceTest, ControlSurvey) {
+  base::test::ScopedFeatureList feature_list;
+  EXPECT_CALL(*delegate(), ShowEvaluationSurvey()).Times(1);
+
+  feature_list.InitWithFeatureState(kMerchantTrustEvaluationControlSurvey,
+                                    true);
+  service()->MaybeShowEvaluationSurvey();
+}
+
+// Test for control evaluation survey disabled.
+TEST_F(MerchantTrustServiceTest, ControlSurveyDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  EXPECT_CALL(*delegate(), ShowEvaluationSurvey()).Times(0);
+
+  feature_list.InitWithFeatureState(kMerchantTrustEvaluationControlSurvey,
+                                    false);
+  service()->MaybeShowEvaluationSurvey();
+}
+
+// Test for experiment evaluation survey.
+TEST_F(MerchantTrustServiceTest, ExperimentSurvey) {
+  base::test::ScopedFeatureList feature_list;
+  EXPECT_CALL(*delegate(), ShowEvaluationSurvey()).Times(1);
+
+  feature_list.InitWithFeatureState(kMerchantTrustEvaluationExperimentSurvey,
+                                    true);
+  service()->MaybeShowEvaluationSurvey();
+}
+
+// Test for experiment evaluation survey disabled.
+TEST_F(MerchantTrustServiceTest, ExperimentSurveyDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  EXPECT_CALL(*delegate(), ShowEvaluationSurvey()).Times(0);
+
+  feature_list.InitWithFeatureState(kMerchantTrustEvaluationExperimentSurvey,
+                                    false);
+  service()->MaybeShowEvaluationSurvey();
+}
+
 }  // namespace page_info