Tests - fix for threading issue involving weakly consistent cache

This commit is contained in:
dragonmacher 2019-06-11 10:46:46 -04:00
parent 6de4092875
commit 4919d6ec54
2 changed files with 36 additions and 10 deletions

View file

@ -15,11 +15,13 @@
*/
package ghidra.app.decompiler.component;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Supplier;
import org.junit.*;
@ -225,20 +227,20 @@ public class DecompilerCachingTest extends AbstractGhidraHeadedIntegrationTest {
}
private void assertCacheSize(int expected) {
long actual = cache.size();
if (expected == actual) {
return;
}
Supplier<String> supplier = () -> getCacheSizeFailureMessage(expected);
waitForCondition(() -> cache.size() == expected, supplier);
}
private String getCacheSizeFailureMessage(int expected) {
StringBuilder buffy = new StringBuilder("Cache size is not as expected - expected " +
expected + "; found " + actual + "\nEntries in cache:\n");
expected + "; found " + cache.size() + "\nEntries in cache:\n");
ConcurrentMap<Function, DecompileResults> map = cache.asMap();
Set<Entry<Function, DecompileResults>> entries = map.entrySet();
for (Entry<Function, DecompileResults> entry : entries) {
Function key = entry.getKey();
buffy.append('\t').append(key.getName()).append('\n');
}
fail(buffy.toString());
return buffy.toString();
}
private void buildDummyFunction(ToyProgramBuilder programBuilder, String functionName,

View file

@ -393,6 +393,20 @@ public abstract class AbstractGTest {
waitForCondition(condition, true /*failOnTimeout*/, failureMessage);
}
/**
* Waits for the given condition to return true
*
* @param condition the condition that returns true when satisfied
* @param failureMessageSupplier the function that will supply the failure message in the
* event of a timeout.
* @throws AssertionFailedError if the condition is not met within the timeout period
*/
public static void waitForCondition(BooleanSupplier condition,
Supplier<String> failureMessageSupplier) throws AssertionFailedError {
waitForCondition(condition, true /*failOnTimeout*/, failureMessageSupplier);
}
/**
* Waits for the given condition to return true. Most of the <code>waitForCondition()</code>
* methods throw an {@link AssertionFailedError} if the timeout period expires.
@ -403,12 +417,18 @@ public abstract class AbstractGTest {
* @param supplier the supplier that returns true when satisfied
*/
public static void waitForConditionWithoutFailing(BooleanSupplier supplier) {
waitForCondition(supplier, false /*failOnTimeout*/, null /*failure message*/);
waitForCondition(supplier, false /*failOnTimeout*/, () -> null /*failure message*/);
}
private static void waitForCondition(BooleanSupplier condition, boolean failOnTimeout,
String failureMessage) throws AssertionFailedError {
waitForCondition(condition, failOnTimeout, () -> failureMessage);
}
private static void waitForCondition(BooleanSupplier condition, boolean failOnTimeout,
Supplier<String> failureMessageSupplier) throws AssertionFailedError {
int totalTime = 0;
while (totalTime <= DEFAULT_WAIT_TIMEOUT) {
@ -423,8 +443,12 @@ public abstract class AbstractGTest {
return;
}
String error = failureMessage != null ? failureMessage : "Timed-out waiting for condition";
throw new AssertionFailedError(error);
String failureMessage = "Timed-out waiting for condition";
if (failureMessageSupplier != null) {
failureMessage = failureMessageSupplier.get();
}
throw new AssertionFailedError(failureMessage);
}
/**