Skip to content

Commit

Permalink
Add tests for scm changes for file watchers
Browse files Browse the repository at this point in the history
Summary:
# Context

We are introducing EdenFS notifications to support scalable and ergonomic file system notifications for EdenFS mounts.

# This Diff

* Tests to validate correct behavior when scm changes (rebase and checkout) occur

# Next Steps

* Fix bug in EdenFS that causes `to` and `from` to be switched in commit transitions.
* After fix deployed - remove work around in edenfs file watcher.

Reviewed By: kavehahmadi60

Differential Revision: D67612766

fbshipit-source-id: e1ec49db93021c804c32f24825331acef1ba2a8b
  • Loading branch information
jdelliot authored and facebook-github-bot committed Dec 24, 2024
1 parent ae9ece5 commit 1f3f676
Show file tree
Hide file tree
Showing 6 changed files with 354 additions and 4 deletions.
7 changes: 3 additions & 4 deletions tests/core/common/io/file_watcher_file_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,9 @@ async def run_replace_file_test(
with open(path, "a"):
pass

# By getting files here, we clear the log of the previous file watcher events
# including the create event for 'def'; this also removes the directory modify event
# that we would normally expect to see when creating a file in a directory on native file systems
await get_files(buck)
# clear log - run build twice
await buck.targets("root//:")
await buck.targets("root//:")

fromPath = os.path.join(buck.cwd, "files", "abc")
toPath = os.path.join(buck.cwd, "files", "def")
Expand Down
187 changes: 187 additions & 0 deletions tests/core/common/io/file_watcher_scm_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.

# pyre-strict


import os
import subprocess
from typing import Tuple

from buck2.tests.core.common.io.file_watcher import (
FileWatcherEvent,
FileWatcherEventType,
FileWatcherKind,
FileWatcherProvider,
get_file_watcher_events,
)
from buck2.tests.core.common.io.file_watcher_tests import (
FileSystemType,
setup_file_watcher_test,
verify_results,
)

from buck2.tests.e2e_util.api.buck import Buck


# Setup repo structure to test these conditions: https://www.internalfb.com/excalidraw/EX346258
async def setup_file_watcher_scm_test(buck: Buck) -> Tuple[str, str, str, str]:
# Run after setup_file_watcher_test to create a simple stack of commits
commit_a = subprocess.check_output(["sl", "whereami"], cwd=buck.cwd).decode()

# Create a file
path = os.path.join(buck.cwd, "files", "def")
with open(path, "a"):
pass

# Commit it
subprocess.run(["sl", "commit", "--addremove", "-m", "commit_b"], cwd=buck.cwd)
commit_b = subprocess.check_output(["sl", "whereami"], cwd=buck.cwd).decode()

# Go back to commit_a
subprocess.run(["sl", "co", commit_a], cwd=buck.cwd)

# Create a file
path = os.path.join(buck.cwd, "files", "ghi")
with open(path, "a"):
pass

# Commit it
subprocess.run(["sl", "commit", "--addremove", "-m", "commit_c"], cwd=buck.cwd)
commit_c = subprocess.check_output(["sl", "whereami"], cwd=buck.cwd).decode()

# Create a file
path = os.path.join(buck.cwd, "files", "jkl")
with open(path, "a"):
pass

# Commit it
subprocess.run(["sl", "commit", "--addremove", "-m", "commit_d"], cwd=buck.cwd)
commit_d = subprocess.check_output(["sl", "whereami"], cwd=buck.cwd).decode()

# clear log- run build twice
await buck.targets("root//:")
await buck.targets("root//:")

return commit_a, commit_b, commit_c, commit_d


async def run_checkout_mergebase_changes_test(
buck: Buck,
file_system_type: FileSystemType,
file_watcher_provider: FileWatcherProvider,
) -> None:
await setup_file_watcher_test(buck)

# Create a file
path = os.path.join(buck.cwd, "files", "def")
with open(path, "a"):
pass

# Commit it
subprocess.run(["sl", "commit", "--addremove", "-m", "next"], cwd=buck.cwd)
commit_a = subprocess.check_output(["sl", "whereami"], cwd=buck.cwd).decode()

# Create a file
path = os.path.join(buck.cwd, "files", "ghi")
with open(path, "a"):
pass

# Commit it
subprocess.run(["sl", "commit", "--addremove", "-m", "next"], cwd=buck.cwd)
commit_b = subprocess.check_output(["sl", "whereami"], cwd=buck.cwd).decode()

# Go back to the previous commit
subprocess.run(["sl", "co", commit_a], cwd=buck.cwd)

is_fresh_instance, _ = await get_file_watcher_events(buck)
if file_watcher_provider in [
FileWatcherProvider.FS_HASH_CRAWLER,
FileWatcherProvider.RUST_NOTIFY,
]:
# Stats only records the first 100 events (https://fburl.com/code/x9esqun4)
# so we can't verify the results when making commit transitions
assert not is_fresh_instance
else:
# We might have some events even for a fresh instance, so we ignore
assert is_fresh_instance

# Go back to the next commit
subprocess.run(["sl", "co", commit_b], cwd=buck.cwd)

is_fresh_instance, _ = await get_file_watcher_events(buck)
if file_watcher_provider in [
FileWatcherProvider.FS_HASH_CRAWLER,
FileWatcherProvider.RUST_NOTIFY,
]:
assert not is_fresh_instance
else:
assert is_fresh_instance


async def run_checkout_wtih_mergebase_test(
buck: Buck,
file_system_type: FileSystemType,
file_watcher_provider: FileWatcherProvider,
) -> None:
await setup_file_watcher_test(buck)
[_, _, commit_c, _] = await setup_file_watcher_scm_test(buck)

# Go back to commit_c
subprocess.run(["sl", "co", commit_c], cwd=buck.cwd)

if file_watcher_provider != FileWatcherProvider.RUST_NOTIFY:
required = [
FileWatcherEvent(
FileWatcherEventType.DELETE, FileWatcherKind.FILE, "root//files/jkl"
)
]
else:
required = [
FileWatcherEvent(
FileWatcherEventType.MODIFY, FileWatcherKind.FILE, "root//files/jkl"
)
]

is_fresh_instance, results = await get_file_watcher_events(buck)
assert not is_fresh_instance
verify_results(results, required)


async def run_rebase_wtih_mergebase_test(
buck: Buck,
file_system_type: FileSystemType,
file_watcher_provider: FileWatcherProvider,
) -> None:
await setup_file_watcher_test(buck)
[_, commit_b, commit_c, _] = await setup_file_watcher_scm_test(buck)

# Rebaase C->D from A to B
subprocess.run(["sl", "rebase", "-s", commit_c, "-d", commit_b], cwd=buck.cwd)

is_fresh_instance, results = await get_file_watcher_events(buck)
if file_system_type == FileSystemType.NATIVE:
# Watchman is flakey on native file systems
if file_watcher_provider != FileWatcherProvider.WATCHMAN:
assert not is_fresh_instance
else:
assert is_fresh_instance


async def run_restack_wtih_mergebase_test(
buck: Buck,
file_system_type: FileSystemType,
file_watcher_provider: FileWatcherProvider,
) -> None:
await setup_file_watcher_test(buck)
[commit_a, _, _, commit_d] = await setup_file_watcher_scm_test(buck)

# Rebaase D from C to A
subprocess.run(["sl", "rebase", "-s", commit_d, "-d", commit_a], cwd=buck.cwd)

is_fresh_instance, results = await get_file_watcher_events(buck)
assert not is_fresh_instance
34 changes: 34 additions & 0 deletions tests/core/io/test_edenfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
run_rename_file_test,
run_replace_file_test,
)
from buck2.tests.core.common.io.file_watcher_scm_tests import (
run_checkout_mergebase_changes_test,
run_checkout_wtih_mergebase_test,
run_rebase_wtih_mergebase_test,
run_restack_wtih_mergebase_test,
)
from buck2.tests.core.common.io.file_watcher_tests import FileSystemType

