/* * 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.artifact_cache; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; import com.facebook.buck.event.BuckEventBusFactory; import com.facebook.buck.io.BorrowablePath; import com.facebook.buck.io.LazyPath; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.rules.RuleKey; import com.facebook.buck.testutil.integration.TemporaryPaths; import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.nio.file.Files; import java.util.Optional; import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; public class TwoLevelArtifactCacheDecoratorTest { @Rule public TemporaryPaths tmp = new TemporaryPaths(); private static final RuleKey dummyRuleKey = new RuleKey("76b1c1beae69428db2d1befb31cf743ac8ce90df"); private static final RuleKey dummyRuleKey2 = new RuleKey("1111111111111111111111111111111111111111"); @Test public void testCacheFetch() throws InterruptedException, IOException { try (InMemoryArtifactCache inMemoryArtifactCache = new InMemoryArtifactCache(); TwoLevelArtifactCacheDecorator twoLevelCache = new TwoLevelArtifactCacheDecorator( inMemoryArtifactCache, new ProjectFilesystem(tmp.getRoot()), BuckEventBusFactory.newInstance(), /* performTwoLevelStores */ true, /* minimumTwoLevelStoredArtifactSize */ 0L, /* maximumTwoLevelStoredArtifactSize */ Optional.empty())) { LazyPath dummyFile = LazyPath.ofInstance(tmp.newFile()); assertThat( twoLevelCache.fetch(dummyRuleKey, dummyFile).getType(), Matchers.equalTo(CacheResultType.MISS)); twoLevelCache.store( ArtifactInfo.builder().addRuleKeys(dummyRuleKey).build(), BorrowablePath.notBorrowablePath(dummyFile.get())); assertThat( twoLevelCache.fetch(dummyRuleKey, dummyFile).getType(), Matchers.equalTo(CacheResultType.HIT)); twoLevelCache.store( ArtifactInfo.builder().addRuleKeys(dummyRuleKey2).build(), BorrowablePath.notBorrowablePath(dummyFile.get())); assertThat( twoLevelCache.fetch(dummyRuleKey2, dummyFile).getType(), Matchers.equalTo(CacheResultType.HIT)); assertThat(inMemoryArtifactCache.getArtifactCount(), Matchers.equalTo(3)); } } private void testStoreThresholds(int artifactSize, int expectedArtifactsInCache) throws InterruptedException, IOException { try (InMemoryArtifactCache inMemoryArtifactCache = new InMemoryArtifactCache(); TwoLevelArtifactCacheDecorator twoLevelCache = new TwoLevelArtifactCacheDecorator( inMemoryArtifactCache, new ProjectFilesystem(tmp.getRoot()), BuckEventBusFactory.newInstance(), /* performTwoLevelStores */ true, /* minimumTwoLevelStoredArtifactSize */ 5L, /* maximumTwoLevelStoredArtifactSize */ Optional.of(10L))) { LazyPath lazyPath = LazyPath.ofInstance(tmp.newFile()); Files.write(lazyPath.get(), new byte[artifactSize]); twoLevelCache.store( ArtifactInfo.builder().addRuleKeys(dummyRuleKey).build(), BorrowablePath.notBorrowablePath(lazyPath.get())); assertThat( inMemoryArtifactCache.getArtifactCount(), Matchers.equalTo(expectedArtifactsInCache)); } } @Test public void noTwoLevelStoreWhenFileSizeBelowThreshold() throws Exception { testStoreThresholds(/* artifactSize */ 3, /* expectedArtifactsInCache */ 1); } @Test public void twoLeveLStoreWhenFileSizeInRange() throws Exception { testStoreThresholds(/* artifactSize */ 6, /* expectedArtifactsInCache */ 2); } @Test public void noTwoLevelStoreWhenFileSizeAboveMax() throws Exception { testStoreThresholds(/* artifactSize */ 11, /* expectedArtifactsInCache */ 1); } @Test public void testMetadataIsNotShared() throws InterruptedException, IOException { try (InMemoryArtifactCache inMemoryArtifactCache = new InMemoryArtifactCache(); TwoLevelArtifactCacheDecorator twoLevelCache = new TwoLevelArtifactCacheDecorator( inMemoryArtifactCache, new ProjectFilesystem(tmp.getRoot()), BuckEventBusFactory.newInstance(), /* performTwoLevelStores */ true, /* minimumTwoLevelStoredArtifactSize */ 0L, /* maximumTwoLevelStoredArtifactSize */ Optional.empty())) { LazyPath dummyFile = LazyPath.ofInstance(tmp.newFile()); final String testMetadataKey = "testMetaKey"; twoLevelCache.store( ArtifactInfo.builder() .addRuleKeys(dummyRuleKey) .setMetadata(ImmutableMap.of(testMetadataKey, "value1")) .build(), BorrowablePath.notBorrowablePath(dummyFile.get())); twoLevelCache.store( ArtifactInfo.builder() .addRuleKeys(dummyRuleKey2) .setMetadata(ImmutableMap.of(testMetadataKey, "value2")) .build(), BorrowablePath.notBorrowablePath(dummyFile.get())); CacheResult fetch1 = twoLevelCache.fetch(dummyRuleKey, dummyFile); CacheResult fetch2 = twoLevelCache.fetch(dummyRuleKey2, dummyFile); // Content hashes should be the same assertEquals( fetch1.getMetadata().get(TwoLevelArtifactCacheDecorator.METADATA_KEY), fetch2.getMetadata().get(TwoLevelArtifactCacheDecorator.METADATA_KEY)); // But the metadata shouldn't be shared assertNotEquals( fetch1.getMetadata().get(testMetadataKey), fetch2.getMetadata().get(testMetadataKey)); } } @Test public void testCanRead2LStoresIfStoresDisabled() throws InterruptedException, IOException { try (InMemoryArtifactCache inMemoryArtifactCache = new InMemoryArtifactCache(); TwoLevelArtifactCacheDecorator twoLevelCache = new TwoLevelArtifactCacheDecorator( inMemoryArtifactCache, new ProjectFilesystem(tmp.getRoot()), BuckEventBusFactory.newInstance(), /* performTwoLevelStores */ true, /* minimumTwoLevelStoredArtifactSize */ 0L, /* maximumTwoLevelStoredArtifactSize */ Optional.empty()); TwoLevelArtifactCacheDecorator twoLevelCacheNoStore = new TwoLevelArtifactCacheDecorator( inMemoryArtifactCache, new ProjectFilesystem(tmp.getRoot()), BuckEventBusFactory.newInstance(), /* performTwoLevelStores */ false, /* minimumTwoLevelStoredArtifactSize */ 0L, /* maximumTwoLevelStoredArtifactSize */ Optional.empty())) { LazyPath dummyFile = LazyPath.ofInstance(tmp.newFile()); twoLevelCache.store( ArtifactInfo.builder().addRuleKeys(dummyRuleKey).build(), BorrowablePath.notBorrowablePath(dummyFile.get())); assertThat(inMemoryArtifactCache.getArtifactCount(), Matchers.equalTo(2)); assertThat( twoLevelCacheNoStore.fetch(dummyRuleKey, dummyFile).getType(), Matchers.equalTo(CacheResultType.HIT)); } } }