Skip to content

Commit 80df79d

Browse files
committed
Replace custom retry with eventually
1 parent 0e38adb commit 80df79d

File tree

1 file changed

+89
-49
lines changed

1 file changed

+89
-49
lines changed

src/test/scala/alpakka/file/DirectoryWatcherSpec.scala

Lines changed: 89 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package alpakka.file
22

33
import alpakka.file.uploader.DirectoryWatcher
44
import org.apache.commons.io.FileUtils
5+
import org.scalatest.concurrent.Eventually
56
import org.scalatest.matchers.should.Matchers
7+
import org.scalatest.time.{Seconds, Span}
68
import org.scalatest.wordspec.AsyncWordSpec
79
import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEachTestData, TestData}
810
import org.slf4j.{Logger, LoggerFactory}
@@ -18,83 +20,134 @@ import scala.util.Random
1820
* Hence we:
1921
* - create the dir structure and copy files before each test
2022
* - clean up dir structure after each test
21-
* - use a shared watcher instance for all tests
2223
*/
23-
final class DirectoryWatcherSpec extends AsyncWordSpec with Matchers with BeforeAndAfterAll with BeforeAndAfterEachTestData {
24+
final class DirectoryWatcherSpec extends AsyncWordSpec with Matchers with BeforeAndAfterAll with BeforeAndAfterEachTestData with Eventually {
2425
val logger: Logger = LoggerFactory.getLogger(this.getClass)
25-
26-
var watcher: DirectoryWatcher = _
26+
val defaultTimeout: FiniteDuration = 5.seconds
27+
implicit val patience: PatienceConfig = PatienceConfig(timeout = Span(20, Seconds))
2728
var tmpRootDir: Path = _
2829
var uploadDir: Path = _
2930
var processedDir: Path = _
3031

32+
case class WatcherFixture(watcher: DirectoryWatcher) {
33+
def withWatcher[T](testCode: DirectoryWatcher => T): T = {
34+
try {
35+
testCode(watcher)
36+
} finally {
37+
Await.result(watcher.stop(), defaultTimeout)
38+
}
39+
}
40+
}
41+
3142
"DirectoryWatcher" should {
3243
"detect_files_on_startup_in_parent_dir" in {
33-
watcher = DirectoryWatcher(uploadDir, processedDir)
34-
waitForCondition(3.seconds)(watcher.countFilesProcessed() == 2) shouldBe true
44+
WatcherFixture(DirectoryWatcher(uploadDir, processedDir))
45+
.withWatcher { watcher =>
46+
eventually {
47+
watcher.countFilesProcessed() shouldBe 2
48+
}
49+
}
3550
}
3651

52+
3753
"detect_added_file_at_runtime_in_parent_dir" in {
38-
watcher = DirectoryWatcher(uploadDir, processedDir)
3954
copyTestFileToDir(uploadDir)
40-
waitForCondition(3.seconds)(watcher.countFilesProcessed() == 2 + 1) shouldBe true
55+
WatcherFixture(DirectoryWatcher(uploadDir, processedDir))
56+
.withWatcher { watcher =>
57+
eventually {
58+
watcher.countFilesProcessed() shouldBe 2 + 1
59+
}
60+
}
4161
}
4262

4363
"detect_added_files_at_runtime_in_sub_dir" in {
44-
watcher = DirectoryWatcher(uploadDir, processedDir)
4564
copyTestFileToDir(uploadDir.resolve("subdir"))
46-
waitForCondition(3.seconds)(watcher.countFilesProcessed() == 2 + 1) shouldBe true
65+
WatcherFixture(DirectoryWatcher(uploadDir, processedDir))
66+
.withWatcher { watcher =>
67+
eventually {
68+
watcher.countFilesProcessed() shouldBe 2 + 1
69+
}
70+
}
4771
}
4872

4973
"detect_added_nested_subdir_at_runtime_with_files_in_subdir" in {
50-
watcher = DirectoryWatcher(uploadDir, processedDir)
51-
val tmpDir = Files.createTempDirectory("tmp")
52-
val sourcePath = Paths.get("src/main/resources/testfile.jpg")
53-
val targetPath = tmpDir.resolve(createUniqueFileName(sourcePath.getFileName))
54-
val targetPath2 = tmpDir.resolve(createUniqueFileName(sourcePath.getFileName))
55-
Files.copy(sourcePath, targetPath)
56-
Files.copy(sourcePath, targetPath2)
57-
val targetDir = Files.createDirectories(uploadDir.resolve("subdir").resolve("nestedDirWithFiles"))
58-
FileUtils.copyDirectory(tmpDir.toFile, targetDir.toFile)
59-
waitForCondition(3.seconds)(watcher.countFilesProcessed() == 2 + 2) shouldBe true
74+
val tmpDir = Files.createTempDirectory("tmp")
75+
val sourcePath = Paths.get("src/main/resources/testfile.jpg")
76+
val targetPath = tmpDir.resolve(createUniqueFileName(sourcePath.getFileName))
77+
val targetPath2 = tmpDir.resolve(createUniqueFileName(sourcePath.getFileName))
78+
Files.copy(sourcePath, targetPath)
79+
Files.copy(sourcePath, targetPath2)
80+
val targetDir = Files.createDirectories(uploadDir.resolve("subdir").resolve("nestedDirWithFiles"))
81+
FileUtils.copyDirectory(tmpDir.toFile, targetDir.toFile)
82+
WatcherFixture(DirectoryWatcher(uploadDir, processedDir))
83+
.withWatcher { watcher =>
84+
eventually {
85+
watcher.countFilesProcessed() shouldBe 2 + 2
86+
}
87+
}
6088
}
6189

6290
"handle_large_number_of_files_in_parent_dir" in {
6391
(1 to 1000).foreach(_ => copyTestFileToDir(uploadDir))
64-
watcher = DirectoryWatcher(uploadDir, processedDir)
65-
waitForCondition(20.seconds)(watcher.countFilesProcessed() == 2 + 1000) shouldBe true
92+
WatcherFixture(DirectoryWatcher(uploadDir, processedDir))
93+
.withWatcher { watcher =>
94+
eventually {
95+
watcher.countFilesProcessed() shouldBe 2 + 1000
96+
}
97+
}
6698
}
6799

68100
"handle_invalid_parent_directory_path" in {
69101
val invalidParentDir = Paths.get("/path/to/non-existent/directory")
70102
val processedDir = Files.createTempDirectory("processed")
71103

72104
the[IllegalArgumentException] thrownBy {
73-
watcher = DirectoryWatcher(invalidParentDir, processedDir)
105+
DirectoryWatcher(invalidParentDir, processedDir)
74106
} should have message s"Invalid upload directory path: $invalidParentDir"
75107
}
76108
}
77109

78110
override protected def beforeEach(testData: TestData): Unit = {
79111
logger.info(s"Starting test: ${testData.name}")
80112

81-
tmpRootDir = Files.createTempDirectory(testData.text)
82-
logger.info(s"Created tmp root dir: $tmpRootDir")
83-
84-
uploadDir = tmpRootDir.resolve("upload")
85-
processedDir = tmpRootDir.resolve("processed")
86-
Files.createDirectories(uploadDir)
87-
Files.createDirectories(uploadDir.resolve("subdir"))
88-
Files.createDirectories(processedDir)
113+
def withDirectoryCreation[T](action: => T): T = {
114+
try {
115+
tmpRootDir = Files.createTempDirectory(testData.text)
116+
logger.info(s"Created tmp root dir: $tmpRootDir")
117+
118+
uploadDir = tmpRootDir.resolve("upload")
119+
processedDir = tmpRootDir.resolve("processed")
120+
121+
Files.createDirectories(uploadDir)
122+
Files.createDirectories(uploadDir.resolve("subdir"))
123+
Files.createDirectories(processedDir)
124+
125+
action
126+
} catch {
127+
case ex: Exception =>
128+
logger.error(s"Failed to set up test directories: ${ex.getMessage}")
129+
if (tmpRootDir != null) {
130+
FileUtils.deleteDirectory(tmpRootDir.toFile)
131+
}
132+
throw ex
133+
}
134+
}
89135

90-
// Populate dirs BEFORE startup
91-
copyTestFileToDir(tmpRootDir.resolve("upload"))
92-
copyTestFileToDir(tmpRootDir.resolve("upload/subdir"))
136+
withDirectoryCreation {
137+
// Populate dirs BEFORE startup
138+
try {
139+
copyTestFileToDir(uploadDir)
140+
copyTestFileToDir(uploadDir.resolve("subdir"))
141+
} catch {
142+
case ex: Exception =>
143+
logger.error(s"Failed to copy test files: ${ex.getMessage}")
144+
throw ex
145+
}
146+
}
93147
}
94148

95149
override protected def afterEach(testData: TestData): Unit = {
96150
logger.info(s"Cleaning up after test: ${testData.name}")
97-
if (watcher != null) Await.result(watcher.stop(), 5.seconds)
98151
FileUtils.deleteDirectory(tmpRootDir.toFile)
99152
logger.info(s"Finished test: ${testData.name}")
100153
}
@@ -104,21 +157,8 @@ final class DirectoryWatcherSpec extends AsyncWordSpec with Matchers with Before
104157
val targetPath = target.resolve(createUniqueFileName(createUniqueFileName(sourcePath.getFileName)))
105158
Files.copy(sourcePath, targetPath)
106159
}
107-
108160
private def createUniqueFileName(fileName: Path) = {
109161
val parts = fileName.toString.split('.').map(_.trim)
110162
Paths.get(s"${parts.head}${Random.nextInt()}.${parts.reverse.head}")
111163
}
112-
113-
private def waitForCondition(maxDuration: FiniteDuration)(condition: => Boolean): Boolean = {
114-
val startTime = System.currentTimeMillis()
115-
var elapsed = 0.millis
116-
117-
while (!condition && elapsed < maxDuration) {
118-
Thread.sleep(100)
119-
elapsed = (System.currentTimeMillis() - startTime).millis
120-
}
121-
logger.info("Condition reached after: {} ms", elapsed.toMillis)
122-
condition
123-
}
124-
}
164+
}

0 commit comments

Comments
 (0)