From 429a2db3eb47d06eb01e355b4d1f8d15e16734da Mon Sep 17 00:00:00 2001 From: Sergey Grigoriev Date: Tue, 22 Oct 2024 16:29:01 +0200 Subject: [PATCH] feat: detect whether upgrade of WeasyPrint Service is required and display it in About page (#263) Refs: #258 --- .../pdf_exporter/util/VersionUtils.java | 28 ++ .../WeasyPrintProbeStatusProvider.java | 38 +++ .../WeasyPrintStatusProvider.java | 52 +++- .../service/model/WeasyPrintInfo.java | 6 + src/main/resources/versions.properties | 1 + .../WeasyPrintProbeStatusProviderTest.java | 43 +++ .../WeasyPrintStatusProviderTest.java | 250 ++++++++++++++++++ 7 files changed, 405 insertions(+), 13 deletions(-) create mode 100644 src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/VersionUtils.java create mode 100644 src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintProbeStatusProvider.java create mode 100644 src/main/resources/versions.properties create mode 100644 src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintProbeStatusProviderTest.java create mode 100644 src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintStatusProviderTest.java diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/VersionUtils.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/VersionUtils.java new file mode 100644 index 00000000..7d33b7bf --- /dev/null +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/VersionUtils.java @@ -0,0 +1,28 @@ +package ch.sbb.polarion.extension.pdf_exporter.util; + +import ch.sbb.polarion.extension.pdf_exporter.util.configuration.WeasyPrintStatusProvider; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +@UtilityClass +public class VersionUtils { + + public static @Nullable String getLatestCompatibleVersionWeasyPrintService() { + try (InputStream input = WeasyPrintStatusProvider.class.getClassLoader().getResourceAsStream("versions.properties")) { + if (input == null) { + return null; + } + + Properties properties = new Properties(); + properties.load(input); + return properties.getProperty("weasyprint-service.version"); + } catch (IOException e) { + return null; + } + } + +} diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintProbeStatusProvider.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintProbeStatusProvider.java new file mode 100644 index 00000000..d76eb761 --- /dev/null +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintProbeStatusProvider.java @@ -0,0 +1,38 @@ +package ch.sbb.polarion.extension.pdf_exporter.util.configuration; + +import ch.sbb.polarion.extension.generic.configuration.ConfigurationStatus; +import ch.sbb.polarion.extension.generic.configuration.ConfigurationStatusProvider; +import ch.sbb.polarion.extension.generic.configuration.Status; +import ch.sbb.polarion.extension.generic.util.Discoverable; +import ch.sbb.polarion.extension.pdf_exporter.converter.HtmlToPdfConverter; +import ch.sbb.polarion.extension.pdf_exporter.rest.model.conversion.Orientation; +import ch.sbb.polarion.extension.pdf_exporter.rest.model.conversion.PaperSize; +import org.jetbrains.annotations.NotNull; + +@Discoverable +public class WeasyPrintProbeStatusProvider extends ConfigurationStatusProvider { + + private static final String WEASY_PRINT_SERVICE_TEST_CONVERSION = "WeasyPrint Service: WeasyPrint probe"; + + private final HtmlToPdfConverter htmlToPdfConverter; + + public WeasyPrintProbeStatusProvider() { + this.htmlToPdfConverter = new HtmlToPdfConverter(); + } + + public WeasyPrintProbeStatusProvider(HtmlToPdfConverter htmlToPdfConverter) { + this.htmlToPdfConverter = htmlToPdfConverter; + } + + @Override + public @NotNull ConfigurationStatus getStatus(@NotNull Context context) { + try { + htmlToPdfConverter.convert("test html", Orientation.PORTRAIT, PaperSize.A4); + + return new ConfigurationStatus(WEASY_PRINT_SERVICE_TEST_CONVERSION, Status.OK); + } catch (Exception e) { + return new ConfigurationStatus(WEASY_PRINT_SERVICE_TEST_CONVERSION, Status.ERROR, e.getMessage()); + } + } + +} diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintStatusProvider.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintStatusProvider.java index e5fcd78d..a089bf69 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintStatusProvider.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintStatusProvider.java @@ -4,9 +4,7 @@ import ch.sbb.polarion.extension.generic.configuration.ConfigurationStatusProvider; import ch.sbb.polarion.extension.generic.configuration.Status; import ch.sbb.polarion.extension.generic.util.Discoverable; -import ch.sbb.polarion.extension.pdf_exporter.converter.HtmlToPdfConverter; -import ch.sbb.polarion.extension.pdf_exporter.rest.model.conversion.Orientation; -import ch.sbb.polarion.extension.pdf_exporter.rest.model.conversion.PaperSize; +import ch.sbb.polarion.extension.pdf_exporter.util.VersionUtils; import ch.sbb.polarion.extension.pdf_exporter.weasyprint.service.WeasyPrintServiceConnector; import ch.sbb.polarion.extension.pdf_exporter.weasyprint.service.model.WeasyPrintInfo; import org.jetbrains.annotations.NotNull; @@ -18,6 +16,16 @@ @Discoverable public class WeasyPrintStatusProvider extends ConfigurationStatusProvider { + private final WeasyPrintServiceConnector weasyPrintServiceConnector; + + public WeasyPrintStatusProvider() { + this.weasyPrintServiceConnector = new WeasyPrintServiceConnector(); + } + + public WeasyPrintStatusProvider(WeasyPrintServiceConnector weasyPrintServiceConnector) { + this.weasyPrintServiceConnector = weasyPrintServiceConnector; + } + private enum WeasyPrintServiceInfo { VERSION, PYTHON, @@ -35,14 +43,9 @@ private enum WeasyPrintServiceInfo { @Override public @NotNull List getStatuses(@NotNull Context context) { try { - HtmlToPdfConverter htmlToPdfConverter = new HtmlToPdfConverter(); - WeasyPrintServiceConnector weasyPrintServiceConnector = new WeasyPrintServiceConnector(); - WeasyPrintInfo weasyPrintInfo = weasyPrintServiceConnector.getWeasyPrintInfo(); - htmlToPdfConverter.convert("test html", Orientation.PORTRAIT, PaperSize.A4); - return List.of( - createWeasyPrintStatus(WEASY_PRINT_SERVICE_INFO.get(WeasyPrintServiceInfo.VERSION), weasyPrintInfo.getWeasyprintService() + " (" + weasyPrintInfo.getTimestamp() + ")"), + createWeasyPrintStatus(WEASY_PRINT_SERVICE_INFO.get(WeasyPrintServiceInfo.VERSION), weasyPrintInfo.getWeasyprintService(), weasyPrintInfo.getTimestamp(), VersionUtils.getLatestCompatibleVersionWeasyPrintService()), createWeasyPrintStatus(WEASY_PRINT_SERVICE_INFO.get(WeasyPrintServiceInfo.PYTHON), weasyPrintInfo.getPython()), createWeasyPrintStatus(WEASY_PRINT_SERVICE_INFO.get(WeasyPrintServiceInfo.WEASYPRINT), weasyPrintInfo.getWeasyprint()), createWeasyPrintStatus(WEASY_PRINT_SERVICE_INFO.get(WeasyPrintServiceInfo.CHROMIUM), weasyPrintInfo.getChromium()) @@ -52,11 +55,34 @@ private enum WeasyPrintServiceInfo { } } - private static @NotNull ConfigurationStatus createWeasyPrintStatus(@NotNull String name, @Nullable String description) { - if (description == null || description.isBlank()) { - return new ConfigurationStatus(name, Status.WARNING, "Unknown"); + private static @NotNull ConfigurationStatus createWeasyPrintStatus(@NotNull String name, @Nullable String version) { + if (version == null || version.isBlank()) { + return new ConfigurationStatus(name, Status.ERROR, "Unknown"); + } else { + return new ConfigurationStatus(name, Status.OK, version); + } + } + + private static @NotNull ConfigurationStatus createWeasyPrintStatus(@NotNull String name, @Nullable String version, @Nullable String timestamp, @Nullable String latestCompatibleVersion) { + if (version == null || version.isBlank()) { + return new ConfigurationStatus(name, Status.ERROR, createUseLatestCompatibleWeasyPrintMessage("Unknown", timestamp, latestCompatibleVersion)); + } else if (!version.equals(latestCompatibleVersion)) { + return new ConfigurationStatus(name, Status.WARNING, createUseLatestCompatibleWeasyPrintMessage(version, timestamp, latestCompatibleVersion)); } else { - return new ConfigurationStatus(name, Status.OK, description); + return new ConfigurationStatus(name, Status.OK, version); + } + } + + private static @NotNull String createUseLatestCompatibleWeasyPrintMessage(@NotNull String version, @Nullable String timestamp, @Nullable String latestCompatibleVersion) { + StringBuilder message = new StringBuilder(); + message.append(version); + if (timestamp != null && !timestamp.isBlank()) { + message.append(" (").append(timestamp).append(")"); } + if (latestCompatibleVersion != null && !latestCompatibleVersion.isBlank()) { + message.append(": use latest compatible ").append(latestCompatibleVersion).append(""); + } + return message.toString(); } + } diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/weasyprint/service/model/WeasyPrintInfo.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/weasyprint/service/model/WeasyPrintInfo.java index 398b3a95..4147515c 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/weasyprint/service/model/WeasyPrintInfo.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/weasyprint/service/model/WeasyPrintInfo.java @@ -1,10 +1,16 @@ package ch.sbb.polarion.extension.pdf_exporter.weasyprint.service.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import org.jetbrains.annotations.Nullable; +@NoArgsConstructor +@AllArgsConstructor @Data +@Builder @JsonIgnoreProperties(ignoreUnknown = true) public class WeasyPrintInfo { private @Nullable String chromium; diff --git a/src/main/resources/versions.properties b/src/main/resources/versions.properties new file mode 100644 index 00000000..b29fee41 --- /dev/null +++ b/src/main/resources/versions.properties @@ -0,0 +1 @@ +weasyprint-service.version=62.4.6 \ No newline at end of file diff --git a/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintProbeStatusProviderTest.java b/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintProbeStatusProviderTest.java new file mode 100644 index 00000000..8ab9beb5 --- /dev/null +++ b/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintProbeStatusProviderTest.java @@ -0,0 +1,43 @@ +package ch.sbb.polarion.extension.pdf_exporter.util.configuration; + +import ch.sbb.polarion.extension.generic.configuration.ConfigurationStatus; +import ch.sbb.polarion.extension.generic.configuration.ConfigurationStatusProvider; +import ch.sbb.polarion.extension.generic.configuration.Status; +import ch.sbb.polarion.extension.pdf_exporter.converter.HtmlToPdfConverter; +import ch.sbb.polarion.extension.pdf_exporter.rest.model.conversion.Orientation; +import ch.sbb.polarion.extension.pdf_exporter.rest.model.conversion.PaperSize; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.ws.rs.ProcessingException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith({MockitoExtension.class}) +class WeasyPrintProbeStatusProviderTest { + + @Test + void testHappyPath() { + HtmlToPdfConverter htmlToPdfConverter = mock(HtmlToPdfConverter.class); + when(htmlToPdfConverter.convert("test html", Orientation.PORTRAIT, PaperSize.A4)).thenReturn(new byte[0]); + WeasyPrintProbeStatusProvider weasyPrintProbeStatusProvider = new WeasyPrintProbeStatusProvider(htmlToPdfConverter); + + ConfigurationStatus status = weasyPrintProbeStatusProvider.getStatus(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(new ConfigurationStatus("WeasyPrint Service: WeasyPrint probe", Status.OK), status); + } + + @Test + void testConnectionRefused() { + HtmlToPdfConverter htmlToPdfConverter = mock(HtmlToPdfConverter.class); + when(htmlToPdfConverter.convert("test html", Orientation.PORTRAIT, PaperSize.A4)).thenThrow(new ProcessingException("java.net.ConnectException: Connection refused")); + WeasyPrintProbeStatusProvider weasyPrintProbeStatusProvider = new WeasyPrintProbeStatusProvider(htmlToPdfConverter); + + ConfigurationStatus status = weasyPrintProbeStatusProvider.getStatus(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(new ConfigurationStatus("WeasyPrint Service: WeasyPrint probe", Status.ERROR, "java.net.ConnectException: Connection refused"), status); + } +} \ No newline at end of file diff --git a/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintStatusProviderTest.java b/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintStatusProviderTest.java new file mode 100644 index 00000000..adbdf945 --- /dev/null +++ b/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/configuration/WeasyPrintStatusProviderTest.java @@ -0,0 +1,250 @@ +package ch.sbb.polarion.extension.pdf_exporter.util.configuration; + +import ch.sbb.polarion.extension.generic.configuration.ConfigurationStatus; +import ch.sbb.polarion.extension.generic.configuration.ConfigurationStatusProvider; +import ch.sbb.polarion.extension.generic.configuration.Status; +import ch.sbb.polarion.extension.pdf_exporter.util.VersionUtils; +import ch.sbb.polarion.extension.pdf_exporter.weasyprint.service.WeasyPrintServiceConnector; +import ch.sbb.polarion.extension.pdf_exporter.weasyprint.service.model.WeasyPrintInfo; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.ws.rs.ProcessingException; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +@ExtendWith({MockitoExtension.class}) +class WeasyPrintStatusProviderTest { + + @Test + void testHappyPath() { + String timestamp = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).format(DateTimeFormatter.ISO_INSTANT); + WeasyPrintInfo weasyPrintInfo = WeasyPrintInfo.builder() + .chromium("129.0.6668.58") + .python("3.12.5") + .timestamp(timestamp) + .weasyprint("62.3") + .weasyprintService("62.4.6") + .build(); + + WeasyPrintServiceConnector weasyPrintServiceConnector = mock(WeasyPrintServiceConnector.class); + when(weasyPrintServiceConnector.getWeasyPrintInfo()).thenReturn(weasyPrintInfo); + WeasyPrintStatusProvider weasyPrintStatusProvider = new WeasyPrintStatusProvider(weasyPrintServiceConnector); + + try (MockedStatic versionsUtilsMockedStatic = mockStatic(VersionUtils.class)) { + versionsUtilsMockedStatic.when(VersionUtils::getLatestCompatibleVersionWeasyPrintService).thenReturn("62.4.6"); + + List configurationStatuses = weasyPrintStatusProvider.getStatuses(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(4, configurationStatuses.size()); + assertThat(configurationStatuses).containsExactlyInAnyOrder( + new ConfigurationStatus("WeasyPrint Service", Status.OK, "62.4.6"), + new ConfigurationStatus("WeasyPrint Service: Chromium", Status.OK, "129.0.6668.58"), + new ConfigurationStatus("WeasyPrint Service: Python", Status.OK, "3.12.5"), + new ConfigurationStatus("WeasyPrint Service: WeasyPrint", Status.OK, "62.3") + ); + } + } + + @Test + void testConnectionRefused() { + WeasyPrintServiceConnector weasyPrintServiceConnector = mock(WeasyPrintServiceConnector.class); + when(weasyPrintServiceConnector.getWeasyPrintInfo()).thenThrow(new ProcessingException("java.net.ConnectException: Connection refused")); + WeasyPrintStatusProvider weasyPrintStatusProvider = new WeasyPrintStatusProvider(weasyPrintServiceConnector); + + List configurationStatuses = weasyPrintStatusProvider.getStatuses(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(1, configurationStatuses.size()); + assertThat(configurationStatuses).containsExactlyInAnyOrder( + new ConfigurationStatus("WeasyPrint Service", Status.ERROR, "java.net.ConnectException: Connection refused") + ); + } + + @Test + void testUpdateWeasyPrintRequired() { + String timestamp = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).format(DateTimeFormatter.ISO_INSTANT); + WeasyPrintInfo weasyPrintInfo = WeasyPrintInfo.builder() + .chromium("129.0.6668.58") + .python("3.12.5") + .timestamp(timestamp) + .weasyprint("62.3") + .weasyprintService("62.4.5") + .build(); + + WeasyPrintServiceConnector weasyPrintServiceConnector = mock(WeasyPrintServiceConnector.class); + when(weasyPrintServiceConnector.getWeasyPrintInfo()).thenReturn(weasyPrintInfo); + WeasyPrintStatusProvider weasyPrintStatusProvider = new WeasyPrintStatusProvider(weasyPrintServiceConnector); + + try (MockedStatic versionsUtilsMockedStatic = mockStatic(VersionUtils.class)) { + versionsUtilsMockedStatic.when(VersionUtils::getLatestCompatibleVersionWeasyPrintService).thenReturn("62.4.6"); + + List configurationStatuses = weasyPrintStatusProvider.getStatuses(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(4, configurationStatuses.size()); + assertThat(configurationStatuses).containsExactlyInAnyOrder( + new ConfigurationStatus("WeasyPrint Service", Status.WARNING, "62.4.5 (" + timestamp + "): use latest compatible 62.4.6"), + new ConfigurationStatus("WeasyPrint Service: Chromium", Status.OK, "129.0.6668.58"), + new ConfigurationStatus("WeasyPrint Service: Python", Status.OK, "3.12.5"), + new ConfigurationStatus("WeasyPrint Service: WeasyPrint", Status.OK, "62.3") + ); + } + } + + @Test + void testUnknownWeasyPrintServiceVersion() { + String timestamp = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).format(DateTimeFormatter.ISO_INSTANT); + WeasyPrintInfo weasyPrintInfo = WeasyPrintInfo.builder() + .chromium("129.0.6668.58") + .python("3.12.5") + .timestamp(timestamp) + .weasyprint("62.3") + .weasyprintService(null) + .build(); + + WeasyPrintServiceConnector weasyPrintServiceConnector = mock(WeasyPrintServiceConnector.class); + when(weasyPrintServiceConnector.getWeasyPrintInfo()).thenReturn(weasyPrintInfo); + WeasyPrintStatusProvider weasyPrintStatusProvider = new WeasyPrintStatusProvider(weasyPrintServiceConnector); + + try (MockedStatic versionsUtilsMockedStatic = mockStatic(VersionUtils.class)) { + versionsUtilsMockedStatic.when(VersionUtils::getLatestCompatibleVersionWeasyPrintService).thenReturn("62.4.6"); + + List configurationStatuses = weasyPrintStatusProvider.getStatuses(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(4, configurationStatuses.size()); + assertThat(configurationStatuses).containsExactlyInAnyOrder( + new ConfigurationStatus("WeasyPrint Service", Status.ERROR, "Unknown (" + timestamp + "): use latest compatible 62.4.6"), + new ConfigurationStatus("WeasyPrint Service: Chromium", Status.OK, "129.0.6668.58"), + new ConfigurationStatus("WeasyPrint Service: Python", Status.OK, "3.12.5"), + new ConfigurationStatus("WeasyPrint Service: WeasyPrint", Status.OK, "62.3") + ); + } + } + + @Test + void testUnknownWeasyPrintServiceVersionNoTimestamp() { + WeasyPrintInfo weasyPrintInfo = WeasyPrintInfo.builder() + .chromium("129.0.6668.58") + .python("3.12.5") + .timestamp(null) + .weasyprint("62.3") + .weasyprintService(null) + .build(); + + WeasyPrintServiceConnector weasyPrintServiceConnector = mock(WeasyPrintServiceConnector.class); + when(weasyPrintServiceConnector.getWeasyPrintInfo()).thenReturn(weasyPrintInfo); + WeasyPrintStatusProvider weasyPrintStatusProvider = new WeasyPrintStatusProvider(weasyPrintServiceConnector); + + try (MockedStatic versionsUtilsMockedStatic = mockStatic(VersionUtils.class)) { + versionsUtilsMockedStatic.when(VersionUtils::getLatestCompatibleVersionWeasyPrintService).thenReturn("62.4.6"); + + List configurationStatuses = weasyPrintStatusProvider.getStatuses(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(4, configurationStatuses.size()); + assertThat(configurationStatuses).containsExactlyInAnyOrder( + new ConfigurationStatus("WeasyPrint Service", Status.ERROR, "Unknown: use latest compatible 62.4.6"), + new ConfigurationStatus("WeasyPrint Service: Chromium", Status.OK, "129.0.6668.58"), + new ConfigurationStatus("WeasyPrint Service: Python", Status.OK, "3.12.5"), + new ConfigurationStatus("WeasyPrint Service: WeasyPrint", Status.OK, "62.3") + ); + } + } + + @Test + void testNoTimestamp() { + WeasyPrintInfo weasyPrintInfo = WeasyPrintInfo.builder() + .chromium("129.0.6668.58") + .python("3.12.5") + .timestamp("") + .weasyprint("62.3") + .weasyprintService("62.4.5") + .build(); + + WeasyPrintServiceConnector weasyPrintServiceConnector = mock(WeasyPrintServiceConnector.class); + when(weasyPrintServiceConnector.getWeasyPrintInfo()).thenReturn(weasyPrintInfo); + WeasyPrintStatusProvider weasyPrintStatusProvider = new WeasyPrintStatusProvider(weasyPrintServiceConnector); + + try (MockedStatic versionsUtilsMockedStatic = mockStatic(VersionUtils.class)) { + versionsUtilsMockedStatic.when(VersionUtils::getLatestCompatibleVersionWeasyPrintService).thenReturn("62.4.6"); + + List configurationStatuses = weasyPrintStatusProvider.getStatuses(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(4, configurationStatuses.size()); + assertThat(configurationStatuses).containsExactlyInAnyOrder( + new ConfigurationStatus("WeasyPrint Service", Status.WARNING, "62.4.5: use latest compatible 62.4.6"), + new ConfigurationStatus("WeasyPrint Service: Chromium", Status.OK, "129.0.6668.58"), + new ConfigurationStatus("WeasyPrint Service: Python", Status.OK, "3.12.5"), + new ConfigurationStatus("WeasyPrint Service: WeasyPrint", Status.OK, "62.3") + ); + } + } + + @Test + void testNoChromiumVersion() { + String timestamp = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).format(DateTimeFormatter.ISO_INSTANT); + WeasyPrintInfo weasyPrintInfo = WeasyPrintInfo.builder() + .chromium("") + .python("3.12.5") + .timestamp(timestamp) + .weasyprint("62.3") + .weasyprintService("62.4.6") + .build(); + + WeasyPrintServiceConnector weasyPrintServiceConnector = mock(WeasyPrintServiceConnector.class); + when(weasyPrintServiceConnector.getWeasyPrintInfo()).thenReturn(weasyPrintInfo); + WeasyPrintStatusProvider weasyPrintStatusProvider = new WeasyPrintStatusProvider(weasyPrintServiceConnector); + + try (MockedStatic versionsUtilsMockedStatic = mockStatic(VersionUtils.class)) { + versionsUtilsMockedStatic.when(VersionUtils::getLatestCompatibleVersionWeasyPrintService).thenReturn("62.4.6"); + + List configurationStatuses = weasyPrintStatusProvider.getStatuses(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(4, configurationStatuses.size()); + assertThat(configurationStatuses).containsExactlyInAnyOrder( + new ConfigurationStatus("WeasyPrint Service", Status.OK, "62.4.6"), + new ConfigurationStatus("WeasyPrint Service: Chromium", Status.ERROR, "Unknown"), + new ConfigurationStatus("WeasyPrint Service: Python", Status.OK, "3.12.5"), + new ConfigurationStatus("WeasyPrint Service: WeasyPrint", Status.OK, "62.3") + ); + } + } + + @Test + void testWeasyPrintVersionIsHigherThanRequired() { + String timestamp = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).format(DateTimeFormatter.ISO_INSTANT); + WeasyPrintInfo weasyPrintInfo = WeasyPrintInfo.builder() + .chromium("129.0.6668.58") + .python("3.12.5") + .timestamp(timestamp) + .weasyprint("62.3") + .weasyprintService("62.4.7") + .build(); + + WeasyPrintServiceConnector weasyPrintServiceConnector = mock(WeasyPrintServiceConnector.class); + when(weasyPrintServiceConnector.getWeasyPrintInfo()).thenReturn(weasyPrintInfo); + WeasyPrintStatusProvider weasyPrintStatusProvider = new WeasyPrintStatusProvider(weasyPrintServiceConnector); + + try (MockedStatic versionsUtilsMockedStatic = mockStatic(VersionUtils.class)) { + versionsUtilsMockedStatic.when(VersionUtils::getLatestCompatibleVersionWeasyPrintService).thenReturn("62.4.6"); + + List configurationStatuses = weasyPrintStatusProvider.getStatuses(ConfigurationStatusProvider.Context.builder().build()); + + assertEquals(4, configurationStatuses.size()); + assertThat(configurationStatuses).containsExactlyInAnyOrder( + new ConfigurationStatus("WeasyPrint Service", Status.WARNING, "62.4.7 (" + timestamp + "): use latest compatible 62.4.6"), + new ConfigurationStatus("WeasyPrint Service: Chromium", Status.OK, "129.0.6668.58"), + new ConfigurationStatus("WeasyPrint Service: Python", Status.OK, "3.12.5"), + new ConfigurationStatus("WeasyPrint Service: WeasyPrint", Status.OK, "62.3") + ); + } + } + +} \ No newline at end of file