processed_study_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/variations/processed_study.h"
  5. #include <cstdint>
  6. #include "base/test/metrics/histogram_tester.h"
  7. #include "components/variations/proto/study.pb.h"
  8. #include "testing/gtest/include/gtest/gtest.h"
  9. namespace variations {
  10. namespace {
  11. const char kInvalidStudyReasonHistogram[] = "Variations.InvalidStudyReason";
  12. const uint32_t kMaxProbabilityValue =
  13. std::numeric_limits<base::FieldTrial::Probability>::max();
  14. // Adds an experiment with the given name and probability to a study.
  15. Study::Experiment* AddExperiment(const std::string& name,
  16. uint32_t probability,
  17. Study* study) {
  18. Study::Experiment* experiment = study->add_experiment();
  19. experiment->set_name(name);
  20. experiment->set_probability_weight(probability);
  21. return experiment;
  22. }
  23. // Creates a study with the given name.
  24. Study CreateStudy(const std::string& name) {
  25. Study study;
  26. study.set_name(name);
  27. return study;
  28. }
  29. // Creates a valid study named "Study". This study has min and max version
  30. // filters, min and max OS version filters, and three groups: Default, Enabled,
  31. // and Disabled. The Enabled and Disabled groups have GWS IDs. The study's
  32. // default experiment is the Default group.
  33. Study CreateValidStudy() {
  34. Study study = CreateStudy("Study");
  35. Study::Filter* filter = study.mutable_filter();
  36. filter->set_min_version("1.1.*");
  37. filter->set_max_version("2.2.2.2");
  38. filter->set_min_os_version("1");
  39. filter->set_max_os_version("2.*");
  40. Study::Experiment* default_experiment = AddExperiment("Default", 0, &study);
  41. Study::Experiment* enabled_experiment = AddExperiment("Enabled", 50, &study);
  42. enabled_experiment->set_google_web_experiment_id(1);
  43. Study::Experiment* disabled_experiment =
  44. AddExperiment("Disabled", 50, &study);
  45. disabled_experiment->set_google_web_experiment_id(2);
  46. study.set_default_experiment_name(default_experiment->name());
  47. return study;
  48. }
  49. } // namespace
  50. TEST(ProcessedStudyTest, InitValidStudy) {
  51. base::HistogramTester histogram_tester;
  52. Study study = CreateValidStudy();
  53. ProcessedStudy processed_study;
  54. EXPECT_TRUE(processed_study.Init(&study, false));
  55. histogram_tester.ExpectTotalCount(kInvalidStudyReasonHistogram, 0);
  56. }
  57. // Verifies that a study with an invalid min version filter is invalid.
  58. TEST(ProcessedStudyTest, InitInvalidMinVersion) {
  59. base::HistogramTester histogram_tester;
  60. Study study = CreateValidStudy();
  61. study.mutable_filter()->set_min_version("invalid");
  62. ProcessedStudy processed_study;
  63. EXPECT_FALSE(processed_study.Init(&study, false));
  64. histogram_tester.ExpectUniqueSample(
  65. kInvalidStudyReasonHistogram, InvalidStudyReason::kInvalidMinVersion, 1);
  66. }
  67. // Verifies that a study with an invalid max version filter is invalid.
  68. TEST(ProcessedStudyTest, InitInvalidMaxVersion) {
  69. base::HistogramTester histogram_tester;
  70. Study study = CreateValidStudy();
  71. study.mutable_filter()->set_max_version("1.invalid.1");
  72. ProcessedStudy processed_study;
  73. EXPECT_FALSE(processed_study.Init(&study, false));
  74. histogram_tester.ExpectUniqueSample(
  75. kInvalidStudyReasonHistogram, InvalidStudyReason::kInvalidMaxVersion, 1);
  76. }
  77. // Verifies that a study with an invalid min OS version filter is invalid.
  78. TEST(ProcessedStudyTest, InitInvalidMinOsVersion) {
  79. base::HistogramTester histogram_tester;
  80. Study study = CreateValidStudy();
  81. study.mutable_filter()->set_min_os_version("0.*.0");
  82. ProcessedStudy processed_study;
  83. EXPECT_FALSE(processed_study.Init(&study, false));
  84. histogram_tester.ExpectUniqueSample(kInvalidStudyReasonHistogram,
  85. InvalidStudyReason::kInvalidMinOsVersion,
  86. 1);
  87. }
  88. // Verifies that a study with an invalid max OS version filter is invalid.
  89. TEST(ProcessedStudyTest, InitInvalidMaxOsVersion) {
  90. base::HistogramTester histogram_tester;
  91. Study study = CreateValidStudy();
  92. study.mutable_filter()->set_max_os_version("\001\000\000\003");
  93. ProcessedStudy processed_study;
  94. EXPECT_FALSE(processed_study.Init(&study, false));
  95. histogram_tester.ExpectUniqueSample(kInvalidStudyReasonHistogram,
  96. InvalidStudyReason::kInvalidMaxOsVersion,
  97. 1);
  98. }
  99. // Verifies that a study with a blank study name is invalid.
  100. TEST(ProcessedStudyTest, InitBlankStudyName) {
  101. base::HistogramTester histogram_tester;
  102. Study study = CreateValidStudy();
  103. study.set_name("");
  104. ProcessedStudy processed_study;
  105. EXPECT_FALSE(processed_study.Init(&study, false));
  106. histogram_tester.ExpectUniqueSample(kInvalidStudyReasonHistogram,
  107. InvalidStudyReason::kBlankStudyName, 1);
  108. }
  109. // Verifies that a study with an experiment that has no name is invalid.
  110. TEST(ProcessedStudyTest, InitMissingExperimentName) {
  111. base::HistogramTester histogram_tester;
  112. Study study = CreateValidStudy();
  113. AddExperiment("", 0, &study);
  114. ProcessedStudy processed_study;
  115. EXPECT_FALSE(processed_study.Init(&study, false));
  116. histogram_tester.ExpectUniqueSample(
  117. kInvalidStudyReasonHistogram, InvalidStudyReason::kMissingExperimentName,
  118. 1);
  119. }
  120. // Verifies that a study with multiple experiments that are named the same is
  121. // invalid.
  122. TEST(ProcessedStudyTest, InitRepeatedExperimentName) {
  123. base::HistogramTester histogram_tester;
  124. Study study = CreateValidStudy();
  125. AddExperiment("Group", 0, &study);
  126. AddExperiment("Group", 0, &study);
  127. ProcessedStudy processed_study;
  128. EXPECT_FALSE(processed_study.Init(&study, false));
  129. histogram_tester.ExpectUniqueSample(
  130. kInvalidStudyReasonHistogram, InvalidStudyReason::kRepeatedExperimentName,
  131. 1);
  132. }
  133. // Verifies that a study with an experiment that specified both a trigger and
  134. // non-trigger GWS id is invalid.
  135. TEST(ProcessedStudyTest, InitTriggerAndNonTriggerExperimentId) {
  136. base::HistogramTester histogram_tester;
  137. Study study = CreateValidStudy();
  138. Study::Experiment* experiment = AddExperiment("Group", 0, &study);
  139. experiment->set_google_web_experiment_id(123);
  140. experiment->set_google_web_trigger_experiment_id(123);
  141. ProcessedStudy processed_study;
  142. EXPECT_FALSE(processed_study.Init(&study, false));
  143. histogram_tester.ExpectUniqueSample(
  144. kInvalidStudyReasonHistogram,
  145. InvalidStudyReason::kTriggerAndNonTriggerExperimentId, 1);
  146. }
  147. // Verifies that a study with an experiment that has a probability over the
  148. // maximum is invalid.
  149. TEST(ProcessedStudyTest, InitExperimentProbabilityOverflow) {
  150. base::HistogramTester histogram_tester;
  151. Study study = CreateStudy("Study");
  152. AddExperiment("Group", kMaxProbabilityValue + 1, &study);
  153. ProcessedStudy processed_study;
  154. EXPECT_FALSE(processed_study.Init(&study, false));
  155. histogram_tester.ExpectUniqueSample(
  156. kInvalidStudyReasonHistogram,
  157. InvalidStudyReason::kExperimentProbabilityOverflow, 1);
  158. }
  159. // Verifies that a study with groups whose total probability is over the maximum
  160. // is invalid.
  161. TEST(ProcessedStudyTest, InitTotalProbabilityOverflow) {
  162. base::HistogramTester histogram_tester;
  163. Study study = CreateStudy("Study");
  164. AddExperiment("Group1", kMaxProbabilityValue, &study);
  165. AddExperiment("Group2", 1, &study);
  166. ProcessedStudy processed_study;
  167. EXPECT_FALSE(processed_study.Init(&study, false));
  168. histogram_tester.ExpectUniqueSample(
  169. kInvalidStudyReasonHistogram,
  170. InvalidStudyReason::kTotalProbabilityOverflow, 1);
  171. }
  172. // Verifies that a study that specifies a default experiment name but does not
  173. // contain an experiment with that name is invalid.
  174. TEST(ProcessedStudyTest, InitMissingDefaultExperimentInList) {
  175. base::HistogramTester histogram_tester;
  176. Study study = CreateValidStudy();
  177. study.set_default_experiment_name("NonExistentGroup");
  178. ProcessedStudy processed_study;
  179. EXPECT_FALSE(processed_study.Init(&study, false));
  180. histogram_tester.ExpectUniqueSample(
  181. kInvalidStudyReasonHistogram,
  182. InvalidStudyReason::kMissingDefaultExperimentInList, 1);
  183. }
  184. TEST(ProcessedStudyTest, ValidateStudy) {
  185. Study study;
  186. study.set_name("study");
  187. study.set_default_experiment_name("def");
  188. AddExperiment("abc", 100, &study);
  189. Study::Experiment* default_group = AddExperiment("def", 200, &study);
  190. ProcessedStudy processed_study;
  191. EXPECT_TRUE(processed_study.Init(&study, false));
  192. EXPECT_EQ(300, processed_study.total_probability());
  193. EXPECT_FALSE(processed_study.all_assignments_to_one_group());
  194. // Min version checks.
  195. study.mutable_filter()->set_min_version("1.2.3.*");
  196. EXPECT_TRUE(processed_study.Init(&study, false));
  197. study.mutable_filter()->set_min_version("1.*.3");
  198. EXPECT_FALSE(processed_study.Init(&study, false));
  199. study.mutable_filter()->set_min_version("1.2.3");
  200. EXPECT_TRUE(processed_study.Init(&study, false));
  201. // Max version checks.
  202. study.mutable_filter()->set_max_version("2.3.4.*");
  203. EXPECT_TRUE(processed_study.Init(&study, false));
  204. study.mutable_filter()->set_max_version("*.3");
  205. EXPECT_FALSE(processed_study.Init(&study, false));
  206. study.mutable_filter()->set_max_version("2.3.4");
  207. EXPECT_TRUE(processed_study.Init(&study, false));
  208. // A blank default study is allowed.
  209. study.clear_default_experiment_name();
  210. EXPECT_TRUE(processed_study.Init(&study, false));
  211. study.set_default_experiment_name("xyz");
  212. EXPECT_FALSE(processed_study.Init(&study, false));
  213. study.set_default_experiment_name("def");
  214. default_group->clear_name();
  215. EXPECT_FALSE(processed_study.Init(&study, false));
  216. default_group->set_name("def");
  217. EXPECT_TRUE(processed_study.Init(&study, false));
  218. Study::Experiment* repeated_group = study.add_experiment();
  219. repeated_group->set_name("abc");
  220. repeated_group->set_probability_weight(1);
  221. EXPECT_FALSE(processed_study.Init(&study, false));
  222. }
  223. TEST(ProcessedStudyTest, ValidateStudyWithAssociatedFeatures) {
  224. Study study;
  225. study.set_name("study");
  226. study.set_default_experiment_name("def");
  227. Study::Experiment* exp1 = AddExperiment("exp1", 100, &study);
  228. Study::Experiment* exp2 = AddExperiment("exp2", 100, &study);
  229. Study::Experiment* exp3 = AddExperiment("exp3", 100, &study);
  230. AddExperiment("def", 100, &study);
  231. ProcessedStudy processed_study;
  232. EXPECT_TRUE(processed_study.Init(&study, false));
  233. EXPECT_EQ(400, processed_study.total_probability());
  234. EXPECT_THAT(processed_study.associated_features(), ::testing::IsEmpty());
  235. const char kFeature1Name[] = "Feature1";
  236. const char kFeature2Name[] = "Feature2";
  237. exp1->mutable_feature_association()->add_enable_feature(kFeature1Name);
  238. EXPECT_TRUE(processed_study.Init(&study, false));
  239. EXPECT_THAT(processed_study.associated_features(),
  240. ::testing::ElementsAre(kFeature1Name));
  241. exp1->clear_feature_association();
  242. exp1->mutable_feature_association()->add_enable_feature(kFeature1Name);
  243. exp1->mutable_feature_association()->add_enable_feature(kFeature2Name);
  244. EXPECT_TRUE(processed_study.Init(&study, false));
  245. // Since there's multiple different features, |associated_features| should now
  246. // contain them all.
  247. EXPECT_THAT(processed_study.associated_features(),
  248. ::testing::ElementsAre(kFeature1Name, kFeature2Name));
  249. exp1->clear_feature_association();
  250. exp1->mutable_feature_association()->add_enable_feature(kFeature1Name);
  251. exp2->mutable_feature_association()->add_enable_feature(kFeature1Name);
  252. exp3->mutable_feature_association()->add_disable_feature(kFeature1Name);
  253. EXPECT_TRUE(processed_study.Init(&study, false));
  254. EXPECT_THAT(processed_study.associated_features(),
  255. ::testing::ElementsAre(kFeature1Name));
  256. // Setting a different feature name on exp2 should cause |associated_features|
  257. // to contain both feature names.
  258. exp2->mutable_feature_association()->set_enable_feature(0, kFeature2Name);
  259. EXPECT_TRUE(processed_study.Init(&study, false));
  260. EXPECT_THAT(processed_study.associated_features(),
  261. ::testing::ElementsAre(kFeature1Name, kFeature2Name));
  262. // Setting a different activation type should result in empty
  263. // |associated_features|.
  264. study.set_activation_type(Study::ACTIVATE_ON_STARTUP);
  265. EXPECT_TRUE(processed_study.Init(&study, false));
  266. EXPECT_THAT(processed_study.associated_features(), ::testing::IsEmpty());
  267. }
  268. TEST(ProcessedStudyTest, ProcessedStudyAllAssignmentsToOneGroup) {
  269. Study study;
  270. study.set_name("study1");
  271. study.set_default_experiment_name("def");
  272. AddExperiment("def", 100, &study);
  273. ProcessedStudy processed_study;
  274. EXPECT_TRUE(processed_study.Init(&study, false));
  275. EXPECT_TRUE(processed_study.all_assignments_to_one_group());
  276. AddExperiment("abc", 0, &study);
  277. AddExperiment("flag", 0, &study)->set_forcing_flag("flag_test1");
  278. EXPECT_TRUE(processed_study.Init(&study, false));
  279. EXPECT_TRUE(processed_study.all_assignments_to_one_group());
  280. AddExperiment("xyz", 1, &study);
  281. EXPECT_TRUE(processed_study.Init(&study, false));
  282. EXPECT_FALSE(processed_study.all_assignments_to_one_group());
  283. // Try with default group and first group being at 0.
  284. Study study2;
  285. study2.set_name("study2");
  286. study2.set_default_experiment_name("def");
  287. AddExperiment("def", 0, &study2);
  288. AddExperiment("xyz", 34, &study2);
  289. EXPECT_TRUE(processed_study.Init(&study2, false));
  290. EXPECT_TRUE(processed_study.all_assignments_to_one_group());
  291. AddExperiment("abc", 12, &study2);
  292. EXPECT_TRUE(processed_study.Init(&study2, false));
  293. EXPECT_FALSE(processed_study.all_assignments_to_one_group());
  294. }
  295. } // namespace variations