Skip to content

Commit

Permalink
Merge pull request #65 from healenium/feature/EPMHLM-295
Browse files Browse the repository at this point in the history
EPMHLM-295
  • Loading branch information
Alex-Reif authored Apr 10, 2023
2 parents fd4ddf6 + 2a6dd21 commit bc082ea
Show file tree
Hide file tree
Showing 17 changed files with 593 additions and 87 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
}

group 'com.epam.healenium'
version '3.3.0'
version '3.3.2'

sourceCompatibility = 1.8

Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/epam/healenium/controller/HealingController.java
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,15 @@ public void setSelectorStatus(@Valid @RequestBody SelectorDto dto) {
log.debug("[Set Selector Status] Request: {}", dto);
selectorService.setSelectorStatus(dto);
}

@GetMapping("/migrate")
public ModelAndView migrate() {
log.debug("[Migrate Selectors]");
selectorService.migrate();
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index");
modelAndView.addObject("message", "The migration of selectors was successful.");
return modelAndView;
}

}
55 changes: 1 addition & 54 deletions src/main/java/com/epam/healenium/listener/MigrateListener.java
Original file line number Diff line number Diff line change
@@ -1,84 +1,31 @@
package com.epam.healenium.listener;


import com.epam.healenium.mapper.SelectorMapper;
import com.epam.healenium.model.domain.Healing;
import com.epam.healenium.model.domain.Selector;
import com.epam.healenium.repository.HealingRepository;
import com.epam.healenium.repository.SelectorRepository;
import com.epam.healenium.service.SelectorService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j(topic = "healenium")
@Service
@RequiredArgsConstructor
@Transactional
public class MigrateListener {

@Value("${app.selector.key.url-for-key}")
private boolean urlForKey;
@Value("${app.selector.key.path-for-key}")
private boolean pathForKey;

private final SelectorRepository selectorRepository;
private final SelectorService selectorService;
private final HealingRepository healingRepository;
private final SelectorMapper selectorMapper;

@EventListener
public void migrateSelectors(ContextRefreshedEvent event) {
List<Selector> sourceSelectors = selectorRepository.findByCommandNull();
if (sourceSelectors.isEmpty()) {
log.debug("[Migrate] There is no selectors to migrate");
return;
}
Map<String, Selector> sourceToTarget = new HashMap<>();
migrateSelectors(sourceSelectors, sourceToTarget);
List<Selector> selectors = selectorRepository.saveAll(sourceToTarget.values());
log.info("[Migrate] Migrated {} Selectors", selectors.size());
List<Healing> sourceHealings = healingRepository.findAll();
migrateHealings(sourceToTarget, selectors, sourceHealings);
healingRepository.saveAll(sourceHealings);
log.info("[Migrate] Migrated {} Healings", sourceHealings.size());
selectorRepository.deleteAll(sourceSelectors);
}

private void migrateHealings(Map<String, Selector> sourceToTarget, List<Selector> selectors, List<Healing> sourceHealings) {
for (Healing sourceHealing : sourceHealings) {
String uid = sourceHealing.getSelector().getUid();
Selector targetSelector = sourceToTarget.get(uid);
Selector selector = selectors.stream()
.filter(s -> s.getUid().equals(targetSelector.getUid()))
.findFirst()
.orElse(null);
sourceHealing.setSelector(selector);
}
}

private void migrateSelectors(List<Selector> sourceSelectors, Map<String, Selector> sourceToTarget) {
for (Selector sourceSelector : sourceSelectors) {
Selector targetSelector = selectorMapper.cloneSelector(sourceSelector)
.setUid(selectorService.getSelectorId(sourceSelector.getLocator().getValue(), sourceSelector.getUrl(),
sourceSelector.getCommand(), urlForKey, pathForKey));
if (sourceSelector.getNodePathWrapper().getNodePath().size() > 1) {
targetSelector.setCommand("findElements")
.setEnableHealing(false);
} else {
targetSelector.setCommand("findElement")
.setEnableHealing(true);
}
sourceToTarget.put(sourceSelector.getUid(), targetSelector);
}
selectorService.migrateSelectors(sourceSelectors);
}

}
3 changes: 3 additions & 0 deletions src/main/java/com/epam/healenium/mapper/SelectorMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.epam.healenium.model.dto.SelectorDto;
import com.epam.healenium.model.dto.SelectorRequestDto;
import com.epam.healenium.model.wrapper.NodePathWrapper;
import com.epam.healenium.util.Utils;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;

