Skip to content

Commit 7d3e13d

Browse files
authored
Merge pull request #35 from Nordstrom/pr/fix-config-notifications
More thread-related fixes
2 parents abafa92 + e708dda commit 7d3e13d

File tree

4 files changed

+37
-58
lines changed

4 files changed

+37
-58
lines changed

pom.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,6 @@
182182
<groupId>org.apache.maven.plugins</groupId>
183183
<artifactId>maven-surefire-plugin</artifactId>
184184
<configuration>
185-
<parallel>classes</parallel>
186-
<threadCount>5</threadCount>
187185
<argLine>-javaagent:src/test/resources/test-agent.jar</argLine>
188186
</configuration>
189187
</plugin>

src/main/java/com/nordstrom/automation/junit/CreateTest.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,10 @@ public class CreateTest {
1919
private static final ServiceLoader<TestObjectWatcher> objectWatcherLoader;
2020
private static final Map<Object, Object> TARGET_TO_RUNNER = new ConcurrentHashMap<>();
2121
private static final Map<Object, Object> RUNNER_TO_TARGET = new ConcurrentHashMap<>();
22-
private static final ThreadLocal<Integer> COUNTER;
23-
private static final DepthGauge DEPTH;
22+
private static final ThreadLocal<DepthGauge> DEPTH = ThreadLocal.withInitial(DepthGauge::new);
2423

2524
static {
2625
objectWatcherLoader = ServiceLoader.load(TestObjectWatcher.class);
27-
COUNTER = DepthGauge.getCounter();
28-
DEPTH = new DepthGauge(COUNTER);
2926
}
3027

3128
/**
@@ -42,17 +39,17 @@ public static Object intercept(@This final Object runner,
4239

4340
Object testObj;
4441
try {
45-
DEPTH.increaseDepth();
42+
DEPTH.get().increaseDepth();
4643
testObj = LifecycleHooks.callProxy(proxy);
4744
} finally {
48-
DEPTH.decreaseDepth();
45+
DEPTH.get().decreaseDepth();
4946
}
5047

5148
TARGET_TO_RUNNER.put(testObj, runner);
5249
RUNNER_TO_TARGET.put(runner, testObj);
5350
LifecycleHooks.applyTimeout(testObj);
5451

55-
if (DEPTH.atGroundLevel()) {
52+
if (DEPTH.get().atGroundLevel()) {
5653
synchronized(objectWatcherLoader) {
5754
for (TestObjectWatcher watcher : objectWatcherLoader) {
5855
watcher.testObjectCreated(testObj, runner);

src/main/java/com/nordstrom/automation/junit/DepthGauge.java

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,15 @@
22

33
public class DepthGauge {
44

5-
private final ThreadLocal<Integer> counter;
6-
7-
public DepthGauge(ThreadLocal<Integer> counter) {
8-
this.counter = counter;
9-
}
5+
private int counter = 0;
106

117
/**
128
* Determine if the depth is at ground level (i.e. - zero).
139
*
1410
* @return {@code true} if depth is 0; otherwise {@code false}
1511
*/
1612
public boolean atGroundLevel() {
17-
return (0 == currentDepth());
13+
return (0 == counter);
1814
}
1915

2016
/**
@@ -23,25 +19,25 @@ public boolean atGroundLevel() {
2319
* @return current depth count
2420
*/
2521
public int currentDepth() {
26-
return counter.get().intValue();
22+
return counter;
2723
}
2824

2925
/**
3026
* Increment intercept depth counter
3127
*
32-
* @return updated depth count
28+
* @return depth count prior to update
3329
*/
34-
public int increaseDepth() {
35-
return adjustDepth(1);
30+
public synchronized int increaseDepth() {
31+
return adjustDepth(1) - 1;
3632
}
3733

3834
/**
3935
* Decrement intercept depth counter
4036
*
41-
* @return updated depth count
37+
* @return depth count after update
4238
*/
43-
public int decreaseDepth() {
44-
if (counter.get().intValue() > 0) {
39+
public synchronized int decreaseDepth() {
40+
if (counter > 0) {
4541
return adjustDepth(-1);
4642
}
4743
throw new IllegalStateException("Unbalanced depth management; negative depth is prohibited");
@@ -54,23 +50,7 @@ public int decreaseDepth() {
5450
* @return updated depth count
5551
*/
5652
private int adjustDepth(final int delta) {
57-
int i = counter.get().intValue() + delta;
58-
counter.set(Integer.valueOf(i));
59-
return i;
60-
}
61-
62-
/**
63-
* Get depth counter.
64-
*
65-
* @return thread-local integer with initial value of 0
66-
*/
67-
public static ThreadLocal<Integer> getCounter() {
68-
return new InheritableThreadLocal<Integer>() {
69-
@Override
70-
protected Integer initialValue() {
71-
return Integer.valueOf(0);
72-
}
73-
};
53+
counter += delta;
54+
return counter;
7455
}
75-
7656
}

src/main/java/com/nordstrom/automation/junit/RunReflectiveCall.java

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
import static com.nordstrom.automation.junit.LifecycleHooks.getFieldValue;
44

5+
import java.util.HashMap;
6+
import java.util.Map;
57
import java.util.Objects;
68
import java.util.Optional;
79
import java.util.ServiceLoader;
8-
import java.util.Set;
910
import java.util.concurrent.Callable;
10-
import java.util.concurrent.CopyOnWriteArraySet;
11-
1211
import org.junit.After;
1312
import org.junit.AfterClass;
1413
import org.junit.Before;
@@ -30,8 +29,7 @@
3029
public class RunReflectiveCall {
3130

3231
private static final ServiceLoader<MethodWatcher> methodWatcherLoader;
33-
private static final Set<Integer> beforeNotified = new CopyOnWriteArraySet<>();
34-
private static final Set<Integer> afterNotified = new CopyOnWriteArraySet<>();
32+
private static final ThreadLocal<Map<Integer, DepthGauge>> methodDepth = ThreadLocal.withInitial(HashMap::new);
3533

3634
static {
3735
methodWatcherLoader = ServiceLoader.load(MethodWatcher.class);
@@ -82,9 +80,9 @@ public static Object intercept(@This final Object callable, @SuperCall final Cal
8280

8381
Object result = null;
8482
Throwable thrown = null;
85-
fireBeforeInvocation(runner, target, method, params);
8683

8784
try {
85+
fireBeforeInvocation(runner, target, method, params);
8886
result = LifecycleHooks.callProxy(proxy);
8987
} catch (Throwable t) {
9088
thrown = t;
@@ -144,13 +142,16 @@ public static boolean isParticleMethod(FrameworkMethod method) {
144142
* @return {@code true} if event the {@code beforeInvocation} was fired; otherwise {@code false}
145143
*/
146144
private static boolean fireBeforeInvocation(Object runner, Object target, FrameworkMethod method, Object... params) {
147-
if ((runner != null) && (method != null) && (beforeNotified.add(methodHash(runner, method)))) {
148-
synchronized(methodWatcherLoader) {
149-
for (MethodWatcher watcher : methodWatcherLoader) {
150-
watcher.beforeInvocation(runner, target, method, params);
145+
if ((runner != null) && (method != null)) {
146+
DepthGauge depthGauge = methodDepth.get().computeIfAbsent(methodHash(runner, method), k -> new DepthGauge());
147+
if (0 == depthGauge.increaseDepth()) {
148+
synchronized(methodWatcherLoader) {
149+
for (MethodWatcher watcher : methodWatcherLoader) {
150+
watcher.beforeInvocation(runner, target, method, params);
151+
}
151152
}
153+
return true;
152154
}
153-
return true;
154155
}
155156
return false;
156157
}
@@ -167,13 +168,16 @@ private static boolean fireBeforeInvocation(Object runner, Object target, Framew
167168
* @return {@code true} if event the {@code afterInvocation} was fired; otherwise {@code false}
168169
*/
169170
private static boolean fireAfterInvocation(Object runner, Object target, FrameworkMethod method, Throwable thrown) {
170-
if ((runner != null) && (method != null) && (afterNotified.add(methodHash(runner, method)))) {
171-
synchronized(methodWatcherLoader) {
172-
for (MethodWatcher watcher : methodWatcherLoader) {
173-
watcher.afterInvocation(runner, target, method, thrown);
171+
if ((runner != null) && (method != null)) {
172+
DepthGauge depthGauge = methodDepth.get().computeIfAbsent(methodHash(runner, method), k -> new DepthGauge());
173+
if (0 == depthGauge.decreaseDepth()) {
174+
synchronized(methodWatcherLoader) {
175+
for (MethodWatcher watcher : methodWatcherLoader) {
176+
watcher.afterInvocation(runner, target, method, thrown);
177+
}
174178
}
179+
return true;
175180
}
176-
return true;
177181
}
178182
return false;
179183
}
@@ -185,7 +189,7 @@ private static boolean fireAfterInvocation(Object runner, Object target, Framewo
185189
* @param method {@link FrameworkMethod} object
186190
* @return hash code for the specified runner/method pair
187191
*/
188-
private static int methodHash(Object runner, FrameworkMethod method) {
189-
return runner.toString().hashCode() * 31 + method.hashCode();
192+
public static int methodHash(Object runner, FrameworkMethod method) {
193+
return ((Thread.currentThread().hashCode() * 31) + runner.hashCode()) * 31 + method.hashCode();
190194
}
191195
}

0 commit comments

Comments
 (0)