proxygen
MultiFilePollerTest.cpp File Reference

Go to the source code of this file.

Classes

class  MultiFilePollerTest
 

Functions

 TEST_F (MultiFilePollerTest, BasicTest)
 
 TEST_F (MultiFilePollerTest, CancellationTest)
 
 TEST_F (MultiFilePollerTest, ComplexTest)
 

Variables

static const std::chrono::milliseconds kPollIntervalMs {200}
 
static const std::chrono::milliseconds kWriteWaitMs {1000}
 
static const std::chrono::milliseconds kMaxSemaphoreWaitMs {1000}
 

Function Documentation

TEST_F ( MultiFilePollerTest  ,
BasicTest   
)

BasicTest This test checks basic usage scenario of MultiFilePoller: (1) registers a callback on one file. (2) writes data to the file, and expects the callback to be triggered. (3) cancels the callback, and expects the callback to not run.

Definition at line 69 of file MultiFilePollerTest.cpp.

References ASSERT_EQ, ASSERT_FALSE, ASSERT_TRUE, count, d3(), EXPECT_EQ, f, folly::get_or_throw(), kMaxSemaphoreWaitMs, now(), folly::SaturatingSemaphore< MayBlock, Atom >::post(), folly::SaturatingSemaphore< MayBlock, Atom >::reset(), string, folly::SaturatingSemaphore< MayBlock, Atom >::try_wait_until(), and folly::writeFile().

69  {
70  const std::string f(tmpdirPath_ + "/Basic1"), d1("a"), d2("b"), d3("c");
71  folly::SaturatingSemaphore<true /* MayBlock */> sem;
72  size_t count = 0;
73 
74  // Write initial data.
75  ASSERT_TRUE(folly::writeFile(d1, f.c_str()));
76 
77  // Register the callback.
78  auto cbId = updater_->registerFile(
79  f, [&](const MultiFilePoller::CallbackArg& newData) {
80  auto& content = folly::get_or_throw(newData, f);
81  EXPECT_EQ(d2, content);
82  EXPECT_EQ(1, ++count);
83  sem.post();
84  });
85 
86  delayedWrite(f, d2);
87 
88  // Check whether the callback is triggered by acquiring the semaphore.
91  sem.reset();
92  ASSERT_EQ(1, count);
93 
94  // Cancel the callback.
95  updater_->cancelCallback(cbId);
96 
97  // Write to the file again. The callback should not run.
98  delayedWrite(f, d3);
99 
102  // If the callback runs, the assertion inside callback will also fail.
103 }
auto f
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::chrono::steady_clock::time_point now()
std::unordered_map< std::string, std::string > CallbackArg
FOLLY_ALWAYS_INLINE void post() noexcept
FOLLY_ALWAYS_INLINE bool try_wait_until(const std::chrono::time_point< Clock, Duration > &deadline, const WaitOptions &opt=wait_options()) noexcept
static const std::chrono::milliseconds kMaxSemaphoreWaitMs
int * count
const char * string
Definition: Conv.cpp:212
const Map::mapped_type & get_or_throw(const Map &map, const Key &key, const std::string &exceptionStrPrefix=std::string())
Definition: MapUtil.h:71
bool writeFile(const Container &data, const char *filename, int flags=O_WRONLY|O_CREAT|O_TRUNC, mode_t mode=0666)
Definition: FileUtil.h:211
#define ASSERT_FALSE(condition)
Definition: gtest.h:1868
RfcParam d3(false, exampleHex1)
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865
TEST_F ( MultiFilePollerTest  ,
CancellationTest   
)

CancellationTest This test tests the basic functionality of callback cancellation.

Definition at line 109 of file MultiFilePollerTest.cpp.

References EXPECT_THROW, f, FAIL, and string.

109  {
110  const std::string f(tmpdirPath_ + "/Cancel1"), d("111");
111 
112  auto cb = updater_->registerFile(
113  f, [&](const MultiFilePoller::CallbackArg& /* unused */) { FAIL(); });
114 
115  // Proper cancellation.
116  updater_->cancelCallback(cb);
117 
118  // Refuse double cancellation.
119  EXPECT_THROW(updater_->cancelCallback(cb), std::out_of_range);
120 
121  delayedWrite(f, d);
122  // Test will also fail if the callback runs.
123 }
auto f
#define FAIL()
Definition: gtest.h:1822
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
std::unordered_map< std::string, std::string > CallbackArg
const char * string
Definition: Conv.cpp:212
TEST_F ( MultiFilePollerTest  ,
ComplexTest   
)

