1
1
package org .testcontainers .junit .jupiter ;
2
2
3
+ import java .util .concurrent .ConcurrentHashMap ;
4
+ import java .util .concurrent .atomic .AtomicInteger ;
3
5
import lombok .Getter ;
4
6
import org .junit .jupiter .api .extension .AfterAllCallback ;
5
7
import org .junit .jupiter .api .extension .AfterEachCallback ;
@@ -41,6 +43,7 @@ public class TestcontainersExtension
41
43
private static final String SHARED_LIFECYCLE_AWARE_CONTAINERS = "sharedLifecycleAwareContainers" ;
42
44
43
45
private static final String LOCAL_LIFECYCLE_AWARE_CONTAINERS = "localLifecycleAwareContainers" ;
46
+ private static final ConcurrentHashMap <String , StoreAdapterThread > STORE_ADAPTER_THREADS = new ConcurrentHashMap <>();
44
47
45
48
@ Override
46
49
public void beforeAll (ExtensionContext context ) {
@@ -74,7 +77,7 @@ private void startContainers(List<StoreAdapter> storeAdapters, Store store, Exte
74
77
Stream <Startable > startables = storeAdapters
75
78
.stream ()
76
79
.map (storeAdapter -> {
77
- store .getOrComputeIfAbsent (storeAdapter .getKey (), k -> storeAdapter );
80
+ store .getOrComputeIfAbsent (storeAdapter .getKey (), k -> storeAdapterStart ( k , storeAdapter ) );
78
81
return storeAdapter .container ;
79
82
});
80
83
Startables .deepStart (startables ).join ();
@@ -130,6 +133,20 @@ public void afterEach(ExtensionContext context) {
130
133
signalAfterTestToContainersFor (LOCAL_LIFECYCLE_AWARE_CONTAINERS , context );
131
134
}
132
135
136
+ private static synchronized StoreAdapter storeAdapterStart (String key , StoreAdapter adapter ) {
137
+ boolean isInitialized = STORE_ADAPTER_THREADS .containsKey (key );
138
+
139
+ if (!isInitialized ) {
140
+ StoreAdapter storeAdapter = adapter .start ();
141
+ STORE_ADAPTER_THREADS .put (key , new StoreAdapterThread (storeAdapter ));
142
+ return storeAdapter ;
143
+ }
144
+
145
+ StoreAdapterThread storeAdapter = STORE_ADAPTER_THREADS .get (key );
146
+ storeAdapter .threads .incrementAndGet ();
147
+ return storeAdapter .storeAdapter ;
148
+ }
149
+
133
150
private void signalBeforeTestToContainers (
134
151
List <TestLifecycleAware > lifecycleAwareContainers ,
135
152
TestDescription testDescription
@@ -267,9 +284,9 @@ private static StoreAdapter getContainerInstance(final Object testInstance, fina
267
284
private static class StoreAdapter implements CloseableResource {
268
285
269
286
@ Getter
270
- private String key ;
287
+ private final String key ;
271
288
272
- private Startable container ;
289
+ private final Startable container ;
273
290
274
291
private StoreAdapter (Class <?> declaringClass , String fieldName , Startable container ) {
275
292
this .key = declaringClass .getName () + "." + fieldName ;
@@ -283,7 +300,25 @@ private StoreAdapter start() {
283
300
284
301
@ Override
285
302
public void close () {
286
- container .stop ();
303
+ int total = STORE_ADAPTER_THREADS .getOrDefault (key , StoreAdapterThread .NULL ).threads .decrementAndGet ();
304
+ if (total < 1 ) {
305
+ container .stop ();
306
+ STORE_ADAPTER_THREADS .remove (key );
307
+ }
308
+ }
309
+
310
+ }
311
+
312
+ private static class StoreAdapterThread {
313
+
314
+ public static final StoreAdapterThread NULL = new StoreAdapterThread (null );
315
+ public final StoreAdapter storeAdapter ;
316
+ public final AtomicInteger threads = new AtomicInteger (1 );
317
+
318
+ private StoreAdapterThread (StoreAdapter storeAdapter ) {
319
+ this .storeAdapter = storeAdapter ;
287
320
}
321
+
288
322
}
323
+
289
324
}
0 commit comments