Adds some tests, cleanup a bit

This commit is contained in:
Guillaume Tâche
2024-09-20 08:36:52 +02:00
parent 17086a87ef
commit 703a4c71ae
47 changed files with 1122 additions and 182 deletions

View File

@@ -65,6 +65,7 @@ public class FFmpegSetupManager extends AbstractSetupManager {
case WINDOWS -> installWindows();
case LINUX -> installLinux();
case MAC -> installMac();
case UNKNOWN -> throw new SetupException("Unknown OS : " + configuration.os());
}
}
@@ -179,15 +180,14 @@ public class FFmpegSetupManager extends AbstractSetupManager {
}
}
@Override
public void uninstall() throws SetupException {
deleteFolder(configuration.root());
}
@Override
public void update() throws SetupException {
public void update() {
//TODO
}
private boolean checkSystemFFmpeg() throws IOException {
@@ -195,7 +195,7 @@ public class FFmpegSetupManager extends AbstractSetupManager {
return result.exitCode() == 0;
}
private boolean checkBundledFFmpeg() throws IOException {
private boolean checkBundledFFmpeg() {
return Files.isRegularFile(configuration.bundledFFmpegPath());
}
}

View File

@@ -30,6 +30,9 @@ class TestTarArchiver {
void testDecompress(@TempDir final Path tempDir) throws IOException {
final var file = tempDir.resolve("test.tar");
try (final var in = getClass().getResourceAsStream("in.tar")) {
if (in == null) {
throw new IOException("Unable to find in.tar");
}
Files.copy(in, file);
}
tarArchiver.decompress(file, tempDir);

View File

@@ -30,6 +30,9 @@ class TestXZArchiver {
void testDecompress(@TempDir final Path tempDir) throws IOException {
final var file = tempDir.resolve("in.txt.xz");
try (final var in = getClass().getResourceAsStream("in.txt.xz")) {
if (in == null) {
throw new IOException("Unable to find in.txt.xz");
}
Files.copy(in, file);
}
xzArchiver.decompress(file, tempDir);

View File

@@ -4,6 +4,7 @@ import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider;
@@ -26,7 +27,7 @@ class TestFFmpegVideoConverter {
private final FFmpegVideoConverter converter;
private final ProcessRunner runner;
private final SubtitleConverter subtitleConverter;
private final SubtitleConverter<Subtitle> subtitleConverter;
private final SubtitleConverterProvider subtitleConverterProvider;
private final Video video;
private final VideoInfo videoInfo;
@@ -35,7 +36,7 @@ class TestFFmpegVideoConverter {
private final SubtitleCollection<?> collection;
private final Preferences preferences;
TestFFmpegVideoConverter(@Mock final SubtitleConverter subtitleConverter, @Mock final ProcessRunner runner, @Mock final SubtitleConverterProvider subtitleConverterProvider, @Mock final Video video,
TestFFmpegVideoConverter(@Mock final SubtitleConverter<Subtitle> subtitleConverter, @Mock final ProcessRunner runner, @Mock final SubtitleConverterProvider subtitleConverterProvider, @Mock final Video video,
@Mock final VideoInfo videoInfo, @Mock final SubtitleCollection<?> collection, @Mock final Preferences preferences) throws IOException {
final var output = (OS.getOS() == OS.WINDOWS ? System.getProperty("java.io.tmpdir") : "/tmp");
final var resource = OS.getOS() == OS.WINDOWS ? "fake-ffmpeg.exe" : "fake-ffmpeg.sh";

View File

@@ -33,6 +33,9 @@ class TestFFmpegVideoLoader {
final var resource = OS.getOS() == OS.WINDOWS ? "fake-ffprobe.exe" : "fake-ffprobe.sh";
this.tmpFile = Files.createTempFile("fake-ffprobe", resource.substring(resource.lastIndexOf('.')));
try (final var in = getClass().getResourceAsStream(resource)) {
if (in == null) {
throw new IOException("Unable to find " + resource);
}
Files.copy(in, tmpFile, StandardCopyOption.REPLACE_EXISTING);
}
this.outputPath = Path.of(output, "test-ffprobe-output.txt");

View File

@@ -1,4 +1,274 @@
package com.github.gtache.autosubtitle.setup.ffmpeg;
import com.github.gtache.autosubtitle.archive.Archiver;
import com.github.gtache.autosubtitle.archive.ArchiverProvider;
import com.github.gtache.autosubtitle.impl.Architecture;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.process.ProcessResult;
import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupStatus;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.List;
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class TestFFmpegSetupManager {
private final FFmpegSetupConfiguration configuration;
private final ArchiverProvider archiverProvider;
private final Archiver archiver;
private final ProcessRunner processRunner;
private final HttpClient httpClient;
private final HttpResponse<Path> response;
private final FFmpegSetupManager setupManager;
private final ProcessResult processResult;
private final Path systemPath;
private final Path ffmpegInstallerPath;
private final Path ffprobeInstallerPath;
private final Path rootPath;
TestFFmpegSetupManager(@Mock final FFmpegSetupConfiguration configuration, @Mock final ArchiverProvider archiverProvider,
@Mock final Archiver archiver, @Mock final ProcessRunner processRunner,
@Mock final HttpClient httpClient, @Mock final ProcessResult processResult, @Mock final HttpResponse<Path> response) {
this.configuration = requireNonNull(configuration);
this.archiverProvider = requireNonNull(archiverProvider);
this.archiver = requireNonNull(archiver);
this.processRunner = requireNonNull(processRunner);
this.httpClient = requireNonNull(httpClient);
this.response = requireNonNull(response);
this.setupManager = new FFmpegSetupManager(configuration, archiverProvider, processRunner, httpClient);
this.processResult = requireNonNull(processResult);
this.systemPath = Paths.get("system");
this.ffmpegInstallerPath = Paths.get("ffmpeg.sh");
this.ffprobeInstallerPath = Paths.get("ffprobe.sh");
this.rootPath = Paths.get("root");
}
@BeforeEach
void beforeEach() throws IOException, InterruptedException {
when(configuration.systemFFmpegPath()).thenReturn(systemPath);
when(configuration.root()).thenReturn(rootPath);
when(configuration.ffmpegInstallerPath()).thenReturn(ffmpegInstallerPath);
when(configuration.ffprobeInstallerPath()).thenReturn(ffprobeInstallerPath);
when(archiverProvider.getArchiver("sh")).thenReturn(archiver);
when(archiverProvider.getArchiver("tar")).thenReturn(archiver);
when(processRunner.run(List.of(systemPath.toString(), "-version"), Duration.ofSeconds(5))).thenReturn(processResult);
when(httpClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenReturn(response);
when(response.statusCode()).thenReturn(200);
}
@Test
void testName() {
assertEquals("FFmpeg", setupManager.name());
}
@Test
void testGetStatusSystemFalse() throws IOException, SetupException {
final var ffmpegPath = Paths.get("path");
when(configuration.bundledFFmpegPath()).thenReturn(ffmpegPath);
when(processResult.exitCode()).thenReturn(1);
when(processRunner.run(List.of(systemPath.toString(), "-version"), Duration.ofSeconds(5))).thenReturn(processResult);
assertEquals(SetupStatus.NOT_INSTALLED, setupManager.getStatus());
verify(processRunner).run(List.of(systemPath.toString(), "-version"), Duration.ofSeconds(5));
}
@Test
void testGetStatusSystemException() throws IOException, SetupException {
final var ffmpegPath = Paths.get("path");
when(configuration.bundledFFmpegPath()).thenReturn(ffmpegPath);
when(processRunner.run(List.of(systemPath.toString(), "-version"), Duration.ofSeconds(5))).thenThrow(IOException.class);
assertThrows(SetupException.class, setupManager::getStatus);
verify(processRunner).run(List.of(systemPath.toString(), "-version"), Duration.ofSeconds(5));
}
@Test
void testGetStatusSystemTrue() throws IOException, SetupException {
final var ffmpegPath = Paths.get("path");
when(configuration.bundledFFmpegPath()).thenReturn(ffmpegPath);
when(processRunner.run(List.of(systemPath.toString(), "-version"), Duration.ofSeconds(5))).thenReturn(processResult);
assertEquals(SetupStatus.SYSTEM_INSTALLED, setupManager.getStatus());
verify(processRunner).run(List.of(systemPath.toString(), "-version"), Duration.ofSeconds(5));
}
@Test
void testGetStatusBundledFalse(@TempDir final Path tempDir) throws IOException, SetupException {
final var ffmpegPath = tempDir.resolve("ffmpeg");
Files.deleteIfExists(ffmpegPath);
when(configuration.bundledFFmpegPath()).thenReturn(ffmpegPath);
when(processResult.exitCode()).thenReturn(1);
when(processRunner.run(anyList(), any())).thenReturn(processResult);
assertEquals(SetupStatus.NOT_INSTALLED, setupManager.getStatus());
}
@Test
void testGetStatusBundledTrue(@TempDir final Path tempDir) throws IOException, SetupException {
final var ffmpegPath = tempDir.resolve("ffmpeg");
Files.createFile(ffmpegPath);
when(configuration.bundledFFmpegPath()).thenReturn(ffmpegPath);
when(processResult.exitCode()).thenReturn(1);
when(processRunner.run(anyList(), any())).thenReturn(processResult);
assertEquals(SetupStatus.BUNDLE_INSTALLED, setupManager.getStatus());
}
@Test
void testInstallWindowsDecompressError() throws IOException, InterruptedException {
when(configuration.os()).thenReturn(OS.WINDOWS);
when(configuration.architecture()).thenReturn(Architecture.UNKNOWN);
doThrow(IOException.class).when(archiver).decompress(ffmpegInstallerPath, rootPath);
assertThrows(SetupException.class, setupManager::install);
verify(archiver).decompress(ffmpegInstallerPath, rootPath);
checkURLRequested("https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip");
}
@Test
void testInstallWindows() throws IOException, InterruptedException {
when(configuration.os()).thenReturn(OS.WINDOWS);
when(configuration.architecture()).thenReturn(Architecture.UNKNOWN);
assertDoesNotThrow(setupManager::install);
verify(archiver).decompress(ffmpegInstallerPath, rootPath);
checkURLRequested("https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip");
}
@Test
void testInstallLinuxAMD64() throws IOException, InterruptedException {
when(configuration.os()).thenReturn(OS.LINUX);
when(configuration.architecture()).thenReturn(Architecture.AMD64);
assertDoesNotThrow(setupManager::install);
verify(archiver).decompress(eq(ffmpegInstallerPath), any());
verify(archiver).decompress(any(), eq(rootPath));
checkURLRequested("https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz");
}
@Test
void testInstallLinuxARM64() throws IOException, InterruptedException {
when(configuration.os()).thenReturn(OS.LINUX);
when(configuration.architecture()).thenReturn(Architecture.ARM64);
assertDoesNotThrow(setupManager::install);
verify(archiver).decompress(eq(ffmpegInstallerPath), any());
verify(archiver).decompress(any(), eq(rootPath));
checkURLRequested("https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-arm64-static.tar.xz");
}
@Test
void testInstallLinuxI686() throws IOException, InterruptedException {
when(configuration.os()).thenReturn(OS.LINUX);
when(configuration.architecture()).thenReturn(Architecture.I686);
assertDoesNotThrow(setupManager::install);
verify(archiver).decompress(eq(ffmpegInstallerPath), any());
verify(archiver).decompress(any(), eq(rootPath));
checkURLRequested("https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-i686-static.tar.xz");
}
@Test
void testInstallLinuxARMHF() throws IOException, InterruptedException {
when(configuration.os()).thenReturn(OS.LINUX);
when(configuration.architecture()).thenReturn(Architecture.ARMHF);
assertDoesNotThrow(setupManager::install);
verify(archiver).decompress(eq(ffmpegInstallerPath), any());
verify(archiver).decompress(any(), eq(rootPath));
checkURLRequested("https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-armhf-static.tar.xz");
}
@Test
void testInstallLinuxARMEL() throws IOException, InterruptedException {
when(configuration.os()).thenReturn(OS.LINUX);
when(configuration.architecture()).thenReturn(Architecture.ARMEL);
assertDoesNotThrow(setupManager::install);
verify(archiver).decompress(eq(ffmpegInstallerPath), any());
verify(archiver).decompress(any(), eq(rootPath));
checkURLRequested("https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-armel-static.tar.xz");
}
@Test
void testInstallLinuxUnsupportedArchitecture() {
when(configuration.os()).thenReturn(OS.LINUX);
when(configuration.architecture()).thenReturn(Architecture.UNKNOWN);
assertThrows(SetupException.class, setupManager::install);
verifyNoInteractions(httpClient, archiver);
}
@Test
void testInstallMacAMD64() throws IOException, InterruptedException {
when(configuration.os()).thenReturn(OS.MAC);
when(configuration.architecture()).thenReturn(Architecture.AMD64);
assertDoesNotThrow(setupManager::install);
verify(archiver).decompress(ffmpegInstallerPath, rootPath);
verify(archiver).decompress(ffprobeInstallerPath, rootPath);
final var requestCapture = ArgumentCaptor.forClass(HttpRequest.class);
verify(httpClient, times(2)).send(requestCapture.capture(), any(HttpResponse.BodyHandler.class));
final var request = requestCapture.getAllValues();
assertTrue(request.stream().anyMatch(r -> r.uri().toString().equals("https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip")));
assertTrue(request.stream().anyMatch(r -> r.uri().toString().equals("https://evermeet.cx/ffmpeg/getrelease/ffprobe/zip")));
}
@Test
void testInstallMacARM64() throws IOException, InterruptedException {
when(configuration.os()).thenReturn(OS.MAC);
when(configuration.architecture()).thenReturn(Architecture.ARM64);
assertDoesNotThrow(setupManager::install);
verify(archiver).decompress(ffmpegInstallerPath, rootPath);
verify(archiver).decompress(ffprobeInstallerPath, rootPath);
final var requestCapture = ArgumentCaptor.forClass(HttpRequest.class);
verify(httpClient, times(2)).send(requestCapture.capture(), any(HttpResponse.BodyHandler.class));
final var request = requestCapture.getAllValues();
assertTrue(request.stream().anyMatch(r -> r.uri().toString().equals("https://www.osxexperts.net/ffmpeg7arm.zip")));
assertTrue(request.stream().anyMatch(r -> r.uri().toString().equals("https://www.osxexperts.net/ffprobe7arm.zip")));
}
@Test
void testInstallMacUnsupportedArchitecture() {
when(configuration.os()).thenReturn(OS.MAC);
when(configuration.architecture()).thenReturn(Architecture.ARM32);
assertThrows(SetupException.class, setupManager::install);
verifyNoInteractions(httpClient, archiver);
}
@Test
void testInstallUnknownOS() {
when(configuration.os()).thenReturn(OS.UNKNOWN);
assertThrows(SetupException.class, setupManager::install);
verifyNoInteractions(httpClient, archiver);
}
@Test
void testUninstall(@TempDir final Path tempDir) throws SetupException, IOException {
final var subdir = tempDir.resolve("subfolder");
Files.createDirectories(subdir);
final var subpath = subdir.resolve("subfile");
Files.createFile(subpath);
final var file = tempDir.resolve("rootfile");
Files.createFile(file);
when(configuration.root()).thenReturn(tempDir);
setupManager.uninstall();
assertFalse(Files.exists(tempDir));
}
private void checkURLRequested(final String url) throws IOException, InterruptedException {
final var requestCapture = ArgumentCaptor.forClass(HttpRequest.class);
verify(httpClient).send(requestCapture.capture(), any(HttpResponse.BodyHandler.class));
final var request = requestCapture.getValue();
assertEquals(url, request.uri().toString());
}
}