From 060d9284fe7530645df465b60df316250b4c1c84 Mon Sep 17 00:00:00 2001 From: Esta Nagy Date: Fri, 29 Jul 2022 12:43:30 +0200 Subject: [PATCH] Optimize report generation (#119) - Removes Spring and spring Boot dependencies from Flight Evaluation report - Adds vanilla app context creation code - Configures Thymeleaf manually - Updates tests - Configures logging - Removes unused configuration Resolves #118 {minor} Signed-off-by: Esta Nagy --- build.gradle | 3 +- gradle/libs.versions.toml | 15 +- gradle/verification-metadata.xml | 180 ------------------ .../flight-evaluation-report/build.gradle | 23 +-- .../flight-evaluation-report/lombok.config | 1 + .../reporting/AbortMissionAppContext.java | 40 ++++ ...AbortMissionFlightEvaluationReportApp.java | 31 ++- .../reporting/PropertiesParser.java | 40 ++++ .../config/ConversionProperties.java | 61 ++++-- .../controller/ConversionController.java | 30 +-- .../reporting/exception/RenderException.java | 8 +- .../reporting/html/ClassHtml.java | 6 +- .../reporting/html/LaunchHtml.java | 4 +- .../reporting/html/StageLaunchStatsHtml.java | 3 +- .../reporting/html/StatsHtml.java | 4 +- .../converter/ClassJsonToHtmlConverter.java | 19 +- .../converter/LaunchJsonToHtmlConverter.java | 28 +-- .../StageLaunchStatsJsonToHtmlConverter.java | 22 +-- .../converter/StatsJsonToHtmlConverter.java | 10 +- .../boot/loader/JarLauncher.java | 17 ++ .../src/main/resources/application.properties | 24 --- .../src/main/resources/logback.xml | 11 ++ ...ghtEvaluationReportAppIntegrationTest.java | 51 ++++- .../config/ConversionPropertiesTest.java | 36 ++++ .../ConversionControllerIntegrationTest.java | 51 +++-- .../ClassJsonToHtmlConverterTest.java | 18 +- .../LaunchJsonToHtmlConverterTest.java | 41 ++-- ...ageLaunchStatsJsonToHtmlConverterTest.java | 25 ++- .../StatsJsonToHtmlConverterTest.java | 2 +- 29 files changed, 434 insertions(+), 370 deletions(-) create mode 100644 mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/AbortMissionAppContext.java create mode 100644 mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/PropertiesParser.java create mode 100644 mission-report/flight-evaluation-report/src/main/java/org/springframework/boot/loader/JarLauncher.java delete mode 100644 mission-report/flight-evaluation-report/src/main/resources/application.properties create mode 100644 mission-report/flight-evaluation-report/src/main/resources/logback.xml create mode 100644 mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/config/ConversionPropertiesTest.java diff --git a/build.gradle b/build.gradle index dab51eb5..b14f9bb5 100644 --- a/build.gradle +++ b/build.gradle @@ -146,7 +146,8 @@ configure(subprojects.findAll({ "com.github.nagyesta.abortmission.testkit.vanilla.ParachuteDropTestAssets", "com.github.nagyesta.abortmission.testkit.NoOpMatcher", "com.github.nagyesta.abortmission.booster.junit4.support.LaunchAbortTestWatcher.1", - "com.github.nagyesta.abortmission.reporting.AbortMissionFlightEvaluationReportApp" + "com.github.nagyesta.abortmission.reporting.AbortMissionFlightEvaluationReportApp", + "org.springframework.boot.loader.JarLauncher" ] } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a288a8e5..00987110 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,8 @@ [versions] spring = "5.3.21" springBoot = "2.7.1" +thymeleaf = "3.0.15.RELEASE" +thymeleafExtrasTime = "3.0.4.RELEASE" logback = "1.2.11" jsonSchemaValidator = "1.0.71" gson = "2.9.0" @@ -9,6 +11,7 @@ h2 = "2.1.214" jdbi3 = "3.30.0" lombok = "1.18.24" +findbugs = "3.0.2" junit4 = "4.13.2" jupiter = "5.8.2" @@ -18,7 +21,6 @@ cucumber = "7.4.1" testNg = "7.6.1" lombokPlugin = "6.5.0.3" -springBootPlugin = "2.7.2" minifyPlugin = "1.3.1" gitVersionerPlugin = "1.6.7" indexScanPlugin = "2.3.0" @@ -30,15 +32,14 @@ jacoco = "0.8.2" [libraries] spring-core = { module = "org.springframework:spring-core", version.ref = "spring" } spring-context = { module = "org.springframework:spring-context", version.ref = "spring" } -spring-web = { module = "org.springframework:spring-web", version.ref = "spring" } spring-test = { module = "org.springframework:spring-test", version.ref = "spring" } spring-boot-starter = { module = "org.springframework.boot:spring-boot-starter", version.ref = "springBoot" } -spring-boot-starter-json = { module = "org.springframework.boot:spring-boot-starter-json", version.ref = "springBoot" } -spring-boot-starter-thymeleaf = { module = "org.springframework.boot:spring-boot-starter-thymeleaf", version.ref = "springBoot" } -spring-boot-configuration-processor = { module = "org.springframework.boot:spring-boot-configuration-processor", version.ref = "springBoot" } spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "springBoot" } +thymeleaf = { module = "org.thymeleaf:thymeleaf", version.ref = "thymeleaf" } +thymeleaf-extras-java8time = { module = "org.thymeleaf.extras:thymeleaf-extras-java8time", version.ref = "thymeleafExtrasTime" } + logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } logback-core = { module = "ch.qos.logback:logback-core", version.ref = "logback" } @@ -51,6 +52,7 @@ h2 = { module = "com.h2database:h2", version.ref = "h2" } jdbi3-sqlobject = { module = "org.jdbi:jdbi3-sqlobject", version.ref = "jdbi3" } lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" } +findbugs-jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "findbugs" } junit = { module = "junit:junit", version.ref = "junit4" } @@ -69,13 +71,10 @@ cucumber-junit = { module = "io.cucumber:cucumber-junit", version.ref = "cucumbe cucumber-spring = { module = "io.cucumber:cucumber-spring", version.ref = "cucumber" } [bundles] -spring-boot-report = ["spring-boot-starter", "spring-boot-starter-json", "spring-boot-starter-thymeleaf"] -spring-web = ["spring-core", "spring-context", "spring-web"] spring-test = ["spring-core", "spring-context", "spring-test"] logback = ["logback-classic", "logback-core"] [plugins] -spring-boot = { id = "org.springframework.boot", version.ref = "springBootPlugin" } lombok = { id = "io.freefair.lombok", version.ref = "lombokPlugin" } minify = { id = "org.gradlewebtools.minify", version.ref = "minifyPlugin" } versioner = { id = "io.toolebox.git-versioner", version.ref = "gitVersionerPlugin" } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index c085dd6a..c824031d 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -142,22 +142,6 @@ - - - - - - - - - - - - - - - - @@ -166,24 +150,11 @@ - - - - - - - - - - - - - @@ -506,14 +477,6 @@ - - - - - - - - @@ -762,11 +725,6 @@ - - - - - @@ -893,22 +851,6 @@ - - - - - - - - - - - - - - - - @@ -949,24 +891,11 @@ - - - - - - - - - - - - - @@ -1124,14 +1053,6 @@ - - - - - - - - @@ -1140,21 +1061,11 @@ - - - - - - - - - - @@ -1165,24 +1076,11 @@ - - - - - - - - - - - - - @@ -2043,11 +1941,6 @@ - - - - - @@ -2064,11 +1957,6 @@ - - - - - @@ -2077,19 +1965,6 @@ - - - - - - - - - - - - - @@ -2106,29 +1981,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -2137,14 +1989,6 @@ - - - - - - - - @@ -2161,14 +2005,6 @@ - - - - - - - - @@ -2201,14 +2037,6 @@ - - - - - - - - @@ -2217,14 +2045,6 @@ - - - - - - - - diff --git a/mission-report/flight-evaluation-report/build.gradle b/mission-report/flight-evaluation-report/build.gradle index 10c9256f..75c2f994 100644 --- a/mission-report/flight-evaluation-report/build.gradle +++ b/mission-report/flight-evaluation-report/build.gradle @@ -1,5 +1,4 @@ plugins { - alias(libs.plugins.spring.boot) id 'java' //noinspection SpellCheckingInspection alias(libs.plugins.lombok) @@ -14,17 +13,14 @@ project.ext { } dependencies { - implementation libs.bundles.spring.boot.report implementation libs.json.schema.validator + implementation libs.thymeleaf + implementation libs.thymeleaf.extras.java8time implementation libs.bundles.logback + implementation libs.findbugs.jsr305 annotationProcessor libs.lombok - annotationProcessor libs.spring.boot.configuration.processor - testImplementation libs.spring.boot.starter.test testImplementation libs.jupiter.core - constraints { - implementation libs.bundles.spring.web - testImplementation libs.bundles.spring.test - } + testImplementation libs.mockito.core } minification { @@ -119,11 +115,17 @@ task processTemplates { } jar { - enabled = false + manifest { + attributes "Main-Class": "com.github.nagyesta.abortmission.reporting.AbortMissionFlightEvaluationReportApp" + } + duplicatesStrategy = DuplicatesStrategy.INCLUDE + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } } processResources.finalizedBy processTemplates -bootJarMainClassName.dependsOn processTemplates +jar.dependsOn processTemplates checkstyleMain.dependsOn processTemplates compileTestJava.dependsOn processTemplates javadoc.dependsOn processTemplates @@ -136,7 +138,6 @@ publishing { publications { mavenJava(MavenPublication) { from components.java - artifact bootJar artifactId = "abort.${project.name}" pom { name = "${project.artifactDisplayName}" diff --git a/mission-report/flight-evaluation-report/lombok.config b/mission-report/flight-evaluation-report/lombok.config index 189c0bef..6a902c83 100644 --- a/mission-report/flight-evaluation-report/lombok.config +++ b/mission-report/flight-evaluation-report/lombok.config @@ -1,3 +1,4 @@ # This file is generated by the 'io.freefair.lombok' Gradle plugin config.stopBubbling = true lombok.addLombokGeneratedAnnotation = true +lombok.nonnull.exceptiontype=IllegalArgumentException diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/AbortMissionAppContext.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/AbortMissionAppContext.java new file mode 100644 index 00000000..bf1d8944 --- /dev/null +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/AbortMissionAppContext.java @@ -0,0 +1,40 @@ +package com.github.nagyesta.abortmission.reporting; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.nagyesta.abortmission.reporting.config.ConversionProperties; +import com.github.nagyesta.abortmission.reporting.controller.ConversionController; +import com.github.nagyesta.abortmission.reporting.html.converter.ClassJsonToHtmlConverter; +import com.github.nagyesta.abortmission.reporting.html.converter.LaunchJsonToHtmlConverter; +import com.github.nagyesta.abortmission.reporting.html.converter.StageLaunchStatsJsonToHtmlConverter; +import com.github.nagyesta.abortmission.reporting.html.converter.StatsJsonToHtmlConverter; +import org.thymeleaf.TemplateEngine; + +public class AbortMissionAppContext { + private final ConversionController controller; + + public AbortMissionAppContext(final ConversionProperties properties) { + final ObjectMapper objectMapper = new ObjectMapper(); + final StatsJsonToHtmlConverter statsConverter = new StatsJsonToHtmlConverter(); + final StageLaunchStatsJsonToHtmlConverter stageConverter = new StageLaunchStatsJsonToHtmlConverter(statsConverter); + final ClassJsonToHtmlConverter classConverter = new ClassJsonToHtmlConverter(statsConverter, stageConverter); + final LaunchJsonToHtmlConverter launchConverter = new LaunchJsonToHtmlConverter(statsConverter, classConverter); + final TemplateEngine templateEngine = new TemplateEngine(); + controller = new ConversionController(properties, objectMapper, launchConverter, templateEngine); + } + + /** + * Returns the controller. + * + * @return controller + */ + public ConversionController controller() { + return controller; + } + + /** + * Exits with an error code (1). + */ + public void exitWithError() { + System.exit(1); + } +} diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/AbortMissionFlightEvaluationReportApp.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/AbortMissionFlightEvaluationReportApp.java index c914adbb..4a93c945 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/AbortMissionFlightEvaluationReportApp.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/AbortMissionFlightEvaluationReportApp.java @@ -1,16 +1,33 @@ package com.github.nagyesta.abortmission.reporting; -import com.github.nagyesta.abortmission.reporting.controller.ConversionController; +import com.github.nagyesta.abortmission.reporting.config.ConversionProperties; import com.github.nagyesta.abortmission.reporting.exception.RenderException; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; +import lombok.extern.slf4j.Slf4j; + +import java.util.Arrays; +import java.util.List; -@SpringBootApplication @SuppressWarnings("checkstyle:HideUtilityClassConstructor") -public class AbortMissionFlightEvaluationReportApp { +@Slf4j +public final class AbortMissionFlightEvaluationReportApp { public static void main(final String[] args) throws RenderException { - SpringApplication.run(AbortMissionFlightEvaluationReportApp.class, args) - .getBean(ConversionController.class).convert(); + final AbortMissionFlightEvaluationReportApp app = new AbortMissionFlightEvaluationReportApp(); + app.execute(app.bootstrap(Arrays.asList(args))); + } + + AbortMissionAppContext bootstrap(final List args) { + final ConversionProperties properties = new PropertiesParser(args).parseArguments(); + return new AbortMissionAppContext(properties); } + + void execute(final AbortMissionAppContext context) { + try { + context.controller().convert(); + } catch (final RenderException ex) { + log.error(ex.getMessage(), ex); + context.exitWithError(); + } + } + } diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/PropertiesParser.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/PropertiesParser.java new file mode 100644 index 00000000..07672eec --- /dev/null +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/PropertiesParser.java @@ -0,0 +1,40 @@ +package com.github.nagyesta.abortmission.reporting; + +import com.github.nagyesta.abortmission.reporting.config.ConversionProperties; + +import java.io.File; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.regex.Pattern; + +public final class PropertiesParser { + + private static final String INPUT = "--report.input"; + private static final String OUTPUT = "--report.output"; + private static final String RELAXED = "--report.relaxed"; + private static final String FAIL_ON_ERROR = "--report.failOnError"; + private static final String EQUALS = "="; + private static final String EMPTY = ""; + + private final List args; + + public PropertiesParser(final List args) { + this.args = List.copyOf(args); + } + + public ConversionProperties parseArguments() { + final ConversionProperties.ConversionPropertiesBuilder builder = ConversionProperties.builder(); + parse(INPUT, File::new, builder::input); + parse(OUTPUT, File::new, builder::output); + parse(RELAXED, Boolean::valueOf, builder::relaxed); + parse(FAIL_ON_ERROR, Boolean::valueOf, builder::failOnError); + return builder.build(); + } + + private void parse(final String parameter, final Function mapper, final Consumer consumer) { + args.stream().filter(s -> s.startsWith(parameter)).findFirst() + .map(s -> s.replaceFirst(Pattern.quote(parameter + EQUALS), EMPTY)) + .map(mapper).ifPresent(consumer); + } +} diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/config/ConversionProperties.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/config/ConversionProperties.java index 830b9c62..92e174d3 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/config/ConversionProperties.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/config/ConversionProperties.java @@ -1,22 +1,61 @@ package com.github.nagyesta.abortmission.reporting.config; import lombok.Data; -import lombok.NoArgsConstructor; import lombok.NonNull; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; +import javax.annotation.Nonnull; import java.io.File; @Data -@NoArgsConstructor -@Component -@ConfigurationProperties(prefix = "report", ignoreInvalidFields = false, ignoreUnknownFields = false) -public class ConversionProperties { - @NonNull +public final class ConversionProperties { private File input; - @NonNull private File output; - private boolean relaxed = false; - private boolean failOnError = false; + private boolean relaxed; + private boolean failOnError; + + private ConversionProperties(@NonNull final File input, @NonNull final File output, final boolean relaxed, final boolean failOnError) { + this.input = input; + this.output = output; + this.relaxed = relaxed; + this.failOnError = failOnError; + } + + public static ConversionPropertiesBuilder builder() { + return new ConversionPropertiesBuilder(); + } + + @SuppressWarnings("checkstyle:HiddenField") + public static final class ConversionPropertiesBuilder { + private File input; + private File output; + private boolean relaxed = false; + private boolean failOnError = false; + + ConversionPropertiesBuilder() { + } + + public ConversionPropertiesBuilder input(@Nonnull final File input) { + this.input = input; + return this; + } + + public ConversionPropertiesBuilder output(@Nonnull final File output) { + this.output = output; + return this; + } + + public ConversionPropertiesBuilder relaxed(final boolean relaxed) { + this.relaxed = relaxed; + return this; + } + + public ConversionPropertiesBuilder failOnError(final boolean failOnError) { + this.failOnError = failOnError; + return this; + } + + public ConversionProperties build() { + return new ConversionProperties(input, output, relaxed, failOnError); + } + } } diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/controller/ConversionController.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/controller/ConversionController.java index c95ac03c..ffe04507 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/controller/ConversionController.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/controller/ConversionController.java @@ -13,18 +13,16 @@ import com.networknt.schema.SpecVersion; import com.networknt.schema.ValidationMessage; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.Assert; -import org.springframework.util.StreamUtils; +import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; -import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect; +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; import java.io.*; import java.nio.charset.StandardCharsets; +import java.util.Objects; import java.util.Set; -@Component @Slf4j public class ConversionController { private static final String ROOT_NODE = "$"; @@ -32,17 +30,18 @@ public class ConversionController { private final ConversionProperties properties; private final ObjectMapper objectMapper; private final LaunchJsonToHtmlConverter converter; - private final SpringTemplateEngine templateEngine; + private final TemplateEngine templateEngine; - @Autowired public ConversionController(final ConversionProperties properties, final ObjectMapper objectMapper, final LaunchJsonToHtmlConverter converter, - final SpringTemplateEngine templateEngine) { + final TemplateEngine templateEngine) { this.properties = properties; this.objectMapper = objectMapper; this.converter = converter; this.templateEngine = templateEngine; + templateEngine.addDialect(new Java8TimeDialect()); + templateEngine.setTemplateResolver(new ClassLoaderTemplateResolver()); } /** @@ -51,7 +50,9 @@ public ConversionController(final ConversionProperties properties, * @throws RenderException When the conversion fails for any reason. */ public void convert() throws RenderException { - Assert.isTrue(properties.getInput().exists(), "Input file does not exist."); + if (!properties.getInput().exists()) { + throw new IllegalArgumentException("Input file does not exist."); + } final LaunchJson json = readValidJson(); render(prepareContext(json)); if (properties.isFailOnError() && json.getStats().getWorstResult() == StageResultJson.FAILURE) { @@ -64,7 +65,7 @@ public void convert() throws RenderException { private void render(final Context context) { try (FileOutputStream stream = new FileOutputStream(properties.getOutput()); OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8)) { - templateEngine.process("html/launch-report", context, writer); + templateEngine.process("/templates/html/launch-report.html", context, writer); } catch (final Exception e) { log.error(e.getMessage(), e); throw new RenderException(); @@ -72,7 +73,7 @@ private void render(final Context context) { } private Context prepareContext(final LaunchJson launchJson) { - final LaunchHtml launchHtml = converter.convert(launchJson); + final LaunchHtml launchHtml = converter.apply(launchJson); final Context context = new Context(); context.setVariable("launchModel", launchHtml); context.setVariable("allCss", readResource("/templates/css/all.min.css")); @@ -81,8 +82,9 @@ private Context prepareContext(final LaunchJson launchJson) { } private String readResource(final String input) throws RenderException { - try { - return StreamUtils.copyToString(ConversionController.class.getResourceAsStream(input), StandardCharsets.UTF_8); + //noinspection LocalCanBeFinal + try (InputStream stream = ConversionController.class.getResourceAsStream(input)) { + return new String(Objects.requireNonNull(stream).readAllBytes(), StandardCharsets.UTF_8); } catch (final IOException e) { log.error(e.getMessage(), e); throw new RenderException(); diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/exception/RenderException.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/exception/RenderException.java index 5992fd7e..056c025e 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/exception/RenderException.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/exception/RenderException.java @@ -1,10 +1,4 @@ package com.github.nagyesta.abortmission.reporting.exception; -import org.springframework.boot.ExitCodeGenerator; - -public class RenderException extends RuntimeException implements ExitCodeGenerator { - @Override - public int getExitCode() { - return 1; - } +public class RenderException extends RuntimeException { } diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/ClassHtml.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/ClassHtml.java index 93916132..6cf798a1 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/ClassHtml.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/ClassHtml.java @@ -1,8 +1,8 @@ package com.github.nagyesta.abortmission.reporting.html; import lombok.Data; -import org.springframework.lang.NonNull; +import javax.annotation.Nonnull; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -22,7 +22,7 @@ public final class ClassHtml implements Comparable { private StatsHtml stats; private Map launches; - private ClassHtml(@NonNull final ClassHtmlBuilder builder) { + private ClassHtml(@Nonnull final ClassHtmlBuilder builder) { this.classNameText = builder.classNameText; this.countdown = builder.countdown; this.stats = builder.stats; @@ -61,7 +61,7 @@ public long startTimeEpochMillis() { } @Override - public int compareTo(@NonNull final ClassHtml o) { + public int compareTo(@Nonnull final ClassHtml o) { return Comparator.comparing(ClassHtml::startTimeEpochMillis) .thenComparing(ClassHtml::getClassNameText) .compare(this, o); diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/LaunchHtml.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/LaunchHtml.java index 7bf51532..438ea23f 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/LaunchHtml.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/LaunchHtml.java @@ -1,8 +1,8 @@ package com.github.nagyesta.abortmission.reporting.html; import lombok.Data; -import org.springframework.lang.NonNull; +import javax.annotation.Nonnull; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.Optional; @@ -29,7 +29,7 @@ public final class LaunchHtml { private StatsHtml countdownStats; private StatsHtml missionStats; - private LaunchHtml(@NonNull final LaunchHtmlBuilder builder) { + private LaunchHtml(@Nonnull final LaunchHtmlBuilder builder) { this.classes = builder.classes; this.stats = builder.stats; this.countdownStats = builder.countdownStats; diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/StageLaunchStatsHtml.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/StageLaunchStatsHtml.java index dbe8996c..5916706e 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/StageLaunchStatsHtml.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/StageLaunchStatsHtml.java @@ -3,6 +3,7 @@ import lombok.Data; import lombok.NonNull; +import javax.annotation.Nonnull; import java.util.Optional; import java.util.SortedMap; import java.util.TreeMap; @@ -19,7 +20,7 @@ public final class StageLaunchStatsHtml { @NonNull private StatsHtml stats; - private StageLaunchStatsHtml(@org.springframework.lang.NonNull final StageLaunchStatsHtmlBuilder builder) { + private StageLaunchStatsHtml(@Nonnull final StageLaunchStatsHtmlBuilder builder) { this.displayName = builder.displayName; this.titleName = builder.titleName; this.matcherNames = builder.matcherNames; diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/StatsHtml.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/StatsHtml.java index 459b6fac..587e40a2 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/StatsHtml.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/StatsHtml.java @@ -1,8 +1,8 @@ package com.github.nagyesta.abortmission.reporting.html; import lombok.Data; -import org.springframework.lang.NonNull; +import javax.annotation.Nonnull; import java.time.LocalDateTime; import java.util.Optional; @@ -25,7 +25,7 @@ public final class StatsHtml { private int abort; private int suppressed; - private StatsHtml(@NonNull final StatsHtmlBuilder builder) { + private StatsHtml(@Nonnull final StatsHtmlBuilder builder) { this.minStart = builder.minStart; this.maxEnd = builder.maxEnd; this.worstResult = builder.worstResult; diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/ClassJsonToHtmlConverter.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/ClassJsonToHtmlConverter.java index 023d19e0..6143b5d4 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/ClassJsonToHtmlConverter.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/ClassJsonToHtmlConverter.java @@ -3,11 +3,8 @@ import com.github.nagyesta.abortmission.reporting.html.ClassHtml; import com.github.nagyesta.abortmission.reporting.html.StageLaunchStatsHtml; import com.github.nagyesta.abortmission.reporting.json.ClassJson; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Component; +import javax.annotation.Nonnull; import java.util.Collection; import java.util.Map; import java.util.Optional; @@ -16,15 +13,13 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -@Component -public class ClassJsonToHtmlConverter implements Converter { +public class ClassJsonToHtmlConverter implements Function { private static final String TEST_METHOD_REGEX = "^test(?[a-zA-Z0-9]+)Should(?[a-zA-Z0-9]+)When(?[a-zA-Z0-9]+)$"; private final StatsJsonToHtmlConverter statsConverter; private final StageLaunchStatsJsonToHtmlConverter stageConverter; - @Autowired public ClassJsonToHtmlConverter(final StatsJsonToHtmlConverter statsConverter, final StageLaunchStatsJsonToHtmlConverter stageConverter) { this.statsConverter = statsConverter; @@ -32,13 +27,13 @@ public ClassJsonToHtmlConverter(final StatsJsonToHtmlConverter statsConverter, } @Override - public ClassHtml convert(@NonNull final ClassJson source) { + public ClassHtml apply(@Nonnull final ClassJson source) { final Map launchMap = convertLaunchMap(source); return ClassHtml.builder(source.getClassName()) .countdown(Optional.ofNullable(source.getCountdown()) - .map(c -> stageConverter.convert(Function.identity(), "Countdown", c)) + .map(c -> stageConverter.apply(Function.identity(), "Countdown", c)) .orElse(null)) - .stats(statsConverter.convert(source.getStats())) + .stats(statsConverter.apply(source.getStats())) .launches(launchMap) .build(); } @@ -49,7 +44,7 @@ public ClassHtml convert(@NonNull final ClassJson source) { * @param s The name of the test method. * @return The tooltip */ - protected String convertTestMethod(@NonNull final String s) { + protected String convertTestMethod(@Nonnull final String s) { final Pattern pattern = Pattern.compile(TEST_METHOD_REGEX); final Matcher matcher = pattern.matcher(s); if (!matcher.matches()) { @@ -65,7 +60,7 @@ private Map convertLaunchMap(final ClassJson sourc .map(Collection::stream) .map(stream -> stream.collect( Collectors.toMap(Map.Entry::getKey, - e -> stageConverter.convert(this::convertTestMethod, e.getKey(), e.getValue())))) + e -> stageConverter.apply(this::convertTestMethod, e.getKey(), e.getValue())))) .orElse(null); } } diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/LaunchJsonToHtmlConverter.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/LaunchJsonToHtmlConverter.java index c344c500..8c246cd7 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/LaunchJsonToHtmlConverter.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/LaunchJsonToHtmlConverter.java @@ -4,25 +4,21 @@ import com.github.nagyesta.abortmission.reporting.html.StageResultHtml; import com.github.nagyesta.abortmission.reporting.html.StatsHtml; import com.github.nagyesta.abortmission.reporting.json.LaunchJson; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Component; -import org.springframework.util.Assert; +import com.github.nagyesta.abortmission.reporting.json.StatsJson; +import javax.annotation.Nonnull; import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.TreeSet; +import java.util.function.Function; import java.util.stream.Collectors; -@Component -public class LaunchJsonToHtmlConverter implements Converter { +public class LaunchJsonToHtmlConverter implements Function { private final StatsJsonToHtmlConverter statsConverter; private final ClassJsonToHtmlConverter classConverter; - @Autowired public LaunchJsonToHtmlConverter(final StatsJsonToHtmlConverter statsConverter, final ClassJsonToHtmlConverter classConverter) { this.statsConverter = statsConverter; @@ -30,20 +26,24 @@ public LaunchJsonToHtmlConverter(final StatsJsonToHtmlConverter statsConverter, } @Override - public LaunchHtml convert(@NonNull final LaunchJson source) { - Assert.notNull(source.getStats(), "Stats cannot be null."); + public LaunchHtml apply(@Nonnull final LaunchJson source) { + final StatsJson stats = source.getStats(); + if (stats == null) { + throw new IllegalArgumentException("Stats cannot be null for launch."); + } final StatsHtml emptyStats = StatsHtml.builder() .worstResult(StageResultHtml.SUPPRESSED) .build(); return LaunchHtml.builder() - .stats(statsConverter.convert(source.getStats())) + .stats(statsConverter.apply(stats)) .classes(Optional.ofNullable(source.getClasses()) .map(Map::values) .map(Collection::stream) - .map(s -> s.map(classConverter::convert).collect(Collectors.toCollection(TreeSet::new))) + .map(s -> s.map(classConverter).collect(Collectors.toCollection(TreeSet::new))) .orElse(new TreeSet<>())) - .countdownStats(Optional.ofNullable(source.getCountdownStats()).map(statsConverter::convert).orElse(emptyStats)) - .missionStats(Optional.ofNullable(source.getMissionStats()).map(statsConverter::convert).orElse(emptyStats)) + .countdownStats(Optional.ofNullable(source.getCountdownStats()).map(statsConverter).orElse(emptyStats)) + .missionStats(Optional.ofNullable(source.getMissionStats()).map(statsConverter).orElse(emptyStats)) .build(); } + } diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/StageLaunchStatsJsonToHtmlConverter.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/StageLaunchStatsJsonToHtmlConverter.java index 829f567f..17407f25 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/StageLaunchStatsJsonToHtmlConverter.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/StageLaunchStatsJsonToHtmlConverter.java @@ -3,21 +3,17 @@ import com.github.nagyesta.abortmission.reporting.html.LaunchHtml; import com.github.nagyesta.abortmission.reporting.html.StageLaunchStatsHtml; import com.github.nagyesta.abortmission.reporting.json.StageLaunchStatsJson; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Component; -import org.springframework.util.Assert; +import com.github.nagyesta.abortmission.reporting.json.StatsJson; +import javax.annotation.Nonnull; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; -@Component public class StageLaunchStatsJsonToHtmlConverter { private final StatsJsonToHtmlConverter statsConverter; - @Autowired public StageLaunchStatsJsonToHtmlConverter(final StatsJsonToHtmlConverter statsConverter) { this.statsConverter = statsConverter; } @@ -31,17 +27,21 @@ public StageLaunchStatsJsonToHtmlConverter(final StatsJsonToHtmlConverter statsC * @param source The source object we want to convert. * @return The converted object */ - public StageLaunchStatsHtml convert(@NonNull final Function titleConverter, - @NonNull final String name, - @NonNull final StageLaunchStatsJson source) { - Assert.notNull(source.getStats(), "Stats cannot be null."); + public StageLaunchStatsHtml apply(@Nonnull final Function titleConverter, + @Nonnull final String name, + @Nonnull final StageLaunchStatsJson source) { + final StatsJson stats = source.getStats(); + if (stats == null) { + throw new IllegalArgumentException("Stats cannot be null for stage."); + } final Map map = Optional.ofNullable(source.getMatcherNames()) .map(Collection::stream) .map(s -> s.collect(Collectors.toMap(Function.identity(), LaunchHtml::shortHash))) .orElse(Collections.emptyMap()); - return StageLaunchStatsHtml.builder(name, statsConverter.convert(source.getStats())) + return StageLaunchStatsHtml.builder(name, statsConverter.apply(stats)) .matcherNames(new TreeMap<>(map)) .titleName(titleConverter.apply(name)) .build(); } + } diff --git a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/StatsJsonToHtmlConverter.java b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/StatsJsonToHtmlConverter.java index 0071d4f9..6f71f613 100644 --- a/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/StatsJsonToHtmlConverter.java +++ b/mission-report/flight-evaluation-report/src/main/java/com/github/nagyesta/abortmission/reporting/html/converter/StatsJsonToHtmlConverter.java @@ -4,17 +4,15 @@ import com.github.nagyesta.abortmission.reporting.html.StatsHtml; import com.github.nagyesta.abortmission.reporting.json.StageResultJson; import com.github.nagyesta.abortmission.reporting.json.StatsJson; -import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Component; +import javax.annotation.Nonnull; import java.util.Optional; +import java.util.function.Function; -@Component -public class StatsJsonToHtmlConverter implements Converter { +public class StatsJsonToHtmlConverter implements Function { @Override - public StatsHtml convert(@NonNull final StatsJson source) { + public StatsHtml apply(@Nonnull final StatsJson source) { return StatsHtml.builder() .minStart(source.getMinStart()) .maxEnd(source.getMaxEnd()) diff --git a/mission-report/flight-evaluation-report/src/main/java/org/springframework/boot/loader/JarLauncher.java b/mission-report/flight-evaluation-report/src/main/java/org/springframework/boot/loader/JarLauncher.java new file mode 100644 index 00000000..216dbfbf --- /dev/null +++ b/mission-report/flight-evaluation-report/src/main/java/org/springframework/boot/loader/JarLauncher.java @@ -0,0 +1,17 @@ +package org.springframework.boot.loader; + +import com.github.nagyesta.abortmission.reporting.AbortMissionFlightEvaluationReportApp; +import lombok.extern.slf4j.Slf4j; + +@SuppressWarnings("checkstyle:HideUtilityClassConstructor") +@Slf4j +@Deprecated +public class JarLauncher { + + @Deprecated + public static void main(final String[] args) { + log.error("This is the legacy launcher. " + + "Please use 'com.github.nagyesta.abortmission.reporting.AbortMissionFlightEvaluationReportApp' instead!"); + AbortMissionFlightEvaluationReportApp.main(args); + } +} diff --git a/mission-report/flight-evaluation-report/src/main/resources/application.properties b/mission-report/flight-evaluation-report/src/main/resources/application.properties deleted file mode 100644 index ea7a7147..00000000 --- a/mission-report/flight-evaluation-report/src/main/resources/application.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Spring -# -spring.main.banner-mode=off -# -# Thymeleaf -# -spring.thymeleaf.prefix=classpath:/templates/ -spring.thymeleaf.suffix=.html -# -# Logging -# -logging.level.root=WARN -logging.level.org.springframework=WARN -logging.level.com.networknt.schema=WARN -# suppress inspection "UnusedMessageFormatParameter" -logging.exception-conversion-word=%ex{2} -logging.pattern.level=%5p -logging.pattern.console=%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(\${logging.pattern.level}) %clr(%-40.40logger{29}){cyan} %clr(:){faint} %m%n\${logging.exception-conversion-word} -# -# App -# -# suppress inspection "SpringBootApplicationProperties" -report.relaxed=false diff --git a/mission-report/flight-evaluation-report/src/main/resources/logback.xml b/mission-report/flight-evaluation-report/src/main/resources/logback.xml new file mode 100644 index 00000000..2f79e593 --- /dev/null +++ b/mission-report/flight-evaluation-report/src/main/resources/logback.xml @@ -0,0 +1,11 @@ + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %-50.50logger{29} : %m%n%ex{2} + + + + + + + diff --git a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/AbortMissionFlightEvaluationReportAppIntegrationTest.java b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/AbortMissionFlightEvaluationReportAppIntegrationTest.java index 48076760..5f89b4dd 100644 --- a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/AbortMissionFlightEvaluationReportAppIntegrationTest.java +++ b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/AbortMissionFlightEvaluationReportAppIntegrationTest.java @@ -1,23 +1,56 @@ package com.github.nagyesta.abortmission.reporting; +import com.github.nagyesta.abortmission.reporting.config.ConversionProperties; +import com.github.nagyesta.abortmission.reporting.exception.RenderException; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; + +import java.io.File; +import java.io.IOException; +import java.util.List; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.*; -@SpringBootTest class AbortMissionFlightEvaluationReportAppIntegrationTest { - @Autowired - private AbortMissionFlightEvaluationReportApp app; + @Test + public void testApplicationContextShouldConfigureSuccessfullyWhenCalled() throws IOException { + //given + final AbortMissionFlightEvaluationReportApp app = new AbortMissionFlightEvaluationReportApp(); + //noinspection ConstantConditions + final String input = getClass().getResource("/abort-mission-report.json").getFile(); + final File output = File.createTempFile("abort-mission-out", ".html"); + output.deleteOnExit(); + final List args = List.of("--report.input=" + input, "--report.output=" + output); + + //when + final AbortMissionAppContext actual = app.bootstrap(args); + + //then + assertNotNull(actual); + } @Test - void testApplicationContextShouldConfigureSuccessfullyWhenCalled() { - //given test instance created - //when injected + public void testApplicationContextShouldExitWithErrorWhenExecutionFails() throws IOException { + //given + final AbortMissionFlightEvaluationReportApp app = new AbortMissionFlightEvaluationReportApp(); + //noinspection ConstantConditions + final File input = new File(getClass().getResource("/abort-mission-report.json").getFile()); + final File output = File.createTempFile("abort-mission-out", ".html"); + output.deleteOnExit(); + final ConversionProperties properties = ConversionProperties.builder() + .input(input) + .output(output) + .build(); + final AbortMissionAppContext context = spy(new AbortMissionAppContext(properties)); + doNothing().when(context).exitWithError(); + doThrow(new RenderException()).when(context).controller(); + + //when + app.execute(context); //then - assertNotNull(app); + verify(context).controller(); + verify(context).exitWithError(); } } diff --git a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/config/ConversionPropertiesTest.java b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/config/ConversionPropertiesTest.java new file mode 100644 index 00000000..90c73ad5 --- /dev/null +++ b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/config/ConversionPropertiesTest.java @@ -0,0 +1,36 @@ +package com.github.nagyesta.abortmission.reporting.config; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.File; + +class ConversionPropertiesTest { + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test + void testConstructorShouldThrowExceptionWhenInputIsnull() { + //given + final ConversionProperties.ConversionPropertiesBuilder builder = ConversionProperties.builder() + .output(new File("out.html")); + + //when + //noinspection Convert2MethodRef + Assertions.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + //then + exception + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test + void testConstructorShouldThrowExceptionWhenOutputIsnull() { + //given + final ConversionProperties.ConversionPropertiesBuilder builder = ConversionProperties.builder() + .input(new File("in.json")); + + //when + Assertions.assertThrows(IllegalArgumentException.class, builder::build); + + //then + exception + } +} diff --git a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/controller/ConversionControllerIntegrationTest.java b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/controller/ConversionControllerIntegrationTest.java index e594e499..fdfdb7b5 100644 --- a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/controller/ConversionControllerIntegrationTest.java +++ b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/controller/ConversionControllerIntegrationTest.java @@ -3,14 +3,15 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.nagyesta.abortmission.reporting.config.ConversionProperties; import com.github.nagyesta.abortmission.reporting.exception.RenderException; +import com.github.nagyesta.abortmission.reporting.html.converter.ClassJsonToHtmlConverter; import com.github.nagyesta.abortmission.reporting.html.converter.LaunchJsonToHtmlConverter; +import com.github.nagyesta.abortmission.reporting.html.converter.StageLaunchStatsJsonToHtmlConverter; +import com.github.nagyesta.abortmission.reporting.html.converter.StatsJsonToHtmlConverter; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.TemplateEngine; import java.io.File; import java.nio.charset.StandardCharsets; @@ -21,14 +22,20 @@ import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -@SpringBootTest class ConversionControllerIntegrationTest { - @Autowired - private ObjectMapper objectMapper; - @Autowired - private LaunchJsonToHtmlConverter converter; - @Autowired - private SpringTemplateEngine templateEngine; + + private final ObjectMapper objectMapper; + private final LaunchJsonToHtmlConverter launchConverter; + private final TemplateEngine templateEngine; + + ConversionControllerIntegrationTest() { + final StatsJsonToHtmlConverter statsConverter = new StatsJsonToHtmlConverter(); + final StageLaunchStatsJsonToHtmlConverter stageConverter = new StageLaunchStatsJsonToHtmlConverter(statsConverter); + final ClassJsonToHtmlConverter classConverter = new ClassJsonToHtmlConverter(statsConverter, stageConverter); + templateEngine = new TemplateEngine(); + launchConverter = new LaunchJsonToHtmlConverter(statsConverter, classConverter); + objectMapper = new ObjectMapper(); + } private static Stream validInputSource() { return Stream.builder() @@ -48,15 +55,16 @@ void testConvertShouldConvertAndRenderDataWhenCalledWithValidJson(final String j //given final File inputFile = new File(this.getClass().getResource(jsonResource).getFile()); final File expectedFile = new File(this.getClass().getResource(expectedHtml).getFile()); - final ConversionProperties properties = new ConversionProperties(); - properties.setInput(inputFile); - properties.setOutput(File.createTempFile("abort-mission-test", ".html")); - properties.setRelaxed(relaxed); - properties.setFailOnError(failOnError); + final ConversionProperties properties = ConversionProperties.builder() + .input(inputFile) + .output(File.createTempFile("abort-mission-test", ".html")) + .relaxed(relaxed) + .failOnError(failOnError) + .build(); properties.getOutput().deleteOnExit(); - final ConversionController underTest = new ConversionController(properties, objectMapper, converter, templateEngine); + final ConversionController underTest = new ConversionController(properties, objectMapper, launchConverter, templateEngine); //when if (failOnError) { @@ -75,14 +83,15 @@ void testConvertShouldConvertAndRenderDataWhenCalledWithValidJson(final String j void testConvertShouldThrowExceptionWhenCalledWithInvalidJson() throws Exception { //given final File inputFile = new File(this.getClass().getResource("/schema/abort-mission-telemetry-relaxed.json").getFile()); - final ConversionProperties properties = new ConversionProperties(); - properties.setInput(inputFile); - properties.setOutput(File.createTempFile("abort-mission-test", ".html")); - properties.setRelaxed(false); + final ConversionProperties properties = ConversionProperties.builder() + .input(inputFile) + .output(File.createTempFile("abort-mission-test", ".html")) + .relaxed(false) + .build(); properties.getOutput().deleteOnExit(); - final ConversionController underTest = new ConversionController(properties, objectMapper, converter, templateEngine); + final ConversionController underTest = new ConversionController(properties, objectMapper, launchConverter, templateEngine); //when assertThrows(RuntimeException.class, underTest::convert); diff --git a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/ClassJsonToHtmlConverterTest.java b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/ClassJsonToHtmlConverterTest.java index f7bd5f56..7d34ff10 100644 --- a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/ClassJsonToHtmlConverterTest.java +++ b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/ClassJsonToHtmlConverterTest.java @@ -69,24 +69,24 @@ private static Stream methodNameProvider() { void testConvertShouldConvertNonNullValuesWhenCalled(final ClassJson input, final ClassHtml expected) { //given final StatsJsonToHtmlConverter statsConverter = mock(StatsJsonToHtmlConverter.class); - when(statsConverter.convert(notNull())).thenReturn(expected.getStats()); - when(statsConverter.convert(isNull())).thenThrow(new NullPointerException()); + when(statsConverter.apply(notNull())).thenReturn(expected.getStats()); + when(statsConverter.apply(isNull())).thenThrow(new NullPointerException()); final StageLaunchStatsJsonToHtmlConverter stageConverter = mock(StageLaunchStatsJsonToHtmlConverter.class); - when(stageConverter.convert(any(), eq(COUNTDOWN), notNull())).thenReturn(expected.getCountdown()); - when(stageConverter.convert(any(), anyString(), isNull())).thenThrow(new NullPointerException()); + when(stageConverter.apply(any(), eq(COUNTDOWN), notNull())).thenReturn(expected.getCountdown()); + when(stageConverter.apply(any(), anyString(), isNull())).thenThrow(new NullPointerException()); final Optional optionalLaunch = Optional.ofNullable(expected.getLaunches()) .map(Map::values) .map(Collection::stream) .flatMap(Stream::findFirst); optionalLaunch.ifPresent(o -> - when(stageConverter.convert(any(), eq(METHOD_NAME), any(StageLaunchStatsJson.class))) + when(stageConverter.apply(any(), eq(METHOD_NAME), any(StageLaunchStatsJson.class))) .thenReturn(o)); final ClassJsonToHtmlConverter underTest = new ClassJsonToHtmlConverter(statsConverter, stageConverter); //when - final ClassHtml actual = underTest.convert(input); + final ClassHtml actual = underTest.apply(input); //then assertNotNull(actual); @@ -96,12 +96,12 @@ void testConvertShouldConvertNonNullValuesWhenCalled(final ClassJson input, fina if (expected.getLaunches() != null) { expected.getLaunches().forEach((k, v) -> { assertSame(v, actual.getLaunches().get(k)); - verify(stageConverter).convert(any(), eq(METHOD_NAME), same(input.getLaunches().get(k))); + verify(stageConverter).apply(any(), eq(METHOD_NAME), same(input.getLaunches().get(k))); }); } - verify(statsConverter).convert(eq(input.getStats())); + verify(statsConverter).apply(eq(input.getStats())); if (input.getCountdown() != null) { - verify(stageConverter).convert(any(), eq(COUNTDOWN), same(input.getCountdown())); + verify(stageConverter).apply(any(), eq(COUNTDOWN), same(input.getCountdown())); } } diff --git a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/LaunchJsonToHtmlConverterTest.java b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/LaunchJsonToHtmlConverterTest.java index bcbad95a..651e46fb 100644 --- a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/LaunchJsonToHtmlConverterTest.java +++ b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/LaunchJsonToHtmlConverterTest.java @@ -7,6 +7,8 @@ import com.github.nagyesta.abortmission.reporting.json.ClassJson; import com.github.nagyesta.abortmission.reporting.json.LaunchJson; import com.github.nagyesta.abortmission.reporting.json.StatsJson; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -63,24 +65,24 @@ private static LaunchJson json(final Map classes) { void testConvertShouldConvertNonNullValuesWhenCalled(final LaunchJson input, final LaunchHtml expected) { //given final StatsJsonToHtmlConverter statsConverter = mock(StatsJsonToHtmlConverter.class); - when(statsConverter.convert(same(input.getStats()))).thenReturn(expected.getStats()); + when(statsConverter.apply(same(input.getStats()))).thenReturn(expected.getStats()); if (input.getCountdownStats() != null) { - when(statsConverter.convert(same(input.getCountdownStats()))).thenReturn(expected.getCountdownStats()); + when(statsConverter.apply(same(input.getCountdownStats()))).thenReturn(expected.getCountdownStats()); } if (input.getMissionStats() != null) { - when(statsConverter.convert(same(input.getMissionStats()))).thenReturn(expected.getMissionStats()); + when(statsConverter.apply(same(input.getMissionStats()))).thenReturn(expected.getMissionStats()); } - when(statsConverter.convert(isNull())).thenThrow(NullPointerException.class); + when(statsConverter.apply(isNull())).thenThrow(NullPointerException.class); final ClassJsonToHtmlConverter classConverter = mock(ClassJsonToHtmlConverter.class); if (expected.getClasses() != null && !expected.getClasses().isEmpty()) { - when(classConverter.convert(notNull())).thenReturn(expected.getClasses().first()); + when(classConverter.apply(notNull())).thenReturn(expected.getClasses().first()); } - when(classConverter.convert(isNull())).thenThrow(NullPointerException.class); + when(classConverter.apply(isNull())).thenThrow(NullPointerException.class); final LaunchJsonToHtmlConverter underTest = new LaunchJsonToHtmlConverter(statsConverter, classConverter); //when - final LaunchHtml actual = underTest.convert(input); + final LaunchHtml actual = underTest.apply(input); //then assertNotNull(actual); @@ -88,18 +90,33 @@ void testConvertShouldConvertNonNullValuesWhenCalled(final LaunchJson input, fin assertSame(expected.getStats(), actual.getStats()); if (expected.getClasses() != null && !expected.getClasses().isEmpty()) { assertSame(expected.getClasses().first(), actual.getClasses().first()); - verify(classConverter).convert(same(input.getClasses().get(CLASS_NAME))); + verify(classConverter).apply(same(input.getClasses().get(CLASS_NAME))); } - verify(statsConverter).convert(same(input.getStats())); + verify(statsConverter).apply(same(input.getStats())); if (input.getCountdownStats() != null) { assertSame(expected.getCountdownStats(), actual.getCountdownStats()); - verify(statsConverter).convert(same(input.getCountdownStats())); + verify(statsConverter).apply(same(input.getCountdownStats())); } if (input.getMissionStats() != null) { assertSame(expected.getMissionStats(), actual.getMissionStats()); - verify(statsConverter).convert(same(input.getMissionStats())); + verify(statsConverter).apply(same(input.getMissionStats())); } - verify(statsConverter).convert(same(input.getStats())); + verify(statsConverter).apply(same(input.getStats())); + } + + @Test + void testConvertShouldThrowExceptionWhenCalledWithNullStats() { + //given + final LaunchJson input = new LaunchJson(); + final StatsJsonToHtmlConverter statsConverter = mock(StatsJsonToHtmlConverter.class); + final ClassJsonToHtmlConverter classConverter = mock(ClassJsonToHtmlConverter.class); + + final LaunchJsonToHtmlConverter underTest = new LaunchJsonToHtmlConverter(statsConverter, classConverter); + + //when + Assertions.assertThrows(IllegalArgumentException.class, () -> underTest.apply(input)); + //then + exception + verifyNoInteractions(statsConverter, classConverter); } } diff --git a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/StageLaunchStatsJsonToHtmlConverterTest.java b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/StageLaunchStatsJsonToHtmlConverterTest.java index a1e48c6d..99bfbd61 100644 --- a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/StageLaunchStatsJsonToHtmlConverterTest.java +++ b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/StageLaunchStatsJsonToHtmlConverterTest.java @@ -5,6 +5,8 @@ import com.github.nagyesta.abortmission.reporting.html.StatsHtml; import com.github.nagyesta.abortmission.reporting.json.StageLaunchStatsJson; import com.github.nagyesta.abortmission.reporting.json.StatsJson; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -12,6 +14,7 @@ import java.util.Collections; import java.util.TreeMap; import java.util.TreeSet; +import java.util.function.Function; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -45,19 +48,33 @@ private static Stream validInputProvider() { void testConvertShouldConvertNonNullValuesWhenCalled(final StageLaunchStatsJson input, final StageLaunchStatsHtml expected) { //given final StatsJsonToHtmlConverter statsConverter = mock(StatsJsonToHtmlConverter.class); - when(statsConverter.convert(notNull())).thenReturn(expected.getStats()); - when(statsConverter.convert(isNull())).thenThrow(new NullPointerException()); + when(statsConverter.apply(notNull())).thenReturn(expected.getStats()); + when(statsConverter.apply(isNull())).thenThrow(new NullPointerException()); final StageLaunchStatsJsonToHtmlConverter underTest = new StageLaunchStatsJsonToHtmlConverter(statsConverter); //when - final StageLaunchStatsHtml actual = underTest.convert(String::toLowerCase, METHOD_NAME, input); + final StageLaunchStatsHtml actual = underTest.apply(String::toLowerCase, METHOD_NAME, input); //then assertNotNull(actual); assertEquals(expected, actual); assertSame(expected.getStats(), actual.getStats()); - verify(statsConverter).convert(same(input.getStats())); + verify(statsConverter).apply(same(input.getStats())); + } + + @Test + void testConvertShouldThrowExceptionWhenCalledWithNullStats() { + //given + final StageLaunchStatsJson input = new StageLaunchStatsJson(); + final StatsJsonToHtmlConverter statsConverter = mock(StatsJsonToHtmlConverter.class); + + final StageLaunchStatsJsonToHtmlConverter underTest = new StageLaunchStatsJsonToHtmlConverter(statsConverter); + + //when + Assertions.assertThrows(IllegalArgumentException.class, () -> underTest.apply(Function.identity(), "name", input)); + //then + exception + verifyNoInteractions(statsConverter); } } diff --git a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/StatsJsonToHtmlConverterTest.java b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/StatsJsonToHtmlConverterTest.java index 1d7e666e..77b2b660 100644 --- a/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/StatsJsonToHtmlConverterTest.java +++ b/mission-report/flight-evaluation-report/src/test/java/com/github/nagyesta/abortmission/reporting/html/converter/StatsJsonToHtmlConverterTest.java @@ -81,7 +81,7 @@ void testConvertShouldConvertNonNullValuesWhenCalled(final StatsJson input, fina final StatsJsonToHtmlConverter underTest = new StatsJsonToHtmlConverter(); //when - final StatsHtml actual = underTest.convert(input); + final StatsHtml actual = underTest.apply(input); //then assertNotNull(actual);