diff --git a/README.md b/README.md index 9059068..b89bb5c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,8 @@ docker run --memory 512m --name converter-prod --rm -p 8080:8080 ghcr.io/eugenma Now convert a `docx` to `html` ```bash cd officeconverter -curl -F file=@examples/example.docx "localhost:14080/conversion?format=html" -o /tmp/test.html +curl -F file=@src/test/resources/testfiles/withpictures.docx "localhost:14080/conversion?format=html" -o /tmp/test.html +curl -F file=@src/test/resources/testfiles/template.dotx "localhost:14080/conversion?format=html" -o /tmp/test.html ``` ## Build diff --git a/build.gradle b/build.gradle index 631525e..471d3e7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,5 @@ buildscript { + ext.kotlin_version = '1.8.0' ext { // @see https://mvnrepository.com/artifact/org.jodconverter/jodconverter-local jodconverterVersion = '4.4.6' @@ -22,6 +23,14 @@ buildscript { // @see https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime jaxb = "4.0.1" } + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } + + ext['log4j2.version'] = '2.19.0' } plugins { @@ -41,85 +50,26 @@ plugins { // @see https://plugins.gradle.org/plugin/org.sonarqube id "org.sonarqube" version "3.5.0.2730" + + id "org.jetbrains.kotlin.jvm" version "1.8.0" + id "org.jetbrains.kotlin.plugin.allopen" version "1.8.0" + id "org.jetbrains.kotlin.plugin.spring" version "1.8.0" } apply plugin: 'io.spring.dependency-management' +apply plugin: 'kotlin' apply plugin: 'org.springframework.boot' apply from: 'gradle/repositories.gradle' +apply from: 'gradle/dependencies.gradle' apply from: 'gradle/build.gradle' apply from: 'gradle/tests.gradle' apply from: 'gradle/spring_bootRun.gradle' apply from: 'gradle/sonarqube.gradle' +apply from: 'gradle/kotlin.gradle' +apply from: 'gradle/configuration.gradle' -configurations { - compileOnly { - extendsFrom annotationProcessor - } - - developmentOnly - - providedRuntime - - // needed to get lombok working in our tests - testImplementation { - extendsFrom annotationProcessor - } -} group = 'de.kontextwork' // this lets us set the version during build using cli -Pversion=1.1.1 version = "${version}" -sourceCompatibility = 17 -targetCompatibility = 17 -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' -} - -ext['log4j2.version'] = '2.19.0' - -// @see https://github.com/sbrannen/spring-events/blob/master/build.gradle#L38 -// and @see https://stackoverflow.com/a/54605523/3625317 -dependencies { - implementation( - "org.jodconverter:jodconverter-local:$jodconverterVersion", - "org.jodconverter:jodconverter-spring-boot-starter:$jodconverterVersion", - "org.springframework.boot:spring-boot-starter-web", - "org.springframework:spring-core", - "commons-io:commons-io:$commonsIo", - - // needed when compiling against > Java 8 since jaxb is no longer included - // you would get Error creating bean with name 'xmlModelPlugin': Lookup method resolution failed - "org.glassfish.jaxb:jaxb-runtime:$jaxb" - ) - - testImplementation( - "org.springframework.boot:spring-boot-starter-test", - "org.junit.jupiter:junit-jupiter-api", - "org.junit.jupiter:junit-jupiter-params", - "org.mockito:mockito-core:$mockitoVersion", - "org.mockito:mockito-junit-jupiter:$mockitoVersion", - "org.apache.tika:tika-core:${tikaVersion}", - "org.apache.tika:tika-parsers:${tikaVersion}", - ) - - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") - - annotationProcessor( - "javax.annotation:javax.annotation-api:$javaxAnnotations", - "org.projectlombok:lombok:$lombokVersion" - ) - - testAnnotationProcessor( - "org.projectlombok:lombok:$lombokVersion", - ) - - compileOnly( - "org.projectlombok:lombok:$lombokVersion", - "org.springframework.boot:spring-boot-configuration-processor" - ) - - developmentOnly("org.springframework.boot:spring-boot-devtools") - - providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' -} diff --git a/examples/example.docx b/examples/example.docx deleted file mode 100644 index 2cdb5f3..0000000 Binary files a/examples/example.docx and /dev/null differ diff --git a/gradle/configuration.gradle b/gradle/configuration.gradle new file mode 100644 index 0000000..1dcdecb --- /dev/null +++ b/gradle/configuration.gradle @@ -0,0 +1,24 @@ +configurations { + compileOnly { + // If we enable this, we will rebuild the entire project everytime we change anything, not compile cache + extendsFrom annotationProcessor + } + developmentOnly {} + runtimeClasspath { + extendsFrom developmentOnly + } + + // needed to get lombok working in our tests + testImplementation { + extendsFrom testAnnotationProcessor + // we do not need junit5 asserts / integrations, remove for more auto include convenience + exclude module: 'junit' + // exclude hamcrest so we do not mix assertThat with assertj - we only use assertj + // exclude group: 'org.hamcrest', module: 'hamcrest-library' + // exclude group: 'org.hamcrest', module: 'hamcrest-core' + } + + // Exclude Springs default logging framework since we use Log4j2g + all*.exclude module : 'spring-boot-starter-logging' + all*.exclude module : 'logback-classic' +} diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle new file mode 100644 index 0000000..4582312 --- /dev/null +++ b/gradle/dependencies.gradle @@ -0,0 +1,51 @@ + +// @see https://github.com/sbrannen/spring-events/blob/master/build.gradle#L38 +// and @see https://stackoverflow.com/a/54605523/3625317 +dependencies { + implementation( + "org.jodconverter:jodconverter-local:$jodconverterVersion", + "org.jodconverter:jodconverter-spring-boot-starter:$jodconverterVersion", + "org.springframework.boot:spring-boot-starter-web", + "org.springframework:spring-core", + "commons-io:commons-io:$commonsIo", + + // needed when compiling against > Java 8 since jaxb is no longer included + // you would get Error creating bean with name 'xmlModelPlugin': Lookup method resolution failed + "org.glassfish.jaxb:jaxb-runtime:$jaxb", + + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + 'org.apache.logging.log4j:log4j-api-kotlin:1.2.0' + ) + + testImplementation( + "org.springframework.boot:spring-boot-starter-test", + "org.junit.jupiter:junit-jupiter-api", + "org.junit.jupiter:junit-jupiter-params", + "org.mockito:mockito-core:$mockitoVersion", + "org.mockito:mockito-junit-jupiter:$mockitoVersion", + "org.apache.tika:tika-core:${tikaVersion}", + "org.apache.tika:tika-parsers:${tikaVersion}", + ) + + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") + + annotationProcessor( + "javax.annotation:javax.annotation-api:$javaxAnnotations", + "org.projectlombok:lombok:$lombokVersion" + ) + + testAnnotationProcessor( + "org.projectlombok:lombok:$lombokVersion", + ) + + compileOnly( + "org.projectlombok:lombok:$lombokVersion", + "org.springframework.boot:spring-boot-configuration-processor" + ) + + developmentOnly("org.springframework.boot:spring-boot-devtools") + + runtimeOnly 'org.springframework.boot:spring-boot-starter-tomcat' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" +} diff --git a/gradle/kotlin.gradle b/gradle/kotlin.gradle new file mode 100644 index 0000000..0ed90e1 --- /dev/null +++ b/gradle/kotlin.gradle @@ -0,0 +1,19 @@ +kotlin { + // see https://docs.gradle.org/current/userguide/toolchains.html + jvmToolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +compileKotlin { + compilerOptions { + freeCompilerArgs = ["-Xjsr305=strict"] + } +} + +compileTestKotlin { + compilerOptions { + freeCompilerArgs = ["-Xjsr305=strict"] + } +} + diff --git a/src/main/java/de/kontextwork/converter/ConverterApplication.java b/src/main/java/de/kontextwork/converter/ConverterApplication.java deleted file mode 100644 index 51fe830..0000000 --- a/src/main/java/de/kontextwork/converter/ConverterApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package de.kontextwork.converter; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class ConverterApplication { - - public static void main(String[] args) { - SpringApplication.run(ConverterApplication.class, args); - } -} diff --git a/src/main/java/de/kontextwork/converter/service/ConverterService.java b/src/main/java/de/kontextwork/converter/service/ConverterService.java deleted file mode 100644 index 9612f1f..0000000 --- a/src/main/java/de/kontextwork/converter/service/ConverterService.java +++ /dev/null @@ -1,56 +0,0 @@ -package de.kontextwork.converter.service; - -import de.kontextwork.converter.service.api.UnknownSourceFormat; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import lombok.RequiredArgsConstructor; -import org.apache.commons.io.FilenameUtils; -import org.jodconverter.core.DocumentConverter; -import org.jodconverter.core.document.DefaultDocumentFormatRegistry; -import org.jodconverter.core.document.DocumentFormat; -import org.jodconverter.core.office.OfficeException; -import org.jodconverter.core.office.OfficeManager; -import org.jodconverter.local.LocalConverter; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class ConverterService -{ - private final OfficeManager officeManager; - - public ByteArrayOutputStream doConvert( - final DocumentFormat targetFormat, - final InputStream inputFile, - String inputFileName - ) throws UnknownSourceFormat, OfficeException - { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - final DocumentConverter converter = LocalConverter.builder() - .officeManager(officeManager) - .build(); - - final DocumentFormat sourceFormat = DefaultDocumentFormatRegistry.getFormatByExtension( - FilenameUtils.getExtension(inputFileName) - ); - - if (sourceFormat == null) { - throw new UnknownSourceFormat( - String.format( - "Cannot convert file with extension %s since we cannot find the format in our registry", - FilenameUtils.getExtension(inputFileName) - ) - ); - } - - // Convert... - converter.convert(inputFile) - .as(sourceFormat) - .to(outputStream) - .as(targetFormat) - .execute(); - - return outputStream; - } -} diff --git a/src/main/java/de/kontextwork/converter/service/api/UnknownSourceFormat.java b/src/main/java/de/kontextwork/converter/service/api/UnknownSourceFormat.java deleted file mode 100644 index 6038f7d..0000000 --- a/src/main/java/de/kontextwork/converter/service/api/UnknownSourceFormat.java +++ /dev/null @@ -1,33 +0,0 @@ -package de.kontextwork.converter.service.api; - -public class UnknownSourceFormat extends Exception -{ - public UnknownSourceFormat() - { - } - - public UnknownSourceFormat(final String message) - { - super(message); - } - - public UnknownSourceFormat(final String message, final Throwable cause) - { - super(message, cause); - } - - public UnknownSourceFormat(final Throwable cause) - { - super(cause); - } - - public UnknownSourceFormat( - final String message, - final Throwable cause, - final boolean enableSuppression, - final boolean writableStackTrace - ) - { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/src/main/java/de/kontextwork/converter/web/ConversionController.java b/src/main/java/de/kontextwork/converter/web/ConversionController.java deleted file mode 100644 index 8a3bf8b..0000000 --- a/src/main/java/de/kontextwork/converter/web/ConversionController.java +++ /dev/null @@ -1,66 +0,0 @@ -package de.kontextwork.converter.web; - -import de.kontextwork.converter.service.ConverterService; -import de.kontextwork.converter.service.api.UnknownSourceFormat; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.jodconverter.core.document.DefaultDocumentFormatRegistry; -import org.jodconverter.core.document.DocumentFormat; -import org.jodconverter.core.office.OfficeException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.*; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -@SuppressWarnings({"SpringJavaAutowiredFieldsWarningInspection", "unused"}) -@Log4j2 -@RestController -@RequestMapping("/conversion") -public class ConversionController -{ - @Autowired - private ConverterService converterService; - - @PostMapping(path = "") - @SuppressWarnings("java:S1452") - public ResponseEntity convert( - @RequestParam(name = "format", defaultValue = "pdf") final String targetFormatExt, - @RequestParam("file") final MultipartFile inputMultipartFile - ) throws IOException - { - final DocumentFormat conversionTargetFormat = DefaultDocumentFormatRegistry.getFormatByExtension(targetFormatExt); - - if (conversionTargetFormat == null) { - log.error(String.format("Unknown conversion target %s", targetFormatExt)); - return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED).build(); - } - - ByteArrayOutputStream convertedFile; - try { - convertedFile = converterService.doConvert( - conversionTargetFormat, - inputMultipartFile.getInputStream(), - inputMultipartFile.getOriginalFilename() - ); - } catch (UnknownSourceFormat unknownSourceFormat) { - log.error(unknownSourceFormat.getMessage()); - return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED).body(unknownSourceFormat.getMessage()); - } catch (OfficeException officeException) { - log.error(officeException.getMessage()); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); - } - - final HttpHeaders headers = new HttpHeaders(); - String targetFilename = String.format( - "%s.%s", - FilenameUtils.getBaseName(inputMultipartFile.getOriginalFilename()), - conversionTargetFormat.getExtension() - ); - headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + targetFilename); - headers.setContentType(MediaType.parseMediaType(conversionTargetFormat.getMediaType())); - return ResponseEntity.ok().headers(headers).body(convertedFile.toByteArray()); - } -} - diff --git a/src/main/kotlin/de/kontextwork/converter/ConverterApplication.kt b/src/main/kotlin/de/kontextwork/converter/ConverterApplication.kt new file mode 100644 index 0000000..fb44f53 --- /dev/null +++ b/src/main/kotlin/de/kontextwork/converter/ConverterApplication.kt @@ -0,0 +1,14 @@ +package de.kontextwork.converter + +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.SpringBootApplication + +@SpringBootApplication +class ConverterApplication { + companion object { + @JvmStatic + fun main(args: Array) { + SpringApplication.run(ConverterApplication::class.java, *args) + } + } +} diff --git a/src/main/kotlin/de/kontextwork/converter/base/FileNameUtils.kt b/src/main/kotlin/de/kontextwork/converter/base/FileNameUtils.kt new file mode 100644 index 0000000..736a380 --- /dev/null +++ b/src/main/kotlin/de/kontextwork/converter/base/FileNameUtils.kt @@ -0,0 +1,12 @@ +package de.kontextwork.converter.base + +import org.springframework.stereotype.Component +import java.nio.file.Paths +import kotlin.io.path.name + +@Component +class FileNameUtils { + fun extractFilenameOnly(originalFileName: String): String { + return Paths.get(originalFileName).name + } +} diff --git a/src/main/kotlin/de/kontextwork/converter/module/convert/ConverterService.kt b/src/main/kotlin/de/kontextwork/converter/module/convert/ConverterService.kt new file mode 100644 index 0000000..9a42b26 --- /dev/null +++ b/src/main/kotlin/de/kontextwork/converter/module/convert/ConverterService.kt @@ -0,0 +1,46 @@ +package de.kontextwork.converter.module.convert + +import de.kontextwork.converter.module.convert.api.UnknownSourceFormatException +import org.apache.commons.io.FilenameUtils +import org.jodconverter.core.DocumentConverter +import org.jodconverter.core.document.DefaultDocumentFormatRegistry +import org.jodconverter.core.document.DocumentFormat +import org.jodconverter.core.office.OfficeException +import org.jodconverter.core.office.OfficeManager +import org.jodconverter.local.LocalConverter +import org.springframework.stereotype.Service +import java.io.ByteArrayOutputStream +import java.io.InputStream + +@Service +class ConverterService( + private val officeManager: OfficeManager +) { + @Throws(UnknownSourceFormatException::class, OfficeException::class) + fun doConvert( + targetFormat: DocumentFormat, + inputFile: InputStream, + inputFileName: String + ): ByteArrayOutputStream { + val outputStream = ByteArrayOutputStream() + val converter: DocumentConverter = LocalConverter.builder().officeManager(officeManager).build() + + val sourceFormat = DefaultDocumentFormatRegistry.getFormatByExtension( + FilenameUtils.getExtension(inputFileName) + ) + ?: throw UnknownSourceFormatException( + String.format( + "Cannot convert file with extension %s since we cannot find the format in our registry", + FilenameUtils.getExtension(inputFileName) + ) + ) + + // Convert... + converter.convert(inputFile) + .`as`(sourceFormat) + .to(outputStream) + .`as`(targetFormat) + .execute() + return outputStream + } +} diff --git a/src/main/kotlin/de/kontextwork/converter/module/convert/api/UnknownSourceFormatException.kt b/src/main/kotlin/de/kontextwork/converter/module/convert/api/UnknownSourceFormatException.kt new file mode 100644 index 0000000..06842a1 --- /dev/null +++ b/src/main/kotlin/de/kontextwork/converter/module/convert/api/UnknownSourceFormatException.kt @@ -0,0 +1,3 @@ +package de.kontextwork.converter.module.convert.api + +class UnknownSourceFormatException(message: String) : Exception(message) diff --git a/src/main/kotlin/de/kontextwork/converter/module/convert/controller/ConversionController.kt b/src/main/kotlin/de/kontextwork/converter/module/convert/controller/ConversionController.kt new file mode 100644 index 0000000..b848f25 --- /dev/null +++ b/src/main/kotlin/de/kontextwork/converter/module/convert/controller/ConversionController.kt @@ -0,0 +1,66 @@ +package de.kontextwork.converter.module.convert.controller + +import de.kontextwork.converter.base.FileNameUtils +import de.kontextwork.converter.module.convert.ConverterService +import de.kontextwork.converter.module.convert.api.UnknownSourceFormatException +import org.apache.commons.io.FilenameUtils +import org.apache.logging.log4j.kotlin.Logging +import org.jodconverter.core.document.DefaultDocumentFormatRegistry +import org.jodconverter.core.office.OfficeException +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.multipart.MultipartFile +import java.io.ByteArrayOutputStream +import java.io.IOException + +@RestController +@RequestMapping("/conversion") +class ConversionController( + private val converterService: ConverterService, + private val fileNameUtils: FileNameUtils +) : Logging { + @PostMapping(path = [""]) + @Throws(IOException::class) + fun convert( + @RequestParam(name = "format", defaultValue = "pdf") targetFormatExt: String, + @RequestParam("file") inputMultipartFile: MultipartFile + ): ResponseEntity<*> { + val targetFormat = DefaultDocumentFormatRegistry.getFormatByExtension(targetFormatExt) + if (targetFormat == null) { + logger.error(String.format("Unknown conversion target %s", targetFormatExt)) + return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED).build() + } + + // we preserve the extension only. Anything else could be dangerous + val inputFilename = fileNameUtils.extractFilenameOnly(inputMultipartFile.originalFilename!!) + + val convertedFile: ByteArrayOutputStream = try { + converterService.doConvert(targetFormat, inputMultipartFile.inputStream, inputFilename) + } catch (unknownSourceFormatException: UnknownSourceFormatException) { + logger.error(unknownSourceFormatException.message!!) + return ResponseEntity + .status(HttpStatus.PRECONDITION_FAILED) + .body(unknownSourceFormatException.message) + } catch (officeException: OfficeException) { + logger.error(officeException.message!!) + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .build() + } + // else + + val headers = HttpHeaders() + val targetFilename = "${FilenameUtils.getBaseName(inputFilename)}.${targetFormat.extension}" + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=$targetFilename") + headers.contentType = MediaType.parseMediaType(targetFormat.mediaType) + return ResponseEntity.ok().headers(headers).body(convertedFile.toByteArray()) + } + + +} diff --git a/src/test/java/de/kontextwork/converter/testingUtils/profiles/SetupE2eTest.java b/src/test/java/de/kontextwork/converter/testingUtils/profiles/SetupE2eTest.java deleted file mode 100644 index b5b8d9c..0000000 --- a/src/test/java/de/kontextwork/converter/testingUtils/profiles/SetupE2eTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.kontextwork.converter.testingUtils.profiles; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -/** - * use that for full stack tests against real *SQL/mongodb databases with prefilled test DBs - * dwtest1 / dwtest 2 - */ -@SuppressWarnings("unused") -@Tag("e2e") -@ActiveProfiles("e2e") -@ExtendWith(SpringExtension.class) -@ExtendWith(MockitoExtension.class) -@Retention(RetentionPolicy.RUNTIME) -public @interface SetupE2eTest -{} diff --git a/src/test/java/de/kontextwork/converter/testingUtils/profiles/SetupItTest.java b/src/test/java/de/kontextwork/converter/testingUtils/profiles/SetupItTest.java deleted file mode 100644 index 4f989e8..0000000 --- a/src/test/java/de/kontextwork/converter/testingUtils/profiles/SetupItTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package de.kontextwork.converter.testingUtils.profiles; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -/** - * use this for integration tests and most probably combine this with a test-slice - */ -@Tag("it") -@ActiveProfiles("it") -@ExtendWith(SpringExtension.class) -@ExtendWith(MockitoExtension.class) -@Import({}) -@Retention(RetentionPolicy.RUNTIME) -public @interface SetupItTest -{ -} diff --git a/src/test/java/de/kontextwork/converter/testingUtils/profiles/SetupUnitTest.java b/src/test/java/de/kontextwork/converter/testingUtils/profiles/SetupUnitTest.java deleted file mode 100644 index 919dda4..0000000 --- a/src/test/java/de/kontextwork/converter/testingUtils/profiles/SetupUnitTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package de.kontextwork.converter.testingUtils.profiles; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.test.context.ActiveProfiles; - -/** - * Pure unit tests, no spring bootstrap - fast any easy - */ -@Tag("unit") -@ActiveProfiles("unit") -@ExtendWith(MockitoExtension.class) -@Retention(RetentionPolicy.RUNTIME) -public @interface SetupUnitTest -{} diff --git a/src/test/java/de/kontextwork/converter/testingUtils/slices/CustomSpringBootTestSlice.java b/src/test/java/de/kontextwork/converter/testingUtils/slices/CustomSpringBootTestSlice.java deleted file mode 100644 index 5fd7fcc..0000000 --- a/src/test/java/de/kontextwork/converter/testingUtils/slices/CustomSpringBootTestSlice.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.kontextwork.converter.testingUtils.slices; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import org.junit.jupiter.api.Tag; -import org.springframework.boot.test.context.SpringBootTest; - -/** - * Use this test slice for a full spring boot test bootstrap, including database, controllers and everything else - */ -@SuppressWarnings("unused") -@SpringBootTest -@Retention(RetentionPolicy.RUNTIME) -public @interface CustomSpringBootTestSlice -{ - -} diff --git a/src/test/java/de/kontextwork/converter/testingUtils/slices/CustomWebMvcWithJpaTestSlice.java b/src/test/java/de/kontextwork/converter/testingUtils/slices/CustomWebMvcWithJpaTestSlice.java deleted file mode 100644 index 57ef05f..0000000 --- a/src/test/java/de/kontextwork/converter/testingUtils/slices/CustomWebMvcWithJpaTestSlice.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.kontextwork.converter.testingUtils.slices; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import org.junit.jupiter.api.Tag; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; - -/** - * Use this test slice for a full spring boot test bootstrap, including database, controllers and everything else - */ -@SpringBootTest( - properties = { - "logging.level.org.springframework.web=TRACE" - } -) -@AutoConfigureCache -@AutoConfigureMockMvc -@ImportAutoConfiguration -@Retention(RetentionPolicy.RUNTIME) -@Tag("controller-test") -public @interface CustomWebMvcWithJpaTestSlice -{ - -} diff --git a/src/test/java/de/kontextwork/converter/web/ConversionControllerTest.java b/src/test/java/de/kontextwork/converter/web/ConversionControllerTest.java deleted file mode 100644 index f6015fc..0000000 --- a/src/test/java/de/kontextwork/converter/web/ConversionControllerTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package de.kontextwork.converter.web; - -import de.kontextwork.converter.testingUtils.profiles.SetupItTest; -import de.kontextwork.converter.testingUtils.slices.CustomWebMvcWithJpaTestSlice; -import org.apache.commons.io.FilenameUtils; -import org.apache.tika.Tika; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.Resource; -import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.web.servlet.MockMvc; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -@SetupItTest -@CustomWebMvcWithJpaTestSlice -class ConversionControllerTest -{ - @Value("classpath:testfiles/withpictures.docx") - private Resource testDocx; - - @Value("classpath:testfiles/template.dotx") - private Resource testDotx; - - @Value("classpath:testfiles/template.xltx") - private Resource testXltx; - - final private String requestUrl = "/conversion"; - - @Autowired - private MockMvc mockMvc; - - @Test - @DisplayName("Should convert docx to html") - void convertWorks() throws Exception - { - var tika = new Tika(); - Resource testResource = testDocx; - - String mimeType = tika.detect(testResource.getFile()); - var testFile = new MockMultipartFile("file", testResource.getFilename(), mimeType, testResource.getInputStream()); - - var targetFilename = String.format("%s.%s", FilenameUtils.getBaseName(testResource.getFilename()), "html"); - var targetMimeType = tika.detect(targetFilename); // should be html obviously - - mockMvc - .perform( - multipart(requestUrl) - .file(testFile) - .param("format", "html") - ) - .andExpect(status().isOk()) - .andExpect(header().string("Content-Disposition", "attachment; filename=" + targetFilename)) - .andExpect(content().contentType(targetMimeType)); - } - - @Test - @DisplayName("Should convert dotx to html") - void convertDotxWorks() throws Exception - { - var tika = new Tika(); - Resource testResource = testDotx; - - String mimeType = tika.detect(testResource.getFile()); - var testFile = new MockMultipartFile("file", testResource.getFilename(), mimeType, testResource.getInputStream()); - - var targetFilename = String.format("%s.%s", FilenameUtils.getBaseName(testResource.getFilename()), "html"); - var targetMimeType = tika.detect(targetFilename); // should be html obviously - - mockMvc - .perform( - multipart(requestUrl) - .file(testFile) - .param("format", "html") - ) - .andExpect(status().isOk()) - .andExpect(header().string("Content-Disposition", "attachment; filename=" + targetFilename)) - .andExpect(content().contentType(targetMimeType)); - } - - @Test - @DisplayName("Should convert xltx to html") - void convertXltxWorks() throws Exception - { - var tika = new Tika(); - Resource testResource = testXltx; - - String mimeType = tika.detect(testResource.getFile()); - var testFile = new MockMultipartFile("file", testResource.getFilename(), mimeType, testResource.getInputStream()); - - var targetFilename = String.format("%s.%s", FilenameUtils.getBaseName(testResource.getFilename()), "html"); - var targetMimeType = tika.detect(targetFilename); // should be html obviously - - mockMvc - .perform( - multipart(requestUrl) - .file(testFile) - .param("format", "html") - ) - .andExpect(status().isOk()) - .andExpect(header().string("Content-Disposition", "attachment; filename=" + targetFilename)) - .andExpect(content().contentType(targetMimeType)); - } - - @Test - @DisplayName("Should convert docx to html using embedded images") - void convertToHtmlEmbedsImages() throws Exception - { - var tika = new Tika(); - Resource testResource = testDocx; - - String mimeType = tika.detect(testResource.getFile()); - var testFile = new MockMultipartFile("file", testResource.getFilename(), mimeType, testResource.getInputStream()); - - var targetFilename = String.format("%s.%s", FilenameUtils.getBaseName(testResource.getFilename()), "html"); - var targetMimeType = tika.detect(targetFilename); // should be html obviously - - mockMvc - .perform( - multipart(requestUrl) - .file(testFile) - .param("format", "html") - ) - .andExpect(status().isOk()) - .andExpect(header().string("Content-Disposition", "attachment; filename=" + targetFilename)) - .andExpect(content().contentType(targetMimeType)) - .andExpect(content().string(containsString("> = [], + @get:AliasFor(annotation = WebMvcTest::class, attribute = "controllers") val controllers: Array> = [] +) { +}