11package com.datadog.iast.util
22
3- import datadog.trace.test.util.DDSpecification
3+
44import groovy.transform.CompileDynamic
5+ import spock.lang.Specification
56
67import java.util.concurrent.Callable
78import java.util.concurrent.CountDownLatch
89import java.util.concurrent.Executors
910import java.util.concurrent.TimeUnit
1011
1112@CompileDynamic
12- class NonBlockingSemaphoreTest extends DDSpecification {
13+ class NonBlockingSemaphoreTest extends Specification {
1314
1415 void 'test that the semaphore controls access to a shared resource (#permitCount )' (final int permitCount) {
1516 given:
@@ -71,6 +72,40 @@ class NonBlockingSemaphoreTest extends DDSpecification {
7172 2 | _
7273 }
7374
75+ void ' can never acquire more permits than the total' (final int permitCount) {
76+ given:
77+ final semaphore = NonBlockingSemaphore.withPermitCount(permitCount)
78+
79+ when:
80+ final acquired = semaphore.acquire(permitCount+1)
81+
82+ then:
83+ !acquired
84+
85+ where:
86+ permitCount | _
87+ 1 | _
88+ 2 | _
89+ }
90+
91+ void ' can perform extra releases' (final int permitCount) {
92+ given:
93+ final semaphore = NonBlockingSemaphore.withPermitCount(permitCount)
94+
95+ when:
96+ for (int i = 0; i < permitCount * 2; i++) {
97+ assert semaphore.release() == permitCount
98+ }
99+
100+ then:
101+ semaphore.available() == permitCount
102+
103+ where:
104+ permitCount | _
105+ 1 | _
106+ 2 | _
107+ }
108+
74109 void ' reset helps recover when there is starvation (#permitCount)' (final int permitCount) {
75110 given:
76111 final semaphore = NonBlockingSemaphore.withPermitCount(permitCount)
@@ -97,24 +132,41 @@ class NonBlockingSemaphoreTest extends DDSpecification {
97132 given:
98133 final int threads = 100
99134 final semaphore = NonBlockingSemaphore.unlimited()
100- final latch = new CountDownLatch(threads)
101- final executors = Executors.newFixedThreadPool(threads)
102135
103136 when:
104137 final acquired = (1..threads).collect {
105- executors.submit({
106- latch.countDown()
107- if (semaphore.acquire()) {
108- TimeUnit.MILLISECONDS.sleep(100)
109- semaphore.release()
110- return 1
111- }
112- return 0
113- } as Callable<Integer>)
114- }.collect { it.get() }.sum()
138+ semaphore.acquire()? 1 : 0
139+ }.collect { it }.sum()
115140
116141 then:
117142 acquired == threads
118143 semaphore.available() == Integer.MAX_VALUE
144+
145+ when:
146+ int availableAfterRelease = semaphore.release()
147+
148+ then:
149+ availableAfterRelease == Integer.MAX_VALUE
150+ semaphore.available() == Integer.MAX_VALUE
151+
152+ when:
153+ semaphore.reset()
154+
155+ then:
156+ semaphore.available() == Integer.MAX_VALUE
157+ }
158+
159+ void ' cannot create a semaphore without at least 1 permit' () {
160+ when:
161+ NonBlockingSemaphore.withPermitCount(0)
162+
163+ then:
164+ thrown(AssertionError)
165+
166+ when:
167+ NonBlockingSemaphore.withPermitCount(-1)
168+
169+ then:
170+ thrown(AssertionError)
119171 }
120172}
0 commit comments