Skip to content

Commit ff34a16

Browse files
committed
refactor: auditEntryExpectation validations
1 parent 85cb196 commit ff34a16

1 file changed

Lines changed: 129 additions & 0 deletions

File tree

core/flamingock-test-support/src/main/java/io/flamingock/support/domain/AuditEntryExpectation.java

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@
2222
import io.flamingock.internal.common.core.audit.AuditEntry;
2323
import io.flamingock.support.stages.ThenStage;
2424
import io.flamingock.support.stages.WhenStage;
25+
import io.flamingock.support.validation.error.FieldMismatchError;
2526

2627
import java.lang.annotation.Annotation;
2728
import java.lang.reflect.Method;
2829
import java.time.LocalDateTime;
30+
import java.util.ArrayList;
31+
import java.util.List;
32+
import java.util.Objects;
2933

3034
import static io.flamingock.internal.common.core.audit.AuditEntry.Status.APPLIED;
3135
import static io.flamingock.internal.common.core.audit.AuditEntry.Status.FAILED;
@@ -466,6 +470,131 @@ public AuditEntryExpectation withTargetSystemId(String targetSystemId) {
466470
return this;
467471
}
468472

473+
// ==================== Comparison Logic ====================
474+
475+
/**
476+
* Compares this expectation against an actual audit entry.
477+
*
478+
* <p>Returns a list of field mismatches (empty if all expected fields match).
479+
* Only fields with non-null expected values are verified, except for
480+
* {@code changeId} and {@code status} which are always verified.</p>
481+
*
482+
* <p>Timestamp verification supports two modes:</p>
483+
* <ul>
484+
* <li>Exact match: when {@code expectedCreatedAt} is set</li>
485+
* <li>Range match: when {@code timestampAfter} and/or {@code timestampBefore} are set</li>
486+
* </ul>
487+
*
488+
* @param actual the actual audit entry to compare against
489+
* @return list of field mismatch errors (empty if all match)
490+
*/
491+
public List<FieldMismatchError> compareWith(AuditEntry actual) {
492+
List<FieldMismatchError> errors = new ArrayList<>();
493+
494+
// Required fields - always verified
495+
if (!expectedChangeId.equals(actual.getTaskId())) {
496+
errors.add(new FieldMismatchError("changeId", expectedChangeId, actual.getTaskId()));
497+
}
498+
499+
if (expectedState != actual.getState()) {
500+
errors.add(new FieldMismatchError("status",
501+
expectedState.name(),
502+
actual.getState() != null ? actual.getState().name() : null));
503+
}
504+
505+
// Optional fields - verified when non-null
506+
if (expectedExecutionId != null && !expectedExecutionId.equals(actual.getExecutionId())) {
507+
errors.add(new FieldMismatchError("executionId", expectedExecutionId, actual.getExecutionId()));
508+
}
509+
510+
if (expectedStageId != null && !expectedStageId.equals(actual.getStageId())) {
511+
errors.add(new FieldMismatchError("stageId", expectedStageId, actual.getStageId()));
512+
}
513+
514+
if (expectedAuthor != null && !expectedAuthor.equals(actual.getAuthor())) {
515+
errors.add(new FieldMismatchError("author", expectedAuthor, actual.getAuthor()));
516+
}
517+
518+
if (expectedClassName != null && !expectedClassName.equals(actual.getClassName())) {
519+
errors.add(new FieldMismatchError("className", expectedClassName, actual.getClassName()));
520+
}
521+
522+
if (expectedMethodName != null && !expectedMethodName.equals(actual.getMethodName())) {
523+
errors.add(new FieldMismatchError("methodName", expectedMethodName, actual.getMethodName()));
524+
}
525+
526+
if (expectedMetadata != null && !Objects.equals(expectedMetadata, actual.getMetadata())) {
527+
errors.add(new FieldMismatchError("metadata",
528+
String.valueOf(expectedMetadata),
529+
String.valueOf(actual.getMetadata())));
530+
}
531+
532+
if (expectedExecutionMillis != null && expectedExecutionMillis != actual.getExecutionMillis()) {
533+
errors.add(new FieldMismatchError("executionMillis",
534+
String.valueOf(expectedExecutionMillis),
535+
String.valueOf(actual.getExecutionMillis())));
536+
}
537+
538+
if (expectedExecutionHostname != null && !expectedExecutionHostname.equals(actual.getExecutionHostname())) {
539+
errors.add(new FieldMismatchError("executionHostname", expectedExecutionHostname, actual.getExecutionHostname()));
540+
}
541+
542+
if (expectedErrorTrace != null && !expectedErrorTrace.equals(actual.getErrorTrace())) {
543+
errors.add(new FieldMismatchError("errorTrace", expectedErrorTrace, actual.getErrorTrace()));
544+
}
545+
546+
if (expectedTargetSystemId != null && !expectedTargetSystemId.equals(actual.getTargetSystemId())) {
547+
errors.add(new FieldMismatchError("targetSystemId", expectedTargetSystemId, actual.getTargetSystemId()));
548+
}
549+
550+
// Timestamp verification
551+
compareTimestamp(actual, errors);
552+
553+
return errors;
554+
}
555+
556+
private void compareTimestamp(AuditEntry actual, List<FieldMismatchError> errors) {
557+
if (expectedCreatedAt != null) {
558+
// Exact match mode
559+
if (!expectedCreatedAt.equals(actual.getCreatedAt())) {
560+
errors.add(new FieldMismatchError("createdAt",
561+
expectedCreatedAt.toString(),
562+
actual.getCreatedAt() != null ? actual.getCreatedAt().toString() : null));
563+
}
564+
} else if (timestampAfter != null || timestampBefore != null) {
565+
// Range match mode
566+
LocalDateTime actualTimestamp = actual.getCreatedAt();
567+
if (actualTimestamp == null) {
568+
errors.add(new FieldMismatchError("createdAt",
569+
formatTimestampRange(),
570+
null));
571+
} else {
572+
boolean afterOk = timestampAfter == null ||
573+
actualTimestamp.isAfter(timestampAfter) ||
574+
actualTimestamp.isEqual(timestampAfter);
575+
boolean beforeOk = timestampBefore == null ||
576+
actualTimestamp.isBefore(timestampBefore) ||
577+
actualTimestamp.isEqual(timestampBefore);
578+
579+
if (!afterOk || !beforeOk) {
580+
errors.add(new FieldMismatchError("createdAt",
581+
formatTimestampRange(),
582+
actualTimestamp.toString()));
583+
}
584+
}
585+
}
586+
}
587+
588+
private String formatTimestampRange() {
589+
if (timestampAfter != null && timestampBefore != null) {
590+
return String.format("between %s and %s", timestampAfter, timestampBefore);
591+
} else if (timestampAfter != null) {
592+
return String.format("after %s", timestampAfter);
593+
} else {
594+
return String.format("before %s", timestampBefore);
595+
}
596+
}
597+
469598
// ==================== Getters (for verification logic) ====================
470599

471600
/** Returns the expected execution ID. */

0 commit comments

Comments
 (0)