Skip to content

Commit 11f491d

Browse files
committed
Add concurrent deprecation logger test
Since deprecation logging involves concurrency, this commit adds a test that the concurrency here is handled safely. Relates #25481
1 parent 30c48ea commit 11f491d

File tree

1 file changed

+88
-4
lines changed

1 file changed

+88
-4
lines changed

qa/evil-tests/src/test/java/org/elasticsearch/common/logging/EvilLoggerTests.java

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@
3030
import org.apache.logging.log4j.message.ParameterizedMessage;
3131
import org.elasticsearch.cli.UserException;
3232
import org.elasticsearch.cluster.ClusterName;
33+
import org.elasticsearch.common.Randomness;
3334
import org.elasticsearch.common.io.PathUtils;
3435
import org.elasticsearch.common.settings.Setting;
3536
import org.elasticsearch.common.settings.Settings;
37+
import org.elasticsearch.common.util.concurrent.ThreadContext;
3638
import org.elasticsearch.env.Environment;
3739
import org.elasticsearch.node.Node;
3840
import org.elasticsearch.test.ESTestCase;
@@ -44,11 +46,18 @@
4446
import java.nio.file.Files;
4547
import java.nio.file.Path;
4648
import java.util.ArrayList;
49+
import java.util.Comparator;
4750
import java.util.List;
51+
import java.util.Set;
52+
import java.util.concurrent.BrokenBarrierException;
53+
import java.util.concurrent.CyclicBarrier;
4854
import java.util.regex.Matcher;
4955
import java.util.regex.Pattern;
56+
import java.util.stream.Collectors;
57+
import java.util.stream.IntStream;
5058

5159
import static org.hamcrest.Matchers.equalTo;
60+
import static org.hamcrest.Matchers.hasItem;
5261
import static org.hamcrest.Matchers.lessThan;
5362
import static org.hamcrest.Matchers.startsWith;
5463

@@ -96,8 +105,7 @@ public void testLocationInfoTest() throws IOException, UserException {
96105
public void testDeprecationLogger() throws IOException, UserException {
97106
setupLogging("deprecation");
98107

99-
final DeprecationLogger deprecationLogger =
100-
new DeprecationLogger(ESLoggerFactory.getLogger("deprecation"));
108+
final DeprecationLogger deprecationLogger = new DeprecationLogger(ESLoggerFactory.getLogger("deprecation"));
101109

102110
final int deprecatedIterations = randomIntBetween(0, 256);
103111
for (int i = 0; i < deprecatedIterations; i++) {
@@ -121,11 +129,87 @@ public void testDeprecationLogger() throws IOException, UserException {
121129
}
122130
}
123131

132+
public void testConcurrentDeprecationLogger() throws IOException, UserException, BrokenBarrierException, InterruptedException {
133+
setupLogging("deprecation");
134+
135+
final DeprecationLogger deprecationLogger = new DeprecationLogger(ESLoggerFactory.getLogger("deprecation"));
136+
137+
final int numberOfThreads = randomIntBetween(2, 4);
138+
final CyclicBarrier barrier = new CyclicBarrier(1 + numberOfThreads);
139+
final List<Thread> threads = new ArrayList<>();
140+
final int iterations = randomIntBetween(1, 4);
141+
for (int i = 0; i < numberOfThreads; i++) {
142+
final Thread thread = new Thread(() -> {
143+
final List<Integer> ids = IntStream.range(0, 128).boxed().collect(Collectors.toList());
144+
Randomness.shuffle(ids);
145+
final ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
146+
DeprecationLogger.setThreadContext(threadContext);
147+
try {
148+
barrier.await();
149+
} catch (final BrokenBarrierException | InterruptedException e) {
150+
throw new RuntimeException(e);
151+
}
152+
for (int j = 0; j < iterations; j++) {
153+
for (final Integer id : ids) {
154+
deprecationLogger.deprecatedAndMaybeLog(Integer.toString(id), "This is a maybe logged deprecation message" + id);
155+
}
156+
}
157+
158+
/*
159+
* We have to manually check that each thread has the right warning headers in the thread context because the act of doing
160+
* this through the test framework on one thread would otherwise clear the thread context and we would be unable to assert
161+
* on the other threads.
162+
*/
163+
final List<String> warnings = threadContext.getResponseHeaders().get("Warning");
164+
final Set<String> actualWarningValues =
165+
warnings.stream().map(DeprecationLogger::extractWarningValueFromWarningHeader).collect(Collectors.toSet());
166+
for (int j = 0; j < 128; j++) {
167+
assertThat(actualWarningValues, hasItem(DeprecationLogger.escape("This is a maybe logged deprecation message" + j)));
168+
}
169+
170+
try {
171+
barrier.await();
172+
} catch (final BrokenBarrierException | InterruptedException e) {
173+
throw new RuntimeException(e);
174+
}
175+
});
176+
threads.add(thread);
177+
thread.start();
178+
}
179+
180+
// synchronize the start of all threads
181+
barrier.await();
182+
183+
// wait for all threads to complete their iterations
184+
barrier.await();
185+
186+
final String deprecationPath =
187+
System.getProperty("es.logs.base_path") +
188+
System.getProperty("file.separator") +
189+
System.getProperty("es.logs.cluster_name") +
190+
"_deprecation.log";
191+
final List<String> deprecationEvents = Files.readAllLines(PathUtils.get(deprecationPath));
192+
// we appended an integer to each log message, use that for sorting
193+
deprecationEvents.sort(Comparator.comparingInt(s -> Integer.parseInt(s.split("message")[1])));
194+
assertThat(deprecationEvents.size(), equalTo(128));
195+
for (int i = 0; i < 128; i++) {
196+
assertLogLine(
197+
deprecationEvents.get(i),
198+
Level.WARN,
199+
"org.elasticsearch.common.logging.DeprecationLogger.deprecated",
200+
"This is a maybe logged deprecation message" + i);
201+
}
202+
203+
for (final Thread thread : threads) {
204+
thread.join();
205+
}
206+
207+
}
208+
124209
public void testDeprecationLoggerMaybeLog() throws IOException, UserException {
125210
setupLogging("deprecation");
126211

127-
final DeprecationLogger deprecationLogger =
128-
new DeprecationLogger(ESLoggerFactory.getLogger("deprecation"));
212+
final DeprecationLogger deprecationLogger = new DeprecationLogger(ESLoggerFactory.getLogger("deprecation"));
129213

130214
final int iterations = randomIntBetween(1, 16);
131215

0 commit comments

Comments
 (0)