proxygen
FilePollerTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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 <chrono>
17 #include <condition_variable>
18 #include <mutex>
19 
20 #include <boost/filesystem.hpp>
23 #include <folly/File.h>
24 #include <folly/FileUtil.h>
26 #include <wangle/util/FilePoller.h>
27 #include <folly/Singleton.h>
28 
29 using namespace testing;
30 using namespace folly;
31 using namespace wangle;
32 using namespace folly::test;
33 
34 class FilePollerTest : public testing::Test {
35  public:
36  void createFile() { File(tmpFile, O_CREAT); }
37 
39  fs::path tmpFilePath{tmpDir.path() / "file-poller"};
40  std::string tmpFile{tmpFilePath.string()};
41 };
42 
43 void updateModifiedTime(const std::string& fileName, bool forward = true) {
44  auto previous = std::chrono::system_clock::from_time_t(
45  boost::filesystem::last_write_time(fileName));
46  auto diff = std::chrono::seconds(10);
47  std::chrono::system_clock::time_point newTime;
48  if (forward) {
49  newTime = previous + diff;
50  } else {
51  newTime = previous - diff;
52  }
53 
54  time_t newTimet = std::chrono::system_clock::to_time_t(newTime);
55  boost::filesystem::last_write_time(fileName, newTimet);
56 }
57 
58 TEST_F(FilePollerTest, TestUpdateFile) {
59  createFile();
60  Baton<> baton;
61  bool updated = false;
62  FilePoller poller(std::chrono::milliseconds(1));
63  poller.addFileToTrack(tmpFile, [&]() {
64  updated = true;
65  baton.post();
66  });
67  updateModifiedTime(tmpFile);
68  ASSERT_TRUE(baton.try_wait_for(std::chrono::seconds(5)));
69  ASSERT_TRUE(updated);
70 }
71 
72 TEST_F(FilePollerTest, TestUpdateFileBackwards) {
73  createFile();
74  Baton<> baton;
75  bool updated = false;
76  FilePoller poller(std::chrono::milliseconds(1));
77  poller.addFileToTrack(tmpFile, [&]() {
78  updated = true;
79  baton.post();
80  });
81  updateModifiedTime(tmpFile, false);
82  ASSERT_TRUE(baton.try_wait_for(std::chrono::seconds(5)));
83  ASSERT_TRUE(updated);
84 }
85 
86 TEST_F(FilePollerTest, TestCreateFile) {
87  Baton<> baton;
88  bool updated = false;
89  createFile();
90  remove(tmpFile.c_str());
91  FilePoller poller(std::chrono::milliseconds(1));
92  poller.addFileToTrack(tmpFile, [&]() {
93  updated = true;
94  baton.post();
95  });
96  File(creat(tmpFile.c_str(), O_RDONLY));
97  ASSERT_TRUE(baton.try_wait_for(std::chrono::seconds(5)));
98  ASSERT_TRUE(updated);
99 }
100 
101 TEST_F(FilePollerTest, TestDeleteFile) {
102  Baton<> baton;
103  bool updated = false;
104  createFile();
105  FilePoller poller(std::chrono::milliseconds(1));
106  poller.addFileToTrack(tmpFile, [&]() {
107  updated = true;
108  baton.post();
109  });
110  remove(tmpFile.c_str());
111  ASSERT_FALSE(baton.try_wait_for(std::chrono::seconds(1)));
112  ASSERT_FALSE(updated);
113 }
114 
117  std::condition_variable cv;
118  bool updated{false};
119 
121  std::unique_lock<std::mutex> lk(m);
122  updated = true;
123  cv.notify_one();
124  }
125 
126  void waitForUpdate(bool expect = true) {
127  std::unique_lock<std::mutex> lk(m);
128  cv.wait_for(lk, std::chrono::milliseconds(100), [&] { return updated; });
129  ASSERT_EQ(updated, expect);
130  updated = false;
131  }
132 };
133 
134 class TestFile {
135  public:
136  TestFile(bool exists, time_t mTime) : exists_(exists), modTime_(mTime) {}
137 
138  void update(bool e, time_t t) {
139  std::unique_lock<std::mutex> lk(m);
140  exists_ = e;
141  modTime_ = t;
142  }
143 
145  std::unique_lock<std::mutex> lk(m);
146  return FilePoller::FileModificationData(exists_, modTime_);
147  }
148 
149  const std::string name{"fakeFile"};
150  private:
151  bool exists_{false};
152  time_t modTime_{0};
154 
155 };
156 
157 class NoDiskPoller : public FilePoller {
158  public:
159  explicit NoDiskPoller(TestFile& testFile)
160  : FilePoller(std::chrono::milliseconds(10)), testFile_(testFile) {}
161 
162  protected:
164  getFileModData(const std::string& path) noexcept override {
165  EXPECT_EQ(path, testFile_.name);
166  return testFile_.toFileModData();
167  }
168 
169  private:
171 };
172 
174  explicit PollerWithState(TestFile& testFile) {
175  poller = std::make_unique<NoDiskPoller>(testFile);
176  poller->addFileToTrack(testFile.name, [&] {
177  state.updateTriggered();
178  });
179  }
180 
181  void waitForUpdate(bool expect = true) {
182  ASSERT_NO_FATAL_FAILURE(state.waitForUpdate(expect));
183  }
184 
185  std::unique_ptr<FilePoller> poller;
187 };
188 
189 TEST_F(FilePollerTest, TestTwoUpdatesAndDelete) {
190  TestFile testFile(true, 1);
191  PollerWithState poller(testFile);
192 
193  testFile.update(true, 2);
195 
196  testFile.update(true, 3);
198 
199  testFile.update(false, 0);
200  ASSERT_NO_FATAL_FAILURE(poller.waitForUpdate(false));
201 }
202 
203 TEST_F(FilePollerTest, TestFileCreatedLate) {
204  TestFile testFile(false, 0); // not created yet
205  PollerWithState poller(testFile);
206  ASSERT_NO_FATAL_FAILURE(poller.waitForUpdate(false));
207 
208  testFile.update(true, 1);
210 }
211 
212 TEST_F(FilePollerTest, TestMultiplePollers) {
213  TestFile testFile(true, 1);
214  PollerWithState p1(testFile);
215  PollerWithState p2(testFile);
216 
217  testFile.update(true, 2);
220 
221  testFile.update(true, 1);
224 
225  // clear one of the pollers and make sure the other is still
226  // getting them
227  p2.poller.reset();
228  testFile.update(true, 3);
231 }
232 
233 TEST(FilePoller, TestFork) {
234  TestFile testFile(true, 1);
235  PollerWithState p1(testFile);
236  testFile.update(true, 2);
238  // nuke singleton
240  testFile.update(true, 3);
242 }
chrono
Definition: CMakeCache.txt:563
PollerWithState(TestFile &testFile)
static SingletonVault * singleton()
Definition: Singleton.h:495
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
NoDiskPoller(TestFile &testFile)
void waitForUpdate(bool expect=true)
TEST_F(TestInfoTest, Names)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
STL namespace.
std::condition_variable cv
std::mutex m
const std::string name
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
void updateModifiedTime(const std::string &fileName, bool forward=true)
FOLLY_ALWAYS_INLINE bool try_wait_for(const std::chrono::duration< Rep, Period > &timeout, const WaitOptions &opt=wait_options()) noexcept
Definition: Baton.h:206
const char * name
Definition: http_parser.c:437
void addFileToTrack(const std::string &fileName, Cob yCob, Cob nCob=nullptr, Condition condition=fileTouchedCondInternal)
Definition: FilePoller.cpp:115
TEST(GTestEnvVarTest, Dummy)
static map< string, int > m
TestFile & testFile_
void update(bool e, time_t t)
void expect(LineReader &lr, const char *expected)
UpdateSyncState state
void post() noexcept
Definition: Baton.h:123
uint64_t diff(uint64_t a, uint64_t b)
Definition: FutexTest.cpp:135
FilePoller::FileModificationData getFileModData(const std::string &path) noexceptoverride
std::mutex mutex
const char * string
Definition: Conv.cpp:212
void waitForUpdate(bool expect=true)
std::unique_ptr< FilePoller > poller
TestFile(bool exists, time_t mTime)
#define ASSERT_NO_FATAL_FAILURE(statement)
Definition: gtest.h:2099
FilePoller::FileModificationData toFileModData()
#define ASSERT_FALSE(condition)
Definition: gtest.h:1868
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865
const fs::path & path() const
Definition: TestUtil.h:116
state
Definition: http_parser.c:272
TemporaryDirectory tmpDir