Expand Down Expand Up @@ -48,6 +49,8 @@ default List<RequestDto> toRequestDto(List<Selector> selector) {
: selectorEntity.getClassName());
requestDto.setEnableHealing(selectorEntity.getEnableHealing());
requestDto.setCommand("findElement".equals(selectorEntity.getCommand()) ? "single" : "multiple");
String selectorIdWithUrl = Utils.buildKey(selectorEntity.getLocator().getValue(), selectorEntity.getCommand(), selectorEntity.getUrl());
requestDto.setUrlKey(selectorEntity.getUid().equals(selectorIdWithUrl));
requestDtoResult.add(requestDto);
}
return requestDtoResult;
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/epam/healenium/model/dto/RecordDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public static class ReportRecord {
private String failedLocatorType;
private String healedLocatorValue;
private String healedLocatorType;
private String score;
private boolean successHealing;
private Integer healingResultId;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.epam.healenium.model.dto;

import com.epam.healenium.model.Locator;
import com.epam.healenium.treecomparing.Node;
import lombok.Data;
import lombok.experimental.Accessors;
Expand All @@ -12,5 +13,6 @@ public class ReferenceElementsDto {

private String pageContent;
private List<List<Node>> paths;
private List<Locator> unsuccessfulLocators;

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ public class SelectorRequestDto extends RequestDto {
private List<String> elementIds;
private String sessionId;
private boolean enableHealing;
private boolean urlKey;
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@

import com.epam.healenium.model.domain.HealingResult;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface HealingResultRepository extends JpaRepository<HealingResult, Integer> {

@Query("select hr from HealingResult hr WHERE hr.healing.uid = :id")
List<HealingResult> findByHealingId(@Param("id") String id);

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.epam.healenium.service;

import com.epam.healenium.model.domain.Selector;
import com.epam.healenium.model.dto.ConfigSelectorDto;
import com.epam.healenium.model.dto.ReferenceElementsDto;
import com.epam.healenium.model.dto.RequestDto;
Expand All @@ -22,5 +23,9 @@ public interface SelectorService {

void setSelectorStatus(SelectorDto dto);

String getSelectorId(String locator, String url, String command, boolean urlForKey, boolean pathForKey);
String getSelectorId(String locator, String url, String command, boolean urlForKey);

void migrate();

void migrateSelectors(List<Selector> sourceSelectors);
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ public class HealingServiceImpl implements HealingService {

@Value("${app.selector.key.url-for-key}")
private boolean urlForKey;
@Value("${app.selector.key.path-for-key}")
private boolean pathForKey;
@Value("${app.metrics.allow}")
private boolean allowCollectMetrics;

Expand Down Expand Up @@ -114,7 +112,7 @@ public Set<HealingDto> getHealings(RequestDto dto) {

@Override
public Set<HealingResultDto> getHealingResults(RequestDto dto) {
String selectorId = selectorService.getSelectorId(dto.getLocator(), dto.getUrl(), dto.getCommand(), urlForKey, pathForKey);
String selectorId = selectorService.getSelectorId(dto.getLocator(), dto.getUrl(), dto.getCommand(), urlForKey);
log.debug("[Get Healing Result] Selector ID: {}", selectorId);
return healingRepository.findBySelectorId(selectorId).stream()
.flatMap(it -> healingMapper.modelToResultDto(it.getResults()).stream())
Expand All @@ -136,7 +134,7 @@ public void saveSuccessHealing(RecordDto.ReportRecord dto) {

private Healing getHealing(HealingRequestDto dto) {
// build selector key
String selectorId = selectorService.getSelectorId(dto.getLocator(), dto.getUrl(), dto.getCommand(), urlForKey, pathForKey);
String selectorId = selectorService.getSelectorId(dto.getLocator(), dto.getUrl(), dto.getCommand(), urlForKey);
// build healing key
String healingId = Utils.buildHealingKey(selectorId, dto.getPageContent());
return healingRepository.findById(healingId).orElseGet(() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.io.File;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
Expand Down Expand Up @@ -115,6 +116,7 @@ private void buildReportRecords(RecordDto result, Report report) {
reportRecord.setHealedLocatorType(it.getHealedLocator().getType());
reportRecord.setHealedLocatorValue(it.getHealedLocator().getValue());
Optional<HealingResult> healingResultOptional = resultRepository.findById(it.getHealingResultId());
reportRecord.setScore(new DecimalFormat("#.###").format(healingResultOptional.get().getScore()));
reportRecord.setSuccessHealing(healingResultOptional.get().isSuccessHealing());
reportRecord.setHealingResultId(it.getHealingResultId());
result.getData().add(reportRecord);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import com.epam.healenium.mapper.SelectorMapper;
import com.epam.healenium.model.SessionContext;
import com.epam.healenium.model.domain.Healing;
import com.epam.healenium.model.domain.Selector;
import com.epam.healenium.model.dto.ConfigSelectorDto;
import com.epam.healenium.model.dto.ReferenceElementsDto;
Expand All @@ -11,6 +12,7 @@
import com.epam.healenium.model.dto.SelectorRequestDto;
import com.epam.healenium.model.dto.SessionDto;
import com.epam.healenium.node.NodeService;
import com.epam.healenium.repository.HealingRepository;
import com.epam.healenium.repository.SelectorRepository;
import com.epam.healenium.restore.RestoreDriverFactory;
import com.epam.healenium.restore.RestoreDriverService;
Expand All @@ -28,7 +30,9 @@

import javax.transaction.Transactional;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
Expand All @@ -41,22 +45,21 @@ public class SelectorServiceImpl implements SelectorService {

@Value("${app.selector.key.url-for-key}")
private boolean urlForKey;
@Value("${app.selector.key.path-for-key}")
private boolean pathForKey;

private PassiveExpiringMap<String, SessionContext> sessionContextCache = new PassiveExpiringMap<>(8, TimeUnit.HOURS);

private final SelectorRepository selectorRepository;
private final SelectorMapper selectorMapper;
private final RestoreDriverFactory restoreDriverFactory;
private final HealingRepository healingRepository;

@Override
public void saveSelector(SelectorRequestDto request) {
if (CollectionUtils.isEmpty(request.getNodePath())) {
log.debug("[Save Elements] Parse Node Path");
parseNodePath(request);
}
String id = getSelectorId(request.getLocator(), request.getUrl(), request.getCommand(), urlForKey, pathForKey);
String id = getSelectorId(request.getLocator(), request.getUrl(), request.getCommand(), urlForKey);
Optional<Selector> existSelector = selectorRepository.findById(id);
final Selector selector = selectorMapper.toSelector(request, id, existSelector);
selectorRepository.save(selector);
Expand All @@ -65,7 +68,7 @@ public void saveSelector(SelectorRequestDto request) {

@Override
public ReferenceElementsDto getReferenceElements(RequestDto dto) {
String selectorId = getSelectorId(dto.getLocator(), dto.getUrl(), dto.getCommand(), urlForKey, pathForKey);
String selectorId = getSelectorId(dto.getLocator(), dto.getUrl(), dto.getCommand(), urlForKey);
List<List<Node>> paths = selectorRepository.findById(selectorId)
.map(t -> t.getNodePathWrapper().getNodePath())
.orElse(Collections.emptyList());
Expand All @@ -87,7 +90,6 @@ public ConfigSelectorDto getConfigSelectors() {
configSelectorDto
.setDisableHealingElementDto(selectorMapper.toSelectorDto(disableHealingElement))
.setEnableHealingElementsDto(selectorMapper.toSelectorDto(enableHealingElements))
.setPathForKey(pathForKey)
.setUrlForKey(urlForKey);
return configSelectorDto;
}
Expand All @@ -112,15 +114,22 @@ public void restoreSession(SessionDto sessionDto) {
}

@Override
public String getSelectorId(String locator, String url, String command, boolean urlForKey, boolean pathForKey) {
String addressForKey = Utils.getAddressForKey(url, urlForKey, pathForKey);
public String getSelectorId(String locator, String url, String command, boolean urlForKey) {
String addressForKey = Utils.getAddressForKey(url, urlForKey);
String id = Utils.buildKey(locator, command, addressForKey);
log.debug("[Selector ID] Locator: {}, URL(source): {}, URL(key): {}, Command: {}, KEY_SELECTOR_URL: {}, KEY_SELECTOR_PATH: {}",
locator, url, addressForKey, command, urlForKey, pathForKey);
log.debug("[Selector ID] Locator: {}, URL(source): {}, URL(key): {}, Command: {}, KEY_SELECTOR_URL: {}",
locator, url, addressForKey, command, urlForKey);
log.debug("[Selector ID] Result ID: {}", id);
return id;
}

@Override
public void migrate() {
List<Selector> all = selectorRepository.findAll();
migrateSelectors(all);
}


private void parseNodePath(SelectorRequestDto request) {
try {
SessionContext sessionContext = sessionContextCache.get(request.getSessionId());
Expand Down Expand Up @@ -149,4 +158,61 @@ private void parseNodePath(SelectorRequestDto request) {
}
}

@Override
public void migrateSelectors(List<Selector> sourceSelectors) {
if (sourceSelectors.isEmpty()) {
log.debug("[Migrate] There is no selectors to migrate");
return;
}
Map<String, Selector> sourceToTarget = new HashMap<>();
buildSourceToTargetMap(sourceSelectors, sourceToTarget);
if (sourceToTarget.isEmpty()) {
return;
}
List<Selector> selectors = selectorRepository.saveAll(sourceToTarget.values());
log.info("[Migrate] Migrated {} Selectors", selectors.size());
List<Healing> sourceHealings = healingRepository.findAll();
migrateHealings(sourceToTarget, selectors, sourceHealings);
healingRepository.saveAll(sourceHealings);
log.info("[Migrate] Migrated {} Healings", sourceHealings.size());
selectorRepository.deleteAll(sourceSelectors);
}

private void migrateHealings(Map<String, Selector> sourceToTarget, List<Selector> selectors, List<Healing> sourceHealings) {
for (Healing sourceHealing : sourceHealings) {
String uid = sourceHealing.getSelector().getUid();
Selector targetSelector = sourceToTarget.get(uid);
Selector selector = selectors.stream()
.filter(s -> s.getUid().equals(targetSelector.getUid()))
.findFirst()
.orElse(null);
sourceHealing.setSelector(selector);
}
}

private void buildSourceToTargetMap(List<Selector> sourceSelectors, Map<String, Selector> sourceToTarget) {
for (Selector sourceSelector : sourceSelectors) {
Selector targetSelector = selectorMapper.cloneSelector(sourceSelector);
if (sourceSelector.getCommand() != null) {
targetSelector.setCommand(sourceSelector.getCommand())
.setEnableHealing(sourceSelector.getEnableHealing());
} else {
if (sourceSelector.getNodePathWrapper().getNodePath().size() > 1) {
targetSelector.setCommand("findElements")
.setEnableHealing(false);
} else {
targetSelector.setCommand("findElement")
.setEnableHealing(true);
}
}
String selectorId = getSelectorId(sourceSelector.getLocator().getValue(), sourceSelector.getUrl(),
targetSelector.getCommand(), urlForKey);
if (sourceSelector.getUid().equals(selectorId)) {
continue;
}
targetSelector.setUid(selectorId);
sourceToTarget.put(sourceSelector.getUid(), targetSelector);
}
}

}
Loading

0 comments on commit bc082ea

Please sign in to comment.