/* * Copyright 2016-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.facebook.buck.util; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeTrue; import com.facebook.buck.event.DefaultBuckEventBus; import com.facebook.buck.io.PathOrGlobMatcher; import com.facebook.buck.io.ProjectWatch; import com.facebook.buck.io.Watchman; import com.facebook.buck.io.WatchmanCursor; import com.facebook.buck.model.BuildId; import com.facebook.buck.testutil.integration.TemporaryPaths; import com.facebook.buck.timing.DefaultClock; import com.facebook.buck.timing.FakeClock; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; public class WatchmanWatcherIntegrationTest { @Rule public TemporaryPaths tmp = new TemporaryPaths(); private Watchman watchman; private EventBus eventBus; private WatchmanEventCollector watchmanEventCollector; @Before public void setUp() throws InterruptedException, IOException { // Create an empty watchman config file. Files.write(tmp.getRoot().resolve(".watchmanconfig"), new byte[0]); watchman = Watchman.build( ImmutableSet.of(tmp.getRoot()), ImmutableMap.copyOf(System.getenv()), new Console(Verbosity.ALL, System.out, System.err, Ansi.withoutTty()), new DefaultClock(), Optional.empty()); assumeTrue(watchman.getWatchmanClient().isPresent()); eventBus = new EventBus(); watchmanEventCollector = new WatchmanEventCollector(); eventBus.register(watchmanEventCollector); } @Test public void ignoreDotFileInGlob() throws IOException, InterruptedException { WatchmanWatcher watcher = createWatchmanWatcher(new PathOrGlobMatcher("**/*.swp")); // Create a dot-file which should be ignored by the above glob. Path path = tmp.getRoot().getFileSystem().getPath("foo/bar/.hello.swp"); Files.createDirectories(tmp.getRoot().resolve(path).getParent()); Files.write(tmp.getRoot().resolve(path), new byte[0]); // Verify we don't get an event for the path. watcher.postEvents( new DefaultBuckEventBus(new FakeClock(0), new BuildId()), WatchmanWatcher.FreshInstanceAction.NONE); assertThat(watchmanEventCollector.getEvents(), Matchers.empty()); } @Test public void globMatchesWholeName() throws IOException, InterruptedException { WatchmanWatcher watcher = createWatchmanWatcher(new PathOrGlobMatcher("*.txt")); // Create a dot-file which should be ignored by the above glob. Path path = tmp.getRoot().getFileSystem().getPath("foo/bar/hello.txt"); Files.createDirectories(tmp.getRoot().resolve(path).getParent()); Files.write(tmp.getRoot().resolve(path), new byte[0]); // Verify we still get an event for the created path. watcher.postEvents( new DefaultBuckEventBus(new FakeClock(0), new BuildId()), WatchmanWatcher.FreshInstanceAction.NONE); ImmutableList<WatchmanEvent> events = watchmanEventCollector.getEvents(); assertThat(events.size(), Matchers.equalTo(1)); WatchmanPathEvent event = (WatchmanPathEvent) events.get(0); Path eventPath = event.getPath(); assertThat(eventPath, Matchers.equalTo(path)); assertSame(event.getKind(), WatchmanPathEvent.Kind.CREATE); } // Create a watcher for the given ignore paths, clearing the initial overflow event before // returning it. private WatchmanWatcher createWatchmanWatcher(PathOrGlobMatcher... ignorePaths) throws IOException, InterruptedException { WatchmanWatcher watcher = new WatchmanWatcher( ImmutableMap.of( tmp.getRoot(), ProjectWatch.of(tmp.getRoot().toString(), Optional.empty())), eventBus, ImmutableSet.copyOf(ignorePaths), watchman, ImmutableMap.of( tmp.getRoot(), new WatchmanCursor( new StringBuilder("n:buckd").append(UUID.randomUUID()).toString()))); // Clear out the initial overflow event. watcher.postEvents( new DefaultBuckEventBus(new FakeClock(0), new BuildId()), WatchmanWatcher.FreshInstanceAction.NONE); watchmanEventCollector.clear(); return watcher; } private static final class WatchmanEventCollector { private final List<WatchmanEvent> events = new ArrayList<>(); @Subscribe protected void handle(WatchmanEvent event) { events.add(event); } public void clear() { events.clear(); } public ImmutableList<WatchmanEvent> getEvents() { return ImmutableList.copyOf(events); } } }