From f9b055b3b574a0355b04426ac4aa19fa527bd4a5 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Sun, 12 Jul 2026 19:06:10 +0100 Subject: [PATCH] test(unit): improve test coverage --- .../services/media/RemuxServiceTest.java | 68 +++++++++++++++---- .../services/media/ThumbnailServiceTest.java | 64 +++++++++++++---- 2 files changed, 105 insertions(+), 27 deletions(-) diff --git a/src/test/java/com/ddf/vodsystem/services/media/RemuxServiceTest.java b/src/test/java/com/ddf/vodsystem/services/media/RemuxServiceTest.java index d95a33e..78fd62d 100644 --- a/src/test/java/com/ddf/vodsystem/services/media/RemuxServiceTest.java +++ b/src/test/java/com/ddf/vodsystem/services/media/RemuxServiceTest.java @@ -1,6 +1,8 @@ package com.ddf.vodsystem.services.media; +import com.ddf.vodsystem.dto.CommandOutput; import com.ddf.vodsystem.dto.ProgressTracker; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -8,11 +10,14 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.io.File; -import java.util.List; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class RemuxServiceTest { @@ -25,24 +30,57 @@ class RemuxServiceTest { @BeforeEach void setUp() { remuxService = new RemuxService(commandRunner); + Thread.interrupted(); + } + + @AfterEach + void clearInterruptFlag() { + Thread.interrupted(); } @Test - void remux_buildsExpectedFfmpegCommand() throws Exception { + void remux_success_completesWithCommandOutput() throws Exception { File input = new File("videos/input.ts"); File output = new File("videos/output.mp4"); + CommandOutput commandOutput = new CommandOutput(); + when(commandRunner.run(anyList(), any())).thenReturn(commandOutput); - remuxService.remux(input, output, new ProgressTracker(), 60f); + var future = remuxService.remux(input, output, new ProgressTracker(), 60f); - verify(commandRunner).run(eq(List.of( - "ffmpeg", - "-progress", "pipe:1", - "-y", - "-i", input.getAbsolutePath(), - "-c:v", "h264", - "-c:a", "aac", - "-f", "mp4", - output.getAbsolutePath() - )), any()); + assertThat(future.get()).isSameAs(commandOutput); + } + + @Test + void remux_ioFailure_completesExceptionally() throws Exception { + when(commandRunner.run(anyList(), any())).thenThrow(new IOException("ffmpeg failed")); + + var future = remuxService.remux( + new File("videos/input.ts"), + new File("videos/output.mp4"), + new ProgressTracker(), + 60f + ); + + assertThatThrownBy(future::get) + .isInstanceOf(ExecutionException.class) + .hasCauseInstanceOf(IOException.class); + assertThat(Thread.currentThread().isInterrupted()).isFalse(); + } + + @Test + void remux_interruption_completesExceptionallyAndRestoresInterruptFlag() throws Exception { + when(commandRunner.run(anyList(), any())).thenThrow(new InterruptedException("interrupted")); + + var future = remuxService.remux( + new File("videos/input.ts"), + new File("videos/output.mp4"), + new ProgressTracker(), + 60f + ); + + assertThatThrownBy(future::get) + .isInstanceOf(ExecutionException.class) + .hasCauseInstanceOf(InterruptedException.class); + assertThat(Thread.currentThread().isInterrupted()).isTrue(); } } diff --git a/src/test/java/com/ddf/vodsystem/services/media/ThumbnailServiceTest.java b/src/test/java/com/ddf/vodsystem/services/media/ThumbnailServiceTest.java index 4fcfbda..3a0f6fc 100644 --- a/src/test/java/com/ddf/vodsystem/services/media/ThumbnailServiceTest.java +++ b/src/test/java/com/ddf/vodsystem/services/media/ThumbnailServiceTest.java @@ -1,15 +1,21 @@ package com.ddf.vodsystem.services.media; +import com.ddf.vodsystem.dto.CommandOutput; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.io.IOException; import java.nio.file.Path; -import java.util.List; +import java.util.concurrent.ExecutionException; -import static org.mockito.Mockito.verify; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class ThumbnailServiceTest { @@ -22,21 +28,55 @@ class ThumbnailServiceTest { @BeforeEach void setUp() { thumbnailService = new ThumbnailService(commandRunner); + Thread.interrupted(); + } + + @AfterEach + void clearInterruptFlag() { + Thread.interrupted(); } @Test - void createThumbnail_buildsExpectedFfmpegCommand() throws Exception { + void createThumbnail_success_completesWithCommandOutput() throws Exception { Path input = Path.of("videos/input.mp4"); Path output = Path.of("thumbnails/output.jpg"); + CommandOutput commandOutput = new CommandOutput(); + when(commandRunner.run(anyList())).thenReturn(commandOutput); - thumbnailService.createThumbnail(input, output, 12.5f); + var future = thumbnailService.createThumbnail(input, output, 12.5f); - verify(commandRunner).run(List.of( - "ffmpeg", - "-ss", "12.5", - "-i", input.toAbsolutePath().toString(), - "-frames:v", "1", - output.toAbsolutePath().toString() - )); + assertThat(future.get()).isSameAs(commandOutput); } -} \ No newline at end of file + + @Test + void createThumbnail_ioFailure_completesExceptionally() throws Exception { + when(commandRunner.run(anyList())).thenThrow(new IOException("ffmpeg failed")); + + var future = thumbnailService.createThumbnail( + Path.of("videos/input.mp4"), + Path.of("thumbnails/output.jpg"), + 12.5f + ); + + assertThatThrownBy(future::get) + .isInstanceOf(ExecutionException.class) + .hasCauseInstanceOf(IOException.class); + assertThat(Thread.currentThread().isInterrupted()).isFalse(); + } + + @Test + void createThumbnail_interruption_completesExceptionallyAndRestoresInterruptFlag() throws Exception { + when(commandRunner.run(anyList())).thenThrow(new InterruptedException("interrupted")); + + var future = thumbnailService.createThumbnail( + Path.of("videos/input.mp4"), + Path.of("thumbnails/output.jpg"), + 12.5f + ); + + assertThatThrownBy(future::get) + .isInstanceOf(ExecutionException.class) + .hasCauseInstanceOf(InterruptedException.class); + assertThat(Thread.currentThread().isInterrupted()).isTrue(); + } +}