184af0c9bSNicolas Bonnefon #include "gmock/gmock.h"
284af0c9bSNicolas Bonnefon
387e05652SNicolas Bonnefon #include "config.h"
487e05652SNicolas Bonnefon
5b827fa8eSNicolas Bonnefon #include <cstdio>
684af0c9bSNicolas Bonnefon #include <fcntl.h>
784af0c9bSNicolas Bonnefon
884af0c9bSNicolas Bonnefon #include <memory>
984af0c9bSNicolas Bonnefon #include <condition_variable>
1084af0c9bSNicolas Bonnefon #include <thread>
1184af0c9bSNicolas Bonnefon #include <mutex>
1284af0c9bSNicolas Bonnefon #include <chrono>
1384af0c9bSNicolas Bonnefon
1484b2179eSNicolas Bonnefon #include "log.h"
1584b2179eSNicolas Bonnefon
16f09fa651SNicolas Bonnefon #include "watchtower.h"
17f09fa651SNicolas Bonnefon
1887e05652SNicolas Bonnefon #ifdef _WIN32
19f09fa651SNicolas Bonnefon # include "winwatchtowerdriver.h"
20f09fa651SNicolas Bonnefon using PlatformWatchTower = WatchTower<WinWatchTowerDriver>;
21*f869e41dSNicolas Bonnefon #elif defined(__APPLE__)
22*f869e41dSNicolas Bonnefon # include "kqueuewatchtowerdriver.h"
23*f869e41dSNicolas Bonnefon using PlatformWatchTower = WatchTower<KQueueWatchTowerDriver>;
2487e05652SNicolas Bonnefon #else
25b278d183SNicolas Bonnefon # include "inotifywatchtowerdriver.h"
26f09fa651SNicolas Bonnefon using PlatformWatchTower = WatchTower<INotifyWatchTowerDriver>;
2787e05652SNicolas Bonnefon #endif
2884af0c9bSNicolas Bonnefon
2984af0c9bSNicolas Bonnefon using namespace std;
3084af0c9bSNicolas Bonnefon using namespace testing;
3184af0c9bSNicolas Bonnefon
3284af0c9bSNicolas Bonnefon class WatchTowerBehaviour: public testing::Test {
3384af0c9bSNicolas Bonnefon public:
3496bde7d5SNicolas Bonnefon shared_ptr<PlatformWatchTower> watch_tower = make_shared<PlatformWatchTower>();
3584af0c9bSNicolas Bonnefon
createTempName()36a0b17fd1SNicolas Bonnefon const char* createTempName()
37a0b17fd1SNicolas Bonnefon {
38a0b17fd1SNicolas Bonnefon const char* name;
39a0b17fd1SNicolas Bonnefon #if _WIN32
40a0b17fd1SNicolas Bonnefon name = _tempnam( "c:\\temp", "glogg_test" );
41a0b17fd1SNicolas Bonnefon #else
42a0b17fd1SNicolas Bonnefon name = tmpnam( nullptr );
43a0b17fd1SNicolas Bonnefon #endif
44a0b17fd1SNicolas Bonnefon return name;
45a0b17fd1SNicolas Bonnefon }
46a0b17fd1SNicolas Bonnefon
createTempEmptyFile(string file_name="")47b827fa8eSNicolas Bonnefon string createTempEmptyFile( string file_name = "" ) {
48b827fa8eSNicolas Bonnefon const char* name;
49b827fa8eSNicolas Bonnefon
50b827fa8eSNicolas Bonnefon if ( ! file_name.empty() ) {
51b827fa8eSNicolas Bonnefon name = file_name.c_str();
52b827fa8eSNicolas Bonnefon }
53b827fa8eSNicolas Bonnefon else {
5484af0c9bSNicolas Bonnefon // I know tmpnam is bad but I need control over the file
5584af0c9bSNicolas Bonnefon // and it is the only one which exits on Windows.
56a0b17fd1SNicolas Bonnefon name = createTempName();
57b827fa8eSNicolas Bonnefon }
58b827fa8eSNicolas Bonnefon int fd = creat( name, S_IRUSR | S_IWUSR );
5984af0c9bSNicolas Bonnefon close( fd );
6084af0c9bSNicolas Bonnefon
61b827fa8eSNicolas Bonnefon return string( name );
6284af0c9bSNicolas Bonnefon }
6384af0c9bSNicolas Bonnefon
getNonExistingFileName()6484af0c9bSNicolas Bonnefon string getNonExistingFileName() {
6584b2179eSNicolas Bonnefon #if _WIN32
6684b2179eSNicolas Bonnefon return string( _tempnam( "c:\\temp", "inexistant" ) );
6784b2179eSNicolas Bonnefon #else
6884af0c9bSNicolas Bonnefon return string( tmpnam( nullptr ) );
6984b2179eSNicolas Bonnefon #endif
7084b2179eSNicolas Bonnefon }
7184b2179eSNicolas Bonnefon
WatchTowerBehaviour()7284b2179eSNicolas Bonnefon WatchTowerBehaviour() {
7384b2179eSNicolas Bonnefon // Default to quiet, but increase to debug
745d489994SNicolas Bonnefon FILELog::setReportingLevel( logERROR );
7584af0c9bSNicolas Bonnefon }
7684af0c9bSNicolas Bonnefon };
7784af0c9bSNicolas Bonnefon
TEST_F(WatchTowerBehaviour,AcceptsAnExistingFileToWatch)7884af0c9bSNicolas Bonnefon TEST_F( WatchTowerBehaviour, AcceptsAnExistingFileToWatch ) {
7984af0c9bSNicolas Bonnefon auto file_name = createTempEmptyFile();
8087e05652SNicolas Bonnefon auto registration = watch_tower->addFile( file_name, [] (void) { } );
8184af0c9bSNicolas Bonnefon }
8284af0c9bSNicolas Bonnefon
TEST_F(WatchTowerBehaviour,AcceptsANonExistingFileToWatch)8384af0c9bSNicolas Bonnefon TEST_F( WatchTowerBehaviour, AcceptsANonExistingFileToWatch ) {
8487e05652SNicolas Bonnefon auto registration = watch_tower->addFile( getNonExistingFileName(), [] (void) { } );
8584af0c9bSNicolas Bonnefon }
8684af0c9bSNicolas Bonnefon
87b827fa8eSNicolas Bonnefon /*****/
88b827fa8eSNicolas Bonnefon
8984af0c9bSNicolas Bonnefon class WatchTowerSingleFile: public WatchTowerBehaviour {
9084af0c9bSNicolas Bonnefon public:
91b827fa8eSNicolas Bonnefon static const int TIMEOUT;
9284af0c9bSNicolas Bonnefon
933104b268SNicolas Bonnefon mutex mutex_;
943104b268SNicolas Bonnefon condition_variable cv_;
953104b268SNicolas Bonnefon
9684af0c9bSNicolas Bonnefon string file_name;
9796bde7d5SNicolas Bonnefon Registration registration;
9884af0c9bSNicolas Bonnefon
998f031b5aSNicolas Bonnefon int notification_received = 0;
10084af0c9bSNicolas Bonnefon
registerFile(const string & filename)10196bde7d5SNicolas Bonnefon Registration registerFile( const string& filename ) {
102b827fa8eSNicolas Bonnefon weak_ptr<void> weakHeartbeat( heartbeat_ );
103b827fa8eSNicolas Bonnefon
10484b2179eSNicolas Bonnefon auto reg = watch_tower->addFile( filename, [this, weakHeartbeat] (void) {
105b827fa8eSNicolas Bonnefon // Ensure the fixture object is still alive using the heartbeat
106b827fa8eSNicolas Bonnefon if ( auto keep = weakHeartbeat.lock() ) {
10784af0c9bSNicolas Bonnefon unique_lock<mutex> lock(mutex_);
1088f031b5aSNicolas Bonnefon ++notification_received;
109b827fa8eSNicolas Bonnefon cv_.notify_one();
110b827fa8eSNicolas Bonnefon } } );
111b827fa8eSNicolas Bonnefon
112b827fa8eSNicolas Bonnefon return reg;
113b827fa8eSNicolas Bonnefon }
114b827fa8eSNicolas Bonnefon
WatchTowerSingleFile()11584b2179eSNicolas Bonnefon WatchTowerSingleFile()
11684b2179eSNicolas Bonnefon : heartbeat_( shared_ptr<void>( (void*) 0xDEADC0DE, [] (void*) {} ) )
11784b2179eSNicolas Bonnefon {
118b827fa8eSNicolas Bonnefon file_name = createTempEmptyFile();
119b827fa8eSNicolas Bonnefon registration = registerFile( file_name );
12084af0c9bSNicolas Bonnefon }
12184af0c9bSNicolas Bonnefon
~WatchTowerSingleFile()12284b2179eSNicolas Bonnefon ~WatchTowerSingleFile() {
12384b2179eSNicolas Bonnefon remove( file_name.c_str() );
12484b2179eSNicolas Bonnefon }
12584b2179eSNicolas Bonnefon
waitNotificationReceived(int number=1,int timeout_ms=TIMEOUT)126fcaa7557SNicolas Bonnefon bool waitNotificationReceived( int number = 1, int timeout_ms = TIMEOUT ) {
12784af0c9bSNicolas Bonnefon unique_lock<mutex> lock(mutex_);
128fcaa7557SNicolas Bonnefon bool result = ( cv_.wait_for( lock, std::chrono::milliseconds(timeout_ms),
1298f031b5aSNicolas Bonnefon [this, number] { return notification_received >= number; } ) );
130b827fa8eSNicolas Bonnefon
131b827fa8eSNicolas Bonnefon // Reinit the notification
1328f031b5aSNicolas Bonnefon notification_received = 0;
133b827fa8eSNicolas Bonnefon
1348f031b5aSNicolas Bonnefon return result;
13584af0c9bSNicolas Bonnefon }
13684af0c9bSNicolas Bonnefon
appendDataToFile(const string & file_name)13784af0c9bSNicolas Bonnefon void appendDataToFile( const string& file_name ) {
13884af0c9bSNicolas Bonnefon static const char* string = "Test line\n";
13984af0c9bSNicolas Bonnefon int fd = open( file_name.c_str(), O_WRONLY | O_APPEND );
14084af0c9bSNicolas Bonnefon write( fd, (void*) string, strlen( string ) );
14184af0c9bSNicolas Bonnefon close( fd );
14284af0c9bSNicolas Bonnefon }
143b827fa8eSNicolas Bonnefon
144b827fa8eSNicolas Bonnefon private:
145b827fa8eSNicolas Bonnefon // Heartbeat ensures the object is still alive
146b827fa8eSNicolas Bonnefon shared_ptr<void> heartbeat_;
14784af0c9bSNicolas Bonnefon };
14884af0c9bSNicolas Bonnefon
149a0936e1eSNicolas Bonnefon #ifdef _WIN32
1503104b268SNicolas Bonnefon const int WatchTowerSingleFile::TIMEOUT = 2000;
151a0936e1eSNicolas Bonnefon #else
152b827fa8eSNicolas Bonnefon const int WatchTowerSingleFile::TIMEOUT = 20;
153a0936e1eSNicolas Bonnefon #endif
154a0936e1eSNicolas Bonnefon
TEST_F(WatchTowerSingleFile,SignalsWhenAWatchedFileIsAppended)15584b2179eSNicolas Bonnefon TEST_F( WatchTowerSingleFile, SignalsWhenAWatchedFileIsAppended ) {
15684af0c9bSNicolas Bonnefon appendDataToFile( file_name );
15784af0c9bSNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
15884af0c9bSNicolas Bonnefon }
15984af0c9bSNicolas Bonnefon
TEST_F(WatchTowerSingleFile,SignalsWhenAWatchedFileIsRemoved)160b827fa8eSNicolas Bonnefon TEST_F( WatchTowerSingleFile, SignalsWhenAWatchedFileIsRemoved) {
16184af0c9bSNicolas Bonnefon remove( file_name.c_str() );
16284af0c9bSNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
16384af0c9bSNicolas Bonnefon }
164b827fa8eSNicolas Bonnefon
TEST_F(WatchTowerSingleFile,SignalsWhenADeletedFileReappears)165b827fa8eSNicolas Bonnefon TEST_F( WatchTowerSingleFile, SignalsWhenADeletedFileReappears ) {
166b827fa8eSNicolas Bonnefon remove( file_name.c_str() );
167b827fa8eSNicolas Bonnefon waitNotificationReceived();
168b827fa8eSNicolas Bonnefon createTempEmptyFile( file_name );
169b827fa8eSNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
170b827fa8eSNicolas Bonnefon }
171b827fa8eSNicolas Bonnefon
TEST_F(WatchTowerSingleFile,SignalsWhenAReappearedFileIsAppended)17291f7c705SNicolas Bonnefon TEST_F( WatchTowerSingleFile, SignalsWhenAReappearedFileIsAppended ) {
17391f7c705SNicolas Bonnefon remove( file_name.c_str() );
17491f7c705SNicolas Bonnefon waitNotificationReceived();
17591f7c705SNicolas Bonnefon createTempEmptyFile( file_name );
17691f7c705SNicolas Bonnefon waitNotificationReceived();
17791f7c705SNicolas Bonnefon
17891f7c705SNicolas Bonnefon appendDataToFile( file_name );
17991f7c705SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
18091f7c705SNicolas Bonnefon }
18191f7c705SNicolas Bonnefon
TEST_F(WatchTowerSingleFile,StopSignalingWhenWatchDeleted)182b827fa8eSNicolas Bonnefon TEST_F( WatchTowerSingleFile, StopSignalingWhenWatchDeleted ) {
183b827fa8eSNicolas Bonnefon auto second_file_name = createTempEmptyFile();
1843104b268SNicolas Bonnefon std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
1853104b268SNicolas Bonnefon // Ensure file creation has been 'digested'
186b827fa8eSNicolas Bonnefon {
187b827fa8eSNicolas Bonnefon auto second_registration = registerFile( second_file_name );
188b827fa8eSNicolas Bonnefon appendDataToFile( second_file_name );
189b827fa8eSNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
190b827fa8eSNicolas Bonnefon }
191b827fa8eSNicolas Bonnefon
192b827fa8eSNicolas Bonnefon // The registration will be removed here.
193b827fa8eSNicolas Bonnefon appendDataToFile( second_file_name );
194b827fa8eSNicolas Bonnefon ASSERT_FALSE( waitNotificationReceived() );
195b827fa8eSNicolas Bonnefon
196b827fa8eSNicolas Bonnefon remove( second_file_name.c_str() );
197b827fa8eSNicolas Bonnefon }
198b827fa8eSNicolas Bonnefon
TEST_F(WatchTowerSingleFile,SignalsWhenSameFileIsFollowedMultipleTimes)199f09fa651SNicolas Bonnefon TEST_F( WatchTowerSingleFile, SignalsWhenSameFileIsFollowedMultipleTimes ) {
200f09fa651SNicolas Bonnefon auto second_file_name = createTempEmptyFile();
201f09fa651SNicolas Bonnefon
2023104b268SNicolas Bonnefon for ( int i = 0; i < 100; i++ )
203f09fa651SNicolas Bonnefon {
204f09fa651SNicolas Bonnefon auto second_registration = registerFile( second_file_name );
205f09fa651SNicolas Bonnefon appendDataToFile( second_file_name );
206f09fa651SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
207f09fa651SNicolas Bonnefon }
208f09fa651SNicolas Bonnefon
209f09fa651SNicolas Bonnefon // The registration will be removed here.
210f09fa651SNicolas Bonnefon appendDataToFile( second_file_name );
211f09fa651SNicolas Bonnefon ASSERT_FALSE( waitNotificationReceived() );
212f09fa651SNicolas Bonnefon
213f09fa651SNicolas Bonnefon remove( second_file_name.c_str() );
214f09fa651SNicolas Bonnefon }
215f09fa651SNicolas Bonnefon
TEST_F(WatchTowerSingleFile,TwoWatchesOnSameFileYieldsTwoNotifications)216a0b17fd1SNicolas Bonnefon TEST_F( WatchTowerSingleFile, TwoWatchesOnSameFileYieldsTwoNotifications ) {
2178f031b5aSNicolas Bonnefon auto second_registration = registerFile( file_name );
2188f031b5aSNicolas Bonnefon appendDataToFile( file_name );
2198f031b5aSNicolas Bonnefon
2208f031b5aSNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived( 2 ) );
2218f031b5aSNicolas Bonnefon }
2228f031b5aSNicolas Bonnefon
TEST_F(WatchTowerSingleFile,RemovingOneWatchOfTwoStillYieldsOneNotification)223a0b17fd1SNicolas Bonnefon TEST_F( WatchTowerSingleFile, RemovingOneWatchOfTwoStillYieldsOneNotification ) {
2248f031b5aSNicolas Bonnefon {
2258f031b5aSNicolas Bonnefon auto second_registration = registerFile( file_name );
2268f031b5aSNicolas Bonnefon }
2278f031b5aSNicolas Bonnefon
2288f031b5aSNicolas Bonnefon appendDataToFile( file_name );
2298f031b5aSNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived( 1 ) );
2308f031b5aSNicolas Bonnefon }
2318f031b5aSNicolas Bonnefon
TEST_F(WatchTowerSingleFile,RenamingTheFileYieldsANotification)232a0b17fd1SNicolas Bonnefon TEST_F( WatchTowerSingleFile, RenamingTheFileYieldsANotification ) {
233a0b17fd1SNicolas Bonnefon auto new_file_name = createTempName();
2348f031b5aSNicolas Bonnefon
235a0b17fd1SNicolas Bonnefon rename( file_name.c_str(), new_file_name );
2368f031b5aSNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
2378f031b5aSNicolas Bonnefon
238a0b17fd1SNicolas Bonnefon rename( new_file_name, file_name.c_str() );
2398f031b5aSNicolas Bonnefon }
2408f031b5aSNicolas Bonnefon
TEST_F(WatchTowerSingleFile,RenamingAFileToTheWatchedNameYieldsANotification)241a0b17fd1SNicolas Bonnefon TEST_F( WatchTowerSingleFile, RenamingAFileToTheWatchedNameYieldsANotification ) {
2428f031b5aSNicolas Bonnefon remove( file_name.c_str() );
2438f031b5aSNicolas Bonnefon waitNotificationReceived();
2448f031b5aSNicolas Bonnefon
245a0b17fd1SNicolas Bonnefon std::string new_file_name = createTempEmptyFile();
2468f031b5aSNicolas Bonnefon appendDataToFile( new_file_name );
2478f031b5aSNicolas Bonnefon
2488f031b5aSNicolas Bonnefon rename( new_file_name.c_str(), file_name.c_str() );
2498f031b5aSNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
2508f031b5aSNicolas Bonnefon }
2518f031b5aSNicolas Bonnefon
2528f031b5aSNicolas Bonnefon /*****/
2538f031b5aSNicolas Bonnefon
25487e05652SNicolas Bonnefon #ifdef HAVE_SYMLINK
2553af68c64SNicolas Bonnefon class WatchTowerSymlink: public WatchTowerSingleFile {
2563af68c64SNicolas Bonnefon public:
2573af68c64SNicolas Bonnefon string symlink_name;
2583af68c64SNicolas Bonnefon
SetUp()2593af68c64SNicolas Bonnefon void SetUp() override {
2603af68c64SNicolas Bonnefon file_name = createTempEmptyFile();
2613af68c64SNicolas Bonnefon symlink_name = createTempEmptyFile();
2623af68c64SNicolas Bonnefon remove( symlink_name.c_str() );
2633af68c64SNicolas Bonnefon symlink( file_name.c_str(), symlink_name.c_str() );
2643af68c64SNicolas Bonnefon
2653af68c64SNicolas Bonnefon registration = registerFile( symlink_name );
2663af68c64SNicolas Bonnefon }
2673af68c64SNicolas Bonnefon
TearDown()2683af68c64SNicolas Bonnefon void TearDown() override {
2693af68c64SNicolas Bonnefon remove( symlink_name.c_str() );
2703af68c64SNicolas Bonnefon remove( file_name.c_str() );
2713af68c64SNicolas Bonnefon }
2723af68c64SNicolas Bonnefon };
2733af68c64SNicolas Bonnefon
TEST_F(WatchTowerSymlink,AppendingToTheSymlinkYieldsANotification)2743af68c64SNicolas Bonnefon TEST_F( WatchTowerSymlink, AppendingToTheSymlinkYieldsANotification ) {
2753af68c64SNicolas Bonnefon appendDataToFile( symlink_name );
2763af68c64SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
2773af68c64SNicolas Bonnefon }
2783af68c64SNicolas Bonnefon
TEST_F(WatchTowerSymlink,AppendingToTheTargetYieldsANotification)2793af68c64SNicolas Bonnefon TEST_F( WatchTowerSymlink, AppendingToTheTargetYieldsANotification ) {
2803af68c64SNicolas Bonnefon appendDataToFile( file_name );
2813af68c64SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
2823af68c64SNicolas Bonnefon }
2833af68c64SNicolas Bonnefon
TEST_F(WatchTowerSymlink,RemovingTheSymlinkYieldsANotification)2843af68c64SNicolas Bonnefon TEST_F( WatchTowerSymlink, RemovingTheSymlinkYieldsANotification ) {
2853af68c64SNicolas Bonnefon remove( symlink_name.c_str() );
2863af68c64SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
2873af68c64SNicolas Bonnefon }
2883af68c64SNicolas Bonnefon
TEST_F(WatchTowerSymlink,RemovingTheTargetYieldsANotification)2893af68c64SNicolas Bonnefon TEST_F( WatchTowerSymlink, RemovingTheTargetYieldsANotification ) {
2903af68c64SNicolas Bonnefon remove( file_name.c_str() );
2913af68c64SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
2923af68c64SNicolas Bonnefon }
2933af68c64SNicolas Bonnefon
TEST_F(WatchTowerSymlink,ReappearingSymlinkYieldsANotification)2943af68c64SNicolas Bonnefon TEST_F( WatchTowerSymlink, ReappearingSymlinkYieldsANotification ) {
2953af68c64SNicolas Bonnefon auto new_target = createTempEmptyFile();
2963af68c64SNicolas Bonnefon remove( symlink_name.c_str() );
2973af68c64SNicolas Bonnefon waitNotificationReceived();
2983af68c64SNicolas Bonnefon
2993af68c64SNicolas Bonnefon symlink( new_target.c_str(), symlink_name.c_str() );
3003af68c64SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
3013af68c64SNicolas Bonnefon
3023af68c64SNicolas Bonnefon remove( new_target.c_str() );
3033af68c64SNicolas Bonnefon }
30491f7c705SNicolas Bonnefon
TEST_F(WatchTowerSymlink,DataAddedInAReappearingSymlinkYieldsANotification)30591f7c705SNicolas Bonnefon TEST_F( WatchTowerSymlink, DataAddedInAReappearingSymlinkYieldsANotification ) {
30691f7c705SNicolas Bonnefon auto new_target = createTempEmptyFile();
30791f7c705SNicolas Bonnefon remove( symlink_name.c_str() );
30891f7c705SNicolas Bonnefon waitNotificationReceived();
30991f7c705SNicolas Bonnefon symlink( new_target.c_str(), symlink_name.c_str() );
31091f7c705SNicolas Bonnefon waitNotificationReceived();
31191f7c705SNicolas Bonnefon
31291f7c705SNicolas Bonnefon appendDataToFile( new_target );
31391f7c705SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
31491f7c705SNicolas Bonnefon
31591f7c705SNicolas Bonnefon remove( new_target.c_str() );
31691f7c705SNicolas Bonnefon }
31787e05652SNicolas Bonnefon #endif //HAVE_SYMLINK
3183af68c64SNicolas Bonnefon
3193af68c64SNicolas Bonnefon /*****/
3203af68c64SNicolas Bonnefon
TEST(WatchTowerLifetime,RegistrationCanBeDeletedWhenWeAreDead)321b827fa8eSNicolas Bonnefon TEST( WatchTowerLifetime, RegistrationCanBeDeletedWhenWeAreDead ) {
32296bde7d5SNicolas Bonnefon auto mortal_watch_tower = new PlatformWatchTower();
323b827fa8eSNicolas Bonnefon auto reg = mortal_watch_tower->addFile( "/tmp/test_file", [] (void) { } );
324b827fa8eSNicolas Bonnefon
325b827fa8eSNicolas Bonnefon delete mortal_watch_tower;
3268f031b5aSNicolas Bonnefon // reg will be destroyed after the watch_tower
327b827fa8eSNicolas Bonnefon }
328af7adfddSNicolas Bonnefon
329af7adfddSNicolas Bonnefon /*****/
330af7adfddSNicolas Bonnefon
3313104b268SNicolas Bonnefon class WatchTowerDirectories: public WatchTowerSingleFile {
3323104b268SNicolas Bonnefon public:
3333104b268SNicolas Bonnefon string second_dir_name;
3343104b268SNicolas Bonnefon string second_file_name;
3353104b268SNicolas Bonnefon string third_file_name;
3363104b268SNicolas Bonnefon
3373104b268SNicolas Bonnefon Registration registration_two;
3383104b268SNicolas Bonnefon Registration registration_three;
3393104b268SNicolas Bonnefon
WatchTowerDirectories()3403104b268SNicolas Bonnefon WatchTowerDirectories() {
3413104b268SNicolas Bonnefon second_dir_name = createTempDir();
3423104b268SNicolas Bonnefon second_file_name = createTempEmptyFileInDir( second_dir_name );
3433104b268SNicolas Bonnefon third_file_name = createTempEmptyFileInDir( second_dir_name );
3443104b268SNicolas Bonnefon }
3453104b268SNicolas Bonnefon
~WatchTowerDirectories()3463104b268SNicolas Bonnefon ~WatchTowerDirectories() {
3473104b268SNicolas Bonnefon remove( third_file_name.c_str() );
3483104b268SNicolas Bonnefon remove( second_file_name.c_str() );
3493104b268SNicolas Bonnefon
3503104b268SNicolas Bonnefon removeDir( second_dir_name );
3513104b268SNicolas Bonnefon }
3523104b268SNicolas Bonnefon
createTempDir()3533104b268SNicolas Bonnefon string createTempDir() {
3543104b268SNicolas Bonnefon #ifdef _WIN32
3553104b268SNicolas Bonnefon static int counter = 1;
3563104b268SNicolas Bonnefon char temp_dir[255];
3573104b268SNicolas Bonnefon
3583104b268SNicolas Bonnefon GetTempPath( sizeof temp_dir, temp_dir );
3593104b268SNicolas Bonnefon
3603104b268SNicolas Bonnefon string dir_name = string { temp_dir } + string { "\\test" } + to_string( counter++ );
3613104b268SNicolas Bonnefon mkdir( dir_name.c_str() );
3623104b268SNicolas Bonnefon return dir_name;
3633104b268SNicolas Bonnefon #else
3643104b268SNicolas Bonnefon char dir_template[] = "/tmp/XXXXXX";
3653104b268SNicolas Bonnefon return { mkdtemp( dir_template ) };
3663104b268SNicolas Bonnefon #endif
3673104b268SNicolas Bonnefon }
3683104b268SNicolas Bonnefon
createTempEmptyFileInDir(const string & dir)3693104b268SNicolas Bonnefon string createTempEmptyFileInDir( const string& dir ) {
3703104b268SNicolas Bonnefon static int counter = 1;
3713104b268SNicolas Bonnefon return createTempEmptyFile( dir + std::string { "/temp" } + to_string( counter++ ) );
3723104b268SNicolas Bonnefon }
3733104b268SNicolas Bonnefon
removeDir(const string & name)3743104b268SNicolas Bonnefon void removeDir( const string& name ) {
3753104b268SNicolas Bonnefon rmdir( name.c_str() );
3763104b268SNicolas Bonnefon }
3773104b268SNicolas Bonnefon };
3783104b268SNicolas Bonnefon
TEST_F(WatchTowerDirectories,FollowThreeFilesInTwoDirs)3793104b268SNicolas Bonnefon TEST_F( WatchTowerDirectories, FollowThreeFilesInTwoDirs ) {
3803104b268SNicolas Bonnefon registration_two = registerFile( second_file_name );
3813104b268SNicolas Bonnefon registration_three = registerFile( third_file_name );
3823104b268SNicolas Bonnefon
3833104b268SNicolas Bonnefon ASSERT_THAT( watch_tower->numberWatchedDirectories(), Eq( 2 ) );
3843104b268SNicolas Bonnefon }
3853104b268SNicolas Bonnefon
TEST_F(WatchTowerDirectories,FollowTwoFilesInTwoDirs)3863104b268SNicolas Bonnefon TEST_F( WatchTowerDirectories, FollowTwoFilesInTwoDirs ) {
3873104b268SNicolas Bonnefon registration_two = registerFile( second_file_name );
3883104b268SNicolas Bonnefon {
3893104b268SNicolas Bonnefon auto temp_registration_three = registerFile( third_file_name );
3903104b268SNicolas Bonnefon }
3913104b268SNicolas Bonnefon
3923104b268SNicolas Bonnefon ASSERT_THAT( watch_tower->numberWatchedDirectories(), Eq( 2 ) );
3933104b268SNicolas Bonnefon }
3943104b268SNicolas Bonnefon
TEST_F(WatchTowerDirectories,FollowOneFileInOneDir)3953104b268SNicolas Bonnefon TEST_F( WatchTowerDirectories, FollowOneFileInOneDir ) {
3963104b268SNicolas Bonnefon {
3973104b268SNicolas Bonnefon auto temp_registration_two = registerFile( second_file_name );
3983104b268SNicolas Bonnefon auto temp_registration_three = registerFile( third_file_name );
3993104b268SNicolas Bonnefon
4003104b268SNicolas Bonnefon ASSERT_THAT( watch_tower->numberWatchedDirectories(), Eq( 2 ) );
4013104b268SNicolas Bonnefon }
4023104b268SNicolas Bonnefon
4033104b268SNicolas Bonnefon ASSERT_THAT( watch_tower->numberWatchedDirectories(), Eq( 1 ) );
4043104b268SNicolas Bonnefon }
4053104b268SNicolas Bonnefon
4063104b268SNicolas Bonnefon /*****/
4073104b268SNicolas Bonnefon
4088b11848fSNicolas Bonnefon class WatchTowerInexistantDirectory: public WatchTowerDirectories {
4098b11848fSNicolas Bonnefon public:
WatchTowerInexistantDirectory()4108b11848fSNicolas Bonnefon WatchTowerInexistantDirectory() {
4118b11848fSNicolas Bonnefon test_dir = createTempDir();
4128b11848fSNicolas Bonnefon rmdir( test_dir.c_str() );
4138b11848fSNicolas Bonnefon }
4148b11848fSNicolas Bonnefon
~WatchTowerInexistantDirectory()4158b11848fSNicolas Bonnefon ~WatchTowerInexistantDirectory() {
4168b11848fSNicolas Bonnefon rmdir( test_dir.c_str() );
4178b11848fSNicolas Bonnefon }
4188b11848fSNicolas Bonnefon
4198b11848fSNicolas Bonnefon string test_dir;
4208b11848fSNicolas Bonnefon };
4218b11848fSNicolas Bonnefon
TEST_F(WatchTowerInexistantDirectory,LaterCreatedDirIsFollowed)4228b11848fSNicolas Bonnefon TEST_F( WatchTowerInexistantDirectory, LaterCreatedDirIsFollowed ) {
4238b11848fSNicolas Bonnefon /* Dir (and file) don't exist */
4248b11848fSNicolas Bonnefon auto file_name = createTempEmptyFileInDir( test_dir );
4258b11848fSNicolas Bonnefon {
4268b11848fSNicolas Bonnefon auto registration = registerFile( file_name );
4278b11848fSNicolas Bonnefon
4288b11848fSNicolas Bonnefon #ifdef _WIN32
4298b11848fSNicolas Bonnefon mkdir( test_dir.c_str() );
4308b11848fSNicolas Bonnefon #else
4318b11848fSNicolas Bonnefon mkdir( test_dir.c_str(), 0777 );
4328b11848fSNicolas Bonnefon #endif
4338b11848fSNicolas Bonnefon createTempEmptyFile( file_name );
4348b11848fSNicolas Bonnefon }
4358b11848fSNicolas Bonnefon
4368b11848fSNicolas Bonnefon auto registration2 = registerFile( file_name );
4378b11848fSNicolas Bonnefon
4388b11848fSNicolas Bonnefon appendDataToFile( file_name );
4398b11848fSNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
4408b11848fSNicolas Bonnefon
4418b11848fSNicolas Bonnefon remove( file_name.c_str() );
4428b11848fSNicolas Bonnefon }
4438b11848fSNicolas Bonnefon
4448b11848fSNicolas Bonnefon /*****/
4458b11848fSNicolas Bonnefon
446a0b17fd1SNicolas Bonnefon #ifdef _WIN32
447af7adfddSNicolas Bonnefon class WinNotificationInfoListTest : public testing::Test {
448af7adfddSNicolas Bonnefon public:
449af7adfddSNicolas Bonnefon using Action = WinNotificationInfo::Action;
450af7adfddSNicolas Bonnefon
451af7adfddSNicolas Bonnefon struct Buffer {
452af7adfddSNicolas Bonnefon uint32_t next_addr;
453af7adfddSNicolas Bonnefon uint32_t action;
454af7adfddSNicolas Bonnefon uint32_t filename_length;
455af7adfddSNicolas Bonnefon wchar_t filename[13];
456af7adfddSNicolas Bonnefon };
457af7adfddSNicolas Bonnefon static struct Buffer buffer[2];
458af7adfddSNicolas Bonnefon
459af7adfddSNicolas Bonnefon WinNotificationInfoList list { reinterpret_cast<char*>( buffer ), sizeof( buffer ) };
460af7adfddSNicolas Bonnefon WinNotificationInfoList::iterator iterator { std::begin( list ) };
461af7adfddSNicolas Bonnefon };
462af7adfddSNicolas Bonnefon
463af7adfddSNicolas Bonnefon struct WinNotificationInfoListTest::Buffer WinNotificationInfoListTest::buffer[] =
464af7adfddSNicolas Bonnefon { { 40, 1, 26, L"Filename.txt" },
465af7adfddSNicolas Bonnefon { 0, 3, 18, L"file2.txt" } };
466af7adfddSNicolas Bonnefon
TEST_F(WinNotificationInfoListTest,FirstNotificationCanBeObtained)467af7adfddSNicolas Bonnefon TEST_F( WinNotificationInfoListTest, FirstNotificationCanBeObtained ) {
468af7adfddSNicolas Bonnefon auto notification = *iterator;
469af7adfddSNicolas Bonnefon ASSERT_THAT( ¬ification, NotNull() );
470af7adfddSNicolas Bonnefon }
471af7adfddSNicolas Bonnefon
TEST_F(WinNotificationInfoListTest,FirstNotificationHasRightAction)472af7adfddSNicolas Bonnefon TEST_F( WinNotificationInfoListTest, FirstNotificationHasRightAction ) {
473af7adfddSNicolas Bonnefon ASSERT_THAT( (*iterator).action(), Eq( Action::ADDED ) );
474af7adfddSNicolas Bonnefon }
475af7adfddSNicolas Bonnefon
TEST_F(WinNotificationInfoListTest,FirstNotificationHasRightFileName)476af7adfddSNicolas Bonnefon TEST_F( WinNotificationInfoListTest, FirstNotificationHasRightFileName ) {
477af7adfddSNicolas Bonnefon ASSERT_THAT( (*iterator).fileName(), Eq( std::wstring( L"Filename.txt\0", 13 ) ) );
478af7adfddSNicolas Bonnefon }
479af7adfddSNicolas Bonnefon
TEST_F(WinNotificationInfoListTest,SecondNotificationCanBeObtained)480af7adfddSNicolas Bonnefon TEST_F( WinNotificationInfoListTest, SecondNotificationCanBeObtained ) {
481af7adfddSNicolas Bonnefon ++iterator;
482af7adfddSNicolas Bonnefon auto notification = *iterator;
483af7adfddSNicolas Bonnefon ASSERT_THAT( ¬ification, NotNull() );
484af7adfddSNicolas Bonnefon }
485af7adfddSNicolas Bonnefon
TEST_F(WinNotificationInfoListTest,SecondNotificationIsCorrect)486af7adfddSNicolas Bonnefon TEST_F( WinNotificationInfoListTest, SecondNotificationIsCorrect ) {
487af7adfddSNicolas Bonnefon iterator++;
488af7adfddSNicolas Bonnefon ASSERT_THAT( iterator->action(), Eq( Action::MODIFIED ) );
489af7adfddSNicolas Bonnefon ASSERT_THAT( iterator->fileName(), Eq( L"file2.txt" ) );
490af7adfddSNicolas Bonnefon }
491af7adfddSNicolas Bonnefon
TEST_F(WinNotificationInfoListTest,CanBeIteratedByFor)492af7adfddSNicolas Bonnefon TEST_F( WinNotificationInfoListTest, CanBeIteratedByFor ) {
493af7adfddSNicolas Bonnefon for ( auto notification : list ) {
494af7adfddSNicolas Bonnefon notification.action();
495af7adfddSNicolas Bonnefon }
496af7adfddSNicolas Bonnefon }
497a0b17fd1SNicolas Bonnefon #endif
498fcaa7557SNicolas Bonnefon
499fcaa7557SNicolas Bonnefon /*****/
500fcaa7557SNicolas Bonnefon
501fcaa7557SNicolas Bonnefon #ifdef _WIN32
502fcaa7557SNicolas Bonnefon class WatchTowerPolling : public WatchTowerSingleFile {
503fcaa7557SNicolas Bonnefon public:
WatchTowerPolling()504fcaa7557SNicolas Bonnefon WatchTowerPolling() : WatchTowerSingleFile() {
505fcaa7557SNicolas Bonnefon // FILELog::setReportingLevel( logDEBUG );
506fcaa7557SNicolas Bonnefon
507fcaa7557SNicolas Bonnefon fd_ = open( file_name.c_str(), O_WRONLY | O_APPEND );
508fcaa7557SNicolas Bonnefon }
509fcaa7557SNicolas Bonnefon
~WatchTowerPolling()510fcaa7557SNicolas Bonnefon ~WatchTowerPolling() {
511fcaa7557SNicolas Bonnefon close( fd_ );
512fcaa7557SNicolas Bonnefon }
513fcaa7557SNicolas Bonnefon
appendDataToFileWoClosing()514fcaa7557SNicolas Bonnefon void appendDataToFileWoClosing() {
515fcaa7557SNicolas Bonnefon static const char* string = "Test line\n";
516fcaa7557SNicolas Bonnefon write( fd_, (void*) string, strlen( string ) );
517fcaa7557SNicolas Bonnefon }
518fcaa7557SNicolas Bonnefon
519fcaa7557SNicolas Bonnefon int fd_;
520fcaa7557SNicolas Bonnefon };
521fcaa7557SNicolas Bonnefon
TEST_F(WatchTowerPolling,OpenFileDoesNotGenerateImmediateNotification)522fcaa7557SNicolas Bonnefon TEST_F( WatchTowerPolling, OpenFileDoesNotGenerateImmediateNotification ) {
523fcaa7557SNicolas Bonnefon appendDataToFileWoClosing();
524fcaa7557SNicolas Bonnefon ASSERT_FALSE( waitNotificationReceived() );
525fcaa7557SNicolas Bonnefon }
526fcaa7557SNicolas Bonnefon
TEST_F(WatchTowerPolling,OpenFileYieldsAPollNotification)527fcaa7557SNicolas Bonnefon TEST_F( WatchTowerPolling, OpenFileYieldsAPollNotification ) {
528fcaa7557SNicolas Bonnefon std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
529fcaa7557SNicolas Bonnefon watch_tower->setPollingInterval( 500 );
530fcaa7557SNicolas Bonnefon appendDataToFileWoClosing();
531fcaa7557SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
532fcaa7557SNicolas Bonnefon }
533fcaa7557SNicolas Bonnefon
TEST_F(WatchTowerPolling,UnchangedFileDoesNotYieldANotification)534fcaa7557SNicolas Bonnefon TEST_F( WatchTowerPolling, UnchangedFileDoesNotYieldANotification ) {
535fcaa7557SNicolas Bonnefon watch_tower->setPollingInterval( 500 );
536fcaa7557SNicolas Bonnefon ASSERT_FALSE( waitNotificationReceived() );
537fcaa7557SNicolas Bonnefon }
538fcaa7557SNicolas Bonnefon
TEST_F(WatchTowerPolling,FileYieldsAnImmediateNotification)539fcaa7557SNicolas Bonnefon TEST_F( WatchTowerPolling, FileYieldsAnImmediateNotification ) {
540fcaa7557SNicolas Bonnefon watch_tower->setPollingInterval( 4000 );
541fcaa7557SNicolas Bonnefon appendDataToFile( file_name );
542fcaa7557SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived( 1, 2000 ) );
543fcaa7557SNicolas Bonnefon }
544fcaa7557SNicolas Bonnefon
TEST_F(WatchTowerPolling,PollIsDelayedIfImmediateNotification)545fcaa7557SNicolas Bonnefon TEST_F( WatchTowerPolling, PollIsDelayedIfImmediateNotification ) {
546fcaa7557SNicolas Bonnefon watch_tower->setPollingInterval( 500 );
547fcaa7557SNicolas Bonnefon appendDataToFile( file_name );
548fcaa7557SNicolas Bonnefon waitNotificationReceived();
549fcaa7557SNicolas Bonnefon appendDataToFileWoClosing();
550fcaa7557SNicolas Bonnefon std::this_thread::sleep_for( std::chrono::milliseconds( 400 ) );
551fcaa7557SNicolas Bonnefon ASSERT_FALSE( waitNotificationReceived( 1, 250 ) );
552fcaa7557SNicolas Bonnefon ASSERT_TRUE( waitNotificationReceived() );
553fcaa7557SNicolas Bonnefon }
554fcaa7557SNicolas Bonnefon
555fcaa7557SNicolas Bonnefon #endif
556