Skip to content

Commit

Permalink
LAU-820 log restorer statistics
Browse files Browse the repository at this point in the history
  • Loading branch information
rapolaskaseliscgi committed Dec 1, 2023
1 parent b1aa27c commit 3a6f779
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import uk.gov.hmcts.reform.idam.service.remote.responses.DeletionLog;
import uk.gov.hmcts.reform.idam.util.LoggingSummaryUtils;
import uk.gov.hmcts.reform.idam.util.RestoreSummary;
import uk.gov.hmcts.reform.idam.util.SecurityUtil;

Expand All @@ -19,6 +20,7 @@ public class IdamUserRestorerService {
private final RestoreUserService restoreService;
private final SecurityUtil securityUtil;
private final RestoreSummary restoreSummary;
private final LoggingSummaryUtils summaryUtils;

@Value("${restorer.requests.limit}")
private int requestsLimit;
Expand All @@ -41,11 +43,15 @@ public void run() {
break;
}

restoreSummary.addProcessedNumber(deletedUsers.size());

for (DeletionLog deletionLog : deletedUsers) {
restoreService.restoreUser(deletionLog);
}

restoreSummary.setEndTime();
}

log.info(summaryUtils.createRestorerStatistics(restoreSummary));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@
import uk.gov.hmcts.reform.idam.parameter.ParameterResolver;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
@RequiredArgsConstructor
public class LoggingSummaryUtils {
private final ParameterResolver parameterResolver;

private static final String DOTTED_LINE = "-----------------------------------------------------------";
private static final String CR_STRING = "\r\n";
private static final String TAB_STRING = "| ";
Expand All @@ -31,15 +38,12 @@ public class LoggingSummaryUtils {
private static final String BATCH_SIZE = "\r\nBatch Size : ";
private static final String REQUEST_LIMIT = "\r\nRequest Limit : ";

private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

@SuppressWarnings("PMD.LawOfDemeter")
public void logSummary(long startTime, long endTime, int processedUsers, int deletedUsers, int failedDeletions) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
StringBuilder stringBuilder = new StringBuilder(SUMMARY_HEADING_STRING);
long executionTime = endTime - startTime;
long hh = TimeUnit.MILLISECONDS.toHours(executionTime);
long mm = TimeUnit.MILLISECONDS.toMinutes(executionTime) % 60;
long ss = TimeUnit.MILLISECONDS.toSeconds(executionTime) % 60;
String hms = String.format("%02d:%02d:%02d", hh, mm, ss);


stringBuilder
.append(CR_STRING)
Expand All @@ -52,7 +56,7 @@ public void logSummary(long startTime, long endTime, int processedUsers, int del
.append(String.format(FORMAT_STR_LENGTH_10,dateFormat.format(new Date(endTime))))
.append(String.format(FORMAT_STR_LENGTH_30,DISPOSER_EXECUTION_TIME))
.append(TAB_STRING)
.append(String.format(FORMAT_STR_LENGTH_10,hms))
.append(String.format(FORMAT_STR_LENGTH_10, getDurationFromLong(endTime - startTime)))
.append(String.format(FORMAT_STR_LENGTH_30,TOTAL_PROCESSED_USERS))
.append(TAB_STRING)
.append(String.format(FORMAT_STR_LENGTH_10,processedUsers))
Expand Down Expand Up @@ -82,4 +86,72 @@ public void logSummary(long startTime, long endTime, int processedUsers, int del
log.info(stringBuilder.toString());
}

private static String format(String template, Map<String, Object> parameters) {
StringBuilder newTemplate = new StringBuilder(template);
List<Object> valueList = new ArrayList<>();

Matcher matcher = Pattern.compile("[$][{](\\w+)}").matcher(template);

while (matcher.find()) {
String key = matcher.group(1);

String paramName = "${" + key + "}";
int index = newTemplate.indexOf(paramName);
if (index != -1) {
newTemplate.replace(index, index + paramName.length(), "%s");
valueList.add(parameters.get(key));
}
}

return String.format(newTemplate.toString(), valueList.toArray());
}

@SuppressWarnings("PMD.LawOfDemeter")
public String getDurationFromLong(long duration) {
long hh = TimeUnit.MILLISECONDS.toHours(duration);
long mm = TimeUnit.MILLISECONDS.toMinutes(duration) % 60;
long ss = TimeUnit.MILLISECONDS.toSeconds(duration) % 60;
return String.format("%02d:%02d:%02d", hh, mm, ss);
}

@SuppressWarnings("PMD.LawOfDemeter")
public String createRestorerStatistics(RestoreSummary summary) {
final String template = """
Restorer Idam User Summary:
-------------------------------------------------------------------
Restorer start time: | ${startTime}
Restorer end time: | ${endTime}
Total run time: | ${totalTime}
-------------------------------------------------------------------
Processed deletion logs: | ${processed}
Total restored users: | ${restored}
Total failed users: | ${totalFailed}
-------------------------------------------------------------------
Total 409 due to user id conflict: | ${conflictUserId}
Total 409 due to archived user id conflict: | ${conflictArchivedUserId}
Total 409 due to email conflict: | ${conflictEmail}
Total 409 due to archived email conflict: | ${conflictArchivedEmail}
Total failed due to other reasons: | ${failedOther}
""";

final Map<String, Object> valueMappings = new ConcurrentHashMap<>();
final long executionTime = summary.getEndTime() - summary.getStartTime();
valueMappings.put("startTime", dateFormat.format(new Date(summary.getStartTime())));
valueMappings.put("endTime", dateFormat.format(new Date(summary.getEndTime())));
valueMappings.put("totalTime", getDurationFromLong(executionTime));
valueMappings.put("processed", summary.getTotalProcessed());
valueMappings.put("restored", summary.getSuccessful().size());
valueMappings.put("conflictUserId", summary.getFailedToRestoreDueToReinstatedAndActiveAccount().size());
valueMappings.put("conflictArchivedUserId", summary.getFailedToRestoreDueToReinstatedAccount().size());
valueMappings.put("conflictEmail", summary.getFailedToRestoreDueToNewAccountWithSameEmail().size());
valueMappings.put("conflictArchivedEmail", summary.getFailedToRestoreDueToDuplicateEmail().size());
valueMappings.put("failedOther", summary.getFailed().size());
valueMappings.put("totalFailed", summary.getTotalFailed());

return format(template, valueMappings);
}

}
13 changes: 13 additions & 0 deletions src/main/java/uk/gov/hmcts/reform/idam/util/RestoreSummary.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@Getter
public class RestoreSummary {

private int totalProcessed;
private final List<String> successful = new LinkedList<>();
private final List<String> failed = new LinkedList<>();
private final List<String> failedToRestoreDueToReinstatedAndActiveAccount = new LinkedList<>();
Expand All @@ -21,6 +22,10 @@ public class RestoreSummary {
private long endTime;


public void addProcessedNumber(int batch) {
totalProcessed += batch;
}

public void addSuccess(String userId) {
successful.add(userId);
}
Expand Down Expand Up @@ -52,4 +57,12 @@ public void setStartTime() {
public void setEndTime() {
endTime = System.currentTimeMillis();
}

public int getTotalFailed() {
return failed.size()
+ failedToRestoreDueToReinstatedAndActiveAccount.size()
+ failedToRestoreDueToReinstatedAccount.size()
+ failedToRestoreDueToNewAccountWithSameEmail.size()
+ failedToRestoreDueToDuplicateEmail.size();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;
import uk.gov.hmcts.reform.idam.service.remote.responses.DeletionLog;
import uk.gov.hmcts.reform.idam.util.LoggingSummaryUtils;
import uk.gov.hmcts.reform.idam.util.RestoreSummary;
import uk.gov.hmcts.reform.idam.util.SecurityUtil;

Expand All @@ -31,6 +32,9 @@ class IdamUserRestorerServiceTest {
@Mock
SecurityUtil securityUtil;

@Mock
LoggingSummaryUtils loggingUtils;

@Spy
RestoreSummary restoreSummary;

Expand All @@ -53,6 +57,7 @@ void shouldRunAtLeastOnce() {

verify(lauService, times(1)).fetchDeletedUsers();
verify(restoreService, times(1)).restoreUser(any());
verify(loggingUtils, times(1)).createRestorerStatistics(any());

}

Expand All @@ -65,6 +70,7 @@ void shouldRunMultipleTimes() {

verify(lauService, times(2)).fetchDeletedUsers();
verify(restoreService, times(4)).restoreUser(any());
verify(loggingUtils, times(1)).createRestorerStatistics(any());
}

@Test
Expand All @@ -76,6 +82,7 @@ void shouldNotCallDeleteLogEntryIfUnsuccessfulRestore() {

verify(lauService, times(1)).fetchDeletedUsers();
verify(restoreService, times(2)).restoreUser(any());
verify(loggingUtils, times(1)).createRestorerStatistics(any());
}

@Test
Expand All @@ -87,6 +94,7 @@ void shouldCallOnlyForSuccessfulRestore() {

verify(lauService, times(1)).fetchDeletedUsers();
verify(restoreService, times(2)).restoreUser(any());
verify(loggingUtils, times(1)).createRestorerStatistics(any());
}

@Test
Expand All @@ -97,6 +105,7 @@ void shouldStopIfLauDeletedUsersFetchReturnsEmpty() {
service.run();

verify(restoreService, times(0)).restoreUser(any());
verify(loggingUtils, times(1)).createRestorerStatistics(any());
}

@Test
Expand All @@ -108,5 +117,6 @@ void shouldStopAfterRequestsLimitIsReached() {

verify(lauService, times(10)).fetchDeletedUsers();
verify(restoreService, times(20)).restoreUser(any());
verify(loggingUtils, times(1)).createRestorerStatistics(any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;
import uk.gov.hmcts.reform.idam.parameter.ParameterResolver;
import uk.gov.hmcts.reform.idam.service.IdamUserDisposerService;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -47,4 +49,55 @@ void shouldCallLogSummary() {
verify(parameterResolver, times(1)).getBatchSize();
verify(parameterResolver, times(1)).getRequestLimit();
}

@Test
void durationFromLongShouldCorrectlyFormat() {
String result = loggingSummaryUtils.getDurationFromLong(1_000L);
assertThat(result).isEqualTo("00:00:01");
result = loggingSummaryUtils.getDurationFromLong(10_000L);
assertThat(result).isEqualTo("00:00:10");
result = loggingSummaryUtils.getDurationFromLong(60_000L);
assertThat(result).isEqualTo("00:01:00");
result = loggingSummaryUtils.getDurationFromLong(61_000L);
assertThat(result).isEqualTo("00:01:01");
result = loggingSummaryUtils.getDurationFromLong(610_000L);
assertThat(result).isEqualTo("00:10:10");
result = loggingSummaryUtils.getDurationFromLong(3_600_000L);
assertThat(result).isEqualTo("01:00:00");
result = loggingSummaryUtils.getDurationFromLong(3_661_000L);
assertThat(result).isEqualTo("01:01:01");
}

@Test
void createRestorerStatisticsShouldReturnFormattedString() {
RestoreSummary summary = new RestoreSummary();
// 2023-11-14 22:13:20
ReflectionTestUtils.setField(summary, "startTime", 1_700_000_000_000L);
// 70s later - 2023-11-14 22:14:30
ReflectionTestUtils.setField(summary, "endTime", 1_700_000_070_000L);
summary.addProcessedNumber(10);
summary.addSuccess("01");
summary.addSuccess("02");
summary.addSuccess("03");
summary.addFailedToRestoreDueToDuplicateEmail("04");
summary.addFailedToRestoreDueToNewAccountWithSameEmail("05");
summary.addFailedToRestoreDueToNewAccountWithSameEmail("06");
summary.addFailedToRestoreDueToReinstatedAccount("07");
summary.addFailedToRestoreDueToReinstatedAccount("08");
summary.addFailedToRestoreDueToReinstatedAccount("09");
summary.addFailedToRestoreDueToReinstatedAndActiveAccount("10");
String stats = loggingSummaryUtils.createRestorerStatistics(summary);
assertThat(stats)
.contains("2023-11-14 22:13:20")
.contains("2023-11-14 22:14:30")
.contains("00:01:10")
.containsIgnoringWhitespaces("Processed deletion logs: | 10")
.containsIgnoringWhitespaces("Total restored users: | 3")
.containsIgnoringWhitespaces("Total failed users: | 7")
.containsIgnoringWhitespaces("Total 409 due to user id conflict: | 1")
.containsIgnoringWhitespaces("Total 409 due to archived user id conflict: | 3")
.containsIgnoringWhitespaces("Total 409 due to email conflict: | 2")
.containsIgnoringWhitespaces("Total 409 due to archived email conflict: | 1")
.containsIgnoringWhitespaces("Total failed due to other reasons: | 0");
}
}

0 comments on commit 3a6f779

Please sign in to comment.