from buck2.tests.e2e_util.api.buck import Buck
Expand Down Expand Up @@ -81,3 +87,31 @@ async def test_edenfs_rename_directory(buck: Buck) -> None:
await run_rename_directory_test(
buck, FileSystemType.EDEN_FS, FileWatcherProvider.EDEN_FS
)


@buck_test(setup_eden=True)
async def test_edenfs_checkout_mergebase_changes(buck: Buck) -> None:
await run_checkout_mergebase_changes_test(
buck, FileSystemType.EDEN_FS, FileWatcherProvider.EDEN_FS
)


@buck_test(setup_eden=True)
async def test_edenfs_checkout_with_mergebase(buck: Buck) -> None:
await run_checkout_wtih_mergebase_test(
buck, FileSystemType.EDEN_FS, FileWatcherProvider.EDEN_FS
)


@buck_test(setup_eden=True)
async def test_edenfs_rebase_with_mergebase(buck: Buck) -> None:
await run_rebase_wtih_mergebase_test(
buck, FileSystemType.EDEN_FS, FileWatcherProvider.EDEN_FS
)


@buck_test(setup_eden=True)
async def test_edenfs_restack_with_mergebase(buck: Buck) -> None:
await run_restack_wtih_mergebase_test(
buck, FileSystemType.EDEN_FS, FileWatcherProvider.EDEN_FS
)
34 changes: 34 additions & 0 deletions tests/core/io/test_fs_hash_crawler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
run_rename_file_test,
run_replace_file_test,
)
from buck2.tests.core.common.io.file_watcher_scm_tests import (
run_checkout_mergebase_changes_test,
run_checkout_wtih_mergebase_test,
run_rebase_wtih_mergebase_test,
run_restack_wtih_mergebase_test,
)
from buck2.tests.core.common.io.file_watcher_tests import FileSystemType