ComplexTest This test constructs a more complex use scenario of MultiFilePoller: (1) There are three files: f1, f2, and f3. (2) There are four callbacks: cb1 = {f1} cb2 = {f2} cb3 = {f3, f1} // So f1 is used by cb1 and cb3, but cb3 also use f3. cb4 = {f2} // So cb2 and cb4 use and only use f2.

Definition at line 135 of file MultiFilePollerTest.cpp.

References ASSERT_EQ, ASSERT_FALSE, ASSERT_NE, ASSERT_TRUE, d3(), EXPECT_EQ, folly::get_default(), folly::get_or_throw(), kMaxSemaphoreWaitMs, now(), folly::SaturatingSemaphore< MayBlock, Atom >::post(), folly::SaturatingSemaphore< MayBlock, Atom >::reset(), string, folly::SaturatingSemaphore< MayBlock, Atom >::try_wait_until(), and folly::writeFile().

135  {
136  const std::string f1(tmpdirPath_ + "/Complex1"), d1("a"), d11("AA");
137  const std::string f2(tmpdirPath_ + "/Complex2"), d2("b"), d21("B"), d22("X");
138  const std::string f3(tmpdirPath_ + "/Complex3"), d3("c");
139 
140  folly::SaturatingSemaphore<true> sem1, sem2, sem3, sem4;
141  std::string data2, data4;
142  std::vector<std::string> data3;
143  size_t count1 = 0, count2 = 0, count3 = 0, count4 = 0;
144 
145  // cb1 is only triggered once. It expects the content to equal d1, which is
146  // written to the file to trigger the callback.
147  auto cb1 = updater_->registerFile(
148  f1, [&](const MultiFilePoller::CallbackArg& newData) {
149  auto& content = folly::get_or_throw(newData, f1);
150  EXPECT_EQ(d1, content);
151  EXPECT_EQ(1, ++count1); // Fail if run more than once.
152  sem1.post();
153  });
154 
155  // cb2 copies content of f2 from arg to data2, and increments count2.
156  auto cb2 = updater_->registerFile(
157  f2, [&](const MultiFilePoller::CallbackArg& newData) {
158  data2 = folly::get_or_throw(newData, f2);
159  count2++;
160  sem2.post();
161  });
162 
163  // cb3 concatenates the data of f3 and f3 and writes the value to data3.
164  /* cb3 */ updater_->registerFiles(
165  {f3, f1}, [&](const MultiFilePoller::CallbackArg& newData) {
166  if (count3 == 0) {
167  // When we write to f3 to trigger cb3, f1 does not exist yet.
168  // Check that f1 is not in the map.
169  ASSERT_EQ(newData.end(), newData.find(f1));
170  } else {
171  // Otherwise f1 must exist in the map.
172  ASSERT_NE(newData.end(), newData.find(f1));
173  }
174  const auto& f3Data = folly::get_or_throw(newData, f3);
175  const auto& f1Data = folly::get_default(newData, f1, "<NODATA>");
176  data3 = {f3Data, f1Data};
177  count3++;
178  sem3.post();
179  });
180 
181  // Create f2 to trigger cb2.
182  ASSERT_TRUE(folly::writeFile(d2, f2.c_str()));
185  sem2.reset();
186  EXPECT_EQ(1, count2); // +1.
187  EXPECT_EQ(0, count1); // No change.
188  EXPECT_EQ(0, count3); // No change.
189  EXPECT_EQ(d2, data2); // The data obtained by cb should equal what's written.
190 
191  // Create f3 to trigger cb3. Note that cb1 should not run.
192  ASSERT_TRUE(folly::writeFile(d3, f3.c_str()));
195  sem3.reset();
196  EXPECT_EQ(1, count3); // +1.
197  EXPECT_EQ(0, count1); // No change.
198  EXPECT_EQ(1, count2); // No change.
199  EXPECT_EQ(std::vector<std::string>({d3, "<NODATA>"}), data3);
200 
201  // Create f1 to trigger cb3 and cb1. Order doesn't matter.
202  ASSERT_TRUE(folly::writeFile(d1, f1.c_str()));
205  sem1.reset();
206  EXPECT_EQ(1, count1); // +1.
207  EXPECT_EQ(1, count2); // No change.
210  sem3.reset();
211  EXPECT_EQ(2, count3); // +1.
212  EXPECT_EQ(std::vector<std::string>({d3, d1}), data3);
213 
214  // cb4 is the same as cb2 except that it's another callback.
215  auto cb4 = updater_->registerFile(
216  f2, [&](const MultiFilePoller::CallbackArg& newData) {
217  data4 = folly::get_or_throw(newData, f2);
218  count4++;
219  sem4.post();
220  });
221 
222  // Write to f2 to trigger second callback.
223  delayedWrite(f2, d21);
224 
227  sem2.reset();
230  sem4.reset();
231  EXPECT_EQ(2, count2); // +1.
232  EXPECT_EQ(1, count4); // +1.
233  EXPECT_EQ(1, count1); // No change.
234  EXPECT_EQ(2, count3); // No change.
235  EXPECT_EQ(d21, data2); // Both data2 and data4 got what was written.
236  EXPECT_EQ(d21, data4);
237 
238  // f1 is in two different callbacks. Cancel cb1 should not affect cb3.
239  updater_->cancelCallback(cb1);
240  ASSERT_TRUE(folly::writeFile(d11, f1.c_str())); // Last write to f1 > 1s ago.
243  sem3.reset();
246  EXPECT_EQ(3, count3); // +1.
247  EXPECT_EQ(1, count1); // No change.
248  EXPECT_EQ(2, count2); // No change.
249  EXPECT_EQ(1, count4); // No change.
250  EXPECT_EQ(std::vector<std::string>({d3, d11}), data3);
251 
252  // cb2 and cb4 use and only use f2. Cancel cb2 should not affect cb4.
253  updater_->cancelCallback(cb2);
254  ASSERT_TRUE(folly::writeFile(d22, f2.c_str())); // Last write to f2 > 1s ago.
257  sem4.reset();
260  EXPECT_EQ(d21, data2); // cb2 should not run, so not updated.
261  EXPECT_EQ(d22, data4); // cb4 should run, so updated to d22.
262  EXPECT_EQ(2, count2); // No change.
263  EXPECT_EQ(2, count4); // +1
264 
265  // Now we cancel cb4. Record of f2 should be cleaned up.
266  updater_->cancelCallback(cb4);
267  ASSERT_TRUE(folly::writeFile(d1, f2.c_str()));
270  EXPECT_EQ(d21, data2); // cb2 should not run, so not updated to d1.
271  EXPECT_EQ(d22, data4); // cb4 should not run, so not updated to d1.
272 }
Map::mapped_type get_default(const Map &map, const Key &key)
Definition: MapUtil.h:31
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::chrono::steady_clock::time_point now()
std::unordered_map< std::string, std::string > CallbackArg
FOLLY_ALWAYS_INLINE void post() noexcept
FOLLY_ALWAYS_INLINE bool try_wait_until(const std::chrono::time_point< Clock, Duration > &deadline, const WaitOptions &opt=wait_options()) noexcept
static const std::chrono::milliseconds kMaxSemaphoreWaitMs
const char * string
Definition: Conv.cpp:212
const Map::mapped_type & get_or_throw(const Map &map, const Key &key, const std::string &exceptionStrPrefix=std::string())
Definition: MapUtil.h:71
bool writeFile(const Container &data, const char *filename, int flags=O_WRONLY|O_CREAT|O_TRUNC, mode_t mode=0666)
Definition: FileUtil.h:211
#define ASSERT_NE(val1, val2)
Definition: gtest.h:1960
#define ASSERT_FALSE(condition)
Definition: gtest.h:1868
RfcParam d3(false, exampleHex1)
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865

Variable Documentation

const std::chrono::milliseconds kMaxSemaphoreWaitMs {1000}
static

Definition at line 36 of file MultiFilePollerTest.cpp.

Referenced by TEST_F().

const std::chrono::milliseconds kPollIntervalMs {200}
static

Definition at line 30 of file MultiFilePollerTest.cpp.

Referenced by MultiFilePollerTest::SetUp().

const std::chrono::milliseconds kWriteWaitMs {1000}
static

Definition at line 33 of file MultiFilePollerTest.cpp.

Referenced by MultiFilePollerTest::delayedWrite().