From 333157d0c5a875d09fb8091999caffc0bd0cc17f Mon Sep 17 00:00:00 2001 From: helen_yrofeeva Date: Thu, 5 Mar 2026 10:47:26 +0300 Subject: [PATCH 1/9] EPMHLM-503 pro release version --- .java-version | 1 + build.gradle | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .java-version diff --git a/.java-version b/.java-version new file mode 100644 index 0000000..98d9bcb --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +17 diff --git a/build.gradle b/build.gradle index 3b3f3eb..0acefd3 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { } group 'com.epam.healenium' -version '3.5.0' +version '3.5.1' repositories { From 63ad86c956cd52cc41af2f307e90d82285b89072 Mon Sep 17 00:00:00 2001 From: helen_yrofeeva Date: Fri, 6 Mar 2026 10:28:53 +0300 Subject: [PATCH 2/9] EPMHLM-498 docker file for remote debug --- Dockerfile_debug | 21 +++++++++++++++++++++ run.sh | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 Dockerfile_debug create mode 100644 run.sh diff --git a/Dockerfile_debug b/Dockerfile_debug new file mode 100644 index 0000000..a903974 --- /dev/null +++ b/Dockerfile_debug @@ -0,0 +1,21 @@ +FROM eclipse-temurin:23 +COPY /build/libs/healenium-backend-*.jar /healenium-backend.jar +CMD java -jar /healenium-backend.jar + + +LABEL maintainer="healenium" + +ENV JAR=healenium-backend.jar +ENV EXECUTABLE=run.sh + +WORKDIR / + +COPY /build/libs/healenium-backend-*.jar /${JAR} +COPY run.sh /${EXECUTABLE} + +RUN chmod +x /${EXECUTABLE} + +EXPOSE 7878 +EXPOSE 5005 + +CMD /${EXECUTABLE} \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..e20bad2 --- /dev/null +++ b/run.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +DEFAULT_JAVA_OPTIONS="-XX:+UseG1GC -XX:MaxRAMPercentage=75" +DEBUG_OPTIONS="" + +if [ -n "${JAVA_DEBUG_ENABLE:-}" ] || [ -n "${JAVA_DEBUG:-}" ]; then + debug_port="${JAVA_DEBUG_PORT:-5005}" + DEBUG_OPTIONS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:${debug_port}" +fi + +echo -e "run.sh configuration:" +echo -e "\tDEFAULT_JAVA_OPTIONS: ${DEFAULT_JAVA_OPTIONS:-}" +echo -e "\tJAVA_OPTIONS: ${JAVA_OPTIONS:-}" +echo -e "\tDEBUG_OPTIONS: ${DEBUG_OPTIONS:-}" + +java $DEFAULT_JAVA_OPTIONS $JAVA_OPTIONS $DEBUG_OPTIONS -jar /$JAR + From 991cb6d4ff494cf6e910286fbf62a9a477962de4 Mon Sep 17 00:00:00 2001 From: helen_yrofeeva Date: Mon, 9 Mar 2026 17:38:11 +0300 Subject: [PATCH 3/9] [EPMHLM-498] update report data endpoint output --- .../service/impl/ReportServiceImpl.java | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java b/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java index 2be45f5..b747349 100644 --- a/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java +++ b/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java @@ -369,16 +369,25 @@ private ReportRecord createReportRecord(RecordWrapper.Record record) { } private void setDeclaringClass(ReportRecord reportRecord, RecordWrapper.Record record) { - String className = getClassNameFromSelector(record); + String classNameFromSelector = getClassNameFromSelector(record); - if ("HealeniumFindElementPostRequest".equals(className)) { + if ("HealeniumFindElementPostRequest".equals(classNameFromSelector)) { reportRecord.setDeclaringClass(record.getFailedLocator().getValue()); + return; } - else if (className != null && !className.trim().isEmpty()) { - reportRecord.setDeclaringClass(className); - } else { - setDeclaringClassFromRecord(reportRecord, record); + + String classNameFromRecord = getDeclaringClassFromRecord(record); + if (org.springframework.util.StringUtils.hasText(classNameFromRecord)) { + reportRecord.setDeclaringClass(classNameFromRecord); + return; } + + if (classNameFromSelector != null && !classNameFromSelector.trim().isEmpty()) { + reportRecord.setDeclaringClass(classNameFromSelector); + return; + } + + reportRecord.setDeclaringClass("Not Set"); } private String getClassNameFromSelector(RecordWrapper.Record record) { @@ -389,18 +398,21 @@ private String getClassNameFromSelector(RecordWrapper.Record record) { .orElse(null); } - private void setDeclaringClassFromRecord(ReportRecord reportRecord, RecordWrapper.Record record) { + private static final List PW_FILE_ENDINGS = List.of(".js",".ts",".cs",".py"); + + private String getDeclaringClassFromRecord(RecordWrapper.Record record) { String className = record.getClassName(); - if (className != null) { + if (className == null) { + return ""; + } + boolean hasPlaywrightFileEnding = PW_FILE_ENDINGS.stream().anyMatch(className::endsWith); + if (!hasPlaywrightFileEnding){ String[] path = className.split("\\."); if (path.length > 0) { - reportRecord.setDeclaringClass(path[path.length - 1]); - } else { - reportRecord.setDeclaringClass(className); + return path[path.length - 1]; } - } else { - reportRecord.setDeclaringClass("Not Set"); } + return className; } private void setCommonFields(ReportRecord reportRecord, RecordWrapper.Record record) { From 9c37ad7c30e70cdc8d3aef2182a1605549408d22 Mon Sep 17 00:00:00 2001 From: helen_yrofeeva Date: Wed, 11 Mar 2026 15:36:55 +0300 Subject: [PATCH 4/9] [EPMHLM-498] don't replace report record class_name if selector class is not HealeniumFindElementPostRequest --- .../service/impl/ReportServiceImpl.java | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java b/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java index b747349..0d44929 100644 --- a/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java +++ b/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java @@ -377,17 +377,7 @@ private void setDeclaringClass(ReportRecord reportRecord, RecordWrapper.Record r } String classNameFromRecord = getDeclaringClassFromRecord(record); - if (org.springframework.util.StringUtils.hasText(classNameFromRecord)) { - reportRecord.setDeclaringClass(classNameFromRecord); - return; - } - - if (classNameFromSelector != null && !classNameFromSelector.trim().isEmpty()) { - reportRecord.setDeclaringClass(classNameFromSelector); - return; - } - - reportRecord.setDeclaringClass("Not Set"); + reportRecord.setDeclaringClass(classNameFromRecord); } private String getClassNameFromSelector(RecordWrapper.Record record) { @@ -398,19 +388,10 @@ private String getClassNameFromSelector(RecordWrapper.Record record) { .orElse(null); } - private static final List PW_FILE_ENDINGS = List.of(".js",".ts",".cs",".py"); - private String getDeclaringClassFromRecord(RecordWrapper.Record record) { String className = record.getClassName(); if (className == null) { - return ""; - } - boolean hasPlaywrightFileEnding = PW_FILE_ENDINGS.stream().anyMatch(className::endsWith); - if (!hasPlaywrightFileEnding){ - String[] path = className.split("\\."); - if (path.length > 0) { - return path[path.length - 1]; - } + return "Not Set"; } return className; } From 4dd11fef6c97be339890e0ded04b5751ec46b8c1 Mon Sep 17 00:00:00 2001 From: helen_yrofeeva Date: Tue, 17 Mar 2026 14:50:31 +0300 Subject: [PATCH 5/9] EPMHLM-498 optimize imports to not use * --- .../healenium/controller/HealingController.java | 6 +++--- .../healenium/controller/ImageController.java | 6 +++++- .../controller/IntegrationController.java | 16 +++++++++++++--- .../epam/healenium/controller/LogController.java | 6 +++++- .../healenium/controller/ReportController.java | 15 +++++++++++---- .../epam/healenium/converter/NodeConverter.java | 1 - .../converter/RecordWrapperConverter.java | 1 - .../com/epam/healenium/mapper/LocatorMapper.java | 6 +++--- .../com/epam/healenium/model/domain/Healing.java | 15 +++++++++++++-- .../healenium/model/domain/HealingResult.java | 13 ++++++++++++- .../com/epam/healenium/model/domain/Report.java | 10 ++++++++-- .../epam/healenium/model/domain/Selector.java | 9 ++++++++- .../epam/healenium/service/SelectorService.java | 7 ++++++- .../service/impl/HealingServiceImpl.java | 7 +------ .../service/impl/IntegrationServiceImpl.java | 5 ++++- .../service/impl/ReportServiceImpl.java | 2 +- .../service/impl/SelectorServiceImpl.java | 8 ++++++-- .../java/com/epam/healenium/util/JpaTools.java | 7 ++++++- .../com/epam/healenium/util/LogFileReader.java | 11 ++++++++--- src/main/resources/templates/selector.html | 3 ++- 20 files changed, 115 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/epam/healenium/controller/HealingController.java b/src/main/java/com/epam/healenium/controller/HealingController.java index 1b0307b..848c749 100644 --- a/src/main/java/com/epam/healenium/controller/HealingController.java +++ b/src/main/java/com/epam/healenium/controller/HealingController.java @@ -16,15 +16,15 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.validation.FieldError; import org.springframework.web.servlet.ModelAndView; import javax.validation.Valid; diff --git a/src/main/java/com/epam/healenium/controller/ImageController.java b/src/main/java/com/epam/healenium/controller/ImageController.java index dda3f65..9a26c44 100644 --- a/src/main/java/com/epam/healenium/controller/ImageController.java +++ b/src/main/java/com/epam/healenium/controller/ImageController.java @@ -4,7 +4,11 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.compress.utils.IOUtils; import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; import java.io.FileInputStream; import java.io.IOException; diff --git a/src/main/java/com/epam/healenium/controller/IntegrationController.java b/src/main/java/com/epam/healenium/controller/IntegrationController.java index 2947097..4a2471b 100644 --- a/src/main/java/com/epam/healenium/controller/IntegrationController.java +++ b/src/main/java/com/epam/healenium/controller/IntegrationController.java @@ -2,15 +2,25 @@ import com.epam.healenium.model.domain.HealingResult; import com.epam.healenium.model.domain.Report; -import com.epam.healenium.model.dto.elitea.*; +import com.epam.healenium.model.dto.elitea.DedicatedInfo; +import com.epam.healenium.model.dto.elitea.LlmDto; +import com.epam.healenium.model.dto.elitea.LocatorPathsDto; +import com.epam.healenium.model.dto.elitea.VcsDto; import com.epam.healenium.repository.ReportRepository; +import com.epam.healenium.service.IntegrationService; import com.epam.healenium.service.ReportService; import com.epam.healenium.service.SelectorService; -import com.epam.healenium.service.IntegrationService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.util.List; diff --git a/src/main/java/com/epam/healenium/controller/LogController.java b/src/main/java/com/epam/healenium/controller/LogController.java index bbea9b1..f06901c 100644 --- a/src/main/java/com/epam/healenium/controller/LogController.java +++ b/src/main/java/com/epam/healenium/controller/LogController.java @@ -4,7 +4,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/src/main/java/com/epam/healenium/controller/ReportController.java b/src/main/java/com/epam/healenium/controller/ReportController.java index 500ee5e..62c58e9 100644 --- a/src/main/java/com/epam/healenium/controller/ReportController.java +++ b/src/main/java/com/epam/healenium/controller/ReportController.java @@ -8,14 +8,21 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +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.servlet.ModelAndView; -import java.time.LocalDateTime; -import java.util.Map; - import java.nio.file.Paths; +import java.time.LocalDateTime; import java.util.List; +import java.util.Map; @Slf4j @RestController diff --git a/src/main/java/com/epam/healenium/converter/NodeConverter.java b/src/main/java/com/epam/healenium/converter/NodeConverter.java index e87f700..da41c97 100644 --- a/src/main/java/com/epam/healenium/converter/NodeConverter.java +++ b/src/main/java/com/epam/healenium/converter/NodeConverter.java @@ -8,7 +8,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; - import java.io.IOException; @Component diff --git a/src/main/java/com/epam/healenium/converter/RecordWrapperConverter.java b/src/main/java/com/epam/healenium/converter/RecordWrapperConverter.java index 781e216..b4c67a0 100644 --- a/src/main/java/com/epam/healenium/converter/RecordWrapperConverter.java +++ b/src/main/java/com/epam/healenium/converter/RecordWrapperConverter.java @@ -8,7 +8,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; - import java.io.IOException; @Slf4j diff --git a/src/main/java/com/epam/healenium/mapper/LocatorMapper.java b/src/main/java/com/epam/healenium/mapper/LocatorMapper.java index fea2e5f..fdbc13f 100644 --- a/src/main/java/com/epam/healenium/mapper/LocatorMapper.java +++ b/src/main/java/com/epam/healenium/mapper/LocatorMapper.java @@ -1,14 +1,14 @@ package com.epam.healenium.mapper; -import java.util.Collection; -import java.util.Set; - import com.epam.healenium.model.Locator; import org.mapstruct.IterableMapping; import org.mapstruct.Mapper; import org.mapstruct.ReportingPolicy; import org.openqa.selenium.By; +import java.util.Collection; +import java.util.Set; + @Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) public interface LocatorMapper { diff --git a/src/main/java/com/epam/healenium/model/domain/Healing.java b/src/main/java/com/epam/healenium/model/domain/Healing.java index 27b90be..0dbfe90 100644 --- a/src/main/java/com/epam/healenium/model/domain/Healing.java +++ b/src/main/java/com/epam/healenium/model/domain/Healing.java @@ -1,7 +1,18 @@ package com.epam.healenium.model.domain; -import jakarta.persistence.*; -import lombok.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; import lombok.experimental.Accessors; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.CreationTimestamp; diff --git a/src/main/java/com/epam/healenium/model/domain/HealingResult.java b/src/main/java/com/epam/healenium/model/domain/HealingResult.java index 4b473d3..e718ebb 100644 --- a/src/main/java/com/epam/healenium/model/domain/HealingResult.java +++ b/src/main/java/com/epam/healenium/model/domain/HealingResult.java @@ -1,7 +1,18 @@ package com.epam.healenium.model.domain; import com.epam.healenium.model.Locator; -import jakarta.persistence.*; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/com/epam/healenium/model/domain/Report.java b/src/main/java/com/epam/healenium/model/domain/Report.java index b700e4d..debba6b 100644 --- a/src/main/java/com/epam/healenium/model/domain/Report.java +++ b/src/main/java/com/epam/healenium/model/domain/Report.java @@ -2,11 +2,17 @@ import com.epam.healenium.converter.RecordWrapperConverter; import com.epam.healenium.model.wrapper.RecordWrapper; -import jakarta.persistence.*; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.Version; import lombok.Data; import lombok.experimental.Accessors; import org.hibernate.annotations.CreationTimestamp; -import org.hibernate.annotations.GenericGenerator; import java.time.LocalDateTime; diff --git a/src/main/java/com/epam/healenium/model/domain/Selector.java b/src/main/java/com/epam/healenium/model/domain/Selector.java index a220fea..888b0de 100644 --- a/src/main/java/com/epam/healenium/model/domain/Selector.java +++ b/src/main/java/com/epam/healenium/model/domain/Selector.java @@ -3,7 +3,13 @@ import com.epam.healenium.converter.NodeConverter; import com.epam.healenium.model.Locator; import com.epam.healenium.model.wrapper.NodePathWrapper; -import jakarta.persistence.*; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import lombok.Data; import lombok.ToString; import lombok.experimental.Accessors; @@ -11,6 +17,7 @@ import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.type.SqlTypes; + import java.time.LocalDateTime; /** diff --git a/src/main/java/com/epam/healenium/service/SelectorService.java b/src/main/java/com/epam/healenium/service/SelectorService.java index 585825a..ba172ef 100644 --- a/src/main/java/com/epam/healenium/service/SelectorService.java +++ b/src/main/java/com/epam/healenium/service/SelectorService.java @@ -1,7 +1,12 @@ package com.epam.healenium.service; import com.epam.healenium.model.domain.Selector; -import com.epam.healenium.model.dto.*; +import com.epam.healenium.model.dto.ConfigSelectorDto; +import com.epam.healenium.model.dto.RecordDto; +import com.epam.healenium.model.dto.ReferenceElementsDto; +import com.epam.healenium.model.dto.RequestDto; +import com.epam.healenium.model.dto.SelectorDto; +import com.epam.healenium.model.dto.SelectorRequestDto; import com.epam.healenium.model.dto.elitea.LocatorPathsDto; import java.util.List; diff --git a/src/main/java/com/epam/healenium/service/impl/HealingServiceImpl.java b/src/main/java/com/epam/healenium/service/impl/HealingServiceImpl.java index 5304fe2..d0a46ef 100644 --- a/src/main/java/com/epam/healenium/service/impl/HealingServiceImpl.java +++ b/src/main/java/com/epam/healenium/service/impl/HealingServiceImpl.java @@ -37,12 +37,7 @@ import java.util.Set; import java.util.stream.Collectors; -import static com.epam.healenium.constants.Constants.EMPTY_PROJECT; -import static com.epam.healenium.constants.Constants.HOST_PROJECT; -import static com.epam.healenium.constants.Constants.SESSION_KEY_V1; -import static com.epam.healenium.constants.Constants.SESSION_KEY_V2; -import static com.epam.healenium.constants.Constants.SUCCESSFUL_HEALING_BUCKET; -import static com.epam.healenium.constants.Constants.UNSUCCESSFUL_HEALING_BUCKET; +import static com.epam.healenium.constants.Constants.*; @Slf4j @Service diff --git a/src/main/java/com/epam/healenium/service/impl/IntegrationServiceImpl.java b/src/main/java/com/epam/healenium/service/impl/IntegrationServiceImpl.java index b65ac44..ac0e856 100644 --- a/src/main/java/com/epam/healenium/service/impl/IntegrationServiceImpl.java +++ b/src/main/java/com/epam/healenium/service/impl/IntegrationServiceImpl.java @@ -15,7 +15,10 @@ import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; -import java.util.*; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.UUID; @Slf4j @Service diff --git a/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java b/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java index 0d44929..1063918 100644 --- a/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java +++ b/src/main/java/com/epam/healenium/service/impl/ReportServiceImpl.java @@ -17,12 +17,12 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.orm.ObjectOptimisticLockingFailureException; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; -import org.apache.commons.io.FileUtils; import java.io.File; import java.nio.file.Paths; diff --git a/src/main/java/com/epam/healenium/service/impl/SelectorServiceImpl.java b/src/main/java/com/epam/healenium/service/impl/SelectorServiceImpl.java index 8fa78dd..94c8f17 100644 --- a/src/main/java/com/epam/healenium/service/impl/SelectorServiceImpl.java +++ b/src/main/java/com/epam/healenium/service/impl/SelectorServiceImpl.java @@ -8,7 +8,12 @@ import com.epam.healenium.model.domain.HealingResult; import com.epam.healenium.model.domain.Report; import com.epam.healenium.model.domain.Selector; -import com.epam.healenium.model.dto.*; +import com.epam.healenium.model.dto.ConfigSelectorDto; +import com.epam.healenium.model.dto.RecordDto; +import com.epam.healenium.model.dto.ReferenceElementsDto; +import com.epam.healenium.model.dto.RequestDto; +import com.epam.healenium.model.dto.SelectorDto; +import com.epam.healenium.model.dto.SelectorRequestDto; import com.epam.healenium.model.dto.elitea.LocatorPathsDto; import com.epam.healenium.model.wrapper.RecordWrapper; import com.epam.healenium.repository.HealingRepository; @@ -21,7 +26,6 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.Collections; diff --git a/src/main/java/com/epam/healenium/util/JpaTools.java b/src/main/java/com/epam/healenium/util/JpaTools.java index 16f7176..3c86203 100644 --- a/src/main/java/com/epam/healenium/util/JpaTools.java +++ b/src/main/java/com/epam/healenium/util/JpaTools.java @@ -1,6 +1,11 @@ package com.epam.healenium.util; -import jakarta.persistence.criteria.*; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Fetch; +import jakarta.persistence.criteria.From; +import jakarta.persistence.criteria.Join; +import jakarta.persistence.criteria.JoinType; +import jakarta.persistence.criteria.Root; import jakarta.persistence.metamodel.SetAttribute; import jakarta.persistence.metamodel.SingularAttribute; import lombok.experimental.UtilityClass; diff --git a/src/main/java/com/epam/healenium/util/LogFileReader.java b/src/main/java/com/epam/healenium/util/LogFileReader.java index d6b5e5e..8cb621b 100644 --- a/src/main/java/com/epam/healenium/util/LogFileReader.java +++ b/src/main/java/com/epam/healenium/util/LogFileReader.java @@ -3,11 +3,16 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import java.io.*; -import java.nio.file.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.GZIPInputStream; diff --git a/src/main/resources/templates/selector.html b/src/main/resources/templates/selector.html index fb89aa1..5d733a5 100644 --- a/src/main/resources/templates/selector.html +++ b/src/main/resources/templates/selector.html @@ -342,7 +342,8 @@

Selectors

method:

- Date: Fri, 20 Mar 2026 17:39:25 +0300 Subject: [PATCH 6/9] Fix Vulnerabilities --- build.gradle | 29 ++++++++---- .../config/JacksonConfiguration.java | 24 +++++----- .../config/LiquibaseConfiguration.java | 2 +- .../config/WebClientConfiguration.java | 18 ++++++++ .../healenium/config/WebConfiguration.java | 14 ------ .../converter/HealingRequestConverter.java | 2 +- .../healenium/converter/NodeConverter.java | 10 ++--- .../healenium/converter/NodeDeserializer.java | 34 +++++++------- .../healenium/converter/NodeSerializer.java | 45 +++++++++++-------- .../converter/RecordWrapperConverter.java | 10 ++--- .../generator/ReportUUIDGenerator.java | 5 ++- .../com/epam/healenium/model/Locator.java | 23 +++++----- .../healenium/model/dto/HealingResultDto.java | 8 ++-- .../healenium/rest/AmazonRestService.java | 6 ++- .../rest/IntegrationRestService.java | 4 +- .../specification/HealingSpecBuilder.java | 2 +- .../com/epam/healenium/TestSaveLocators.java | 13 +++--- 17 files changed, 138 insertions(+), 111 deletions(-) create mode 100644 src/main/java/com/epam/healenium/config/WebClientConfiguration.java delete mode 100644 src/main/java/com/epam/healenium/config/WebConfiguration.java diff --git a/build.gradle b/build.gradle index 0acefd3..3d7d798 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'org.springframework.boot' version '3.5.8' - id 'io.spring.dependency-management' version "1.1.4" + id 'org.springframework.boot' version '4.0.4' + id 'io.spring.dependency-management' version "1.1.7" id 'java' id 'maven-publish' id 'jacoco' @@ -24,8 +24,10 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'org.springframework.boot:spring-boot-starter-logging' implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springframework.retry:spring-retry' - implementation 'org.springframework.boot:spring-boot-starter-aop' + + implementation 'org.springframework.retry:spring-retry:2.0.12' + + implementation 'org.springframework.boot:spring-boot-starter-aspectj' implementation 'org.liquibase:liquibase-core:4.33.0' implementation 'org.postgresql:postgresql:42.7.7' implementation 'com.zaxxer:HikariCP:3.3.1' @@ -35,12 +37,13 @@ dependencies { implementation 'com.google.guava:guava:32.1.1-jre' implementation 'com.epam.healenium:tree-comparing:0.4.14' implementation 'org.seleniumhq.selenium:selenium-java:4.25.0' - implementation 'org.projectlombok:lombok:1.18.22' + compileOnly 'org.projectlombok:lombok:1.18.36' implementation 'org.mapstruct:mapstruct:1.3.1.Final' implementation group: 'io.netty', name: 'netty-handler', version: '4.1.125.Final' implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.16' implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.5.16' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.0' + + implementation 'org.testcontainers:junit-jupiter:1.19.3' implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.26.0' @@ -50,10 +53,13 @@ dependencies { testImplementation 'io.rest-assured:rest-assured:5.3.2' testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test' + - annotationProcessor 'org.hibernate.orm:hibernate-jpamodelgen:6.3.1.Final' - annotationProcessor 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' + + annotationProcessor 'org.hibernate.orm:hibernate-processor' + annotationProcessor 'org.projectlombok:lombok:1.18.36' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.36' annotationProcessor 'org.mapstruct:mapstruct-processor:1.3.1.Final' testAnnotationProcessor 'org.mapstruct:mapstruct-processor:1.3.1.Final' } @@ -70,3 +76,8 @@ jacocoTestReport { group = "reporting" description = "Generate Jacoco coverage reports after running tests." } + +tasks.withType(JavaCompile).configureEach { + options.compilerArgs.add('-parameters') +} + diff --git a/src/main/java/com/epam/healenium/config/JacksonConfiguration.java b/src/main/java/com/epam/healenium/config/JacksonConfiguration.java index 9dc041c..bf93b3f 100644 --- a/src/main/java/com/epam/healenium/config/JacksonConfiguration.java +++ b/src/main/java/com/epam/healenium/config/JacksonConfiguration.java @@ -3,27 +3,29 @@ import com.epam.healenium.converter.NodeDeserializer; import com.epam.healenium.converter.NodeSerializer; import com.epam.healenium.treecomparing.Node; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import tools.jackson.databind.DeserializationFeature; +import tools.jackson.databind.ObjectMapper; +import tools.jackson.databind.cfg.DateTimeFeature; +import tools.jackson.databind.json.JsonMapper; +import tools.jackson.databind.module.SimpleModule; @Configuration public class JacksonConfiguration { @Bean public ObjectMapper objectMapper() { - SimpleModule module = new SimpleModule("node") + SimpleModule nodeModule = new SimpleModule("node") .addSerializer(Node.class, new NodeSerializer()) .addDeserializer(Node.class, new NodeDeserializer()); - return new ObjectMapper() - .registerModule(module) - .registerModule(new JavaTimeModule()) + return JsonMapper.builder() + .findAndAddModules() + .addModule(nodeModule) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) - .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); + .configure(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT) + .build(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/epam/healenium/config/LiquibaseConfiguration.java b/src/main/java/com/epam/healenium/config/LiquibaseConfiguration.java index 4fdcafc..d2c3004 100644 --- a/src/main/java/com/epam/healenium/config/LiquibaseConfiguration.java +++ b/src/main/java/com/epam/healenium/config/LiquibaseConfiguration.java @@ -1,7 +1,7 @@ package com.epam.healenium.config; import com.zaxxer.hikari.HikariDataSource; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; diff --git a/src/main/java/com/epam/healenium/config/WebClientConfiguration.java b/src/main/java/com/epam/healenium/config/WebClientConfiguration.java new file mode 100644 index 0000000..db75996 --- /dev/null +++ b/src/main/java/com/epam/healenium/config/WebClientConfiguration.java @@ -0,0 +1,18 @@ +package com.epam.healenium.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +/** + * Servlet-based apps do not get a {@link WebClient.Builder} bean from auto-configuration in Spring Boot 4; + * outbound WebClient calls still need an explicit bean. + */ +@Configuration +public class WebClientConfiguration { + + @Bean + public WebClient.Builder webClientBuilder() { + return WebClient.builder(); + } +} diff --git a/src/main/java/com/epam/healenium/config/WebConfiguration.java b/src/main/java/com/epam/healenium/config/WebConfiguration.java deleted file mode 100644 index 992609b..0000000 --- a/src/main/java/com/epam/healenium/config/WebConfiguration.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.epam.healenium.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class WebConfiguration implements WebMvcConfigurer { - - @Override - public void configurePathMatch(PathMatchConfigurer configurer) { - configurer.setUseTrailingSlashMatch(true); - } -} diff --git a/src/main/java/com/epam/healenium/converter/HealingRequestConverter.java b/src/main/java/com/epam/healenium/converter/HealingRequestConverter.java index 7213ad1..18fb80c 100644 --- a/src/main/java/com/epam/healenium/converter/HealingRequestConverter.java +++ b/src/main/java/com/epam/healenium/converter/HealingRequestConverter.java @@ -1,12 +1,12 @@ package com.epam.healenium.converter; import com.epam.healenium.model.dto.HealingRequestDto; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; +import tools.jackson.databind.ObjectMapper; @Slf4j @Component diff --git a/src/main/java/com/epam/healenium/converter/NodeConverter.java b/src/main/java/com/epam/healenium/converter/NodeConverter.java index da41c97..8ed8150 100644 --- a/src/main/java/com/epam/healenium/converter/NodeConverter.java +++ b/src/main/java/com/epam/healenium/converter/NodeConverter.java @@ -1,14 +1,12 @@ package com.epam.healenium.converter; import com.epam.healenium.model.wrapper.NodePathWrapper; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.AttributeConverter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; - -import java.io.IOException; +import tools.jackson.core.JacksonException; +import tools.jackson.databind.ObjectMapper; @Component @Slf4j @@ -23,7 +21,7 @@ public String convertToDatabaseColumn(NodePathWrapper nodePathWrapper) { String nodePathWrapperJson = null; try { nodePathWrapperJson = objectMapper.writeValueAsString(nodePathWrapper); - } catch (final JsonProcessingException e) { + } catch (final JacksonException e) { log.error("JSON writing error", e); } @@ -36,7 +34,7 @@ public NodePathWrapper convertToEntityAttribute(String nodePathWrapperJson) { NodePathWrapper nodePathWrapper = null; try { nodePathWrapper = objectMapper.readValue(nodePathWrapperJson, NodePathWrapper.class); - } catch (final IOException e) { + } catch (final JacksonException e) { log.error("JSON reading error", e); } diff --git a/src/main/java/com/epam/healenium/converter/NodeDeserializer.java b/src/main/java/com/epam/healenium/converter/NodeDeserializer.java index 6b93a11..693cc2e 100644 --- a/src/main/java/com/epam/healenium/converter/NodeDeserializer.java +++ b/src/main/java/com/epam/healenium/converter/NodeDeserializer.java @@ -3,28 +3,30 @@ import com.epam.healenium.constants.FieldName; import com.epam.healenium.treecomparing.Node; import com.epam.healenium.treecomparing.NodeBuilder; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.TreeNode; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; +import tools.jackson.core.JacksonException; +import tools.jackson.core.JsonParser; +import tools.jackson.databind.DeserializationContext; +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.deser.std.StdDeserializer; -import java.io.IOException; import java.util.Map; @SuppressWarnings("unchecked") -public class NodeDeserializer extends JsonDeserializer { +public class NodeDeserializer extends StdDeserializer { + + public NodeDeserializer() { + super(Node.class); + } @Override - public Node deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException { - ObjectCodec codec = parser.getCodec(); - TreeNode tree = parser.readValueAsTree(); - String tag = codec.treeToValue(tree.path(FieldName.TAG), String.class); - Integer index = codec.treeToValue(tree.path(FieldName.INDEX), Integer.class); - String innerText = codec.treeToValue(tree.path(FieldName.INNER_TEXT), String.class); - String id = codec.treeToValue(tree.path(FieldName.ID), String.class); - String classes = codec.treeToValue(tree.path(FieldName.CLASSES), String.class); - Map attributes = codec.treeToValue(tree.path(FieldName.OTHER), Map.class); + public Node deserialize(JsonParser parser, DeserializationContext ctxt) throws JacksonException { + JsonNode tree = ctxt.readTree(parser); + String tag = ctxt.readTreeAsValue(tree.path(FieldName.TAG), String.class); + Integer index = ctxt.readTreeAsValue(tree.path(FieldName.INDEX), Integer.class); + String innerText = ctxt.readTreeAsValue(tree.path(FieldName.INNER_TEXT), String.class); + String id = ctxt.readTreeAsValue(tree.path(FieldName.ID), String.class); + String classes = ctxt.readTreeAsValue(tree.path(FieldName.CLASSES), String.class); + Map attributes = ctxt.readTreeAsValue(tree.path(FieldName.OTHER), Map.class); attributes.put(FieldName.ID, id); attributes.put(FieldName.CLASS, classes); diff --git a/src/main/java/com/epam/healenium/converter/NodeSerializer.java b/src/main/java/com/epam/healenium/converter/NodeSerializer.java index d13663f..739a4d1 100644 --- a/src/main/java/com/epam/healenium/converter/NodeSerializer.java +++ b/src/main/java/com/epam/healenium/converter/NodeSerializer.java @@ -2,34 +2,43 @@ import com.epam.healenium.constants.FieldName; import com.epam.healenium.treecomparing.Node; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.core.type.WritableTypeId; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.jsontype.TypeSerializer; +import tools.jackson.core.JacksonException; +import tools.jackson.core.JsonGenerator; +import tools.jackson.core.JsonToken; +import tools.jackson.core.type.WritableTypeId; +import tools.jackson.databind.SerializationContext; +import tools.jackson.databind.jsontype.TypeSerializer; +import tools.jackson.databind.ser.std.StdSerializer; -import java.io.IOException; +public class NodeSerializer extends StdSerializer { -public class NodeSerializer extends JsonSerializer { + public NodeSerializer() { + super(Node.class); + } @Override - public void serializeWithType(Node value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException { + public void serializeWithType(Node value, JsonGenerator gen, SerializationContext serializers, TypeSerializer typeSer) + throws JacksonException { WritableTypeId typeId = typeSer.typeId(value, Node.class, JsonToken.START_OBJECT); - typeSer.writeTypePrefix(gen, typeId); + typeSer.writeTypePrefix(gen, serializers, typeId); serialize(value, gen, serializers); - typeSer.writeTypeSuffix(gen, typeId); + typeSer.writeTypeSuffix(gen, serializers, typeId); } @Override - public void serialize(Node value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + public void serialize(Node value, JsonGenerator gen, SerializationContext serializers) throws JacksonException { gen.writeStartObject(); - gen.writeStringField(FieldName.TAG, value.getTag()); - gen.writeNumberField(FieldName.INDEX, value.getIndex()); - gen.writeStringField(FieldName.INNER_TEXT, value.getInnerText()); - gen.writeStringField(FieldName.ID, value.getId()); - gen.writeStringField(FieldName.CLASSES, String.join(" ", value.getClasses())); - gen.writeObjectField(FieldName.OTHER, value.getOtherAttributes()); + gen.writeStringProperty(FieldName.TAG, value.getTag()); + Integer index = value.getIndex(); + if (index != null) { + gen.writeNumberProperty(FieldName.INDEX, index); + } else { + gen.writeNullProperty(FieldName.INDEX); + } + gen.writeStringProperty(FieldName.INNER_TEXT, value.getInnerText()); + gen.writeStringProperty(FieldName.ID, value.getId()); + gen.writeStringProperty(FieldName.CLASSES, String.join(" ", value.getClasses())); + gen.writePOJOProperty(FieldName.OTHER, value.getOtherAttributes()); gen.writeEndObject(); gen.flush(); } diff --git a/src/main/java/com/epam/healenium/converter/RecordWrapperConverter.java b/src/main/java/com/epam/healenium/converter/RecordWrapperConverter.java index b4c67a0..dd614c8 100644 --- a/src/main/java/com/epam/healenium/converter/RecordWrapperConverter.java +++ b/src/main/java/com/epam/healenium/converter/RecordWrapperConverter.java @@ -1,14 +1,12 @@ package com.epam.healenium.converter; import com.epam.healenium.model.wrapper.RecordWrapper; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.AttributeConverter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; - -import java.io.IOException; +import tools.jackson.core.JacksonException; +import tools.jackson.databind.ObjectMapper; @Slf4j @Component @@ -22,7 +20,7 @@ public String convertToDatabaseColumn(RecordWrapper recordWrapper) { String recordWrapperJson = null; try { recordWrapperJson = objectMapper.writeValueAsString(recordWrapper); - } catch (final JsonProcessingException e) { + } catch (final JacksonException e) { log.error("JSON writing error", e); } @@ -34,7 +32,7 @@ public RecordWrapper convertToEntityAttribute(String recordJSON) { RecordWrapper recordWrapper = null; try { recordWrapper = objectMapper.readValue(recordJSON, RecordWrapper.class); - } catch (final IOException e) { + } catch (final JacksonException e) { log.error("JSON reading error", e); } diff --git a/src/main/java/com/epam/healenium/generator/ReportUUIDGenerator.java b/src/main/java/com/epam/healenium/generator/ReportUUIDGenerator.java index a2763d7..3677082 100644 --- a/src/main/java/com/epam/healenium/generator/ReportUUIDGenerator.java +++ b/src/main/java/com/epam/healenium/generator/ReportUUIDGenerator.java @@ -3,6 +3,7 @@ import org.hibernate.HibernateException; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.UUIDGenerator; +import org.hibernate.persister.entity.EntityPersister; import java.io.Serializable; @@ -10,8 +11,8 @@ public class ReportUUIDGenerator extends UUIDGenerator { @Override public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException { - Serializable id = (Serializable) session.getEntityPersister(null, object) - .getClassMetadata().getIdentifier(object, session); + EntityPersister persister = session.getEntityPersister(null, object); + Serializable id = (Serializable) persister.getIdentifier(object, session); return id != null ? id : (Serializable) super.generate(session, object); } } diff --git a/src/main/java/com/epam/healenium/model/Locator.java b/src/main/java/com/epam/healenium/model/Locator.java index b9d2ee2..53fc72b 100644 --- a/src/main/java/com/epam/healenium/model/Locator.java +++ b/src/main/java/com/epam/healenium/model/Locator.java @@ -1,20 +1,19 @@ package com.epam.healenium.model; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.io.Serializable; -@Data -public class Locator implements Serializable { +/** + * Immutable locator value; JSON maps {@code {"value","type"}} to record components. + * Requires {@code -parameters} on compile so Jackson 3 binds JSON property names to components. + * {@code getValue()}/{@code getType()} exist for MapStruct and existing call sites. + */ +public record Locator(String value, String type) implements Serializable { - private final String value; - private final String type; + public String getValue() { + return value; + } - @JsonCreator - public Locator(@JsonProperty("value") String value, @JsonProperty("type") String type) { - this.value = value; - this.type = type; + public String getType() { + return type; } } diff --git a/src/main/java/com/epam/healenium/model/dto/HealingResultDto.java b/src/main/java/com/epam/healenium/model/dto/HealingResultDto.java index 7c3f251..ce13906 100644 --- a/src/main/java/com/epam/healenium/model/dto/HealingResultDto.java +++ b/src/main/java/com/epam/healenium/model/dto/HealingResultDto.java @@ -1,11 +1,11 @@ package com.epam.healenium.model.dto; import com.epam.healenium.model.Locator; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; -import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import lombok.Data; +import tools.jackson.databind.annotation.JsonDeserialize; +import tools.jackson.databind.annotation.JsonSerialize; +import tools.jackson.databind.ext.javatime.deser.LocalDateTimeDeserializer; +import tools.jackson.databind.ext.javatime.ser.LocalDateTimeSerializer; import java.time.LocalDateTime; diff --git a/src/main/java/com/epam/healenium/rest/AmazonRestService.java b/src/main/java/com/epam/healenium/rest/AmazonRestService.java index 33fe21e..8aa6dfd 100644 --- a/src/main/java/com/epam/healenium/rest/AmazonRestService.java +++ b/src/main/java/com/epam/healenium/rest/AmazonRestService.java @@ -31,7 +31,8 @@ public void uploadMetrics(String metrics, HealingResult selectedResult, String h .queryParam("url", url) .build()) .bodyValue(metrics) - .exchange() + .retrieve() + .bodyToMono(Void.class) .subscribe(); } @@ -48,7 +49,8 @@ public void moveMetrics(String sourceBucketName, HealingResult healingResult) { .queryParam("result", healingResult.getId().toString()) .queryParam("healing", healingResult.getHealing().getUid()) .build()) - .exchange() + .retrieve() + .bodyToMono(Void.class) .subscribe(); } } diff --git a/src/main/java/com/epam/healenium/rest/IntegrationRestService.java b/src/main/java/com/epam/healenium/rest/IntegrationRestService.java index 0c70281..0c916c2 100644 --- a/src/main/java/com/epam/healenium/rest/IntegrationRestService.java +++ b/src/main/java/com/epam/healenium/rest/IntegrationRestService.java @@ -1,7 +1,6 @@ package com.epam.healenium.rest; import com.epam.healenium.model.domain.Vcs; -import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; @@ -10,6 +9,7 @@ import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClientResponseException; import reactor.core.publisher.Mono; +import tools.jackson.databind.node.ObjectNode; @Slf4j @RequiredArgsConstructor @@ -80,7 +80,7 @@ public Mono callUpdateEliteaApplicationDetails(Vcs vcs, String agent .doOnError(WebClientResponseException.class, e -> log.error("[ELITEA] Update Elitea API response error: Status {}, Body {}", e.getStatusCode(), e.getResponseBodyAsString())) .onErrorResume(e -> { - log.error("[ELITEA] Error during Update Elitea application: ", e); + log.error("[ELITEA] Error during Update Elitea details", e); return Mono.empty(); }); } diff --git a/src/main/java/com/epam/healenium/specification/HealingSpecBuilder.java b/src/main/java/com/epam/healenium/specification/HealingSpecBuilder.java index e69aa1e..3dcc22d 100644 --- a/src/main/java/com/epam/healenium/specification/HealingSpecBuilder.java +++ b/src/main/java/com/epam/healenium/specification/HealingSpecBuilder.java @@ -17,7 +17,7 @@ public class HealingSpecBuilder { public Specification buildSpec(RequestDto filter){ - Specification spec = Specification.where(null); + Specification spec = Specification.where((Specification) null); if(StringUtils.hasText(filter.getLocator())){ spec = spec.and(HealingSpecifications.hasLocator(filter.getLocator())); diff --git a/src/test/java/com/epam/healenium/TestSaveLocators.java b/src/test/java/com/epam/healenium/TestSaveLocators.java index 3782c12..2041720 100644 --- a/src/test/java/com/epam/healenium/TestSaveLocators.java +++ b/src/test/java/com/epam/healenium/TestSaveLocators.java @@ -10,15 +10,16 @@ import com.epam.healenium.service.HealingService; import com.epam.healenium.service.SelectorService; import com.epam.healenium.treecomparing.Node; -import com.fasterxml.jackson.databind.ObjectMapper; +import tools.jackson.core.JacksonException; +import tools.jackson.databind.ObjectMapper; import io.restassured.RestAssured; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.test.context.bean.override.mockito.MockitoSpyBean; import org.springframework.test.context.ActiveProfiles; import org.springframework.util.StreamUtils; import org.testcontainers.junit.jupiter.Testcontainers; @@ -35,9 +36,9 @@ @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) public class TestSaveLocators extends TestContainersInitializer { - @SpyBean + @MockitoSpyBean private HealingService healingService; - @SpyBean + @MockitoSpyBean private SelectorService selectorService; private final SelectorRepository selectorRepository; @@ -120,7 +121,7 @@ private List> getLastValidPath() { try { byte[] bytes = StreamUtils.copyToByteArray(this.getClass().getResourceAsStream("/nodes")); return this.objectMapper.readValue(bytes, NodePathWrapper.class).getNodePath(); - } catch (IOException e) { + } catch (IOException | JacksonException e) { throw new RuntimeException(e); } } From e7c5c3849605280f1e1d3c7d2c2c0885b4712ce4 Mon Sep 17 00:00:00 2001 From: helen_yrofeeva Date: Mon, 23 Mar 2026 12:41:19 +0300 Subject: [PATCH 7/9] [EPMHLM-503] align liquibase with spring boot 4 --- build.gradle | 14 ++++++-------- src/main/resources/application.yml | 4 +++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 3d7d798..2977413 100644 --- a/build.gradle +++ b/build.gradle @@ -28,16 +28,16 @@ dependencies { implementation 'org.springframework.retry:spring-retry:2.0.12' implementation 'org.springframework.boot:spring-boot-starter-aspectj' - implementation 'org.liquibase:liquibase-core:4.33.0' - implementation 'org.postgresql:postgresql:42.7.7' - implementation 'com.zaxxer:HikariCP:3.3.1' + implementation 'org.springframework.boot:spring-boot-starter-liquibase' + implementation 'org.postgresql:postgresql' + implementation 'com.zaxxer:HikariCP' implementation 'com.vladmihalcea:hibernate-types-52:2.7.0' implementation 'javax.validation:validation-api:2.0.1.Final' implementation 'org.yaml:snakeyaml:2.0' implementation 'com.google.guava:guava:32.1.1-jre' implementation 'com.epam.healenium:tree-comparing:0.4.14' implementation 'org.seleniumhq.selenium:selenium-java:4.25.0' - compileOnly 'org.projectlombok:lombok:1.18.36' + compileOnly 'org.projectlombok:lombok:1.18.44' implementation 'org.mapstruct:mapstruct:1.3.1.Final' implementation group: 'io.netty', name: 'netty-handler', version: '4.1.125.Final' implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.16' @@ -48,15 +48,13 @@ dependencies { implementation 'org.testcontainers:junit-jupiter:1.19.3' implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.26.0' implementation 'commons-io:commons-io:2.15.1' - testImplementation 'org.testcontainers:postgresql:1.19.3' - testImplementation('org.testcontainers:testcontainers:1.19.3') + testImplementation 'org.testcontainers:postgresql' + testImplementation 'org.testcontainers:testcontainers' testImplementation 'io.rest-assured:rest-assured:5.3.2' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test' - - annotationProcessor 'org.hibernate.orm:hibernate-processor' annotationProcessor 'org.projectlombok:lombok:1.18.36' testAnnotationProcessor 'org.projectlombok:lombok:1.18.36' diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7984e99..c7959ef 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -16,6 +16,7 @@ spring: jpa: properties.hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect + default_schema: ${SPRING_POSTGRES_SCHEMA:healenium} temp.use_jdbc_metadata_defaults: false jdbc.batch_size: 40 order_inserts: true @@ -47,7 +48,7 @@ spring: liquibase: change-log: classpath:/db/changelog/changelog-main.xml enabled: true - liquibase-schema: + default-schema: ${SPRING_POSTGRES_SCHEMA:healenium} app: host: ${SPRING_HOST_NAME:localhost} @@ -74,6 +75,7 @@ cloud: logging: level: + liquibase: INFO org.springframework.web: INFO org.springframework.security: INFO org.springframework.cloud.gateway: INFO From 55ed2f01ca9de8c2876c9a64dd538e1c4ece1d86 Mon Sep 17 00:00:00 2001 From: helen_yrofeeva Date: Mon, 23 Mar 2026 17:33:04 +0300 Subject: [PATCH 8/9] [EPMHLM-503] align json mapper with hibernate --- build.gradle | 1 + .../config/HibernateJsonConfiguration.java | 18 +++++++++++++++++ .../config/JacksonConfiguration.java | 20 +++++++++---------- .../config/LiquibaseConfiguration.java | 2 +- .../controller/HealingController.java | 7 +++---- .../controller/IntegrationController.java | 5 +++++ .../controller/ReportController.java | 11 ++++++++++ .../controller/SettingsController.java | 2 ++ .../service/impl/HealingServiceImpl.java | 7 ++----- .../java/com/epam/healenium/util/Utils.java | 15 ++++++++++++++ 10 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/epam/healenium/config/HibernateJsonConfiguration.java diff --git a/build.gradle b/build.gradle index 2977413..7961c83 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ plugins { group 'com.epam.healenium' version '3.5.1' +ext['hibernate.version'] = '7.3.0.Final' repositories { mavenCentral() diff --git a/src/main/java/com/epam/healenium/config/HibernateJsonConfiguration.java b/src/main/java/com/epam/healenium/config/HibernateJsonConfiguration.java new file mode 100644 index 0000000..51b66e2 --- /dev/null +++ b/src/main/java/com/epam/healenium/config/HibernateJsonConfiguration.java @@ -0,0 +1,18 @@ +package com.epam.healenium.config; + +import org.hibernate.cfg.MappingSettings; +import org.hibernate.type.format.jackson.Jackson3JsonFormatMapper; +import org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import tools.jackson.databind.json.JsonMapper; + +@Configuration +public class HibernateJsonConfiguration { + + @Bean + public HibernatePropertiesCustomizer jsonFormatMapperPropertiesCustomizer(JsonMapper jsonMapper) { + Jackson3JsonFormatMapper formatMapper = new Jackson3JsonFormatMapper(jsonMapper); + return properties -> properties.put(MappingSettings.JSON_FORMAT_MAPPER, formatMapper); + } +} diff --git a/src/main/java/com/epam/healenium/config/JacksonConfiguration.java b/src/main/java/com/epam/healenium/config/JacksonConfiguration.java index bf93b3f..cde31ea 100644 --- a/src/main/java/com/epam/healenium/config/JacksonConfiguration.java +++ b/src/main/java/com/epam/healenium/config/JacksonConfiguration.java @@ -3,29 +3,29 @@ import com.epam.healenium.converter.NodeDeserializer; import com.epam.healenium.converter.NodeSerializer; import com.epam.healenium.treecomparing.Node; -import org.springframework.context.annotation.Bean; +import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import tools.jackson.databind.DeserializationFeature; -import tools.jackson.databind.ObjectMapper; import tools.jackson.databind.cfg.DateTimeFeature; import tools.jackson.databind.json.JsonMapper; import tools.jackson.databind.module.SimpleModule; +/** Hooks {@link Node} serde into Boot 4's {@link JsonMapper} (used by MVC), not a standalone {@code ObjectMapper} bean. */ @Configuration -public class JacksonConfiguration { +@Order(Ordered.LOWEST_PRECEDENCE) +public class JacksonConfiguration implements JsonMapperBuilderCustomizer { - @Bean - public ObjectMapper objectMapper() { + @Override + public void customize(JsonMapper.Builder builder) { SimpleModule nodeModule = new SimpleModule("node") .addSerializer(Node.class, new NodeSerializer()) .addDeserializer(Node.class, new NodeDeserializer()); - return JsonMapper.builder() - .findAndAddModules() - .addModule(nodeModule) + builder.addModule(nodeModule) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .configure(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS, false) - .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT) - .build(); + .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); } } diff --git a/src/main/java/com/epam/healenium/config/LiquibaseConfiguration.java b/src/main/java/com/epam/healenium/config/LiquibaseConfiguration.java index d2c3004..8a0cfc2 100644 --- a/src/main/java/com/epam/healenium/config/LiquibaseConfiguration.java +++ b/src/main/java/com/epam/healenium/config/LiquibaseConfiguration.java @@ -1,10 +1,10 @@ package com.epam.healenium.config; import com.zaxxer.hikari.HikariDataSource; -import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/epam/healenium/controller/HealingController.java b/src/main/java/com/epam/healenium/controller/HealingController.java index 848c749..446d24a 100644 --- a/src/main/java/com/epam/healenium/controller/HealingController.java +++ b/src/main/java/com/epam/healenium/controller/HealingController.java @@ -12,6 +12,7 @@ import com.epam.healenium.model.dto.SessionDto; import com.epam.healenium.service.HealingService; import com.epam.healenium.service.SelectorService; +import com.epam.healenium.util.Utils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; @@ -33,9 +34,6 @@ import java.util.Map; import java.util.Set; -import static com.epam.healenium.constants.Constants.SESSION_KEY_V1; -import static com.epam.healenium.constants.Constants.SESSION_KEY_V2; - @Slf4j @RestController @RequestMapping("/healenium") @@ -82,7 +80,8 @@ public ConfigSelectorDto getElements() { public void save(@Valid @RequestBody List dto, @RequestHeader Map headers) { log.debug("[Save Healing] Request: {}. Headers: {}", dto, headers); - if (StringUtils.isEmpty(headers.get(SESSION_KEY_V1)) && StringUtils.isEmpty(headers.get(SESSION_KEY_V2))) { + String sessionKey = Utils.getSessionKey(headers); + if (!StringUtils.hasText(sessionKey)) { log.warn("Session key is not present. Current issue would not be presented in any reports, but still available in replacement!"); } dto.forEach(requestDto -> healingService.saveHealing(requestDto, headers)); diff --git a/src/main/java/com/epam/healenium/controller/IntegrationController.java b/src/main/java/com/epam/healenium/controller/IntegrationController.java index 4a2471b..ab09e29 100644 --- a/src/main/java/com/epam/healenium/controller/IntegrationController.java +++ b/src/main/java/com/epam/healenium/controller/IntegrationController.java @@ -38,6 +38,7 @@ public class IntegrationController { @GetMapping("/dedicated-info/{reportId}") public ResponseEntity getDedicatedInfo(@PathVariable String reportId) { + log.debug("[Integration] Get dedicated-info, reportId: {}", reportId); if (reportId == null || reportId.trim().isEmpty()) { throw new IllegalArgumentException("Report ID cannot be null or empty"); } @@ -96,18 +97,21 @@ public ResponseEntity> saveLlmCredentials(@Valid @RequestBody LlmDt @GetMapping("/vcs/{platform}") public ResponseEntity getVcs(@PathVariable String platform) { + log.debug("[Integration] Get vcs, platform: {}", platform); VcsDto vcsDto = integrationService.getVcs(platform); return ResponseEntity.ok(vcsDto); } @GetMapping("/llm/{platform}") public ResponseEntity getLlm(@PathVariable String platform) { + log.debug("[Integration] Get llm, platform: {}", platform); LlmDto llmDto = integrationService.getLlm(platform); return ResponseEntity.ok(llmDto); } @GetMapping("/llm/all") public ResponseEntity> getAllLlms() { + log.debug("[Integration] Get llm all"); List llmDtos = integrationService.getLlmAll(); return ResponseEntity.ok(llmDtos); } @@ -121,6 +125,7 @@ public ResponseEntity> activateLlm(@PathVariable String id) { @GetMapping("/llm/active") public ResponseEntity getActiveLlm() { + log.debug("[Integration] Get llm active"); LlmDto activeLlm = integrationService.getActiveLlm(); return ResponseEntity.ok(activeLlm); } diff --git a/src/main/java/com/epam/healenium/controller/ReportController.java b/src/main/java/com/epam/healenium/controller/ReportController.java index 62c58e9..ed38b78 100644 --- a/src/main/java/com/epam/healenium/controller/ReportController.java +++ b/src/main/java/com/epam/healenium/controller/ReportController.java @@ -37,6 +37,7 @@ public class ReportController { @GetMapping("/{uid}") public ModelAndView get(@PathVariable String uid) { + log.debug("[Report] Get by Id: {}", uid); ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("report"); modelAndView.addObject("dto", reportService.generate(uid)); @@ -45,6 +46,7 @@ public ModelAndView get(@PathVariable String uid) { @GetMapping() public ModelAndView get() { + log.debug("[Report] Get"); ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("report"); modelAndView.addObject("dto", reportService.generate()); @@ -53,6 +55,7 @@ public ModelAndView get() { @PostMapping("/init") public String init() { + log.debug("[Report] Init Request"); return reportService.initialize(); } @@ -65,6 +68,7 @@ public String initById(@PathVariable String uid) { @PostMapping("/build") public String build(@RequestHeader("sessionKey") String key) { + log.debug("[Report] Build. Session Id: {}", key); return Paths.get(reportUrl, key).toString(); } @@ -73,6 +77,7 @@ public List getAllReports( @RequestParam(required = false, defaultValue = "false") boolean hideEmpty, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate) { + log.debug("[Report] Get all, hideEmpty: {}", hideEmpty); return reportService.getAllReports(hideEmpty, startDate, endDate); } @@ -82,6 +87,7 @@ public Map> getReportsGroupedByTime( @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate, @RequestParam(required = false, defaultValue = "day") String groupLevel) { + log.debug("[Report] Get grouped-by-time, hideEmpty: {}", hideEmpty); return reportService.getReportsGroupedByTime(hideEmpty, startDate, endDate, groupLevel); } @@ -89,16 +95,20 @@ public Map> getReportsGroupedByTime( public RecordDto getAggregatedReport( @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate, @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate) { + log.debug("[Report] Get aggregated {}, {}", startDate, endDate); return reportService.generateAggregatedReport(startDate, endDate); } @GetMapping("/data") public RecordDto getRecords() { + log.debug("[Report] Get data"); return reportService.generate(); } @GetMapping("/data/{uid}") public ResponseEntity getReport(@PathVariable String uid) { + log.debug("[Report] Get data by Id: {}", uid); + if (uid == null || uid.trim().isEmpty()) { log.warn("[REPORT] Invalid report UID provided: {}", uid); return ResponseEntity.badRequest().build(); @@ -120,6 +130,7 @@ public ResponseEntity getReport(@PathVariable String uid) { @PatchMapping("/data/{uid}") public RecordDto editReport(@PathVariable String uid, @RequestBody ReportDto editReportDto) { + log.debug("[Report] Patch data by Id: {}", uid); return reportService.editReport(uid, editReportDto); } diff --git a/src/main/java/com/epam/healenium/controller/SettingsController.java b/src/main/java/com/epam/healenium/controller/SettingsController.java index d006ef5..01cafb5 100644 --- a/src/main/java/com/epam/healenium/controller/SettingsController.java +++ b/src/main/java/com/epam/healenium/controller/SettingsController.java @@ -27,6 +27,7 @@ public class SettingsController { */ @PostMapping("/update") public ResponseEntity> updateSetting(@RequestBody Map request) { + log.debug("[Settings] Update: {}", request); String key = request.get("key"); String value = request.get("value"); Map result = settingService.updateSetting(key, value); @@ -40,6 +41,7 @@ public ResponseEntity> updateSetting(@RequestBody Map> getAllSettings() { + log.debug("[Settings] Get all"); Map settings = settingService.getAllSettings(); return ResponseEntity.ok(settings); } diff --git a/src/main/java/com/epam/healenium/service/impl/HealingServiceImpl.java b/src/main/java/com/epam/healenium/service/impl/HealingServiceImpl.java index d0a46ef..b6e0f7a 100644 --- a/src/main/java/com/epam/healenium/service/impl/HealingServiceImpl.java +++ b/src/main/java/com/epam/healenium/service/impl/HealingServiceImpl.java @@ -70,7 +70,8 @@ public void saveHealing(HealingRequestDto dto, Map headers) { .findFirst() .orElseThrow(() -> new IllegalArgumentException("[Save Healing] Internal exception! Somehow we lost selected healing result on save")); // add report record - reportService.createReportRecord(selectedResult, healing, getSessionKey(headers), dto.getScreenshot()); + String sessionKey = Utils.getSessionKey(headers); + reportService.createReportRecord(selectedResult, healing, sessionKey, dto.getScreenshot()); if (dynamicSettings.isCollectMetrics()) { pushMetrics(dto.getMetrics(), headers, selectedResult, dto.getUrl()); } @@ -179,8 +180,4 @@ private void moveMetrics(RecordDto.ReportRecord dto, HealingResult healingResult log.warn("[Set Healing Status] Error during move metrics: {}", ex.getMessage()); } } - - private String getSessionKey(Map headers) { - return !headers.get(SESSION_KEY_V1).isEmpty() ? headers.get(SESSION_KEY_V1) : headers.get(SESSION_KEY_V2); - } } diff --git a/src/main/java/com/epam/healenium/util/Utils.java b/src/main/java/com/epam/healenium/util/Utils.java index acaa9d2..e00906f 100644 --- a/src/main/java/com/epam/healenium/util/Utils.java +++ b/src/main/java/com/epam/healenium/util/Utils.java @@ -9,6 +9,10 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; +import java.util.Map; + +import static com.epam.healenium.constants.Constants.SESSION_KEY_V1; +import static com.epam.healenium.constants.Constants.SESSION_KEY_V2; @Slf4j @UtilityClass @@ -59,4 +63,15 @@ public String getAddressForKey(String url, boolean urlForKey) { return StringUtils.EMPTY; } + public static String getSessionKey(Map headers) { + String sessionKey = headers.get(SESSION_KEY_V1); + if (org.springframework.util.StringUtils.hasText(sessionKey)){ + return sessionKey; + } + sessionKey = headers.get(SESSION_KEY_V2); + if (org.springframework.util.StringUtils.hasText(sessionKey)){ + return sessionKey; + } + return null; + } } \ No newline at end of file From 55b2bbe2cbf13288f24afc1572210e74c2b3ef32 Mon Sep 17 00:00:00 2001 From: helen_yrofeeva Date: Mon, 23 Mar 2026 18:40:18 +0300 Subject: [PATCH 9/9] [EPMHLM-503] fix tests compile --- build.gradle | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 7961c83..576d81a 100644 --- a/build.gradle +++ b/build.gradle @@ -39,18 +39,20 @@ dependencies { implementation 'com.epam.healenium:tree-comparing:0.4.14' implementation 'org.seleniumhq.selenium:selenium-java:4.25.0' compileOnly 'org.projectlombok:lombok:1.18.44' + implementation 'org.jetbrains:annotations:24.1.0' implementation 'org.mapstruct:mapstruct:1.3.1.Final' implementation group: 'io.netty', name: 'netty-handler', version: '4.1.125.Final' implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.16' implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.5.16' - - implementation 'org.testcontainers:junit-jupiter:1.19.3' implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.26.0' implementation 'commons-io:commons-io:2.15.1' - testImplementation 'org.testcontainers:postgresql' - testImplementation 'org.testcontainers:testcontainers' + + def testcontainersVersion = '2.0.4' + testImplementation "org.testcontainers:testcontainers-junit-jupiter:${testcontainersVersion}" + testImplementation "org.testcontainers:testcontainers-postgresql:${testcontainersVersion}" + testImplementation "org.testcontainers:testcontainers:${testcontainersVersion}" testImplementation 'io.rest-assured:rest-assured:5.3.2' testImplementation 'org.springframework.boot:spring-boot-starter-test'