from buck2.tests.e2e_util.api.buck import Buck
Expand Down Expand Up @@ -82,3 +88,31 @@ async def test_fs_hash_cralwer_rename_directory(buck: Buck) -> None:
await run_rename_directory_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.FS_HASH_CRAWLER
)


@buck_test(setup_eden=False)
async def test_fs_hash_cralwer_checkout_mergebase_changes(buck: Buck) -> None:
await run_checkout_mergebase_changes_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.FS_HASH_CRAWLER
)


@buck_test(setup_eden=False)
async def test_fs_hash_cralwer_checkout_with_mergebase(buck: Buck) -> None:
await run_checkout_wtih_mergebase_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.FS_HASH_CRAWLER
)


@buck_test(setup_eden=False)
async def test_fs_hash_cralwer_rebase_with_mergebase(buck: Buck) -> None:
await run_rebase_wtih_mergebase_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.FS_HASH_CRAWLER
)


@buck_test(setup_eden=False)
async def test_fs_hash_cralwer_restack_with_mergebase(buck: Buck) -> None:
await run_restack_wtih_mergebase_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.FS_HASH_CRAWLER
)
34 changes: 34 additions & 0 deletions tests/core/io/test_notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
run_rename_file_test,
run_replace_file_test,
)
from buck2.tests.core.common.io.file_watcher_scm_tests import (
run_checkout_mergebase_changes_test,
run_checkout_wtih_mergebase_test,
run_rebase_wtih_mergebase_test,
run_restack_wtih_mergebase_test,
)
from buck2.tests.core.common.io.file_watcher_tests import FileSystemType

from buck2.tests.e2e_util.api.buck import Buck
Expand Down Expand Up @@ -82,3 +88,31 @@ async def test_notify_rename_directory(buck: Buck) -> None:
await run_rename_directory_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.RUST_NOTIFY
)


@buck_test(setup_eden=False)
async def test_notify_checkout_mergebase_changes(buck: Buck) -> None:
await run_checkout_mergebase_changes_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.RUST_NOTIFY
)


@buck_test(setup_eden=False)
async def test_notify_checkout_with_mergebase(buck: Buck) -> None:
await run_checkout_wtih_mergebase_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.RUST_NOTIFY
)


@buck_test(setup_eden=False)
async def test_notify_rebase_with_mergebase(buck: Buck) -> None:
await run_rebase_wtih_mergebase_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.RUST_NOTIFY
)


@buck_test(setup_eden=False)
async def test_notify_restack_with_mergebase(buck: Buck) -> None:
await run_restack_wtih_mergebase_test(
buck, FileSystemType.NATIVE, FileWatcherProvider.RUST_NOTIFY
)
Loading

0 comments on commit 1f3f676

Please sign in to comment.