def test_scmHgRequestId(self) -> None: if not is_hg_installed(): self.skipTest("Hg not installed") self.skipIfNoHgRequestIdSupport() root = self.mkdtemp() # In this test, the repo does not necessarily need fsmonitor enabled, # since watchman calls HGREQUESTID=... hg status and that would also # have request_id logged without fsmonitor. env = os.environ.copy() env["HGPLAIN"] = "1" env["WATCHMAN_SOCK"] = (WatchmanInstance.getSharedInstance(). getSockPath().legacy_sockpath()) subprocess.call(["hg", "init"], env=env, cwd=root) subprocess.call( [ "hg", "commit", "-mempty", "-utest", "-d0 0", "--config=ui.allowemptycommit=1", ], env=env, cwd=root, ) commit_hash = subprocess.check_output(["hg", "log", "-r.", "-T{node}"], env=env, cwd=root).decode("utf-8") # Must watch the directory after it's an HG repo to perform scm-aware # queries. self.watchmanCommand("watch", root) request_id = "4c05a798ea1acc7c97b75e61fec5f640d90f8209" params = { "fields": ["name"], "request_id": request_id, "since": { "scm": { "mergebase-with": commit_hash } }, } self.watchmanCommand("query", root, params) blackbox_path = os.path.join(root, ".hg", "blackbox.log") def try_read_blackbox(): try: with open(blackbox_path) as f: return f.read() except IOError: return "" self.assertWaitFor( lambda: request_id in try_read_blackbox(), message="request_id passed to and logged by hg", )
def test_sock_name(self) -> None: resp = self.watchmanCommand("get-sockname") self.assertEqual( resp["sockname"], WatchmanInstance.getSharedInstance().getSockPath().legacy_sockpath( ), )
def test_cppclient(self) -> None: env = os.environ.copy() env["WATCHMAN_SOCK"] = (WatchmanInstance.getSharedInstance(). getSockPath().legacy_sockpath()) proc = subprocess.Popen( TEST_BINARY, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.tmpDir, ) (stdout, stderr) = proc.communicate() status = proc.poll() if status == -signal.SIGINT: Interrupt.setInterrupted() self.fail("Interrupted by SIGINT") return if status != 0: self.fail("Exit status %d\n%s\n%s\n" % (status, stdout.decode("utf-8"), stderr.decode("utf-8"))) return self.assertTrue(True, TEST_BINARY)
def runWatchTests(self, config, expect) -> None: with WatchmanInstance.Instance(config=config) as inst: inst.start() client = self.getClient(inst) for filetype, name, expect_pass in expect: for watch_type in ["watch", "watch-project"]: # encode the test criteria in the dirname so that we can # figure out which test scenario failed more easily d = self.mkdtemp(suffix="-%s-%s-%s-%s" % (filetype, name, expect_pass, watch_type)) if filetype == "directory": os.mkdir(os.path.join(d, name)) elif filetype == "file": self.touchRelative(d, name) assert_functions = { (True, "watch"): self.assertWatchSucceeds, (True, "watch-project"): self.assertWatchProjectSucceeds, (False, "watch"): self.assertWatchIsRestricted, (False, "watch-project"): self.assertWatchProjectIsRestricted, } assert_function = assert_functions[(expect_pass, watch_type)] assert_function(inst, client, d)
def test_failing_to_start_when_nice(self) -> None: inst = WatchmanInstance.Instance() stdout, stderr = inst.commandViaCLI(["version"], prefix=["nice"]) print("stdout", stdout.decode(errors="replace")) print("stderr", stderr.decode(errors="replace")) stderr = stderr.decode("ascii") self.assertEqual(b"", stdout) self.assertRegex(stderr, "refusing to start")
def _new_instance(self, config, expect_success: bool = True): if expect_success: start_timeout = 20 else: # If the instance is going to fail anyway then there's no point # waiting so long start_timeout = 5 return WatchmanInstance.InstanceWithStateDir( config=config, start_timeout=start_timeout)
def test_spawner(self) -> None: config = {"spawn_watchman_service": SITE_SPAWN} inst = WatchmanInstance.Instance(config=config) stdout, stderr = inst.commandViaCLI(["version"]) parsed = json.loads(stdout.decode("ascii")) self.assertTrue("version" in parsed) # Shut down that process, as we have no automatic way to deal with it inst.commandViaCLI(["--no-spawn", "--no-local", "shutdown-server"])
def runProjectTests(self, config, expect, touch_watchmanconfig: bool = False) -> None: with WatchmanInstance.Instance(config=config) as inst: inst.start() client = self.getClient(inst) for touch, expect_watch, expect_rel, expect_pass in expect: # encode the test criteria in the dirname so that we can # figure out which test scenario failed more easily suffix = "-%s-%s-%s-%s" % (touch, expect_watch, expect_rel, expect_pass) suffix = suffix.replace("/", "Z") d = self.mkdtemp(suffix=suffix) dir_to_watch = os.path.join(d, "a", "b", "c") os.makedirs(dir_to_watch, 0o777) dir_to_watch = norm_absolute_path(dir_to_watch) self.touchRelative(d, touch) if touch_watchmanconfig: make_empty_watchmanconfig(d) if expect_watch: expect_watch = os.path.join(d, expect_watch) else: expect_watch = d if expect_pass: res = client.query("watch-project", dir_to_watch) self.assertEqual( norm_absolute_path(os.path.join(d, expect_watch)), norm_absolute_path(res["watch"]), ) if not expect_rel: self.assertEqual(None, res.get("relative_path")) else: self.assertEqual( norm_relative_path(expect_rel), norm_relative_path(res.get("relative_path")), ) else: with self.assertRaises(pywatchman.WatchmanError) as ctx: client.query("watch-project", dir_to_watch) self.assertIn( ("None of the files listed in global config " + "root_files are present in path `" + dir_to_watch + "` or any of its parent directories. " + "root_files is defined by the"), str(ctx.exception), )
def test_bulkstat_off(self) -> None: config = {"_use_bulkstat": False} with WatchmanInstance.Instance(config=config) as inst: inst.start() self.getClient(inst, replace_cached=True) root = self.mkdtemp() # pyre-fixme[16]: `TestBulkStat` has no attribute `client`. self.client.query("watch", root) self.touchRelative(root, "foo") self.touchRelative(root, "bar") self.assertFileList(root, ["foo", "bar"])
def test_no_site_spawner(self) -> None: """With a site spawner configured to otherwise fail, pass `--no-site-spawner` and ensure that a failure didn't occur.""" config = {"spawn_watchman_service": SITE_SPAWN_FAIL} inst = WatchmanInstance.Instance(config=config) stdout, stderr = inst.commandViaCLI(["version", "--no-site-spawner"]) print(stdout, stderr.decode("ascii")) parsed = json.loads(stdout.decode("ascii")) self.assertTrue("version" in parsed) inst.commandViaCLI(["--no-spawn", "--no-local", "shutdown-server"])
def test_failingSpawner(self) -> None: config = {"spawn_watchman_service": SITE_SPAWN_FAIL} inst = WatchmanInstance.Instance(config=config) stdout, stderr = inst.commandViaCLI(["version"]) sys.stdout.buffer.write(b"stdout:\n") sys.stdout.buffer.write(stdout) sys.stdout.buffer.write(b"stderr:\n") sys.stdout.buffer.write(stderr) stderr = stderr.decode("ascii") self.assertEqual(b"", stdout) self.assertRegex(stderr, "failed to start\n") self.assertRegex(stderr, "site_spawn_fail.py: exited with status 1")
def test_shutdown_and_restart(self) -> None: def populate(repo: hgrepo.HgRepository) -> None: repo.write_file("hello", "hola\n") repo.commit("initial commit.") root = self.makeEdenMount(populate) inst = WatchmanInstance.Instance() _, stderr = inst.commandViaCLI(["watch", root]) self.assertEqual(stderr, b"") _, stderr = inst.commandViaCLI(["shutdown-server"]) self.assertEqual(stderr, b"") _, stderr = inst.commandViaCLI(["get-sockname"]) self.assertEqual(stderr, b"")
def is_hg_installed() -> bool: with open(os.devnull, "wb") as devnull: try: env = os.environ.copy() env["HGPLAIN"] = "1" env["WATCHMAN_SOCK"] = (WatchmanInstance.getSharedInstance(). getSockPath().legacy_sockpath()) exit_code = subprocess.call(["hg", "--version"], stdout=devnull, stderr=devnull, env=env) return exit_code == 0 except OSError as e: if e.errno == errno.ENOENT: return False raise
def test_failing_to_start_when_nice_foreground(self) -> None: inst = WatchmanInstance.Instance() stdout, stderr = inst.commandViaCLI(["--foreground", "version"], prefix=["nice"]) print("stdout", stdout) print("stderr", stderr) output = stderr.decode("ascii") try: output += inst.getServerLogContents() except IOError: # on macos, we may not have gotten as far # as creating the log file when the error # triggers, so we're fine with passing # on io errors here pass self.assertRegex(output, "refusing to start")
def runTest(self) -> None: env = os.environ.copy() env["WATCHMAN_SOCK"] = (WatchmanInstance.getSharedInstance(). getSockPath().legacy_sockpath()) env["TMPDIR"] = self.tempdir # build the node module with yarn node_dir = os.path.join(env["TMPDIR"], "fb-watchman") shutil.copytree(os.path.join(WATCHMAN_SRC_DIR, "node"), node_dir) install_args = [yarn_bin, "install"] if "YARN_OFFLINE" in env: install_args.append("--offline") bser_dir = os.path.join(node_dir, "bser") subprocess.check_call(install_args, cwd=bser_dir, env=env) env["TMP"] = env["TMPDIR"] env["TEMP"] = env["TMPDIR"] env["IN_PYTHON_HARNESS"] = "1" env["NODE_PATH"] = "%s:%s" % (node_dir, env["TMPDIR"]) proc = subprocess.Popen( # pyre-fixme[16]: `NodeTestCase` has no attribute `getCommandArgs`. self.getCommandArgs(), env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) (stdout, stderr) = proc.communicate() status = proc.poll() if status == -signal.SIGINT: Interrupt.setInterrupted() self.fail("Interrupted by SIGINT") return if status != 0: self.fail("Exit status %d\n%s\n%s\n" % (status, stdout.decode("utf-8"), stderr.decode("utf-8"))) return self.assertTrue(True, self.getCommandArgs())
def test_Illegal(self) -> None: config = { "illegal_fstypes": [ # This should include any/all fs types. If this test fails on # your platform, look in /tmp/watchman-test.log for a line like: # "path /var/tmp/a3osdzvzqnco0sok is on filesystem type zfs" # then add the type name to this list, in sorted order "NTFS", "apfs", "btrfs", "cifs", "ext2", "ext3", "ext4", "fuse", "hfs", "msdos", "nfs", "smb", "tmpfs", "ufs", "unknown", "xfs", "zfs", ], "illegal_fstypes_advice": "just cos", } with WatchmanInstance.Instance(config=config) as inst: inst.start() client = self.getClient(inst) d = self.mkdtemp() with self.assertRaises(pywatchman.WatchmanError) as ctx: client.query("watch", d) self.assertIn( ("filesystem and is disallowed by global config" + " illegal_fstypes: just cos"), str(ctx.exception), )
def skipIfNoHgRequestIdSupport(self) -> None: root = self.mkdtemp() request_id = "bf8a47014bd1b66103a8ab0aece4be7ada871660" env = os.environ.copy() env["HGPLAIN"] = "1" env["HGREQUESTID"] = request_id env["WATCHMAN_SOCK"] = (WatchmanInstance.getSharedInstance(). getSockPath().legacy_sockpath()) subprocess.call(["hg", "init"], env=env, cwd=root) subprocess.call(["hg", "log"], env=env, cwd=root) try: with open(os.path.join(root, ".hg/blackbox.log")) as f: if request_id in f.read(): return except IOError: pass self.skipTest("HGREQUESTID is not supported")
def spawnWatchmanWait(self, cmdArgs): wait_script = os.environ.get("WATCHMAN_WAIT_PATH") if wait_script: args = [wait_script] else: args = [ sys.executable, os.path.join(os.environ["WATCHMAN_PYTHON_BIN"], "watchman-wait"), ] args.extend(cmdArgs) env = os.environ.copy() sock_path = WatchmanInstance.getSharedInstance().getSockPath() env["WATCHMAN_SOCK"] = sock_path.legacy_sockpath() pywatchman_path = env.get("PYWATCHMAN_PATH") if pywatchman_path: env["PYTHONPATH"] = pywatchman_path return subprocess.Popen(args, env=env, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def getSockPath(self): return WatchmanInstance.getSharedInstance().getSockPath()