Skip to content

Commit 2f8c79e

Browse files
author
Matt
committed
Replace naive wait with file watching
1 parent 5f837f1 commit 2f8c79e

File tree

1 file changed

+100
-20
lines changed

1 file changed

+100
-20
lines changed

dd-smoke-tests/tracer-flare/src/test/groovy/datadog/smoketest/TracerFlareSmokeTest.groovy

Lines changed: 100 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ package datadog.smoketest
22

33
import spock.lang.Shared
44

5+
import java.nio.file.FileSystems
6+
import java.nio.file.Path
7+
import java.nio.file.StandardWatchEventKinds
8+
import java.nio.file.WatchEvent
9+
import java.nio.file.WatchKey
10+
import java.nio.file.WatchService
11+
import java.util.concurrent.TimeUnit
512
import java.util.zip.ZipEntry
613
import java.util.zip.ZipInputStream
714

@@ -17,9 +24,7 @@ import java.util.zip.ZipInputStream
1724
class TracerFlareSmokeTest extends AbstractSmokeTest {
1825

1926
// Time in seconds after which flare is triggered
20-
private static final int FLARE_TRIGGER_SECONDS = 10
21-
// Additional buffer time to ensure flare is written to disk
22-
private static final int FLARE_WRITE_BUFFER_SECONDS = 5
27+
private static final int FLARE_TRIGGER_SECONDS = 15
2328
// Number of processes to run in parallel for testing
2429
private static final int NUMBER_OF_PROCESSES = 2
2530

@@ -118,14 +123,22 @@ class TracerFlareSmokeTest extends AbstractSmokeTest {
118123
"profiling_template_override.jfp" // Only if template override is configured
119124
] as Set<String>
120125

121-
def "tracer generates flare with profiling enabled (default)"() {
122-
given:
123-
// Wait for flare to be generated (triggered after FLARE_TRIGGER_SECONDS + buffer time)
124-
Thread.sleep((FLARE_TRIGGER_SECONDS + FLARE_WRITE_BUFFER_SECONDS) * 1000)
126+
// Flare file naming pattern constants
127+
private static final String FLARE_FILE_PREFIX = "dd-java-flare-"
128+
private static final String FLARE_FILE_EXTENSION = ".zip"
129+
130+
/**
131+
* Checks if a filename matches the expected flare file pattern
132+
*/
133+
private static boolean isFlareFile(String fileName) {
134+
fileName.startsWith(FLARE_FILE_PREFIX) && fileName.endsWith(FLARE_FILE_EXTENSION)
135+
}
125136

137+
def "tracer generates flare with profiling enabled (default)"() {
126138
when:
127-
// Find the generated flare file from process 0
128-
def flareFile = findFlareFile(flareDirs[0])
139+
// Wait for flare file to be created using filesystem watcher
140+
// The flare is triggered after FLARE_TRIGGER_SECONDS, plus some write time
141+
def flareFile = waitForFlareFile(flareDirs[0])
129142
def zipContents = extractZipContents(flareFile)
130143
131144
then:
@@ -143,9 +156,9 @@ class TracerFlareSmokeTest extends AbstractSmokeTest {
143156
144157
def "tracer generates flare with profiling disabled"() {
145158
when:
146-
// Find the generated flare file from process 1
147-
// The flare should already be generated from the wait in the first test
148-
def flareFile = findFlareFile(flareDirs[1])
159+
// Wait for flare file to be created independently for process 1
160+
// Each test should be independent and not rely on timing from other tests
161+
def flareFile = waitForFlareFile(flareDirs[1])
149162
def zipContents = extractZipContents(flareFile)
150163
151164
then:
@@ -163,14 +176,6 @@ class TracerFlareSmokeTest extends AbstractSmokeTest {
163176
validateNoUnexpectedFiles(zipContents, CORE_FILES + OPTIONAL_FILES)
164177
}
165178
166-
private static File findFlareFile(File flareDir) {
167-
def flareFiles = flareDir.listFiles({ File dir, String name ->
168-
name.startsWith("dd-java-flare-") && name.endsWith(".zip")
169-
} as FilenameFilter)
170-
assert flareFiles.size() == 1 : "Expected exactly one flare file, found: ${flareFiles.size()}"
171-
flareFiles.first()
172-
}
173-
174179
private static void validateNoUnexpectedFiles(Set<String> zipContents, Set<String> expectedFiles) {
175180
def unexpectedFiles = zipContents - expectedFiles
176181
assert !unexpectedFiles : "Found unexpected files in flare: ${unexpectedFiles}"
@@ -193,4 +198,79 @@ class TracerFlareSmokeTest extends AbstractSmokeTest {
193198
194199
fileNames
195200
}
201+
202+
/**
203+
* Waits for a flare file to be created in the specified directory using filesystem watching.
204+
*
205+
* @param flareDir The directory to watch for flare files
206+
* @param timeoutSeconds Maximum time to wait for the file
207+
* @return The created flare file
208+
* @throws AssertionError if no flare file is created within the timeout
209+
*/
210+
private static File waitForFlareFile(File flareDir, int timeoutSeconds = FLARE_TRIGGER_SECONDS + 5) {
211+
Path dirPath = flareDir.toPath()
212+
WatchService watchService = FileSystems.getDefault().newWatchService()
213+
214+
try {
215+
def existingFile = findFlareFileIfExists(flareDir)
216+
if (existingFile) {
217+
return existingFile
218+
}
219+
220+
dirPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE)
221+
long deadlineMillis = System.currentTimeMillis() + (timeoutSeconds * 1000)
222+
223+
while (System.currentTimeMillis() < deadlineMillis) {
224+
long remainingMillis = deadlineMillis - System.currentTimeMillis()
225+
if (remainingMillis <= 0) {
226+
break
227+
}
228+
229+
WatchKey key = watchService.poll(remainingMillis, TimeUnit.MILLISECONDS)
230+
if (key == null) {
231+
existingFile = findFlareFileIfExists(flareDir)
232+
if (existingFile) {
233+
return existingFile
234+
}
235+
break
236+
}
237+
238+
for (WatchEvent<?> event : key.pollEvents()) {
239+
WatchEvent<Path> pathEvent = (WatchEvent<Path>) event
240+
Path fileName = pathEvent.context()
241+
242+
if (isFlareFile(fileName.toString())) {
243+
return new File(flareDir, fileName.toString())
244+
}
245+
}
246+
247+
boolean valid = key.reset()
248+
if (!valid) {
249+
throw new AssertionError("Watch directory ${flareDir} is no longer accessible")
250+
}
251+
}
252+
253+
existingFile = findFlareFileIfExists(flareDir)
254+
if (existingFile) {
255+
return existingFile
256+
}
257+
258+
throw new AssertionError("No flare file created in ${flareDir} within ${timeoutSeconds} seconds")
259+
260+
} finally {
261+
watchService.close()
262+
}
263+
}
264+
265+
/**
266+
* Attempts to find an existing flare file in the directory.
267+
* Returns null if no flare file exists.
268+
*/
269+
private static File findFlareFileIfExists(File flareDir) {
270+
def flareFiles = flareDir.listFiles({ File dir, String name ->
271+
isFlareFile(name)
272+
} as FilenameFilter)
273+
274+
return flareFiles?.size() > 0 ? flareFiles.first() : null
275+
}
196276
}

0 commit comments

Comments
 (0)