function testMatch() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($dir->getPath()); touch("{$root}/foo.c"); touch("{$root}/bar.txt"); mkdir("{$root}/foo"); touch("{$root}/foo/.bar.c"); touch("{$root}/foo/baz.c"); $this->watch($root); $this->assertFileList($root, array('bar.txt', 'foo.c', 'foo', 'foo/.bar.c', 'foo/baz.c')); $res = $this->watchmanCommand('query', $root, array('expression' => array('match', '*.c'), 'fields' => array('name'))); sort($res['files']); $this->assertEqual(array('foo.c', 'foo/baz.c'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('match', '*.c', 'wholename'), 'fields' => array('name'))); sort($res['files']); $this->assertEqual(array('foo.c'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('match', 'foo/*.c', 'wholename'), 'fields' => array('name'))); sort($res['files']); $this->assertEqual(array('foo/baz.c'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('match', '**/*.c', 'wholename'), 'fields' => array('name'))); sort($res['files']); $this->assertEqual(array('foo.c', 'foo/baz.c'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('match', '**/*.c', 'wholename', array('includedotfiles' => true)), 'fields' => array('name'))); sort($res['files']); $this->assertEqual(array('foo.c', 'foo/.bar.c', 'foo/baz.c'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('match', 'foo/**/*.c', 'wholename'), 'fields' => array('name'))); sort($res['files']); $this->assertEqual(array('foo/baz.c'), $res['files']); }
function testEmpty() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 testMoveReAdd() { if (PHP_OS == 'Linux' && getenv('TRAVIS')) { $this->assertSkipped('openvz and inotify unlinks == bad time'); } $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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') { // 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 runProjectTests($tests, $touch_watchmanconfig = false) { foreach ($tests as $info) { list($touch, $expected_watch, $expect_rel, $expected_pass) = $info; $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($dir->getPath()); mkdir("{$root}/a/b/c", 0777, true); touch("{$root}/{$touch}"); if ($touch_watchmanconfig) { touch("{$root}/.watchmanconfig"); } $res = $this->watchProject("{$root}/a/b/c"); $err = idx($res, 'error'); // Dump some info to make it easier to diagnose failures $label = json_encode($info) . " res=" . json_encode($res); if ($expected_watch === null) { $full_watch = $root; } else { $full_watch = "{$root}/{$expected_watch}"; } if ($expected_pass) { if ($err) { $this->assertFailure("failed to watch-project: {$err}"); } $this->assertEqual($full_watch, idx($res, 'watch'), $label); $this->assertEqual($expect_rel, idx($res, 'relative_path'), $label); } else { if ($err) { $this->assertEqual("resolve_projpath: none of the files listed in global config " . "root_files are present in path `{$root}/a/b/c` or any " . "of its parent directories", $err, $label); } else { $this->assertFailure("didn't expect watch-project success {$label}"); } } } }
function testRemove() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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'); Filesystem::remove("{$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')); 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 testTwoDeep() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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'); execx('rm -rf %s', "{$root}/foo/bar"); $this->assertFileList($root, array("foo")); }
function testFind() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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}/adir", "{$root}/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 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 = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 testFishy() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($dir->getPath()); mkdir("{$root}/foo"); touch("{$root}/foo/a"); $watch = $this->watch($root); $base = $this->watchmanCommand('find', $root, '.'); // This is "c:PID:1" because nothing has changed in $root yet $clock = $base['clock']; $this->startLogging('debug'); $this->watchmanCommand('log', 'debug', 'testFishy:START'); $this->suspendWatchman(); system("cd {$root}; " . "mv foo bar; " . "ln -s bar foo"); $this->resumeWatchman(); $this->assertFileListUsingSince($root, $clock, array('bar', 'bar/a', 'foo')); $this->watchmanCommand('log', 'debug', 'testFishy:END'); $this->assertWaitForLog('/testFishy:END/'); $this->stopLogging(); $on = false; $log = array(); foreach ($this->watchman_instance->getLogData() as $item) { if (preg_match('/testFishy:START/', $item)) { $on = true; } else { if (preg_match('/testFishy:END/', $item)) { break; } } if ($on && preg_match('/fishy/', $item)) { $log[] = $item; } } $this->assertEqual(array(), $log, 'nothing fishy'); }
function testFields() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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', 'ino', 'dev', 'nlink'); 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 testWatchDelAll() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $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']; sort($watched); $this->assertEqual($dirs, $watched); $resp = $this->watchmanCommand('watch-del-all'); $watched = $resp['roots']; sort($watched); $this->assertEqual($dirs, $watched); $resp = $this->watchmanCommand('watch-list'); $this->assertEqual(0, count($resp['roots'])); }
function testDirName() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $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']; sort($files); $this->assertEqual($expect, $files, $label); } }
function testInvalidRoot() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($dir->getPath()); $res = $this->watch("{$root}/invalid", false); $this->assertEqual("unable to resolve root {$root}/invalid: " . "realpath({$root}/invalid) -> No such file or directory", $res['error']); }
function testClock() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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->assertEqual(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 testGetConfig() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 testInvalidSyncTimeout() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 testJsonNameAndSize() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $log = $dir->getPath() . "log"; $root = realpath($dir->getPath()) . "/dir"; mkdir($root); $this->watch($root); $this->trigger($root, array('name' => 'cat', 'command' => array('cat'), 'expression' => array('suffix', 'txt'), 'stdin' => array('name', 'size'), 'stdout' => ">{$log}")); touch("{$root}/A.txt"); $this->assertFileContents($log, '[{"name": "A.txt", "size": 0}]' . "\n"); }
function testIllegal() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 = PhutilDirectoryFixture::newEmptyFixture(); $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('a/b/c', idx($res, 'relative_path'), 'should re-use other watch'); }
function testSuffixExpr() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 testEvenMoreMoves() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 testDot() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($dir->getPath()); $this->assertEqual(true, chdir($root), "failed to chdir {$root}"); $this->assertEqual($root, getcwd(), "chdir/getcwd are consistent"); $is_cli = $this->isUsingCLI(); $res = $this->watch('.', false); if (!$this->isUsingCLI()) { $this->assertEqual('unable to resolve root .: path "." must be absolute', idx($res, 'error')); } else { $this->assertEqual($root, idx($res, 'watch')); } chdir($this->getRoot()); }
function testOtherCookies() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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 testGeneratorExpr() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($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'))); sort($res['files']); $this->assertEqual(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->assertEqual(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 testPathGeneratorRelativeRoot() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $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 testSinceExpr() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($dir->getPath()); touch("{$root}/foo.c"); mkdir("{$root}/subdir"); touch("{$root}/subdir/bar.txt"); $this->watch($root); $this->assertFileList($root, array('foo.c', 'subdir', 'subdir/bar.txt')); $foo_data = $this->watchmanCommand('find', $root, 'foo.c'); $first_clock = $foo_data['clock']; $foo_data = $foo_data['files'][0]; $base = $foo_data['mtime']; // since is GT, not GTE $res = $this->watchmanCommand('query', $root, array('expression' => array('since', $base, 'mtime'), 'fields' => array('name'))); $this->assertEqual(array(), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('allof', array('since', $base - 1, 'mtime'), array('name', 'foo.c')), 'fields' => array('name'))); $this->assertEqual(array('foo.c'), $res['files']); if ($this->isCaseInsensitive()) { $res = $this->watchmanCommand('query', $root, array('expression' => array('allof', array('since', $base - 1, 'mtime'), array('name', 'FOO.C')), 'fields' => array('name'))); $this->assertEqual(array('foo.c'), $res['files']); } // try with a clock $res = $this->watchmanCommand('query', $root, array('expression' => array('since', $first_clock), 'fields' => array('name'))); $this->assertEqual(array(), $res['files']); $target = $base + 15; touch("{$root}/foo.c", $target); $foo_data = $this->watchmanCommand('find', $root, 'foo.c'); $foo_data = $foo_data['files'][0]; // try again with a clock $res = $this->watchmanCommand('query', $root, array('expression' => array('since', $first_clock), 'fields' => array('name'))); $this->assertEqual(array('foo.c'), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('since', $foo_data['ctime'], 'ctime'), 'fields' => array('name'))); $this->assertEqual(array(), $res['files']); $res = $this->watchmanCommand('query', $root, array('expression' => array('allof', array('since', $base, 'mtime'), array('name', 'foo.c')), 'fields' => array('name'))); $this->assertEqual(array('foo.c'), $res['files']); // try with a fresh clock instance -- make sure that this only returns // files that exist unlink("{$root}/subdir/bar.txt"); $res = $this->watchmanCommand('query', $root, array('expression' => array('since', 'c:1:1'), 'fields' => array('name'))); $files = $res['files']; sort($files); $this->assertEqual(array('foo.c', 'subdir'), $files); }
function testModify() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($dir->getPath()); mkdir("{$root}/foo"); touch("{$root}/foo/111"); $watch = $this->watch($root); $this->watchmanCommand('subscribe', $root, 'test', array('fields' => array('name'), 'expression' => array('type', 'f'))); $this->waitForSub('test', function ($data) { return true; }); $this->getSubData('test'); $this->watchmanCommand('log', 'error', 'XXX: touch foo/111'); touch("{$root}/foo/111"); $this->waitForSub('test', function ($data) { return true; }); list($sub) = $this->getSubData('test'); $this->assertEqual(array("foo/111"), $sub['files']); $this->watchmanCommand('unsubscribe', $root, 'test'); }
function testIgnoreGeneric() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($dir->getPath()); $cfg = array('ignore_dirs' => array('build')); file_put_contents("{$root}/.watchmanconfig", json_encode($cfg)); mkdir("{$root}/build"); mkdir("{$root}/build/lower"); mkdir("{$root}/builda"); touch("{$root}/foo"); touch("{$root}/build/bar"); touch("{$root}/buildfile"); touch("{$root}/build/lower/baz"); touch("{$root}/builda/hello"); $this->watch($root); $this->assertFileList($root, array('.watchmanconfig', 'builda', 'builda/hello', 'buildfile', 'foo')); touch("{$root}/build/lower/dontlookatme"); touch("{$root}/build/orme"); touch("{$root}/buil"); $this->assertFileList($root, array('.watchmanconfig', 'buil', 'builda', 'builda/hello', 'buildfile', 'foo')); }
function testChangeCase() { $dir = PhutilDirectoryFixture::newEmptyFixture(); $root = realpath($dir->getPath()); mkdir("{$root}/foo"); $watch = $this->watch($root); $this->assertFileList($root, array('foo')); rename("{$root}/foo", "{$root}/FOO"); $this->assertFileList($root, array('FOO')); touch("{$root}/FOO/bar"); $this->assertFileList($root, array('FOO', 'FOO/bar')); rename("{$root}/FOO/bar", "{$root}/FOO/BAR"); $this->assertFileList($root, array('FOO', 'FOO/BAR')); rename("{$root}/FOO", "{$root}/foo"); $this->assertFileList($root, array('foo', 'foo/BAR')); mkdir("{$root}/foo/baz"); touch("{$root}/foo/baz/file"); $this->assertFileList($root, array('foo', 'foo/BAR', 'foo/baz', 'foo/baz/file')); rename("{$root}/foo", "{$root}/Foo"); $this->assertFileList($root, array('Foo', 'Foo/BAR', 'Foo/baz', 'Foo/baz/file')); }