field_trial_unittest.cc 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527
  1. // Copyright (c) 2012 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 "base/metrics/field_trial.h"
  5. #include <stddef.h>
  6. #include <utility>
  7. #include "base/base_switches.h"
  8. #include "base/build_time.h"
  9. #include "base/command_line.h"
  10. #include "base/feature_list.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "base/metrics/field_trial_param_associator.h"
  13. #include "base/rand_util.h"
  14. #include "base/run_loop.h"
  15. #include "base/strings/string_number_conversions.h"
  16. #include "base/strings/stringprintf.h"
  17. #include "base/test/gtest_util.h"
  18. #include "base/test/mock_entropy_provider.h"
  19. #include "base/test/multiprocess_test.h"
  20. #include "base/test/scoped_feature_list.h"
  21. #include "base/test/task_environment.h"
  22. #include "base/test/test_shared_memory_util.h"
  23. #include "base/test/test_timeouts.h"
  24. #include "build/build_config.h"
  25. #include "testing/gtest/include/gtest/gtest.h"
  26. #include "testing/multiprocess_func_list.h"
  27. #if !BUILDFLAG(IS_IOS)
  28. #include "base/process/launch.h"
  29. #endif
  30. #if BUILDFLAG(IS_ANDROID)
  31. #include "base/posix/global_descriptors.h"
  32. #endif
  33. #if BUILDFLAG(IS_MAC)
  34. #include "base/mac/mach_port_rendezvous.h"
  35. #endif
  36. namespace base {
  37. namespace {
  38. // Default group name used by several tests.
  39. const char kDefaultGroupName[] = "DefaultGroup";
  40. // Call FieldTrialList::FactoryGetFieldTrial().
  41. scoped_refptr<FieldTrial> CreateFieldTrial(
  42. const std::string& trial_name,
  43. int total_probability,
  44. const std::string& default_group_name,
  45. int* default_group_number) {
  46. return FieldTrialList::FactoryGetFieldTrial(
  47. trial_name, total_probability, default_group_name,
  48. FieldTrial::SESSION_RANDOMIZED, default_group_number);
  49. }
  50. // A FieldTrialList::Observer implementation which stores the trial name and
  51. // group name received via OnFieldTrialGroupFinalized() for later inspection.
  52. class TestFieldTrialObserver : public FieldTrialList::Observer {
  53. public:
  54. TestFieldTrialObserver() { FieldTrialList::AddObserver(this); }
  55. TestFieldTrialObserver(const TestFieldTrialObserver&) = delete;
  56. TestFieldTrialObserver& operator=(const TestFieldTrialObserver&) = delete;
  57. ~TestFieldTrialObserver() override { FieldTrialList::RemoveObserver(this); }
  58. void OnFieldTrialGroupFinalized(const std::string& trial,
  59. const std::string& group) override {
  60. trial_name_ = trial;
  61. group_name_ = group;
  62. }
  63. const std::string& trial_name() const { return trial_name_; }
  64. const std::string& group_name() const { return group_name_; }
  65. private:
  66. std::string trial_name_;
  67. std::string group_name_;
  68. };
  69. // A FieldTrialList::Observer implementation which accesses the group of a
  70. // FieldTrial from OnFieldTrialGroupFinalized(). Used to test reentrancy.
  71. class FieldTrialObserverAccessingGroup : public FieldTrialList::Observer {
  72. public:
  73. // |trial_to_access| is the FieldTrial on which to invoke group() when
  74. // receiving an OnFieldTrialGroupFinalized() notification.
  75. explicit FieldTrialObserverAccessingGroup(
  76. scoped_refptr<FieldTrial> trial_to_access)
  77. : trial_to_access_(trial_to_access) {
  78. FieldTrialList::AddObserver(this);
  79. }
  80. FieldTrialObserverAccessingGroup(const FieldTrialObserverAccessingGroup&) =
  81. delete;
  82. FieldTrialObserverAccessingGroup& operator=(
  83. const FieldTrialObserverAccessingGroup&) = delete;
  84. ~FieldTrialObserverAccessingGroup() override {
  85. FieldTrialList::RemoveObserver(this);
  86. }
  87. void OnFieldTrialGroupFinalized(const std::string& trial,
  88. const std::string& group) override {
  89. trial_to_access_->group();
  90. }
  91. private:
  92. scoped_refptr<FieldTrial> trial_to_access_;
  93. };
  94. std::string MockEscapeQueryParamValue(const std::string& input) {
  95. return input;
  96. }
  97. } // namespace
  98. class FieldTrialTest : public ::testing::Test {
  99. public:
  100. FieldTrialTest() {
  101. // The test suite instantiates a FieldTrialList but for the purpose of these
  102. // tests it's cleaner to start from scratch.
  103. scoped_feature_list_.InitWithEmptyFeatureAndFieldTrialLists();
  104. }
  105. FieldTrialTest(const FieldTrialTest&) = delete;
  106. FieldTrialTest& operator=(const FieldTrialTest&) = delete;
  107. private:
  108. test::TaskEnvironment task_environment_;
  109. test::ScopedFeatureList scoped_feature_list_;
  110. };
  111. // Test registration, and also check that destructors are called for trials.
  112. TEST_F(FieldTrialTest, Registration) {
  113. const char name1[] = "name 1 test";
  114. const char name2[] = "name 2 test";
  115. EXPECT_FALSE(FieldTrialList::Find(name1));
  116. EXPECT_FALSE(FieldTrialList::Find(name2));
  117. scoped_refptr<FieldTrial> trial1 =
  118. CreateFieldTrial(name1, 10, "default name 1 test", nullptr);
  119. EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_);
  120. EXPECT_EQ(name1, trial1->trial_name());
  121. EXPECT_EQ("", trial1->group_name_internal());
  122. trial1->AppendGroup(std::string(), 7);
  123. EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
  124. EXPECT_FALSE(FieldTrialList::Find(name2));
  125. scoped_refptr<FieldTrial> trial2 =
  126. CreateFieldTrial(name2, 10, "default name 2 test", nullptr);
  127. EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_);
  128. EXPECT_EQ(name2, trial2->trial_name());
  129. EXPECT_EQ("", trial2->group_name_internal());
  130. trial2->AppendGroup("a first group", 7);
  131. EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
  132. EXPECT_EQ(trial2.get(), FieldTrialList::Find(name2));
  133. // Note: FieldTrialList should delete the objects at shutdown.
  134. }
  135. TEST_F(FieldTrialTest, AbsoluteProbabilities) {
  136. char always_true[] = " always true";
  137. char default_always_true[] = " default always true";
  138. char always_false[] = " always false";
  139. char default_always_false[] = " default always false";
  140. for (int i = 1; i < 250; ++i) {
  141. // Try lots of names, by changing the first character of the name.
  142. char c = static_cast<char>(i);
  143. always_true[0] = c;
  144. default_always_true[0] = c;
  145. always_false[0] = c;
  146. default_always_false[0] = c;
  147. scoped_refptr<FieldTrial> trial_true =
  148. CreateFieldTrial(always_true, 10, default_always_true, nullptr);
  149. const std::string winner = "TheWinner";
  150. int winner_group = trial_true->AppendGroup(winner, 10);
  151. EXPECT_EQ(winner_group, trial_true->group());
  152. EXPECT_EQ(winner, trial_true->group_name());
  153. scoped_refptr<FieldTrial> trial_false =
  154. CreateFieldTrial(always_false, 10, default_always_false, nullptr);
  155. int loser_group = trial_false->AppendGroup("ALoser", 0);
  156. EXPECT_NE(loser_group, trial_false->group());
  157. }
  158. }
  159. TEST_F(FieldTrialTest, RemainingProbability) {
  160. // First create a test that hasn't had a winner yet.
  161. const std::string winner = "Winner";
  162. const std::string loser = "Loser";
  163. scoped_refptr<FieldTrial> trial;
  164. int counter = 0;
  165. int default_group_number = -1;
  166. do {
  167. std::string name = StringPrintf("trial%d", ++counter);
  168. trial = CreateFieldTrial(name, 10, winner, &default_group_number);
  169. trial->AppendGroup(loser, 5); // 50% chance of not being chosen.
  170. // If a group is not assigned, group_ will be kNotFinalized.
  171. } while (trial->group_ != FieldTrial::kNotFinalized);
  172. // And that 'default' group (winner) should always win.
  173. EXPECT_EQ(default_group_number, trial->group());
  174. // And that winner should ALWAYS win.
  175. EXPECT_EQ(winner, trial->group_name());
  176. }
  177. TEST_F(FieldTrialTest, FiftyFiftyProbability) {
  178. // Check that even with small divisors, we have the proper probabilities, and
  179. // all outcomes are possible. Since this is a 50-50 test, it should get both
  180. // outcomes in a few tries, but we'll try no more than 100 times (and be flaky
  181. // with probability around 1 in 2^99).
  182. bool first_winner = false;
  183. bool second_winner = false;
  184. int counter = 0;
  185. do {
  186. std::string name = StringPrintf("FiftyFifty%d", ++counter);
  187. std::string default_group_name =
  188. StringPrintf("Default FiftyFifty%d", ++counter);
  189. scoped_refptr<FieldTrial> trial =
  190. CreateFieldTrial(name, 2, default_group_name, nullptr);
  191. trial->AppendGroup("first", 1); // 50% chance of being chosen.
  192. // If group_ is kNotFinalized, then a group assignement hasn't been done.
  193. if (trial->group_ != FieldTrial::kNotFinalized) {
  194. first_winner = true;
  195. continue;
  196. }
  197. trial->AppendGroup("second", 1); // Always chosen at this point.
  198. EXPECT_NE(FieldTrial::kNotFinalized, trial->group());
  199. second_winner = true;
  200. } while ((!second_winner || !first_winner) && counter < 100);
  201. EXPECT_TRUE(second_winner);
  202. EXPECT_TRUE(first_winner);
  203. }
  204. TEST_F(FieldTrialTest, MiddleProbabilities) {
  205. char name[] = " same name";
  206. char default_group_name[] = " default same name";
  207. bool false_event_seen = false;
  208. bool true_event_seen = false;
  209. for (int i = 1; i < 250; ++i) {
  210. char c = static_cast<char>(i);
  211. name[0] = c;
  212. default_group_name[0] = c;
  213. scoped_refptr<FieldTrial> trial =
  214. CreateFieldTrial(name, 10, default_group_name, nullptr);
  215. int might_win = trial->AppendGroup("MightWin", 5);
  216. if (trial->group() == might_win) {
  217. true_event_seen = true;
  218. } else {
  219. false_event_seen = true;
  220. }
  221. if (false_event_seen && true_event_seen)
  222. return; // Successful test!!!
  223. }
  224. // Very surprising to get here. Probability should be around 1 in 2 ** 250.
  225. // One of the following will fail.
  226. EXPECT_TRUE(false_event_seen);
  227. EXPECT_TRUE(true_event_seen);
  228. }
  229. TEST_F(FieldTrialTest, OneWinner) {
  230. char name[] = "Some name";
  231. char default_group_name[] = "Default some name";
  232. int group_count(10);
  233. int default_group_number = -1;
  234. scoped_refptr<FieldTrial> trial =
  235. CreateFieldTrial(name, group_count, default_group_name, nullptr);
  236. int winner_index(-2);
  237. std::string winner_name;
  238. for (int i = 1; i <= group_count; ++i) {
  239. int might_win = trial->AppendGroup(std::string(), 1);
  240. // Because we keep appending groups, we want to see if the last group that
  241. // was added has been assigned or not.
  242. if (trial->group_ == might_win) {
  243. EXPECT_EQ(-2, winner_index);
  244. winner_index = might_win;
  245. StringAppendF(&winner_name, "%d", might_win);
  246. EXPECT_EQ(winner_name, trial->group_name());
  247. }
  248. }
  249. EXPECT_GE(winner_index, 0);
  250. // Since all groups cover the total probability, we should not have
  251. // chosen the default group.
  252. EXPECT_NE(trial->group(), default_group_number);
  253. EXPECT_EQ(trial->group(), winner_index);
  254. EXPECT_EQ(trial->group_name(), winner_name);
  255. }
  256. TEST_F(FieldTrialTest, DisableProbability) {
  257. const std::string default_group_name = "Default group";
  258. const std::string loser = "Loser";
  259. const std::string name = "Trial";
  260. // Create a field trail that is disabled.
  261. int default_group_number = -1;
  262. FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
  263. name, 1000000000, default_group_name, FieldTrial::SESSION_RANDOMIZED,
  264. &default_group_number);
  265. trial->Disable();
  266. trial->AppendGroup(loser, 999999999); // 99.9999999% chance of being chosen.
  267. // Because trial has expired, we should always be in the default group.
  268. EXPECT_EQ(default_group_number, trial->group());
  269. // And that default_group_name should ALWAYS win.
  270. EXPECT_EQ(default_group_name, trial->group_name());
  271. }
  272. TEST_F(FieldTrialTest, ActiveGroups) {
  273. std::string no_group("No Group");
  274. scoped_refptr<FieldTrial> trial =
  275. CreateFieldTrial(no_group, 10, "Default", nullptr);
  276. // There is no winner yet, so no NameGroupId should be returned.
  277. FieldTrial::ActiveGroup active_group;
  278. EXPECT_FALSE(trial->GetActiveGroup(&active_group));
  279. // Create a single winning group.
  280. std::string one_winner("One Winner");
  281. trial = CreateFieldTrial(one_winner, 10, "Default", nullptr);
  282. std::string winner("Winner");
  283. trial->AppendGroup(winner, 10);
  284. EXPECT_FALSE(trial->GetActiveGroup(&active_group));
  285. // Finalize the group selection by accessing the selected group.
  286. trial->group();
  287. EXPECT_TRUE(trial->GetActiveGroup(&active_group));
  288. EXPECT_EQ(one_winner, active_group.trial_name);
  289. EXPECT_EQ(winner, active_group.group_name);
  290. std::string multi_group("MultiGroup");
  291. scoped_refptr<FieldTrial> multi_group_trial =
  292. CreateFieldTrial(multi_group, 9, "Default", nullptr);
  293. multi_group_trial->AppendGroup("Me", 3);
  294. multi_group_trial->AppendGroup("You", 3);
  295. multi_group_trial->AppendGroup("Them", 3);
  296. EXPECT_FALSE(multi_group_trial->GetActiveGroup(&active_group));
  297. // Finalize the group selection by accessing the selected group.
  298. multi_group_trial->group();
  299. EXPECT_TRUE(multi_group_trial->GetActiveGroup(&active_group));
  300. EXPECT_EQ(multi_group, active_group.trial_name);
  301. EXPECT_EQ(multi_group_trial->group_name(), active_group.group_name);
  302. // Now check if the list is built properly...
  303. FieldTrial::ActiveGroups active_groups;
  304. FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
  305. EXPECT_EQ(2U, active_groups.size());
  306. for (size_t i = 0; i < active_groups.size(); ++i) {
  307. // Order is not guaranteed, so check all values.
  308. EXPECT_NE(no_group, active_groups[i].trial_name);
  309. EXPECT_TRUE(one_winner != active_groups[i].trial_name ||
  310. winner == active_groups[i].group_name);
  311. EXPECT_TRUE(multi_group != active_groups[i].trial_name ||
  312. multi_group_trial->group_name() == active_groups[i].group_name);
  313. }
  314. }
  315. TEST_F(FieldTrialTest, GetActiveFieldTrialGroupsFromString) {
  316. FieldTrial::ActiveGroups active_groups;
  317. FieldTrialList::GetActiveFieldTrialGroupsFromString("*A/X/B/Y/*C/Z",
  318. &active_groups);
  319. ASSERT_EQ(2U, active_groups.size());
  320. EXPECT_EQ("A", active_groups[0].trial_name);
  321. EXPECT_EQ("X", active_groups[0].group_name);
  322. EXPECT_EQ("C", active_groups[1].trial_name);
  323. EXPECT_EQ("Z", active_groups[1].group_name);
  324. }
  325. TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
  326. const char kTrialName[] = "TestTrial";
  327. const char kSecondaryGroupName[] = "SecondaryGroup";
  328. int default_group = -1;
  329. scoped_refptr<FieldTrial> trial =
  330. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
  331. const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
  332. // Before |group()| is called, |GetActiveGroup()| should return false.
  333. FieldTrial::ActiveGroup active_group;
  334. EXPECT_FALSE(trial->GetActiveGroup(&active_group));
  335. // |GetActiveFieldTrialGroups()| should also not include the trial.
  336. FieldTrial::ActiveGroups active_groups;
  337. FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
  338. EXPECT_TRUE(active_groups.empty());
  339. // After |group()| has been called, both APIs should succeed.
  340. const int chosen_group = trial->group();
  341. EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
  342. EXPECT_TRUE(trial->GetActiveGroup(&active_group));
  343. EXPECT_EQ(kTrialName, active_group.trial_name);
  344. if (chosen_group == default_group)
  345. EXPECT_EQ(kDefaultGroupName, active_group.group_name);
  346. else
  347. EXPECT_EQ(kSecondaryGroupName, active_group.group_name);
  348. FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
  349. ASSERT_EQ(1U, active_groups.size());
  350. EXPECT_EQ(kTrialName, active_groups[0].trial_name);
  351. EXPECT_EQ(active_group.group_name, active_groups[0].group_name);
  352. }
  353. TEST_F(FieldTrialTest, GetGroupNameWithoutActivation) {
  354. const char kTrialName[] = "TestTrial";
  355. const char kSecondaryGroupName[] = "SecondaryGroup";
  356. int default_group = -1;
  357. scoped_refptr<FieldTrial> trial =
  358. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
  359. trial->AppendGroup(kSecondaryGroupName, 50);
  360. // The trial should start inactive.
  361. EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
  362. // Calling |GetGroupNameWithoutActivation()| should not activate the trial.
  363. std::string group_name = trial->GetGroupNameWithoutActivation();
  364. EXPECT_FALSE(group_name.empty());
  365. EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
  366. // Calling |group_name()| should activate it and return the same group name.
  367. EXPECT_EQ(group_name, trial->group_name());
  368. EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
  369. }
  370. TEST_F(FieldTrialTest, Save) {
  371. std::string save_string;
  372. scoped_refptr<FieldTrial> trial =
  373. CreateFieldTrial("Some name", 10, "Default some name", nullptr);
  374. // There is no winner yet, so no textual group name is associated with trial.
  375. // In this case, the trial should not be included.
  376. EXPECT_EQ("", trial->group_name_internal());
  377. FieldTrialList::StatesToString(&save_string);
  378. EXPECT_EQ("", save_string);
  379. save_string.clear();
  380. // Create a winning group.
  381. trial->AppendGroup("Winner", 10);
  382. // Finalize the group selection by accessing the selected group.
  383. trial->group();
  384. FieldTrialList::StatesToString(&save_string);
  385. EXPECT_EQ("Some name/Winner/", save_string);
  386. save_string.clear();
  387. // Create a second trial and winning group.
  388. scoped_refptr<FieldTrial> trial2 =
  389. CreateFieldTrial("xxx", 10, "Default xxx", nullptr);
  390. trial2->AppendGroup("yyyy", 10);
  391. // Finalize the group selection by accessing the selected group.
  392. trial2->group();
  393. FieldTrialList::StatesToString(&save_string);
  394. // We assume names are alphabetized... though this is not critical.
  395. EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string);
  396. save_string.clear();
  397. // Create a third trial with only the default group.
  398. scoped_refptr<FieldTrial> trial3 =
  399. CreateFieldTrial("zzz", 10, "default", nullptr);
  400. // Finalize the group selection by accessing the selected group.
  401. trial3->group();
  402. FieldTrialList::StatesToString(&save_string);
  403. EXPECT_EQ("Some name/Winner/xxx/yyyy/zzz/default/", save_string);
  404. }
  405. TEST_F(FieldTrialTest, SaveAll) {
  406. std::string save_string;
  407. scoped_refptr<FieldTrial> trial =
  408. CreateFieldTrial("Some name", 10, "Default some name", nullptr);
  409. EXPECT_EQ("", trial->group_name_internal());
  410. FieldTrialList::AllStatesToString(&save_string, false);
  411. EXPECT_EQ("Some name/Default some name/", save_string);
  412. // Getting all states should have finalized the trial.
  413. EXPECT_EQ("Default some name", trial->group_name_internal());
  414. save_string.clear();
  415. // Create a winning group.
  416. trial = CreateFieldTrial("trial2", 10, "Default some name", nullptr);
  417. trial->AppendGroup("Winner", 10);
  418. // Finalize the group selection by accessing the selected group.
  419. trial->group();
  420. FieldTrialList::AllStatesToString(&save_string, false);
  421. EXPECT_EQ("Some name/Default some name/*trial2/Winner/", save_string);
  422. save_string.clear();
  423. // Create a second trial and winning group.
  424. scoped_refptr<FieldTrial> trial2 =
  425. CreateFieldTrial("xxx", 10, "Default xxx", nullptr);
  426. trial2->AppendGroup("yyyy", 10);
  427. // Finalize the group selection by accessing the selected group.
  428. trial2->group();
  429. FieldTrialList::AllStatesToString(&save_string, false);
  430. // We assume names are alphabetized... though this is not critical.
  431. EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/",
  432. save_string);
  433. save_string.clear();
  434. // Create a third trial with only the default group.
  435. scoped_refptr<FieldTrial> trial3 =
  436. CreateFieldTrial("zzz", 10, "default", nullptr);
  437. FieldTrialList::AllStatesToString(&save_string, false);
  438. EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default/",
  439. save_string);
  440. // Create disabled study.
  441. int default_group_number = -1;
  442. scoped_refptr<FieldTrial> disabled_trial =
  443. FieldTrialList::FactoryGetFieldTrial(
  444. "Disabled trial name", 1000000000, "Default group",
  445. FieldTrial::SESSION_RANDOMIZED, &default_group_number);
  446. disabled_trial->AppendGroup("Disabled trial group name", 999999999);
  447. disabled_trial->Disable();
  448. save_string.clear();
  449. FieldTrialList::AllStatesToString(&save_string, false);
  450. EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default/",
  451. save_string);
  452. save_string.clear();
  453. FieldTrialList::AllStatesToString(&save_string, true);
  454. EXPECT_EQ(
  455. "Disabled trial name/Default group/"
  456. "Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default/",
  457. save_string);
  458. }
  459. TEST_F(FieldTrialTest, Restore) {
  460. ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
  461. ASSERT_FALSE(FieldTrialList::TrialExists("xxx"));
  462. FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/");
  463. FieldTrial* trial = FieldTrialList::Find("Some_name");
  464. ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial);
  465. EXPECT_EQ("Winner", trial->group_name());
  466. EXPECT_EQ("Some_name", trial->trial_name());
  467. trial = FieldTrialList::Find("xxx");
  468. ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial);
  469. EXPECT_EQ("yyyy", trial->group_name());
  470. EXPECT_EQ("xxx", trial->trial_name());
  471. }
  472. TEST_F(FieldTrialTest, RestoreNotEndingWithSlash) {
  473. EXPECT_TRUE(FieldTrialList::CreateTrialsFromString("tname/gname"));
  474. FieldTrial* trial = FieldTrialList::Find("tname");
  475. ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial);
  476. EXPECT_EQ("gname", trial->group_name());
  477. EXPECT_EQ("tname", trial->trial_name());
  478. }
  479. TEST_F(FieldTrialTest, BogusRestore) {
  480. EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingSlash"));
  481. EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingGroupName/"));
  482. EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("noname, only group/"));
  483. EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("/emptyname"));
  484. EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("*/emptyname"));
  485. }
  486. TEST_F(FieldTrialTest, DuplicateRestore) {
  487. scoped_refptr<FieldTrial> trial =
  488. CreateFieldTrial("Some name", 10, "Default", nullptr);
  489. trial->AppendGroup("Winner", 10);
  490. // Finalize the group selection by accessing the selected group.
  491. trial->group();
  492. std::string save_string;
  493. FieldTrialList::StatesToString(&save_string);
  494. EXPECT_EQ("Some name/Winner/", save_string);
  495. // It is OK if we redundantly specify a winner.
  496. EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(save_string));
  497. // But it is an error to try to change to a different winner.
  498. EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("Some name/Loser/"));
  499. }
  500. TEST_F(FieldTrialTest, CreateTrialsFromStringNotActive) {
  501. ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
  502. ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
  503. ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/Xyz/zyx/"));
  504. FieldTrial::ActiveGroups active_groups;
  505. FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
  506. ASSERT_TRUE(active_groups.empty());
  507. // Check that the values still get returned and querying them activates them.
  508. EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
  509. EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz"));
  510. FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
  511. ASSERT_EQ(2U, active_groups.size());
  512. EXPECT_EQ("Abc", active_groups[0].trial_name);
  513. EXPECT_EQ("def", active_groups[0].group_name);
  514. EXPECT_EQ("Xyz", active_groups[1].trial_name);
  515. EXPECT_EQ("zyx", active_groups[1].group_name);
  516. }
  517. TEST_F(FieldTrialTest, CreateTrialsFromStringForceActivation) {
  518. ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
  519. ASSERT_FALSE(FieldTrialList::TrialExists("def"));
  520. ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
  521. ASSERT_TRUE(
  522. FieldTrialList::CreateTrialsFromString("*Abc/cba/def/fed/*Xyz/zyx/"));
  523. FieldTrial::ActiveGroups active_groups;
  524. FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
  525. ASSERT_EQ(2U, active_groups.size());
  526. EXPECT_EQ("Abc", active_groups[0].trial_name);
  527. EXPECT_EQ("cba", active_groups[0].group_name);
  528. EXPECT_EQ("Xyz", active_groups[1].trial_name);
  529. EXPECT_EQ("zyx", active_groups[1].group_name);
  530. }
  531. TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) {
  532. ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
  533. TestFieldTrialObserver observer;
  534. ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/"));
  535. RunLoop().RunUntilIdle();
  536. // Observer shouldn't be notified.
  537. EXPECT_TRUE(observer.trial_name().empty());
  538. // Check that the values still get returned and querying them activates them.
  539. EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
  540. EXPECT_EQ("Abc", observer.trial_name());
  541. EXPECT_EQ("def", observer.group_name());
  542. }
  543. TEST_F(FieldTrialTest, CreateFieldTrial) {
  544. ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
  545. FieldTrialList::CreateFieldTrial("Some_name", "Winner");
  546. FieldTrial* trial = FieldTrialList::Find("Some_name");
  547. ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial);
  548. EXPECT_EQ("Winner", trial->group_name());
  549. EXPECT_EQ("Some_name", trial->trial_name());
  550. }
  551. TEST_F(FieldTrialTest, CreateFieldTrialIsNotActive) {
  552. const char kTrialName[] = "CreateFieldTrialIsActiveTrial";
  553. const char kWinnerGroup[] = "Winner";
  554. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  555. FieldTrialList::CreateFieldTrial(kTrialName, kWinnerGroup);
  556. FieldTrial::ActiveGroups active_groups;
  557. FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
  558. EXPECT_TRUE(active_groups.empty());
  559. }
  560. TEST_F(FieldTrialTest, DuplicateFieldTrial) {
  561. scoped_refptr<FieldTrial> trial =
  562. CreateFieldTrial("Some_name", 10, "Default", nullptr);
  563. trial->AppendGroup("Winner", 10);
  564. // It is OK if we redundantly specify a winner.
  565. FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Some_name", "Winner");
  566. EXPECT_TRUE(trial1 != nullptr);
  567. // But it is an error to try to change to a different winner.
  568. FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Some_name", "Loser");
  569. EXPECT_TRUE(trial2 == nullptr);
  570. }
  571. TEST_F(FieldTrialTest, DisableImmediately) {
  572. int default_group_number = -1;
  573. scoped_refptr<FieldTrial> trial =
  574. CreateFieldTrial("trial", 100, "default", &default_group_number);
  575. trial->Disable();
  576. ASSERT_EQ("default", trial->group_name());
  577. ASSERT_EQ(default_group_number, trial->group());
  578. }
  579. TEST_F(FieldTrialTest, DisableAfterInitialization) {
  580. scoped_refptr<FieldTrial> trial =
  581. CreateFieldTrial("trial", 100, "default", nullptr);
  582. trial->AppendGroup("non_default", 100);
  583. trial->Disable();
  584. ASSERT_EQ("default", trial->group_name());
  585. }
  586. TEST_F(FieldTrialTest, ForcedFieldTrials) {
  587. // Validate we keep the forced choice.
  588. FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Use the",
  589. "Force");
  590. EXPECT_STREQ("Force", forced_trial->group_name().c_str());
  591. int default_group_number = -1;
  592. scoped_refptr<FieldTrial> factory_trial =
  593. CreateFieldTrial("Use the", 1000, "default", &default_group_number);
  594. EXPECT_EQ(factory_trial.get(), forced_trial);
  595. int chosen_group = factory_trial->AppendGroup("Force", 100);
  596. EXPECT_EQ(chosen_group, factory_trial->group());
  597. int not_chosen_group = factory_trial->AppendGroup("Dark Side", 100);
  598. EXPECT_NE(chosen_group, not_chosen_group);
  599. // Since we didn't force the default group, we should not be returned the
  600. // chosen group as the default group.
  601. EXPECT_NE(default_group_number, chosen_group);
  602. int new_group = factory_trial->AppendGroup("Duck Tape", 800);
  603. EXPECT_NE(chosen_group, new_group);
  604. // The new group should not be the default group either.
  605. EXPECT_NE(default_group_number, new_group);
  606. }
  607. TEST_F(FieldTrialTest, ForcedFieldTrialsDefaultGroup) {
  608. // Forcing the default should use the proper group ID.
  609. FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Trial Name",
  610. "Default");
  611. int default_group_number = -1;
  612. scoped_refptr<FieldTrial> factory_trial =
  613. CreateFieldTrial("Trial Name", 1000, "Default", &default_group_number);
  614. EXPECT_EQ(forced_trial, factory_trial.get());
  615. int other_group = factory_trial->AppendGroup("Not Default", 100);
  616. EXPECT_STREQ("Default", factory_trial->group_name().c_str());
  617. EXPECT_EQ(default_group_number, factory_trial->group());
  618. EXPECT_NE(other_group, factory_trial->group());
  619. int new_other_group = factory_trial->AppendGroup("Not Default Either", 800);
  620. EXPECT_NE(new_other_group, factory_trial->group());
  621. }
  622. TEST_F(FieldTrialTest, SetForced) {
  623. // Start by setting a trial for which we ensure a winner...
  624. int default_group_number = -1;
  625. scoped_refptr<FieldTrial> forced_trial =
  626. CreateFieldTrial("Use the", 1, "default", &default_group_number);
  627. EXPECT_EQ(forced_trial, forced_trial);
  628. int forced_group = forced_trial->AppendGroup("Force", 1);
  629. EXPECT_EQ(forced_group, forced_trial->group());
  630. // Now force it.
  631. forced_trial->SetForced();
  632. // Now try to set it up differently as a hard coded registration would.
  633. scoped_refptr<FieldTrial> hard_coded_trial =
  634. CreateFieldTrial("Use the", 1, "default", &default_group_number);
  635. EXPECT_EQ(hard_coded_trial, forced_trial);
  636. int would_lose_group = hard_coded_trial->AppendGroup("Force", 0);
  637. EXPECT_EQ(forced_group, hard_coded_trial->group());
  638. EXPECT_EQ(forced_group, would_lose_group);
  639. // Same thing if we would have done it to win again.
  640. scoped_refptr<FieldTrial> other_hard_coded_trial =
  641. CreateFieldTrial("Use the", 1, "default", &default_group_number);
  642. EXPECT_EQ(other_hard_coded_trial, forced_trial);
  643. int would_win_group = other_hard_coded_trial->AppendGroup("Force", 1);
  644. EXPECT_EQ(forced_group, other_hard_coded_trial->group());
  645. EXPECT_EQ(forced_group, would_win_group);
  646. }
  647. TEST_F(FieldTrialTest, SetForcedDefaultOnly) {
  648. const char kTrialName[] = "SetForcedDefaultOnly";
  649. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  650. int default_group = -1;
  651. scoped_refptr<FieldTrial> trial =
  652. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
  653. trial->SetForced();
  654. trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr);
  655. EXPECT_EQ(default_group, trial->group());
  656. EXPECT_EQ(kDefaultGroupName, trial->group_name());
  657. }
  658. TEST_F(FieldTrialTest, SetForcedDefaultWithExtraGroup) {
  659. const char kTrialName[] = "SetForcedDefaultWithExtraGroup";
  660. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  661. int default_group = -1;
  662. scoped_refptr<FieldTrial> trial =
  663. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
  664. trial->SetForced();
  665. trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr);
  666. const int extra_group = trial->AppendGroup("Extra", 100);
  667. EXPECT_EQ(default_group, trial->group());
  668. EXPECT_NE(extra_group, trial->group());
  669. EXPECT_EQ(kDefaultGroupName, trial->group_name());
  670. }
  671. TEST_F(FieldTrialTest, SetForcedTurnFeatureOn) {
  672. const char kTrialName[] = "SetForcedTurnFeatureOn";
  673. const char kExtraGroupName[] = "Extra";
  674. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  675. // Simulate a server-side (forced) config that turns the feature on when the
  676. // original hard-coded config had it disabled.
  677. scoped_refptr<FieldTrial> forced_trial =
  678. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr);
  679. forced_trial->AppendGroup(kExtraGroupName, 100);
  680. forced_trial->SetForced();
  681. int default_group = -1;
  682. scoped_refptr<FieldTrial> client_trial =
  683. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
  684. const int extra_group = client_trial->AppendGroup(kExtraGroupName, 0);
  685. EXPECT_NE(default_group, extra_group);
  686. EXPECT_FALSE(client_trial->group_reported_);
  687. EXPECT_EQ(extra_group, client_trial->group());
  688. EXPECT_TRUE(client_trial->group_reported_);
  689. EXPECT_EQ(kExtraGroupName, client_trial->group_name());
  690. }
  691. TEST_F(FieldTrialTest, SetForcedTurnFeatureOff) {
  692. const char kTrialName[] = "SetForcedTurnFeatureOff";
  693. const char kExtraGroupName[] = "Extra";
  694. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  695. // Simulate a server-side (forced) config that turns the feature off when the
  696. // original hard-coded config had it enabled.
  697. scoped_refptr<FieldTrial> forced_trial =
  698. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr);
  699. forced_trial->AppendGroup(kExtraGroupName, 0);
  700. forced_trial->SetForced();
  701. int default_group = -1;
  702. scoped_refptr<FieldTrial> client_trial =
  703. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
  704. const int extra_group = client_trial->AppendGroup(kExtraGroupName, 100);
  705. EXPECT_NE(default_group, extra_group);
  706. EXPECT_FALSE(client_trial->group_reported_);
  707. EXPECT_EQ(default_group, client_trial->group());
  708. EXPECT_TRUE(client_trial->group_reported_);
  709. EXPECT_EQ(kDefaultGroupName, client_trial->group_name());
  710. }
  711. TEST_F(FieldTrialTest, SetForcedChangeDefault_Default) {
  712. const char kTrialName[] = "SetForcedDefaultGroupChange";
  713. const char kGroupAName[] = "A";
  714. const char kGroupBName[] = "B";
  715. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  716. // Simulate a server-side (forced) config that switches which group is default
  717. // and ensures that the non-forced code receives the correct group numbers.
  718. scoped_refptr<FieldTrial> forced_trial =
  719. CreateFieldTrial(kTrialName, 100, kGroupAName, nullptr);
  720. forced_trial->AppendGroup(kGroupBName, 100);
  721. forced_trial->SetForced();
  722. int default_group = -1;
  723. scoped_refptr<FieldTrial> client_trial =
  724. CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
  725. const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
  726. EXPECT_NE(default_group, extra_group);
  727. EXPECT_FALSE(client_trial->group_reported_);
  728. EXPECT_EQ(default_group, client_trial->group());
  729. EXPECT_TRUE(client_trial->group_reported_);
  730. EXPECT_EQ(kGroupBName, client_trial->group_name());
  731. }
  732. TEST_F(FieldTrialTest, SetForcedChangeDefault_NonDefault) {
  733. const char kTrialName[] = "SetForcedDefaultGroupChange";
  734. const char kGroupAName[] = "A";
  735. const char kGroupBName[] = "B";
  736. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  737. // Simulate a server-side (forced) config that switches which group is default
  738. // and ensures that the non-forced code receives the correct group numbers.
  739. scoped_refptr<FieldTrial> forced_trial =
  740. CreateFieldTrial(kTrialName, 100, kGroupAName, nullptr);
  741. forced_trial->AppendGroup(kGroupBName, 0);
  742. forced_trial->SetForced();
  743. int default_group = -1;
  744. scoped_refptr<FieldTrial> client_trial =
  745. CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
  746. const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
  747. EXPECT_NE(default_group, extra_group);
  748. EXPECT_FALSE(client_trial->group_reported_);
  749. EXPECT_EQ(extra_group, client_trial->group());
  750. EXPECT_TRUE(client_trial->group_reported_);
  751. EXPECT_EQ(kGroupAName, client_trial->group_name());
  752. }
  753. TEST_F(FieldTrialTest, Observe) {
  754. const char kTrialName[] = "TrialToObserve1";
  755. const char kSecondaryGroupName[] = "SecondaryGroup";
  756. TestFieldTrialObserver observer;
  757. int default_group = -1;
  758. scoped_refptr<FieldTrial> trial =
  759. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
  760. const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
  761. const int chosen_group = trial->group();
  762. EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
  763. // The observer should be notified synchronously by the group() call.
  764. EXPECT_EQ(kTrialName, observer.trial_name());
  765. if (chosen_group == default_group)
  766. EXPECT_EQ(kDefaultGroupName, observer.group_name());
  767. else
  768. EXPECT_EQ(kSecondaryGroupName, observer.group_name());
  769. }
  770. // Verify that no hang occurs when a FieldTrial group is selected from a
  771. // FieldTrialList::Observer::OnFieldTrialGroupFinalized() notification. If the
  772. // FieldTrialList's lock is held when observers are notified, this test will
  773. // hang due to reentrant lock acquisition when selecting the FieldTrial group.
  774. TEST_F(FieldTrialTest, ObserveReentrancy) {
  775. const char kTrialName1[] = "TrialToObserve1";
  776. const char kTrialName2[] = "TrialToObserve2";
  777. int default_group_1 = -1;
  778. scoped_refptr<FieldTrial> trial_1 =
  779. CreateFieldTrial(kTrialName1, 100, kDefaultGroupName, &default_group_1);
  780. FieldTrialObserverAccessingGroup observer(trial_1);
  781. int default_group_2 = -1;
  782. scoped_refptr<FieldTrial> trial_2 =
  783. CreateFieldTrial(kTrialName2, 100, kDefaultGroupName, &default_group_2);
  784. // No group should be selected for |trial_1| yet.
  785. EXPECT_EQ(FieldTrial::kNotFinalized, trial_1->group_);
  786. // Force selection of a group for |trial_2|. This will notify |observer| which
  787. // will force the selection of a group for |trial_1|. This should not hang.
  788. trial_2->group();
  789. // The above call should have selected a group for |trial_1|.
  790. EXPECT_NE(FieldTrial::kNotFinalized, trial_1->group_);
  791. }
  792. TEST_F(FieldTrialTest, ObserveDisabled) {
  793. const char kTrialName[] = "TrialToObserve2";
  794. TestFieldTrialObserver observer;
  795. int default_group = -1;
  796. scoped_refptr<FieldTrial> trial =
  797. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
  798. trial->AppendGroup("A", 25);
  799. trial->AppendGroup("B", 25);
  800. trial->AppendGroup("C", 25);
  801. trial->Disable();
  802. // Observer shouldn't be notified of a disabled trial.
  803. RunLoop().RunUntilIdle();
  804. EXPECT_TRUE(observer.trial_name().empty());
  805. EXPECT_TRUE(observer.group_name().empty());
  806. // Observer shouldn't be notified even after a |group()| call.
  807. EXPECT_EQ(default_group, trial->group());
  808. RunLoop().RunUntilIdle();
  809. EXPECT_TRUE(observer.trial_name().empty());
  810. EXPECT_TRUE(observer.group_name().empty());
  811. }
  812. TEST_F(FieldTrialTest, ObserveForcedDisabled) {
  813. const char kTrialName[] = "TrialToObserve3";
  814. TestFieldTrialObserver observer;
  815. int default_group = -1;
  816. scoped_refptr<FieldTrial> trial =
  817. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
  818. trial->AppendGroup("A", 25);
  819. trial->AppendGroup("B", 25);
  820. trial->AppendGroup("C", 25);
  821. trial->SetForced();
  822. trial->Disable();
  823. // Observer shouldn't be notified of a disabled trial, even when forced.
  824. RunLoop().RunUntilIdle();
  825. EXPECT_TRUE(observer.trial_name().empty());
  826. EXPECT_TRUE(observer.group_name().empty());
  827. // Observer shouldn't be notified even after a |group()| call.
  828. EXPECT_EQ(default_group, trial->group());
  829. RunLoop().RunUntilIdle();
  830. EXPECT_TRUE(observer.trial_name().empty());
  831. EXPECT_TRUE(observer.group_name().empty());
  832. }
  833. TEST_F(FieldTrialTest, DisabledTrialNotActive) {
  834. const char kTrialName[] = "DisabledTrial";
  835. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  836. scoped_refptr<FieldTrial> trial =
  837. CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr);
  838. trial->AppendGroup("X", 50);
  839. trial->Disable();
  840. // Ensure the trial is not listed as active.
  841. FieldTrial::ActiveGroups active_groups;
  842. FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
  843. EXPECT_TRUE(active_groups.empty());
  844. // Ensure the trial is not listed in the |StatesToString()| result.
  845. std::string states;
  846. FieldTrialList::StatesToString(&states);
  847. EXPECT_TRUE(states.empty());
  848. }
  849. TEST_F(FieldTrialTest, NotDisabled) {
  850. const char kTrialName[] = "NotDisabled";
  851. const char kGroupName[] = "Group2";
  852. const int kProbability = 100;
  853. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  854. scoped_refptr<FieldTrial> trial =
  855. CreateFieldTrial(kTrialName, kProbability, kDefaultGroupName, nullptr);
  856. trial->AppendGroup(kGroupName, kProbability);
  857. EXPECT_EQ(kGroupName, trial->group_name());
  858. }
  859. TEST_F(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes) {
  860. const int kBucketCount = 100;
  861. // Try each boundary value |i / 100.0| as the entropy value.
  862. for (int i = 0; i < kBucketCount; ++i) {
  863. const double entropy = i / static_cast<double>(kBucketCount);
  864. scoped_refptr<FieldTrial> trial(
  865. new FieldTrial("test", kBucketCount, "default", entropy));
  866. for (int j = 0; j < kBucketCount; ++j)
  867. trial->AppendGroup(NumberToString(j), 1);
  868. EXPECT_EQ(NumberToString(i), trial->group_name());
  869. }
  870. }
  871. TEST_F(FieldTrialTest, DoesNotSurpassTotalProbability) {
  872. const double kEntropyValue = 1.0 - 1e-9;
  873. ASSERT_LT(kEntropyValue, 1.0);
  874. scoped_refptr<FieldTrial> trial(
  875. new FieldTrial("test", 2, "default", kEntropyValue));
  876. trial->AppendGroup("1", 1);
  877. trial->AppendGroup("2", 1);
  878. EXPECT_EQ("2", trial->group_name());
  879. }
  880. TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) {
  881. const char kTrialName[] = "CreateSimulatedFieldTrial";
  882. ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
  883. // Different cases to test, e.g. default vs. non default group being chosen.
  884. struct {
  885. double entropy_value;
  886. const char* expected_group;
  887. } test_cases[] = {
  888. { 0.4, "A" },
  889. { 0.85, "B" },
  890. { 0.95, kDefaultGroupName },
  891. };
  892. for (auto& test_case : test_cases) {
  893. TestFieldTrialObserver observer;
  894. scoped_refptr<FieldTrial> trial(FieldTrial::CreateSimulatedFieldTrial(
  895. kTrialName, 100, kDefaultGroupName, test_case.entropy_value));
  896. trial->AppendGroup("A", 80);
  897. trial->AppendGroup("B", 10);
  898. EXPECT_EQ(test_case.expected_group, trial->group_name());
  899. // Field trial shouldn't have been registered with the list.
  900. EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName));
  901. EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount());
  902. // Observer shouldn't have been notified.
  903. RunLoop().RunUntilIdle();
  904. EXPECT_TRUE(observer.trial_name().empty());
  905. // The trial shouldn't be in the active set of trials.
  906. FieldTrial::ActiveGroups active_groups;
  907. FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
  908. EXPECT_TRUE(active_groups.empty());
  909. // The trial shouldn't be listed in the |StatesToString()| result.
  910. std::string states;
  911. FieldTrialList::StatesToString(&states);
  912. EXPECT_TRUE(states.empty());
  913. }
  914. }
  915. TEST(FieldTrialTestWithoutList, StatesStringFormat) {
  916. std::string save_string;
  917. test::ScopedFeatureList scoped_feature_list;
  918. // The test suite instantiates a FieldTrialList but for the purpose of these
  919. // tests it's cleaner to start from scratch.
  920. scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
  921. // Scoping the first FieldTrialList, as we need another one to test the
  922. // importing function.
  923. {
  924. test::ScopedFeatureList scoped_feature_list1;
  925. scoped_feature_list1.InitWithNullFeatureAndFieldTrialLists();
  926. FieldTrialList field_trial_list(nullptr);
  927. scoped_refptr<FieldTrial> trial =
  928. CreateFieldTrial("Abc", 10, "Default some name", nullptr);
  929. trial->AppendGroup("cba", 10);
  930. trial->group();
  931. scoped_refptr<FieldTrial> trial2 =
  932. CreateFieldTrial("Xyz", 10, "Default xxx", nullptr);
  933. trial2->AppendGroup("zyx", 10);
  934. trial2->group();
  935. scoped_refptr<FieldTrial> trial3 =
  936. CreateFieldTrial("zzz", 10, "default", nullptr);
  937. FieldTrialList::AllStatesToString(&save_string, false);
  938. }
  939. // Starting with a new blank FieldTrialList.
  940. test::ScopedFeatureList scoped_feature_list2;
  941. scoped_feature_list2.InitWithNullFeatureAndFieldTrialLists();
  942. FieldTrialList field_trial_list(nullptr);
  943. ASSERT_TRUE(field_trial_list.CreateTrialsFromString(save_string));
  944. FieldTrial::ActiveGroups active_groups;
  945. field_trial_list.GetActiveFieldTrialGroups(&active_groups);
  946. ASSERT_EQ(2U, active_groups.size());
  947. EXPECT_EQ("Abc", active_groups[0].trial_name);
  948. EXPECT_EQ("cba", active_groups[0].group_name);
  949. EXPECT_EQ("Xyz", active_groups[1].trial_name);
  950. EXPECT_EQ("zyx", active_groups[1].group_name);
  951. EXPECT_TRUE(field_trial_list.TrialExists("zzz"));
  952. }
  953. TEST(FieldTrialDeathTest, OneTimeRandomizedTrialWithoutFieldTrialList) {
  954. test::ScopedFeatureList scoped_feature_list1;
  955. scoped_feature_list1.InitWithNullFeatureAndFieldTrialLists();
  956. // Trying to instantiate a one-time randomized field trial before the
  957. // FieldTrialList is created should crash.
  958. EXPECT_DEATH_IF_SUPPORTED(
  959. FieldTrialList::FactoryGetFieldTrial(
  960. "OneTimeRandomizedTrialWithoutFieldTrialList", 100, kDefaultGroupName,
  961. FieldTrial::ONE_TIME_RANDOMIZED, nullptr),
  962. "");
  963. }
  964. class FieldTrialListTest : public ::testing::Test {
  965. public:
  966. FieldTrialListTest() {
  967. // The test suite instantiates a FieldTrialList but for the purpose of these
  968. // tests it's cleaner to start from scratch.
  969. scoped_feature_list_.InitWithEmptyFeatureAndFieldTrialLists();
  970. }
  971. private:
  972. test::ScopedFeatureList scoped_feature_list_;
  973. };
  974. #if !BUILDFLAG(IS_IOS)
  975. // LaunchOptions is not available on iOS.
  976. TEST_F(FieldTrialListTest, TestCopyFieldTrialStateToFlags) {
  977. test::ScopedFeatureList scoped_feature_list1;
  978. scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists();
  979. std::unique_ptr<FeatureList> feature_list(new FeatureList);
  980. feature_list->InitializeFromCommandLine("A,B", "C");
  981. FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial1", "Group1");
  982. feature_list->RegisterFieldTrialOverride(
  983. "MyFeature", FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
  984. test::ScopedFeatureList scoped_feature_list2;
  985. scoped_feature_list2.InitWithFeatureList(std::move(feature_list));
  986. FilePath test_file_path = FilePath(FILE_PATH_LITERAL("Program"));
  987. CommandLine command_line = CommandLine(test_file_path);
  988. LaunchOptions launch_options;
  989. FieldTrialList::PopulateLaunchOptionsWithFieldTrialState(&command_line,
  990. &launch_options);
  991. EXPECT_TRUE(command_line.HasSwitch(switches::kFieldTrialHandle));
  992. // Explicitly specified enabled/disabled features should be specified.
  993. EXPECT_EQ("A,B", command_line.GetSwitchValueASCII(switches::kEnableFeatures));
  994. EXPECT_EQ("C", command_line.GetSwitchValueASCII(switches::kDisableFeatures));
  995. }
  996. #endif // !BUILDFLAG(IS_IOS)
  997. TEST_F(FieldTrialListTest, InstantiateAllocator) {
  998. test::ScopedFeatureList scoped_feature_list;
  999. scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
  1000. FieldTrialList* field_trial_list = FieldTrialList::GetInstance();
  1001. FieldTrialList::CreateFieldTrial("Trial1", "Group1");
  1002. FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
  1003. const void* memory = field_trial_list->field_trial_allocator_->data();
  1004. size_t used = field_trial_list->field_trial_allocator_->used();
  1005. // Ensure that the function is idempotent.
  1006. FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
  1007. const void* new_memory = field_trial_list->field_trial_allocator_->data();
  1008. size_t new_used = field_trial_list->field_trial_allocator_->used();
  1009. EXPECT_EQ(memory, new_memory);
  1010. EXPECT_EQ(used, new_used);
  1011. }
  1012. TEST_F(FieldTrialListTest, AddTrialsToAllocator) {
  1013. std::string save_string;
  1014. base::ReadOnlySharedMemoryRegion shm_region;
  1015. // Scoping the first FieldTrialList, as we need another one to test that it
  1016. // matches.
  1017. {
  1018. test::ScopedFeatureList scoped_feature_list1;
  1019. scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists();
  1020. FieldTrialList::CreateFieldTrial("Trial1", "Group1");
  1021. FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
  1022. FieldTrialList::AllStatesToString(&save_string, false);
  1023. shm_region = FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting();
  1024. ASSERT_TRUE(shm_region.IsValid());
  1025. }
  1026. test::ScopedFeatureList scoped_feature_list2;
  1027. scoped_feature_list2.InitWithEmptyFeatureAndFieldTrialLists();
  1028. // 4 KiB is enough to hold the trials only created for this test.
  1029. base::ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, 4 << 10);
  1030. ASSERT_TRUE(shm_mapping.IsValid());
  1031. FieldTrialList::CreateTrialsFromSharedMemoryMapping(std::move(shm_mapping));
  1032. std::string check_string;
  1033. FieldTrialList::AllStatesToString(&check_string, false);
  1034. EXPECT_EQ(save_string, check_string);
  1035. }
  1036. TEST_F(FieldTrialListTest, DoNotAddSimulatedFieldTrialsToAllocator) {
  1037. constexpr char kTrialName[] = "trial";
  1038. base::ReadOnlySharedMemoryRegion shm_region;
  1039. {
  1040. test::ScopedFeatureList scoped_feature_list1;
  1041. scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists();
  1042. // Create a simulated trial and a real trial and call group() on them, which
  1043. // should only add the real trial to the field trial allocator.
  1044. FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
  1045. // This shouldn't add to the allocator.
  1046. scoped_refptr<FieldTrial> simulated_trial =
  1047. FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, "Simulated",
  1048. 0.95);
  1049. simulated_trial->group();
  1050. // This should add to the allocator.
  1051. FieldTrial* real_trial =
  1052. FieldTrialList::CreateFieldTrial(kTrialName, "Real");
  1053. real_trial->group();
  1054. shm_region = FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting();
  1055. ASSERT_TRUE(shm_region.IsValid());
  1056. }
  1057. // Check that there's only one entry in the allocator.
  1058. test::ScopedFeatureList scoped_feature_list2;
  1059. scoped_feature_list2.InitWithEmptyFeatureAndFieldTrialLists();
  1060. // 4 KiB is enough to hold the trials only created for this test.
  1061. base::ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, 4 << 10);
  1062. ASSERT_TRUE(shm_mapping.IsValid());
  1063. FieldTrialList::CreateTrialsFromSharedMemoryMapping(std::move(shm_mapping));
  1064. std::string check_string;
  1065. FieldTrialList::AllStatesToString(&check_string, false);
  1066. ASSERT_EQ(check_string.find("Simulated"), std::string::npos);
  1067. }
  1068. TEST_F(FieldTrialListTest, AssociateFieldTrialParams) {
  1069. test::ScopedFeatureList scoped_feature_list;
  1070. scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
  1071. std::string trial_name("Trial1");
  1072. std::string group_name("Group1");
  1073. // Create a field trial with some params.
  1074. FieldTrialList::CreateFieldTrial(trial_name, group_name);
  1075. std::map<std::string, std::string> params;
  1076. params["key1"] = "value1";
  1077. params["key2"] = "value2";
  1078. FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
  1079. trial_name, group_name, params);
  1080. FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
  1081. // Clear all cached params from the associator.
  1082. FieldTrialParamAssociator::GetInstance()->ClearAllCachedParamsForTesting();
  1083. // Check that the params have been cleared from the cache.
  1084. std::map<std::string, std::string> cached_params;
  1085. FieldTrialParamAssociator::GetInstance()->GetFieldTrialParamsWithoutFallback(
  1086. trial_name, group_name, &cached_params);
  1087. EXPECT_EQ(0U, cached_params.size());
  1088. // Check that we fetch the param from shared memory properly.
  1089. std::map<std::string, std::string> new_params;
  1090. GetFieldTrialParams(trial_name, &new_params);
  1091. EXPECT_EQ("value1", new_params["key1"]);
  1092. EXPECT_EQ("value2", new_params["key2"]);
  1093. EXPECT_EQ(2U, new_params.size());
  1094. }
  1095. TEST_F(FieldTrialListTest, ClearParamsFromSharedMemory) {
  1096. std::string trial_name("Trial1");
  1097. std::string group_name("Group1");
  1098. base::ReadOnlySharedMemoryRegion shm_region;
  1099. {
  1100. test::ScopedFeatureList scoped_feature_list1;
  1101. scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists();
  1102. // Create a field trial with some params.
  1103. FieldTrial* trial =
  1104. FieldTrialList::CreateFieldTrial(trial_name, group_name);
  1105. std::map<std::string, std::string> params;
  1106. params["key1"] = "value1";
  1107. params["key2"] = "value2";
  1108. FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
  1109. trial_name, group_name, params);
  1110. FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
  1111. // Clear all params from the associator AND shared memory. The allocated
  1112. // segments should be different.
  1113. FieldTrial::FieldTrialRef old_ref = trial->ref_;
  1114. FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
  1115. FieldTrial::FieldTrialRef new_ref = trial->ref_;
  1116. EXPECT_NE(old_ref, new_ref);
  1117. // Check that there are no params associated with the field trial anymore.
  1118. std::map<std::string, std::string> new_params;
  1119. GetFieldTrialParams(trial_name, &new_params);
  1120. EXPECT_EQ(0U, new_params.size());
  1121. // Now duplicate the handle so we can easily check that the trial is still
  1122. // in shared memory via AllStatesToString.
  1123. shm_region = FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting();
  1124. ASSERT_TRUE(shm_region.IsValid());
  1125. }
  1126. // Check that we have the trial.
  1127. test::ScopedFeatureList scoped_feature_list2;
  1128. scoped_feature_list2.InitWithEmptyFeatureAndFieldTrialLists();
  1129. // 4 KiB is enough to hold the trials only created for this test.
  1130. base::ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, 4 << 10);
  1131. ASSERT_TRUE(shm_mapping.IsValid());
  1132. FieldTrialList::CreateTrialsFromSharedMemoryMapping(std::move(shm_mapping));
  1133. std::string check_string;
  1134. FieldTrialList::AllStatesToString(&check_string, false);
  1135. EXPECT_EQ("*Trial1/Group1/", check_string);
  1136. }
  1137. TEST_F(FieldTrialListTest, DumpAndFetchFromSharedMemory) {
  1138. std::string trial_name("Trial1");
  1139. std::string group_name("Group1");
  1140. // Create a field trial with some params.
  1141. test::ScopedFeatureList scoped_feature_list;
  1142. scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
  1143. FieldTrialList::CreateFieldTrial(trial_name, group_name);
  1144. std::map<std::string, std::string> params;
  1145. params["key1"] = "value1";
  1146. params["key2"] = "value2";
  1147. FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
  1148. trial_name, group_name, params);
  1149. // 4 KiB is enough to hold the trials only created for this test.
  1150. base::MappedReadOnlyRegion shm =
  1151. base::ReadOnlySharedMemoryRegion::Create(4 << 10);
  1152. ASSERT_TRUE(shm.IsValid());
  1153. // We _could_ use PersistentMemoryAllocator, this just has less params.
  1154. WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
  1155. "");
  1156. // Dump and subsequently retrieve the field trial to |allocator|.
  1157. FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(&allocator);
  1158. std::vector<const FieldTrial::FieldTrialEntry*> entries =
  1159. FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(allocator);
  1160. // Check that we have the entry we put in.
  1161. EXPECT_EQ(1u, entries.size());
  1162. const FieldTrial::FieldTrialEntry* entry = entries[0];
  1163. // Check that the trial and group names match.
  1164. StringPiece shm_trial_name;
  1165. StringPiece shm_group_name;
  1166. entry->GetTrialAndGroupName(&shm_trial_name, &shm_group_name);
  1167. EXPECT_EQ(trial_name, shm_trial_name);
  1168. EXPECT_EQ(group_name, shm_group_name);
  1169. // Check that the params match.
  1170. std::map<std::string, std::string> shm_params;
  1171. entry->GetParams(&shm_params);
  1172. EXPECT_EQ(2u, shm_params.size());
  1173. EXPECT_EQ("value1", shm_params["key1"]);
  1174. EXPECT_EQ("value2", shm_params["key2"]);
  1175. }
  1176. #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_IOS)
  1177. MULTIPROCESS_TEST_MAIN(SerializeSharedMemoryRegionMetadata) {
  1178. std::string serialized =
  1179. CommandLine::ForCurrentProcess()->GetSwitchValueASCII("field_trials");
  1180. std::string guid_string =
  1181. CommandLine::ForCurrentProcess()->GetSwitchValueASCII("guid");
  1182. int fd = 42;
  1183. #if BUILDFLAG(IS_ANDROID)
  1184. fd = base::GlobalDescriptors::GetInstance()->MaybeGet(42);
  1185. CHECK_NE(fd, -1);
  1186. #endif
  1187. base::ReadOnlySharedMemoryRegion deserialized =
  1188. FieldTrialList::DeserializeSharedMemoryRegionMetadata(serialized, fd);
  1189. CHECK(deserialized.IsValid());
  1190. CHECK_EQ(deserialized.GetGUID().ToString(), guid_string);
  1191. CHECK(!deserialized.GetGUID().is_empty());
  1192. return 0;
  1193. }
  1194. TEST_F(FieldTrialListTest, SerializeSharedMemoryRegionMetadata) {
  1195. base::MappedReadOnlyRegion shm =
  1196. base::ReadOnlySharedMemoryRegion::Create(4 << 10);
  1197. ASSERT_TRUE(shm.IsValid());
  1198. LaunchOptions options;
  1199. std::string serialized =
  1200. FieldTrialList::SerializeSharedMemoryRegionMetadata(shm.region, &options);
  1201. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
  1202. #if BUILDFLAG(IS_ANDROID)
  1203. int shm_fd = shm.region.GetPlatformHandle();
  1204. #else
  1205. int shm_fd = shm.region.GetPlatformHandle().fd;
  1206. #endif // BUILDFLAG(IS_ANDROID)
  1207. // Pick an arbitrary FD number to use for the shmem FD in the child.
  1208. options.fds_to_remap.emplace_back(std::make_pair(shm_fd, 42));
  1209. #endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
  1210. CommandLine cmd_line = GetMultiProcessTestChildBaseCommandLine();
  1211. cmd_line.AppendSwitchASCII("field_trials", serialized);
  1212. cmd_line.AppendSwitchASCII("guid", shm.region.GetGUID().ToString());
  1213. Process process = SpawnMultiProcessTestChild(
  1214. "SerializeSharedMemoryRegionMetadata", cmd_line, options);
  1215. int exit_code;
  1216. EXPECT_TRUE(WaitForMultiprocessTestChildExit(
  1217. process, TestTimeouts::action_timeout(), &exit_code));
  1218. EXPECT_EQ(0, exit_code);
  1219. }
  1220. #endif // !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_IOS)
  1221. // Verify that the field trial shared memory handle is really read-only, and
  1222. // does not allow writable mappings. Test disabled on NaCl, Fuchsia, and Mac,
  1223. // which don't support/implement shared memory configuration.
  1224. #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_MAC)
  1225. TEST_F(FieldTrialListTest, CheckReadOnlySharedMemoryRegion) {
  1226. test::ScopedFeatureList scoped_feature_list;
  1227. scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists();
  1228. FieldTrialList::CreateFieldTrial("Trial1", "Group1");
  1229. FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
  1230. base::ReadOnlySharedMemoryRegion region =
  1231. FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting();
  1232. ASSERT_TRUE(region.IsValid());
  1233. ASSERT_TRUE(CheckReadOnlyPlatformSharedMemoryRegionForTesting(
  1234. base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
  1235. std::move(region))));
  1236. }
  1237. #endif // !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_MAC)
  1238. TEST_F(FieldTrialTest, TestAllParamsToString) {
  1239. std::string exptected_output = "t1.g1:p1/v1/p2/v2";
  1240. // Create study with one group and two params.
  1241. std::map<std::string, std::string> params;
  1242. params["p1"] = "v1";
  1243. params["p2"] = "v2";
  1244. FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
  1245. "t1", "g1", params);
  1246. EXPECT_EQ(
  1247. "", FieldTrialList::AllParamsToString(false, &MockEscapeQueryParamValue));
  1248. scoped_refptr<FieldTrial> trial1 =
  1249. CreateFieldTrial("t1", 100, "Default", nullptr);
  1250. trial1->AppendGroup("g1", 100);
  1251. trial1->group();
  1252. EXPECT_EQ(exptected_output, FieldTrialList::AllParamsToString(
  1253. false, &MockEscapeQueryParamValue));
  1254. // Create study with two groups and params that don't belog to the assigned
  1255. // group. This should be in the output.
  1256. FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
  1257. "t2", "g2", params);
  1258. scoped_refptr<FieldTrial> trial2 =
  1259. CreateFieldTrial("t2", 100, "Default", nullptr);
  1260. trial2->AppendGroup("g1", 100);
  1261. trial2->AppendGroup("g2", 0);
  1262. trial2->group();
  1263. EXPECT_EQ(exptected_output, FieldTrialList::AllParamsToString(
  1264. false, &MockEscapeQueryParamValue));
  1265. }
  1266. } // namespace base