Skip to content

Commit af30cc1

Browse files
authored
Add more tests to NonBlockingSemaphore and make boolean semaphore release atomic (#8446)
1 parent 6d2c673 commit af30cc1

File tree

2 files changed

+67
-15
lines changed

2 files changed

+67
-15
lines changed

dd-java-agent/agent-iast/src/main/java/com/datadog/iast/util/NonBlockingSemaphore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public boolean acquire(final int count) {
6666
@Override
6767
public int release(final int count) {
6868
reset();
69-
return available();
69+
return 1;
7070
}
7171

7272
@Override

dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/util/NonBlockingSemaphoreTest.groovy

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package com.datadog.iast.util
22

3-
import datadog.trace.test.util.DDSpecification
3+
44
import groovy.transform.CompileDynamic
5+
import spock.lang.Specification
56

67
import java.util.concurrent.Callable
78
import java.util.concurrent.CountDownLatch
89
import java.util.concurrent.Executors
910
import 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

Comments
 (0)