/* * Copyright 2017-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.rules.keys; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import com.facebook.buck.event.BuckEventBus; import com.facebook.buck.event.DefaultBuckEventBus; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.BuildId; import com.facebook.buck.rules.ActionGraph; import com.facebook.buck.rules.RuleKeyAppendable; import com.facebook.buck.testutil.FakeProjectFilesystem; import com.facebook.buck.timing.FakeClock; import com.facebook.buck.util.WatchmanOverflowEvent; import com.facebook.buck.util.WatchmanPathEvent; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; import org.junit.Test; public class RuleKeyCacheRecyclerTest { private static final ProjectFilesystem FILESYSTEM = new FakeProjectFilesystem(); private static final EventBus EVENT_BUS = new EventBus(); private static final BuckEventBus BUCK_EVENT_BUS = new DefaultBuckEventBus(new FakeClock(0), new BuildId()); private static final int RULE_KEY_SEED = 0; private static final ActionGraph ACTION_GRAPH = new ActionGraph(ImmutableList.of()); private static final RuleKeyCacheRecycler.SettingsAffectingCache SETTINGS = new RuleKeyCacheRecycler.SettingsAffectingCache(RULE_KEY_SEED, ACTION_GRAPH); @Test public void pathWatchEventDoesNotInvalidateDifferentInput() { DefaultRuleKeyCache<Void> cache = new DefaultRuleKeyCache<>(); RuleKeyInput input1 = RuleKeyInput.of(FILESYSTEM, FILESYSTEM.getPath("input1")); RuleKeyAppendable appendable1 = sink -> {}; RuleKeyInput input2 = RuleKeyInput.of(FILESYSTEM, FILESYSTEM.getPath("input2")); RuleKeyAppendable appendable2 = sink -> {}; cache.get( appendable1, a -> new RuleKeyResult<>(null, ImmutableList.of(), ImmutableList.of(input1))); cache.get( appendable2, a -> new RuleKeyResult<>(null, ImmutableList.of(), ImmutableList.of(input2))); RuleKeyCacheRecycler<Void> recycler = RuleKeyCacheRecycler.createAndRegister(EVENT_BUS, cache, ImmutableSet.of(FILESYSTEM)); recycler.onFilesystemChange( WatchmanPathEvent.of( FILESYSTEM.getRootPath(), WatchmanPathEvent.Kind.MODIFY, input2.getPath())); assertTrue(cache.isCached(appendable1)); assertFalse(cache.isCached(appendable2)); } @Test public void pathWatchEventDoesInvalidateDirectoryInputContainingIt() { DefaultRuleKeyCache<Void> cache = new DefaultRuleKeyCache<>(); RuleKeyInput input = RuleKeyInput.of(FILESYSTEM, FILESYSTEM.getPath("input")); RuleKeyAppendable appendable = sink -> {}; cache.get( appendable, a -> new RuleKeyResult<>(null, ImmutableList.of(), ImmutableList.of(input))); RuleKeyCacheRecycler<Void> recycler = RuleKeyCacheRecycler.createAndRegister(EVENT_BUS, cache, ImmutableSet.of(FILESYSTEM)); recycler.onFilesystemChange( WatchmanPathEvent.of( FILESYSTEM.getRootPath(), WatchmanPathEvent.Kind.MODIFY, input.getPath().resolve("subpath"))); assertFalse(cache.isCached(appendable)); } @Test public void overflowWatchEventInvalidatesEverything() { DefaultRuleKeyCache<Void> cache = new DefaultRuleKeyCache<>(); // Create a rule key appendable with an input and cache it. RuleKeyInput input1 = RuleKeyInput.of(FILESYSTEM, FILESYSTEM.getPath("input1")); RuleKeyAppendable appendable1 = sink -> {}; cache.get( appendable1, a -> new RuleKeyResult<>(null, ImmutableList.of(), ImmutableList.of(input1))); // Create another rule key appendable with an input and cache it. RuleKeyInput input2 = RuleKeyInput.of(FILESYSTEM, FILESYSTEM.getPath("input2")); RuleKeyAppendable appendable2 = sink -> {}; cache.get( appendable2, a -> new RuleKeyResult<>(null, ImmutableList.of(), ImmutableList.of(input2))); RuleKeyCacheRecycler<Void> recycler = RuleKeyCacheRecycler.createAndRegister(EVENT_BUS, cache, ImmutableSet.of(FILESYSTEM)); // Verify that everything is cached before the overflow event. assertTrue(cache.isCached(appendable1)); assertTrue(cache.isCached(appendable2)); // Send an overflow event and verify everything was invalidated. recycler.onFilesystemChange(WatchmanOverflowEvent.of(FILESYSTEM.getRootPath(), "")); assertFalse(cache.isCached(appendable1)); assertFalse(cache.isCached(appendable2)); } @Test public void getCacheWithIdenticalSettingsDoesNotInvalidate() { DefaultRuleKeyCache<Void> cache = new DefaultRuleKeyCache<>(); RuleKeyCacheRecycler<Void> recycler = RuleKeyCacheRecycler.createAndRegister(EVENT_BUS, cache, ImmutableSet.of(FILESYSTEM)); RuleKeyAppendable appendable = sink -> {}; recycler.withRecycledCache( BUCK_EVENT_BUS, SETTINGS, c -> { cache.get( appendable, a -> new RuleKeyResult<>(null, ImmutableList.of(), ImmutableList.of())); }); assertTrue(cache.isCached(appendable)); recycler.withRecycledCache(BUCK_EVENT_BUS, SETTINGS, c -> {}); assertTrue(cache.isCached(appendable)); } @Test public void getCacheWithDifferentRuleKeySeedInvalidates() { DefaultRuleKeyCache<Void> cache = new DefaultRuleKeyCache<>(); RuleKeyCacheRecycler<Void> recycler = RuleKeyCacheRecycler.createAndRegister(EVENT_BUS, cache, ImmutableSet.of(FILESYSTEM)); RuleKeyAppendable appendable = sink -> {}; recycler.withRecycledCache( BUCK_EVENT_BUS, SETTINGS, c -> { cache.get( appendable, a -> new RuleKeyResult<>(null, ImmutableList.of(), ImmutableList.of())); }); assertTrue(cache.isCached(appendable)); recycler.withRecycledCache( BUCK_EVENT_BUS, new RuleKeyCacheRecycler.SettingsAffectingCache(RULE_KEY_SEED + 1, ACTION_GRAPH), c -> {}); assertFalse(cache.isCached(appendable)); } @Test public void getCacheWithDifferentActionGraphInstanceInvalidates() { DefaultRuleKeyCache<Void> cache = new DefaultRuleKeyCache<>(); RuleKeyCacheRecycler<Void> recycler = RuleKeyCacheRecycler.createAndRegister(EVENT_BUS, cache, ImmutableSet.of(FILESYSTEM)); RuleKeyAppendable appendable = sink -> {}; recycler.withRecycledCache( BUCK_EVENT_BUS, SETTINGS, c -> { cache.get( appendable, a -> new RuleKeyResult<>(null, ImmutableList.of(), ImmutableList.of())); }); assertTrue(cache.isCached(appendable)); recycler.withRecycledCache( BUCK_EVENT_BUS, new RuleKeyCacheRecycler.SettingsAffectingCache( RULE_KEY_SEED, new ActionGraph(ImmutableList.of())), c -> {}); assertFalse(cache.isCached(appendable)); } }