function testChdirRelativeRoot() { $dir = new WatchmanDirectoryFixture(); $log = $dir->getPath() . "log"; $env = $dir->getPath() . "env"; $root = realpath($dir->getPath()) . "/dir"; mkdir($root); mkdir("{$root}/sub1"); mkdir("{$root}/sub1/sub2"); $this->watch($root); $this->trigger($root, array('name' => 'cap', 'command' => array(PHP_BINARY, '-d variables_order=EGPCS', '-d register_argc_argv=1', dirname(__FILE__) . DIRECTORY_SEPARATOR . '_capture.php', $log, $env), 'expression' => array('suffix', 'txt'), 'stdin' => array('name'), 'relative_root' => 'sub1', 'chdir' => 'sub2')); touch("{$root}/sub1/A.txt"); $obj = $this->waitForJsonInput($log); $this->assertEqual(1, count($obj)); $root_pat = preg_quote(w_normalize_filename($root) . DIRECTORY_SEPARATOR . 'sub1' . DIRECTORY_SEPARATOR . 'sub2'); $this->waitFor(function () use($env, $root, $root_pat) { $envdata = @file_get_contents($env); $root = preg_quote($root); return preg_match(",PWD={$root_pat},i", $envdata) == 1; }, 10, function () use($env, $root, $root_pat) { $envdata = @file_get_contents($env); return "{$envdata}\nwaiting for PWD to show in {$env} log file " . "(pat: {$root_pat})"; }); $envdata = file_get_contents($env); $sub1_pat = preg_quote(w_normalize_filename("{$root}/sub1")); $root_pat = preg_quote(w_normalize_filename($root)); $this->assertRegex(",PWD={$root_pat},i", $envdata); $this->assertRegex("/WATCHMAN_EMPTY_ENV_VAR=\$/m", $envdata); $this->assertRegex(",^WATCHMAN_ROOT={$root_pat}\$,mi", $envdata); $this->assertRegex(",^WATCHMAN_RELATIVE_ROOT={$sub1_pat}\$,mi", $envdata); }
function testJsonNameAndSize() { $dir = new WatchmanDirectoryFixture(); $log = $dir->getPath("log"); $root = $dir->getPath("dir"); mkdir($root); $this->watch($root); $this->trigger($root, array('name' => 'cat', 'command' => $this->catCommand(), 'expression' => array('suffix', 'txt'), 'stdin' => array('name', 'size'), 'stdout' => ">{$log}")); touch("{$root}/A.txt"); $this->assertFileContents($log, '[{"name": "A.txt", "size": 0}]' . "\n"); }
function testMoveReAdd() { if (PHP_OS == 'Linux' && getenv('TRAVIS')) { $this->assertSkipped('openvz and inotify unlinks == bad time'); } $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); mkdir("{$root}/foo"); $watch = $this->watch($root); $this->assertFileListUsingSince($root, 'n:foo', array('foo'), array('foo')); $this->watchmanCommand('log', 'debug', 'XXX: touch foo/222'); touch("{$root}/foo/222"); $this->assertFileListUsingSince($root, 'n:foo', array('foo', 'foo/222'), array('foo/222')); $this->watchmanCommand('log', 'debug', 'XXX: mkdir foo/bar'); mkdir("{$root}/foo/bar"); $since = array('foo/bar'); if (in_array($watch['watcher'], array('win32', 'portfs', 'kqueue'))) { // the parent dir reflects as changed when we mkdir within it array_unshift($since, 'foo'); } $this->assertFileListUsingSince($root, 'n:foo', array('foo', 'foo/222', 'foo/bar'), $since); $this->watchmanCommand('log', 'debug', 'XXX: rmdir foo/bar'); w_rmdir_recursive("{$root}/foo/bar"); $this->watchmanCommand('log', 'debug', 'XXX: unlink foo/222'); unlink("{$root}/foo/222"); $this->watchmanCommand('log', 'debug', 'XXX: rmdir foo'); w_rmdir_recursive("{$root}/foo"); $this->assertFileListUsingSince($root, 'n:foo', array(), array()); $this->watchmanCommand('log', 'debug', 'XXX: mkdir foo'); mkdir("{$root}/foo"); $this->watchmanCommand('log', 'debug', 'XXX: touch foo/222'); touch("{$root}/foo/222"); $this->assertFileListUsingSince($root, 'n:foo', array("foo", "foo/222"), array("foo", "foo/222")); }
function testFields() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $watch = $this->watch($root); $this->assertFileList($root, array()); $this->watchmanCommand('log', 'debug', 'XXX: touch a'); touch("{$root}/a"); $this->assertFileList($root, array('a')); $query = $this->watchmanCommand('query', $root, array('fields' => array('name', 'exists', 'new', 'size', 'mode', 'uid', 'gid', 'mtime', 'mtime_ms', 'mtime_us', 'mtime_ns', 'mtime_f', 'ctime', 'ctime_ms', 'ctime_us', 'ctime_ns', 'ctime_f', 'ino', 'dev', 'nlink', 'oclock', 'cclock'), 'since' => 'n:foo')); $this->assertEqual(null, idx($query, 'error')); $this->assertEqual(1, count($query['files'])); $file = $query['files'][0]; $this->assertEqual('a', $file['name']); $this->assertEqual(true, $file['exists']); $this->assertEqual(true, $file['new']); $stat = stat("{$root}/a"); $compare_fields = array('size', 'mode', 'uid', 'gid', 'nlink'); if (!phutil_is_windows()) { // These are meaningless in msvcrt, so no sense in comparing them $compare_fields[] = 'dev'; $compare_fields[] = 'ino'; } foreach ($compare_fields as $field) { $this->assertEqual($stat[$field], $file[$field], $field); } $time_fields = array('mtime', 'ctime'); foreach ($time_fields as $field) { $this->assertTimeEqual($stat[$field], $file[$field], $file[$field . '_ms'], $file[$field . '_us'], $file[$field . '_ns'], $file[$field . '_f']); } $this->assertRegex('/^c:\\d+:\\d+:\\d+:\\d+$/', $file['cclock'], "cclock looks clocky"); $this->assertRegex('/^c:\\d+:\\d+:\\d+:\\d+$/', $file['oclock'], "oclock looks clocky"); }
function testDirName() { $dir = new WatchmanDirectoryFixture(); $root = realpath($dir->getPath()); for ($i = 0; $i < 5; $i++) { mkdir("{$root}/{$i}/{$i}/{$i}/{$i}/{$i}", 0777, true); touch("{$root}/a"); touch("{$root}/{$i}/a"); touch("{$root}/{$i}a"); touch("{$root}/{$i}/{$i}/a"); touch("{$root}/{$i}/{$i}/{$i}/a"); touch("{$root}/{$i}/{$i}/{$i}/{$i}/a"); touch("{$root}/{$i}/{$i}/{$i}/{$i}/{$i}/a"); } $this->watch($root); $tests = array(array('', null, array('0/0/0/0/0/a', '0/0/0/0/a', '0/0/0/a', '0/0/a', '0/a', '1/1/1/1/1/a', '1/1/1/1/a', '1/1/1/a', '1/1/a', '1/a', '2/2/2/2/2/a', '2/2/2/2/a', '2/2/2/a', '2/2/a', '2/a', '3/3/3/3/3/a', '3/3/3/3/a', '3/3/3/a', '3/3/a', '3/a', '4/4/4/4/4/a', '4/4/4/4/a', '4/4/4/a', '4/4/a', '4/a', 'a')), array('', 4, array('0/0/0/0/0/a', '1/1/1/1/1/a', '2/2/2/2/2/a', '3/3/3/3/3/a', '4/4/4/4/4/a')), array('', 3, array('0/0/0/0/0/a', '0/0/0/0/a', '1/1/1/1/1/a', '1/1/1/1/a', '2/2/2/2/2/a', '2/2/2/2/a', '3/3/3/3/3/a', '3/3/3/3/a', '4/4/4/4/4/a', '4/4/4/4/a')), array('0', null, array('0/0/0/0/0/a', '0/0/0/0/a', '0/0/0/a', '0/0/a', '0/a')), array('1', null, array('1/1/1/1/1/a', '1/1/1/1/a', '1/1/1/a', '1/1/a', '1/a')), array('1', 0, array('1/1/1/1/1/a', '1/1/1/1/a', '1/1/1/a', '1/1/a')), array('1', 1, array('1/1/1/1/1/a', '1/1/1/1/a', '1/1/1/a')), array('1', 2, array('1/1/1/1/1/a', '1/1/1/1/a')), array('1', 3, array('1/1/1/1/1/a')), array('1', 4, array())); foreach ($tests as $tdata) { list($dirname, $depth, $expect) = $tdata; if ($depth === null) { $term = array('dirname', $dirname); // Equivalent to depth ge 0 } else { $term = array('dirname', $dirname, array('depth', 'gt', $depth)); } $label = json_encode(array('tdata' => $tdata, 'term' => $term)); $results = $this->watchmanCommand('query', $root, array('expression' => array('allof', $term, array('name', 'a')), 'fields' => array('name'))); if (isset($results['error'])) { $this->assertFailure($results['error'] . ' ' . $label); } $files = $results['files']; $this->assertEqualFileList($expect, $files, $label); } }
function testDot() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); try { $this->assertEqual(true, chdir($root), "failed to chdir {$root}"); $this->assertEqual($root, getcwd(), "chdir/getcwd are consistent"); $is_cli = $this->isUsingCLI(); if (phutil_is_windows()) { $dot = ''; $err = 'unable to resolve root : path "" must be absolute'; } else { $dot = '.'; $err = 'unable to resolve root .: path "." must be absolute'; } $res = $this->watch($dot, false); if (!$this->isUsingCLI()) { $this->assertEqual($err, idx($res, 'error')); } else { $this->assertEqual(null, idx($res, 'error')); $this->assertEqual($root, idx($res, 'watch')); } } catch (Exception $e) { chdir($this->getRoot()); throw $e; } }
function testWatchDelAll() { $dir = new WatchmanDirectoryFixture(); $root = realpath($dir->getPath()); $files = array('a', 'b', 'c', 'd', 'e'); $dirs = array_map(function ($file) use($root) { return "{$root}/{$file}"; }, $files); foreach ($dirs as $d) { mkdir($d); foreach ($files as $f) { touch("{$d}/{$f}"); } $this->watch($d); $this->assertFileList($d, $files); } $resp = $this->watchmanCommand('watch-list'); $watched = $resp['roots']; $this->assertEqualFileList($dirs, $watched); $resp = $this->watchmanCommand('watch-del-all'); $watched = $resp['roots']; $this->assertEqualFileList($dirs, $watched); $resp = $this->watchmanCommand('watch-list'); $this->assertEqual(0, count($resp['roots'])); }
function testFind() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); touch("{$root}/foo.c"); touch("{$root}/bar.txt"); $out = $this->watch($root); $this->assertEqual($root, $out['watch']); $this->assertFileList($root, array('bar.txt', 'foo.c')); // Make sure we correctly observe deletions $this->assertEqual(true, unlink("{$root}/bar.txt")); $this->assertFileList($root, array('foo.c')); // touch -> delete -> touch, should show up as exists $this->assertEqual(true, touch("{$root}/bar.txt")); $this->assertFileList($root, array('bar.txt', 'foo.c')); $this->assertEqual(true, unlink("{$root}/bar.txt")); // A moderately more complex set of changes $this->assertEqual(true, mkdir("{$root}/adir")); $this->assertEqual(true, mkdir("{$root}/adir/subdir")); $this->assertEqual(true, touch("{$root}/adir/subdir/file")); $this->assertEqual(true, rename("{$root}/adir/subdir", "{$root}/adir/overhere")); $this->assertFileList($root, array('adir', 'adir/overhere', 'adir/overhere/file', 'foo.c')); $this->assertEqual(true, rename($root . DIRECTORY_SEPARATOR . 'adir', $root . DIRECTORY_SEPARATOR . 'bdir')); $this->assertFileList($root, array('bdir', 'bdir/overhere', 'bdir/overhere/file', 'foo.c')); $list = $this->watchmanCommand('watch-list'); $this->assertEqual(true, in_array($root, $list['roots'])); $del = $this->watchmanCommand('watch-del', $root); $watches = $this->waitForWatchman(array('watch-list'), function ($list) use($root) { return !in_array($root, $list['roots']); }); $this->assertEqual(false, in_array($root, $watches['roots']), "watch deleted"); }
function testPCRE() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); touch("{$root}/foo.c"); touch("{$root}/bar.txt"); $this->watch($root); $this->assertFileList($root, array('bar.txt', 'foo.c')); $out = $this->watchmanCommand('find', $root, '-p', '.*c$'); if (idx($out, 'error', '') == "unknown expression term 'pcre'") { $this->assertSkipped('no PCRE support'); } $this->assertEqual('foo.c', $out['files'][0]['name']); $out = $this->watchmanCommand('find', $root, '-p', '.*txt$'); $this->assertEqual('bar.txt', $out['files'][0]['name']); // Cleanup for invalid pcre $out = $this->watchmanCommand('find', $root, '-p', '('); $this->assertRegex("/invalid i?pcre: code 14 missing \\) at offset 1 in \\(/", $out['error']); if ($this->isCaseInsensitive()) { // -p matches case sensitivity of filesystem $out = $this->watchmanCommand('find', $root, '-p', '.*C$'); $this->assertEqual('foo.c', $out['files'][0]['name']); } // Test case insensitive mode $out = $this->watchmanCommand('find', $root, '-P', '.*C$'); $this->assertEqual('foo.c', $out['files'][0]['name']); }
function testRemoveRoot() { if (PHP_OS == 'Linux' && getenv('TRAVIS')) { $this->assertSkipped('openvz and inotify unlinks == bad time'); } $dir = new WatchmanDirectoryFixture(); $top = $dir->getPath(); $root = $top . DIRECTORY_SEPARATOR . "root"; mkdir($root); touch("{$root}/hello"); $this->watch($root); $this->assertFileList($root, array('hello')); w_rmdir_recursive($root); $this->assertFileList($root, array()); $watches = $this->waitForWatchman(array('watch-list'), function ($list) use($root) { return !in_array($root, $list['roots']); }); $this->assertEqual(false, in_array($root, $watches['roots']), "watch deleted"); // Really need to ensure that we mkdir, otherwise the $dir fixture // will throw when the scope unwinds $this->waitFor(function () use($root) { return @mkdir($root); }, 10, "mkdir({$root}) to succeed"); touch("{$root}/hello"); $this->assertFileList($root, array()); }
function testEmpty() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); touch("{$root}/empty"); file_put_contents("{$root}/notempty", "foo"); $this->watch($root); $results = $this->watchmanCommand('query', $root, array('expression' => 'empty')); $this->assertEqual('empty', $results['files'][0]['name']); $results = $this->watchmanCommand('query', $root, array('expression' => 'exists')); $exists = array(); foreach ($results['files'] as $file) { $exists[] = $file['name']; } sort($exists); $this->assertEqual(array('empty', 'notempty'), $exists); $clock = $results['clock']; unlink("{$root}/empty"); // Wait for change to be observed $this->assertFileList($root, array('notempty')); $results = $this->watchmanCommand('query', $root, array('expression' => 'exists')); $this->assertEqual('notempty', $results['files'][0]['name']); // "files that don't exist" without a since term is absurd, so pass that in $results = $this->watchmanCommand('query', $root, array('since' => $clock, 'expression' => array('not', 'exists'))); $this->assertEqual('empty', $results['files'][0]['name']); }
function testRootRestrict() { $passes = array(array("directory", ".git"), array("directory", ".hg"), array("file", ".foo"), array("file", ".bar"), array("directory", ".bar")); $fails = array(NULL, array("directory", ".svn"), array("file", "baz")); foreach ($passes as $p) { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); if ($p[0] === "directory") { mkdir("{$root}/{$p['1']}"); } else { touch("{$root}/{$p['1']}"); } $res = $this->watch($root); // Make sure the watch actually happened touch("{$root}/f"); $this->assertFileList($root, array('f', $p[1])); } foreach ($fails as $f) { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); if ($f) { if ($f[0] === "directory") { mkdir("{$root}/{$f['1']}"); } else { touch("{$root}/{$f['1']}"); } } $res = $this->watch($root, false); $this->assertEqual("unable to resolve root {$root}: none of the files " . "listed in global config root_files are " . "present and enforce_root_files is set to true", $res['error']); } }
function testInvalidRoot() { $dir = new WatchmanDirectoryFixture(); $invalid = $dir->getPath('invalid'); $res = $this->watch("{$invalid}", false); $this->assertEqual("unable to resolve root {$invalid}: " . "realpath({$invalid}) -> No such file or directory", $res['error']); }
function testTwoDeep() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $watch = $this->watch($root); $this->assertFileList($root, array()); $this->assertEqual(true, mkdir("{$root}/foo")); $this->assertEqual(true, mkdir("{$root}/foo/bar")); // Guarantee that 111's mtime is greater than its directory's sleep(1); $this->assertEqual(3, file_put_contents("{$root}/foo/bar/111", "111")); $this->watchmanCommand('log', 'debug', 'XXX: created 111'); $this->assertFileList($root, array("foo", "foo/bar", "foo/bar/111")); $query = $this->watchmanCommand('find', $root, 'foo/bar/111'); $wfile = $query['files'][0]; clearstatcache(); $sfile = stat("{$root}/foo/bar/111"); $query = $this->watchmanCommand('find', $root, 'foo/bar'); $wdir = $query['files'][0]; clearstatcache(); $sdir = stat("{$root}/foo/bar"); $this->watchmanCommand('log', 'debug', 'XXX: perform assertions'); $compare_fields = array('size', 'mode', 'uid', 'gid', 'ino', 'dev', 'nlink', 'mtime', 'ctime'); foreach ($compare_fields as $field) { $this->assertEqual($sfile[$field], $wfile[$field], "file: {$field} {$sfile[$field]} vs watchman {$wfile[$field]}"); $this->assertEqual($sdir[$field], $wdir[$field], "dir: {$field} {$sdir[$field]} vs watchman {$wdir[$field]}"); } $this->watchmanCommand('log', 'debug', 'XXX: remove it all'); w_rmdir_recursive("{$root}/foo/bar"); $this->assertFileList($root, array("foo")); }
function testMoveReAdd() { if (PHP_OS == 'Linux' && getenv('TRAVIS')) { $this->assertSkipped('openvz and inotify unlinks == bad time'); } $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); mkdir("{$root}/foo"); $watch = $this->watch($root); $this->assertFileListUsingSince($root, 'n:foo', array('foo'), array('foo')); $this->watchmanCommand('log', 'debug', 'XXX: touch foo/222'); touch("{$root}/foo/222"); $this->assertFileListUsingSince($root, 'n:foo', array('foo', 'foo/222'), array('foo/222')); $this->watchmanCommand('log', 'debug', 'XXX: mkdir foo/bar'); mkdir("{$root}/foo/bar"); $since = array('foo/bar'); if (PHP_OS == 'SunOS' || phutil_is_windows()) { // This makes me sad, but Solaris reports the parent dir // as changed when we mkdir within it array_unshift($since, 'foo'); } $this->assertFileListUsingSince($root, 'n:foo', array('foo', 'foo/222', 'foo/bar'), $since); $this->watchmanCommand('log', 'debug', 'XXX: rmdir foo/bar'); rmdir("{$root}/foo/bar"); $this->watchmanCommand('log', 'debug', 'XXX: unlink foo/222'); unlink("{$root}/foo/222"); $this->watchmanCommand('log', 'debug', 'XXX: rmdir foo'); rmdir("{$root}/foo"); $this->assertFileListUsingSince($root, 'n:foo', array(), array()); $this->watchmanCommand('log', 'debug', 'XXX: mkdir foo'); mkdir("{$root}/foo"); $this->watchmanCommand('log', 'debug', 'XXX: touch foo/222'); touch("{$root}/foo/222"); $this->assertFileListUsingSince($root, 'n:foo', array("foo", "foo/222"), array("foo", "foo/222")); }
function testClock() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $watch = $this->watch($root); $clock = $this->watchmanCommand('clock', $root); $this->assertRegex('/^c:\\d+:\\d+:\\d+:\\d+$/', $clock['clock'], "looks clocky"); }
function testAge1() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); mkdir("{$root}/a"); touch("{$root}/a/file.txt"); touch("{$root}/b.txt"); $this->watch($root); $this->assertFileList($root, array('a', 'a/file.txt', 'b.txt')); $res = $this->watchmanCommand('query', $root, array('fields' => array('name', 'exists'))); $this->assertEqual(true, $res['is_fresh_instance']); $clock = $res['clock']; // Removing file nodes also impacts the suffix list, so we test // that it is operating as intended in here too $res = $this->watchmanCommand('query', $root, array('expression' => array('suffix', 'txt'), 'fields' => array('name'))); $this->assertEqualFileList(array('a/file.txt', 'b.txt'), $res['files']); // Let's track a named cursor; we need to validate that it is // correctly aged out $this->watchmanCommand('since', $root, 'n:foo'); $cursors = $this->watchmanCommand('debug-show-cursors', $root); $this->assertTrue(array_key_exists('n:foo', $cursors['cursors'])); unlink("{$root}/a/file.txt"); rmdir("{$root}/a"); $this->assertFileList($root, array('b.txt')); // Prune all deleted items $this->watchmanCommand('debug-ageout', $root, 0); // Wait for 'a' to age out and cause is_fresh_instance to be set $res = $this->waitForWatchman(array('query', $root, array('since' => $clock, 'fields' => array('name', 'exists'))), function ($list) { return idx($list, 'is_fresh_instance') === true; }); // Verify that the file list is what we expect $this->assertFileListUsingSince($root, $clock, array('b.txt')); // Our cursor should have been collected $cursors = $this->watchmanCommand('debug-show-cursors', $root); $this->assertFalse(array_key_exists('n:foo', $cursors['cursors'])); // Add a new file to the suffix list; this will insert at the head touch("{$root}/c.txt"); // suffix query to verify that linkage is safe $res = $this->watchmanCommand('query', $root, array('expression' => array('suffix', 'txt'), 'fields' => array('name'))); sort($res['files']); $this->assertEqual(array('b.txt', 'c.txt'), $res['files']); for ($attempts = 0; $attempts < 3; $attempts++) { // Let's stress it a bit mkdir("{$root}/dir"); for ($i = 0; $i < 100; $i++) { touch("{$root}/stress-{$i}"); touch("{$root}/dir/{$i}"); } for ($i = 0; $i < 100; $i++) { unlink("{$root}/stress-{$i}"); unlink("{$root}/dir/{$i}"); } rmdir("{$root}/dir"); $this->assertFileList($root, array('b.txt', 'c.txt')); $this->watchmanCommand('debug-ageout', $root, 0); $this->assertFileList($root, array('b.txt', 'c.txt')); } }
function testInvalidSyncTimeout() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $this->watch($root); $results = $this->watchmanCommand('query', $root, array('expression' => array('exists'), 'sync_timeout' => -1)); $this->assertEqual("failed to parse query: sync_timeout must be an integer value >= 0", $results['error']); $results = $this->watchmanCommand('query', $root, array('expression' => array('exists'), 'sync_timeout' => 200)); $this->assertEqual(array(), $results['files'], "parsed sync_timeout"); }
function testGetConfig() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $cfg = array('test-key' => 'test-value'); file_put_contents("{$root}/.watchmanconfig", json_encode($cfg)); $this->watch($root); $res = $this->watchmanCommand('get-config', $root); $this->assertEqual($cfg, $res['config']); }
function testClockSync() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $watch = $this->watch($root); $clock1 = $this->watchmanCommand('clock', $root, array('sync_timeout' => 100)); $this->assertRegex('/^c:\\d+:\\d+:\\d+:\\d+$/', $clock1['clock'], "looks clocky " . json_encode($clock1)); $clock2 = $this->watchmanCommand('clock', $root, array('sync_timeout' => 100)); $this->assertRegex('/^c:\\d+:\\d+:\\d+:\\d+$/', $clock2['clock'], "looks clocky"); $this->assertFalse($clock1 === $clock2); }
function testIllegal() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $res = $this->watch($root, false); if (idx($res, 'error')) { $this->assertRegex("/unable to resolve root .*: path uses the \".*\" filesystem " . "and is disallowed by global config illegal_fstypes: just cos/", $res['error']); } else { $this->assertEqual("Look in /tmp/watchman-test.log for a line matching " . "'is on filesystem type XXX', then add the XXX string to the list " . "of types in fstype.php", 'should not succeed in watching'); } }
function testReuseNestedWatch() { $dir = new WatchmanDirectoryFixture(); $root = realpath($dir->getPath()); mkdir("{$root}/a/b/c", 0777, true); touch("{$root}/a/b/c/.watchmanconfig"); $res = $this->watchProject($root); $this->assertEqual($root, idx($res, 'watch')); $res = $this->watchProject("{$root}/a/b/c"); $this->assertEqual($root, idx($res, 'watch'), 'watch other root'); $this->assertEqual(w_normalize_filename('a/b/c'), idx($res, 'relative_path'), 'should re-use other watch'); }
function testSuffixExpr() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); touch("{$root}/foo.c"); mkdir("{$root}/subdir"); touch("{$root}/subdir/bar.txt"); $this->watch($root); $res = $this->watchmanCommand('query', $root, array('expression' => array('suffix', 'c'), 'fields' => array('name'))); $this->assertEqual(array('foo.c'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => 'suffix', 'fields' => array('name'))); $this->assertEqual('failed to parse query: must use ["suffix", "suffixstring"]', $res['error']); }
function testMaxFiles() { $dir = new WatchmanDirectoryFixture(); $log = $dir->getPath('log'); $env = $dir->getPath('env'); $root = $dir->getPath('dir'); mkdir($root); file_put_contents("{$root}/.watchmanconfig", json_encode(array('settle' => 200))); $this->watch($root); $this->trigger($root, array('name' => 'cap', 'command' => array(PHP_BINARY, '-d variables_order=EGPCS', '-d register_argc_argv=1', dirname(__FILE__) . DIRECTORY_SEPARATOR . '_capture.php', $log, $env), 'expression' => array('suffix', 'txt'), 'stdin' => array('name'), 'max_files_stdin' => 2)); touch("{$root}/A.txt"); $obj = $this->waitForJsonInput($log); $this->assertEqual(1, count($obj)); $this->waitForNoThrow(function () use($env) { return file_exists($env) && filesize($env) > 0; }); $this->assertEqual(true, file_exists($env)); $data = file_get_contents($env); $this->assertEqual(true, strlen($data) > 0); $this->assertEqual(0, preg_match('/WATCHMAN_FILES_OVERFLOW/', $data), "WATCHMAN_FILES_OVERFLOW should not be in {$env}"); $observed = false; $deadline = time() + 5; while (time() < $deadline) { @unlink($log); @unlink($env); touch("{$root}/B.txt"); touch("{$root}/A.txt"); touch("{$root}/C.txt"); touch("{$root}/D.txt"); $obj = $this->waitForJsonInput($log); $this->assertEqual(2, count($obj)); $envdata = @file_get_contents($env); if (preg_match('/WATCHMAN_FILES_OVERFLOW/', $envdata)) { $observed = true; break; } } $this->assertTrue($observed, "Observed an overflow"); }
function testEvenMoreMoves() { if (phutil_is_windows()) { $this->assertSkipped("no unix userland on windows"); } $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $watch = $this->watch($root); $base = $this->watchmanCommand('find', $root, '.'); // This is "c:PID:1" because nothing has changed in $root yet $clock = $base['clock']; // TODO: this should work even if Watchman is suspended. Investigate failure // on Travis. system("cd {$root}; " . "mkdir d1 d2; " . "touch d1/a; " . "mkdir d3; " . "mv d1 d2 d3; " . "mv d3/* .; " . "mv d1 d2 d3; " . "mv d3/* .; " . "mv d1/a d2; "); $this->assertFileListUsingSince($root, $clock, array('d1', 'd2', 'd2/a', 'd3')); }
function testRemove() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); mkdir("{$root}/one"); touch("{$root}/one/onefile"); mkdir("{$root}/one/two"); touch("{$root}/one/two/twofile"); touch("{$root}/top"); $this->watch($root); $this->assertFileList($root, array('one', 'one/onefile', 'one/two', 'one/two/twofile', 'top')); $this->watchmanCommand('log', 'debug', 'XXX: remove dir one'); w_rmdir_recursive("{$root}/one"); $this->assertFileList($root, array('top')); $this->watchmanCommand('log', 'debug', 'XXX: touch file one'); touch("{$root}/one"); $this->assertFileList($root, array('one', 'top')); $this->watchmanCommand('log', 'debug', 'XXX: unlink file one'); unlink("{$root}/one"); $this->assertFileList($root, array('top')); if (phutil_is_windows()) { // This looks so fugly system("rd /s /q {$root}"); for ($i = 0; $i < 10; $i++) { if (!is_dir($root)) { break; } usleep(20000); } for ($i = 0; $i < 10; $i++) { if (@mkdir("{$root}")) { break; } usleep(20000); } @mkdir("{$root}/notme"); } else { system("rm -rf {$root} ; mkdir -p {$root}/notme"); } if (PHP_OS == 'Linux' && getenv('TRAVIS')) { $this->assertSkipped('openvz and inotify unlinks == bad time'); } $watches = $this->waitForWatchman(array('watch-list'), function ($list) use($root) { return !in_array($root, $list['roots']); }); $this->assertEqual(false, in_array($root, $watches['roots']), "watch deleted"); }
function testGeneratorExpr() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); touch("{$root}/foo.c"); mkdir("{$root}/subdir"); touch("{$root}/subdir/bar.txt"); $this->watch($root); $res = $this->watchmanCommand('query', $root, array('expression' => array('true'), 'fields' => array('name'), 'suffix' => 'c')); $this->assertEqual(array('foo.c'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('true'), 'fields' => array('name'), 'suffix' => array('c', 'txt'))); $this->assertEqualFileList(array('foo.c', 'subdir/bar.txt'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('true'), 'fields' => array('name'), 'suffix' => array('c', 'txt'), 'relative_root' => 'subdir')); $this->assertEqualFileList(array('bar.txt'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('true'), 'fields' => array('name'), 'suffix' => array('a' => 'b'))); $this->assertEqual('failed to parse query: \'suffix\' must be a ' . 'string or an array of strings', $res['error']); }
function testOtherCookies() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); mkdir("{$root}/.git"); $watch = $this->watch($root); $host = gethostname(); $pid = $this->watchman_instance->getProcessID(); $this->assertFileList($root, array('.git')); $this->assertEqual(true, mkdir("{$root}/foo")); // Same process, same watch $this->assertEqual(true, touch("{$root}/.git/.watchman-cookie-{$host}-{$pid}-100000")); $diff_cookies = array("foo/.watchman-cookie-{$host}-{$pid}-100000", ".watchman-cookie-{$host}-{$pid}-100000", ".git/.watchman-cookie-{$host}-1-100000", ".watchman-cookie-{$host}-1-100000", "foo/.watchman-cookie-{$host}-1-100000"); foreach ($diff_cookies as $cookie) { $this->assertEqual(true, touch("{$root}/{$cookie}")); } $this->assertFileList($root, array_merge(array('foo', '.git'), $diff_cookies)); }
function testPathGeneratorRelativeRoot() { $dir = new WatchmanDirectoryFixture(); $root = realpath($dir->getPath()); touch("{$root}/a"); mkdir("{$root}/foo"); touch("{$root}/foo/bar"); $this->watch($root); $results = $this->watchmanCommand('query', $root, array('relative_root' => 'foo', 'path' => array('bar'), 'fields' => array('name'))); $this->assertEqual(array('bar'), $results['files']); if ($this->isCaseInsensitive()) { rename("{$root}/foo", "{$root}/Foo"); $results = $this->watchmanCommand('query', $root, array('relative_root' => 'foo', 'path' => array('bar'), 'fields' => array('name'))); // Note: no matches. We don't currently support case insensitive matching // for relative_root $this->assertEqual(array(), $results['files']); } }
function testBigPCRE() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); touch("{$root}/foo.c"); touch("{$root}/bar.txt"); $this->watch($root); $fill = str_repeat('lemon\\.php', 3600); $pcre = '^(' . chunk_split($fill, 100, '|') . 'sss)'; $res = $this->watchmanCommand('query', $root, array('expression' => array('pcre', $pcre, 'wholename'), 'fields' => array('name'))); // Some libraries will happily parse this big pcre if (isset($res['error'])) { if ($res['error'] == "failed to parse query: unknown expression term 'pcre'") { $this->assertSkipped('no PCRE support'); } $possible = array('code 50 repeated subpattern is too long', 'code 20 regular expression is too large'); $matched = false; foreach ($possible as $frag) { if (preg_match("/^failed to parse query: invalid i?pcre: " . "{$frag} at offset \\d+/", $res['error'])) { $matched = true; } } $this->assertEqual(true, $matched, "got useful message: " . substr($res['error'], 0, 128)); } }