Issue #3489: restore config hash on property cache clear

This commit is contained in:
rnveach 2016-10-03 10:49:20 -04:00 committed by Roman Ivanov
parent a3e4bcc8b7
commit c2847eae88
3 changed files with 70 additions and 23 deletions

View File

@ -562,7 +562,7 @@ public class Checker extends AutomaticBean implements MessageDispatcher {
*/
public void clearCache() {
if (cache != null) {
cache.clear();
cache.reset();
}
}
}

View File

@ -68,7 +68,7 @@ final class PropertyCacheFile {
* checked the key is chosen in such a way that it cannot be a
* valid file name.
*/
private static final String CONFIG_HASH_KEY = "configuration*?";
public static final String CONFIG_HASH_KEY = "configuration*?";
/** Size of buffer which is used to read external configuration resources. */
private static final int BUFFER_SIZE = 1024;
@ -82,6 +82,9 @@ final class PropertyCacheFile {
/** File name of cache. **/
private final String fileName;
/** Generated configuration hash. **/
private String configHash;
/**
* Creates a new {@code PropertyCacheFile} instance.
*
@ -106,17 +109,16 @@ final class PropertyCacheFile {
public void load() throws IOException {
// get the current config so if the file isn't found
// the first time the hash will be added to output file
final String currentConfigHash = getHashCodeBasedOnObjectContent(config);
configHash = getHashCodeBasedOnObjectContent(config);
if (new File(fileName).exists()) {
FileInputStream inStream = null;
try {
inStream = new FileInputStream(fileName);
details.load(inStream);
final String cachedConfigHash = details.getProperty(CONFIG_HASH_KEY);
if (!currentConfigHash.equals(cachedConfigHash)) {
if (!configHash.equals(cachedConfigHash)) {
// Detected configuration change - clear cache
details.clear();
details.setProperty(CONFIG_HASH_KEY, currentConfigHash);
reset();
}
}
finally {
@ -125,7 +127,7 @@ final class PropertyCacheFile {
}
else {
// put the hash in the file if the file is going to be created
details.setProperty(CONFIG_HASH_KEY, currentConfigHash);
reset();
}
}
@ -149,10 +151,11 @@ final class PropertyCacheFile {
}
/**
* Clears the cache.
* Resets the cache to be empty except for the configuration hash.
*/
public void clear() {
public void reset() {
details.clear();
details.setProperty(CONFIG_HASH_KEY, configHash);
}
/**
@ -188,6 +191,15 @@ final class PropertyCacheFile {
details.setProperty(checkedFileName, Long.toString(timestamp));
}
/**
* Retrieves the hash of a specific file.
* @param name The name of the file to retrieve.
* @return The has of the file or {@code null}.
*/
public String get(String name) {
return details.getProperty(name);
}
/**
* Calculates the hashcode for the serializable object based on its content.
* @param object serializable object.
@ -230,7 +242,7 @@ final class PropertyCacheFile {
public void putExternalResources(Set<String> locations) {
final Set<ExternalResource> resources = loadExternalResources(locations);
if (areExternalResourcesChanged(resources)) {
details.clear();
reset();
}
fillCacheWithExternalResources(resources);
}

View File

@ -21,13 +21,13 @@ package com.puppycrawl.tools.checkstyle;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
@ -36,7 +36,9 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
@ -82,18 +84,55 @@ public class PropertyCacheFileTest {
assertFalse(cache.isInCache("myFile1", 1));
}
@Test
public void testConfigHashOnReset() throws IOException {
final Configuration config = new DefaultConfiguration("myName");
final String filePath = temporaryFolder.newFile().getPath();
final PropertyCacheFile cache = new PropertyCacheFile(config, filePath);
cache.load();
final String hash = cache.get(PropertyCacheFile.CONFIG_HASH_KEY);
assertNotNull(hash);
cache.reset();
assertEquals(hash, cache.get(PropertyCacheFile.CONFIG_HASH_KEY));
}
@Test
public void testConfigHashRemainsOnResetExternalResources() throws IOException {
final Configuration config = new DefaultConfiguration("myName");
final String filePath = temporaryFolder.newFile().getPath();
final PropertyCacheFile cache = new PropertyCacheFile(config, filePath);
// create cache with one file
cache.load();
cache.put("myFile", 1);
final String hash = cache.get(PropertyCacheFile.CONFIG_HASH_KEY);
assertNotNull(hash);
// apply new external resource to clear cache
final Set<String> resources = new HashSet<>();
resources.add("dummy");
cache.putExternalResources(resources);
assertEquals(hash, cache.get(PropertyCacheFile.CONFIG_HASH_KEY));
assertFalse(cache.isInCache("myFile", 1));
}
@Test
public void testCacheDirectoryDoesNotExistAndShouldBeCreated() throws IOException {
final Configuration config = new DefaultConfiguration("myName");
final String filePath = String.format(Locale.getDefault(), "%s%2$stemp%2$scache.temp",
temporaryFolder.getRoot(), File.separator);
final PropertyCacheFile cache = new PropertyCacheFile(config, filePath);
try {
cache.persist();
}
catch (FileNotFoundException ex) {
fail("Exception is not expected. Cache directory should be created successfully!");
}
// no exception expected, cache directory should be created
cache.persist();
assertTrue("cache exists in directory", new File(filePath).exists());
}
@Test
@ -102,12 +141,8 @@ public class PropertyCacheFileTest {
final String filePath = "temp.cache";
final PropertyCacheFile cache = new PropertyCacheFile(config, filePath);
try {
cache.persist();
}
catch (FileNotFoundException ex) {
fail("Exception is not expected!");
}
// no exception expected
cache.persist();
if (Files.exists(Paths.get(filePath))) {
Files.delete(Paths.get(filePath));