1
0

M1 Vollständiger Grundstand mit Build, Konfiguration, Tests und Smoke-Tests

This commit is contained in:
2026-03-31 14:04:47 +02:00
commit ea83f8fa8c
52 changed files with 2819 additions and 0 deletions

View File

@@ -0,0 +1 @@
# Keep directory

View File

@@ -0,0 +1,686 @@
package de.gecheckt.pdf.umbenenner.application.config;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for {@link StartConfigurationValidator}.
* <p>
* Tests cover valid configuration, missing mandatory fields, invalid values,
* and path relationship validations.
*/
class StartConfigurationValidatorTest {
private final StartConfigurationValidator validator = new StartConfigurationValidator();
@TempDir
Path tempDir;
@Test
void validate_successWithValidConfiguration() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
tempDir.resolve("lock.lock"),
tempDir.resolve("logs"),
"INFO",
"test-api-key"
);
assertDoesNotThrow(() -> validator.validate(config));
}
@Test
void validate_failsWhenSourceFolderIsNull() {
StartConfiguration config = new StartConfiguration(
null,
tempDir.resolve("target"),
tempDir.resolve("db.sqlite"),
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
tempDir.resolve("prompt.txt"),
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("source.folder: must not be null"));
}
@Test
void validate_failsWhenTargetFolderIsNull() {
StartConfiguration config = new StartConfiguration(
tempDir.resolve("source"),
null,
tempDir.resolve("db.sqlite"),
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
tempDir.resolve("prompt.txt"),
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("target.folder: must not be null"));
}
@Test
void validate_failsWhenSqliteFileIsNull() {
StartConfiguration config = new StartConfiguration(
tempDir.resolve("source"),
tempDir.resolve("target"),
null,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
tempDir.resolve("prompt.txt"),
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("sqlite.file: must not be null"));
}
@Test
void validate_failsWhenApiBaseUrlIsNull() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
null,
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("api.baseUrl: must not be null"));
}
@Test
void validate_failsWhenApiModelIsNull() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
null,
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("api.model: must not be null or blank"));
}
@Test
void validate_failsWhenPromptTemplateFileIsNull() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
null,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("prompt.template.file: must not be null"));
}
@Test
void validate_failsWhenApiTimeoutSecondsIsZeroOrNegative() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
0,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("api.timeoutSeconds: must be > 0"));
}
@Test
void validate_failsWhenMaxRetriesTransientIsNegative() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
-1,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("max.retries.transient: must be >= 0"));
}
@Test
void validate_failsWhenMaxPagesIsZeroOrNegative() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
0,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("max.pages: must be > 0"));
}
@Test
void validate_failsWhenMaxTextCharactersIsZeroOrNegative() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
-1,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("max.text.characters: must be > 0"));
}
@Test
void validate_failsWhenSourceFolderDoesNotExist() throws Exception {
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
tempDir.resolve("nonexistent"),
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("source.folder: path does not exist"));
}
@Test
void validate_failsWhenSourceFolderIsNotADirectory() throws Exception {
Path sourceFile = Files.createFile(tempDir.resolve("sourcefile.txt"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFile,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("source.folder: path is not a directory"));
}
@Test
void validate_failsWhenTargetFolderDoesNotExist() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
tempDir.resolve("nonexistent"),
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("target.folder: path does not exist"));
}
@Test
void validate_failsWhenTargetFolderIsNotADirectory() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFile = Files.createFile(tempDir.resolve("targetfile.txt"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFile,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("target.folder: path is not a directory"));
}
@Test
void validate_failsWhenSqliteFileParentDoesNotExist() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
tempDir.resolve("nonexistent/db.sqlite"),
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("sqlite.file: parent directory does not exist"));
}
@Test
void validate_failsWhenApiBaseUrlIsNotAbsolute() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("/api/v1"),
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("api.baseUrl: must be an absolute URI"));
}
@Test
void validate_failsWhenApiBaseUrlHasUnsupportedScheme() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("ftp://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("api.baseUrl: scheme must be http or https"));
}
@Test
void validate_failsWhenPromptTemplateFileDoesNotExist() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
tempDir.resolve("nonexistent.txt"),
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("prompt.template.file: path does not exist"));
}
@Test
void validate_failsWhenPromptTemplateFileIsNotARegularFile() throws Exception {
Path sourceFolder = Files.createDirectory(tempDir.resolve("source"));
Path targetFolder = Files.createDirectory(tempDir.resolve("target"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path dirForPrompt = Files.createDirectory(tempDir.resolve("promptdir"));
StartConfiguration config = new StartConfiguration(
sourceFolder,
targetFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
dirForPrompt,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("prompt.template.file: path is not a regular file"));
}
@Test
void validate_failsWhenSourceAndTargetAreSamePath() throws Exception {
Path sameFolder = Files.createDirectory(tempDir.resolve("samefolder"));
Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite"));
Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt"));
StartConfiguration config = new StartConfiguration(
sameFolder,
sameFolder,
sqliteFile,
URI.create("https://api.example.com"),
"gpt-4",
30,
3,
100,
50000,
promptTemplateFile,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
assertTrue(exception.getMessage().contains("source.folder and target.folder must not resolve to the same path"));
}
@Test
void validate_failsWhenMultipleErrorsOccur() {
StartConfiguration config = new StartConfiguration(
null,
null,
null,
null,
null,
0,
-1,
0,
-1,
null,
null,
null,
"INFO",
"test-api-key"
);
InvalidStartConfigurationException exception = assertThrows(
InvalidStartConfigurationException.class,
() -> validator.validate(config)
);
String message = exception.getMessage();
assertTrue(message.contains("source.folder: must not be null"));
assertTrue(message.contains("target.folder: must not be null"));
assertTrue(message.contains("sqlite.file: must not be null"));
assertTrue(message.contains("api.baseUrl: must not be null"));
assertTrue(message.contains("api.model: must not be null or blank"));
assertTrue(message.contains("prompt.template.file: must not be null"));
assertTrue(message.contains("api.timeoutSeconds: must be > 0"));
assertTrue(message.contains("max.retries.transient: must be >= 0"));
assertTrue(message.contains("max.pages: must be > 0"));
assertTrue(message.contains("max.text.characters: must be > 0"));
}
}

View File

@@ -0,0 +1 @@
# Keep directory