SettingsTest.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Copyright 2018-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/experimental/settings/Settings.h>
  17. #include <folly/Format.h>
  18. #include <folly/portability/GTest.h>
  19. #include <folly/experimental/settings/test/a.h>
  20. #include <folly/experimental/settings/test/b.h>
  21. namespace some_ns {
  22. FOLLY_SETTING_DEFINE(
  23. follytest,
  24. some_flag,
  25. std::string,
  26. "default",
  27. "Description");
  28. FOLLY_SETTING_DEFINE(
  29. follytest,
  30. unused,
  31. std::string,
  32. "unused_default",
  33. "Not used, but should still be in the list");
  34. FOLLY_SETTING_DEFINE(
  35. follytest,
  36. multi_token_type,
  37. unsigned int,
  38. 123,
  39. "Test that multi-token type names can be used");
  40. // Enable to test runtime collision checking logic
  41. #if 0
  42. FOLLY_SETTING_DEFINE(follytest, internal_flag_to_a, std::string,
  43. "collision_with_a",
  44. "Collision_with_a");
  45. #endif
  46. /* Test user defined type support */
  47. struct UserDefinedType {
  48. explicit UserDefinedType(folly::StringPiece value) {
  49. if (value == "a") {
  50. value_ = 0;
  51. } else if (value == "b") {
  52. value_ = 100;
  53. } else {
  54. throw std::runtime_error("Invalid value passed to UserDefinedType ctor");
  55. }
  56. }
  57. bool operator==(const UserDefinedType& other) const {
  58. return value_ == other.value_;
  59. }
  60. int value_;
  61. };
  62. /* Note: conversion intentionally to different strings to test that this
  63. function is called */
  64. template <class String>
  65. void toAppend(const UserDefinedType& t, String* out) {
  66. if (t.value_ == 0) {
  67. out->append("a_out");
  68. } else if (t.value_ == 100) {
  69. out->append("b_out");
  70. } else {
  71. throw std::runtime_error("Can't convert UserDefinedType to string");
  72. }
  73. }
  74. FOLLY_SETTING_DEFINE(
  75. follytest,
  76. user_defined,
  77. UserDefinedType,
  78. "b",
  79. "User defined type constructed from string");
  80. } // namespace some_ns
  81. TEST(Settings, user_defined) {
  82. EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 100);
  83. {
  84. folly::settings::Snapshot sn;
  85. EXPECT_TRUE(sn.setFromString("follytest_user_defined", "a", "test"));
  86. sn.publish();
  87. EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 0);
  88. }
  89. {
  90. folly::settings::Snapshot sn;
  91. auto info = sn.getAsString("follytest_user_defined");
  92. EXPECT_TRUE(info.hasValue());
  93. EXPECT_EQ(info->first, "a_out");
  94. EXPECT_EQ(info->second, "test");
  95. }
  96. {
  97. folly::settings::Snapshot sn;
  98. EXPECT_THROW(
  99. sn.setFromString("follytest_user_defined", "c", "test2"),
  100. std::runtime_error);
  101. sn.publish();
  102. EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 0);
  103. }
  104. {
  105. folly::settings::Snapshot sn;
  106. auto info = sn.getAsString("follytest_user_defined");
  107. EXPECT_TRUE(info.hasValue());
  108. EXPECT_EQ(info->first, "a_out");
  109. EXPECT_EQ(info->second, "test");
  110. }
  111. {
  112. folly::settings::Snapshot sn;
  113. EXPECT_TRUE(sn.resetToDefault("follytest_user_defined"));
  114. sn.publish();
  115. EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 100);
  116. }
  117. {
  118. folly::settings::Snapshot sn;
  119. auto info = sn.getAsString("follytest_user_defined");
  120. EXPECT_TRUE(info.hasValue());
  121. EXPECT_EQ(info->first, "b_out");
  122. EXPECT_EQ(info->second, "default");
  123. }
  124. /* Test that intentionally setting to something non-converteable fails */
  125. some_ns::UserDefinedType bad("a");
  126. bad.value_ = 50;
  127. EXPECT_THROW(
  128. some_ns::FOLLY_SETTING(follytest, user_defined).set(bad),
  129. std::runtime_error);
  130. EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 100);
  131. {
  132. folly::settings::Snapshot sn;
  133. auto info = sn.getAsString("follytest_user_defined");
  134. EXPECT_TRUE(info.hasValue());
  135. EXPECT_EQ(info->first, "b_out");
  136. EXPECT_EQ(info->second, "default");
  137. }
  138. }
  139. TEST(Settings, basic) {
  140. EXPECT_EQ(a_ns::a_func(), 1245);
  141. EXPECT_EQ(b_ns::b_func(), "testbasdf");
  142. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "default");
  143. // Test -> API
  144. EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, some_flag)->size(), 7);
  145. a_ns::FOLLY_SETTING(follytest, public_flag_to_a).set(100);
  146. EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 100);
  147. EXPECT_EQ(a_ns::getRemote(), 100);
  148. a_ns::setRemote(200);
  149. EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 200);
  150. EXPECT_EQ(a_ns::getRemote(), 200);
  151. {
  152. folly::settings::Snapshot sn;
  153. auto res = sn.getAsString("follytest_public_flag_to_a");
  154. EXPECT_TRUE(res.hasValue());
  155. EXPECT_EQ(res->first, "200");
  156. EXPECT_EQ(res->second, "remote_set");
  157. }
  158. {
  159. auto meta = folly::settings::getSettingsMeta("follytest_public_flag_to_a");
  160. EXPECT_TRUE(meta.hasValue());
  161. const auto& md = meta.value();
  162. EXPECT_EQ(md.project, "follytest");
  163. EXPECT_EQ(md.name, "public_flag_to_a");
  164. EXPECT_EQ(md.typeStr, "int");
  165. EXPECT_EQ(md.typeId, typeid(int));
  166. }
  167. {
  168. auto meta = folly::settings::getSettingsMeta("follytest_some_flag");
  169. EXPECT_TRUE(meta.hasValue());
  170. const auto& md = meta.value();
  171. EXPECT_EQ(md.project, "follytest");
  172. EXPECT_EQ(md.name, "some_flag");
  173. EXPECT_EQ(md.typeStr, "std::string");
  174. EXPECT_EQ(md.typeId, typeid(std::string));
  175. }
  176. {
  177. folly::settings::Snapshot sn;
  178. auto res = sn.getAsString("follytest_nonexisting");
  179. EXPECT_FALSE(res.hasValue());
  180. }
  181. {
  182. folly::settings::Snapshot sn;
  183. EXPECT_TRUE(
  184. sn.setFromString("follytest_public_flag_to_a", "300", "from_string"));
  185. sn.publish();
  186. EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 300);
  187. }
  188. EXPECT_EQ(a_ns::getRemote(), 300);
  189. {
  190. folly::settings::Snapshot sn;
  191. auto res = sn.getAsString("follytest_public_flag_to_a");
  192. EXPECT_TRUE(res.hasValue());
  193. EXPECT_EQ(res->first, "300");
  194. EXPECT_EQ(res->second, "from_string");
  195. }
  196. {
  197. folly::settings::Snapshot sn;
  198. EXPECT_FALSE(
  199. sn.setFromString("follytest_nonexisting", "300", "from_string"));
  200. }
  201. EXPECT_EQ(
  202. some_ns::FOLLY_SETTING(follytest, multi_token_type).defaultValue(), 123);
  203. EXPECT_EQ(
  204. a_ns::FOLLY_SETTING(follytest, public_flag_to_a).defaultValue(), 456);
  205. EXPECT_EQ(
  206. b_ns::FOLLY_SETTING(follytest, public_flag_to_b).defaultValue(), "basdf");
  207. EXPECT_EQ(
  208. some_ns::FOLLY_SETTING(follytest, some_flag).defaultValue(), "default");
  209. EXPECT_EQ(
  210. some_ns::FOLLY_SETTING(follytest, user_defined).defaultValue(),
  211. some_ns::UserDefinedType("b"));
  212. {
  213. std::string allFlags;
  214. folly::settings::Snapshot sn;
  215. sn.forEachSetting([&allFlags](
  216. const folly::settings::SettingMetadata& meta,
  217. folly::StringPiece value,
  218. folly::StringPiece reason) {
  219. if (meta.typeId == typeid(int)) {
  220. EXPECT_EQ(meta.typeStr, "int");
  221. } else if (meta.typeId == typeid(std::string)) {
  222. EXPECT_EQ(meta.typeStr, "std::string");
  223. } else if (meta.typeId == typeid(unsigned int)) {
  224. EXPECT_EQ(meta.typeStr, "unsigned int");
  225. } else if (meta.typeId == typeid(some_ns::UserDefinedType)) {
  226. EXPECT_EQ(meta.typeStr, "UserDefinedType");
  227. } else {
  228. ASSERT_FALSE(true);
  229. }
  230. allFlags += folly::sformat(
  231. "{}/{}/{}/{}/{}/{}/{}\n",
  232. meta.project,
  233. meta.name,
  234. meta.typeStr,
  235. meta.defaultStr,
  236. meta.description,
  237. value,
  238. reason);
  239. });
  240. EXPECT_EQ(
  241. allFlags,
  242. "follytest/internal_flag_to_a/int/789/Desc of int/789/default\n"
  243. "follytest/internal_flag_to_b/std::string/\"test\"/Desc of str/test/default\n"
  244. "follytest/multi_token_type/unsigned int/123/Test that multi-token type names can be used/123/default\n"
  245. "follytest/public_flag_to_a/int/456/Public flag to a/300/from_string\n"
  246. "follytest/public_flag_to_b/std::string/\"basdf\"/Public flag to b/basdf/default\n"
  247. "follytest/some_flag/std::string/\"default\"/Description/default/default\n"
  248. "follytest/unused/std::string/\"unused_default\"/Not used, but should still be in the list/unused_default/default\n"
  249. "follytest/user_defined/UserDefinedType/\"b\"/User defined type constructed from string/b_out/default\n");
  250. }
  251. {
  252. folly::settings::Snapshot sn;
  253. EXPECT_TRUE(sn.resetToDefault("follytest_public_flag_to_a"));
  254. sn.publish();
  255. EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 456);
  256. EXPECT_EQ(a_ns::getRemote(), 456);
  257. }
  258. {
  259. folly::settings::Snapshot sn;
  260. EXPECT_FALSE(sn.resetToDefault("follytest_nonexisting"));
  261. }
  262. }
  263. TEST(Settings, snapshot) {
  264. // Test discarding a snapshot
  265. {
  266. folly::settings::Snapshot snapshot;
  267. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "default");
  268. EXPECT_EQ(
  269. *snapshot(some_ns::FOLLY_SETTING(follytest, some_flag)), "default");
  270. // Set the global value, snapshot doesn't see it
  271. some_ns::FOLLY_SETTING(follytest, some_flag).set("global_value");
  272. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "global_value");
  273. EXPECT_EQ(
  274. *snapshot(some_ns::FOLLY_SETTING(follytest, some_flag)), "default");
  275. // Set the value in the snapshot only
  276. snapshot(some_ns::FOLLY_SETTING(follytest, some_flag))
  277. .set("snapshot_value");
  278. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "global_value");
  279. EXPECT_EQ(
  280. *snapshot(some_ns::FOLLY_SETTING(follytest, some_flag)),
  281. "snapshot_value");
  282. }
  283. // Discard the snapshot
  284. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "global_value");
  285. // Test publishing a snapshot
  286. {
  287. folly::settings::Snapshot snapshot;
  288. // Set the value in the snapshot only
  289. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "global_value");
  290. EXPECT_EQ(
  291. *snapshot(some_ns::FOLLY_SETTING(follytest, some_flag)),
  292. "global_value");
  293. snapshot(some_ns::FOLLY_SETTING(follytest, some_flag))
  294. .set("snapshot_value2");
  295. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "global_value");
  296. EXPECT_EQ(
  297. *snapshot(some_ns::FOLLY_SETTING(follytest, some_flag)),
  298. "snapshot_value2");
  299. // Set the global value, snapshot doesn't see it
  300. some_ns::FOLLY_SETTING(follytest, some_flag).set("global_value2");
  301. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "global_value2");
  302. EXPECT_EQ(
  303. *snapshot(some_ns::FOLLY_SETTING(follytest, some_flag)),
  304. "snapshot_value2");
  305. snapshot.publish();
  306. }
  307. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "snapshot_value2");
  308. // Snapshots at different points in time
  309. {
  310. some_ns::FOLLY_SETTING(follytest, some_flag).set("a");
  311. a_ns::FOLLY_SETTING(follytest, public_flag_to_a).set(123);
  312. folly::settings::Snapshot snapshot_1;
  313. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "a");
  314. EXPECT_EQ(*snapshot_1(some_ns::FOLLY_SETTING(follytest, some_flag)), "a");
  315. EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 123);
  316. EXPECT_EQ(
  317. *snapshot_1(a_ns::FOLLY_SETTING(follytest, public_flag_to_a)), 123);
  318. some_ns::FOLLY_SETTING(follytest, some_flag).set("b");
  319. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "b");
  320. EXPECT_EQ(*snapshot_1(some_ns::FOLLY_SETTING(follytest, some_flag)), "a");
  321. EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 123);
  322. EXPECT_EQ(
  323. *snapshot_1(a_ns::FOLLY_SETTING(follytest, public_flag_to_a)), 123);
  324. folly::settings::Snapshot snapshot_2;
  325. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "b");
  326. EXPECT_EQ(*snapshot_1(some_ns::FOLLY_SETTING(follytest, some_flag)), "a");
  327. EXPECT_EQ(*snapshot_2(some_ns::FOLLY_SETTING(follytest, some_flag)), "b");
  328. EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 123);
  329. EXPECT_EQ(
  330. *snapshot_1(a_ns::FOLLY_SETTING(follytest, public_flag_to_a)), 123);
  331. EXPECT_EQ(
  332. *snapshot_2(a_ns::FOLLY_SETTING(follytest, public_flag_to_a)), 123);
  333. some_ns::FOLLY_SETTING(follytest, some_flag).set("c");
  334. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "c");
  335. EXPECT_EQ(*snapshot_1(some_ns::FOLLY_SETTING(follytest, some_flag)), "a");
  336. EXPECT_EQ(*snapshot_2(some_ns::FOLLY_SETTING(follytest, some_flag)), "b");
  337. EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 123);
  338. EXPECT_EQ(
  339. *snapshot_1(a_ns::FOLLY_SETTING(follytest, public_flag_to_a)), 123);
  340. EXPECT_EQ(
  341. *snapshot_2(a_ns::FOLLY_SETTING(follytest, public_flag_to_a)), 123);
  342. a_ns::FOLLY_SETTING(follytest, public_flag_to_a).set(456);
  343. EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "c");
  344. EXPECT_EQ(*snapshot_1(some_ns::FOLLY_SETTING(follytest, some_flag)), "a");
  345. EXPECT_EQ(*snapshot_2(some_ns::FOLLY_SETTING(follytest, some_flag)), "b");
  346. EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 456);
  347. EXPECT_EQ(
  348. *snapshot_1(a_ns::FOLLY_SETTING(follytest, public_flag_to_a)), 123);
  349. EXPECT_EQ(
  350. *snapshot_2(a_ns::FOLLY_SETTING(follytest, public_flag_to_a)), 123);
  351. }
  352. }