Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import io.flamingock.internal.core.builder.args.FlamingockArguments;
import io.flamingock.internal.core.configuration.core.CoreConfigurable;
import io.flamingock.internal.core.event.EventPublisher;
import io.flamingock.internal.common.core.audit.AuditPersistence;
import io.flamingock.internal.core.external.store.AuditStore;
import io.flamingock.internal.core.external.targets.TargetSystemManager;
import io.flamingock.internal.core.operation.audit.AuditFixArgs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,9 @@
*/
package io.flamingock.internal.core.operation.audit;

import io.flamingock.internal.common.core.audit.AuditEntry;
import io.flamingock.internal.common.core.audit.AuditReader;
import io.flamingock.internal.core.operation.Operation;

import java.util.List;
import java.util.stream.Collectors;

public class AuditListOperation implements Operation<AuditListArgs, AuditListResult> {

private final AuditReader auditReader;
Expand All @@ -32,19 +28,7 @@ public AuditListOperation(AuditReader auditReader) {

@Override
public AuditListResult execute(AuditListArgs args) {
// Step 1: Get base data based on --history flag
List<AuditEntry> entries = args.isHistory()
? auditReader.getAuditHistory()
: auditReader.getAuditSnapshot();

// Step 2: Apply --since filter if present (works on both modes)
if (args.getSince() != null) {
entries = entries.stream()
.filter(e -> e.getCreatedAt() != null && !e.getCreatedAt().isBefore(args.getSince()))
.collect(Collectors.toList());
}

// Step 3: Return with extended flag
return new AuditListResult(entries, args.isExtended());
throw new UnsupportedOperationException(
"Audit list is an enterprise feature. Upgrade to Flamingock Cloud or Self-Hosted Edition to use it.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/
package io.flamingock.internal.core.builder.runner;

import io.flamingock.internal.core.operation.audit.AuditListArgs;
import io.flamingock.internal.core.operation.audit.AuditListResult;
import io.flamingock.internal.core.operation.issue.IssueListArgs;
import io.flamingock.internal.core.operation.issue.IssueListResult;
import io.flamingock.internal.core.operation.Operation;
import io.flamingock.internal.core.operation.RunnableOperation;
import io.flamingock.internal.util.id.RunnerId;
Expand All @@ -34,28 +34,28 @@
class DefaultRunnerTest {

@Mock
private Operation<AuditListArgs, AuditListResult> operation;
private Operation<IssueListArgs, IssueListResult> operation;

@Mock
private Runnable finalizer;

private RunnerId runnerId;
private AuditListArgs args;
private RunnableOperation<AuditListArgs, AuditListResult> runnableOperation;
private IssueListArgs args;
private RunnableOperation<IssueListArgs, IssueListResult> runnableOperation;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
runnerId = RunnerId.generate("test-service");
args = new AuditListArgs();
args = new IssueListArgs();
runnableOperation = new RunnableOperation<>(operation, args);
}

@Test
@DisplayName("Should execute operation when run is called")
void shouldExecuteOperationWhenRunIsCalled() {
// Given
when(operation.execute(args)).thenReturn(new AuditListResult(Collections.emptyList()));
when(operation.execute(args)).thenReturn(new IssueListResult(Collections.emptyList()));
DefaultRunner runner = new DefaultRunner(runnerId, runnableOperation, finalizer);

// When
Expand All @@ -69,7 +69,7 @@ void shouldExecuteOperationWhenRunIsCalled() {
@DisplayName("Should call finalizer after successful execution")
void shouldCallFinalizerAfterSuccessfulExecution() {
// Given
when(operation.execute(args)).thenReturn(new AuditListResult(Collections.emptyList()));
when(operation.execute(args)).thenReturn(new IssueListResult(Collections.emptyList()));
DefaultRunner runner = new DefaultRunner(runnerId, runnableOperation, finalizer);

// When
Expand Down Expand Up @@ -108,7 +108,7 @@ void shouldRethrowExceptionFromOperation() {
@DisplayName("Should pass correct args to operation")
void shouldPassCorrectArgsToOperation() {
// Given
when(operation.execute(any())).thenReturn(new AuditListResult(Collections.emptyList()));
when(operation.execute(any())).thenReturn(new IssueListResult(Collections.emptyList()));
DefaultRunner runner = new DefaultRunner(runnerId, runnableOperation, finalizer);

// When
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,161 +15,35 @@
*/
package io.flamingock.internal.core.operation;

import io.flamingock.internal.common.core.audit.AuditEntry;
import io.flamingock.internal.common.core.audit.AuditPersistence;
import io.flamingock.internal.common.core.audit.AuditReader;
import io.flamingock.internal.core.operation.audit.AuditListArgs;
import io.flamingock.internal.core.operation.audit.AuditListOperation;
import io.flamingock.internal.core.operation.audit.AuditListResult;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.verifyNoInteractions;

class AuditListOperationTest {

@Mock
private AuditPersistence persistence;
private AuditReader auditReader;

private AuditListOperation operation;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
operation = new AuditListOperation(persistence);
}

@Test
@DisplayName("Should return empty list when no audit entries exist")
void shouldReturnEmptyListWhenNoAuditEntriesExist() {
// Given - default args (no history flag) uses snapshot
when(persistence.getAuditSnapshot()).thenReturn(Collections.emptyList());
AuditListArgs args = new AuditListArgs();

// When
AuditListResult result = operation.execute(args);

// Then
assertNotNull(result);
assertTrue(result.getAuditEntries().isEmpty());
}

@Test
@DisplayName("Should return audit entries from snapshot when no history flag")
void shouldReturnAuditEntriesFromSnapshotWhenNoHistoryFlag() {
// Given
AuditEntry entry1 = createAuditEntry("exec-1", "change-1");
AuditEntry entry2 = createAuditEntry("exec-2", "change-2");
List<AuditEntry> entries = Arrays.asList(entry1, entry2);
when(persistence.getAuditSnapshot()).thenReturn(entries);
AuditListArgs args = new AuditListArgs();

// When
AuditListResult result = operation.execute(args);

// Then
assertNotNull(result);
assertEquals(2, result.getAuditEntries().size());
assertEquals(entries, result.getAuditEntries());
}

@Test
@DisplayName("Should delegate to AuditPersistence getAuditSnapshot by default")
void shouldDelegateToAuditPersistenceGetAuditSnapshotByDefault() {
// Given
when(persistence.getAuditSnapshot()).thenReturn(Collections.emptyList());
AuditListArgs args = new AuditListArgs();

// When
operation.execute(args);

// Then
verify(persistence, times(1)).getAuditSnapshot();
verify(persistence, never()).getAuditHistory();
}

@Test
@DisplayName("Should delegate to AuditPersistence getAuditHistory when history flag is set")
void shouldDelegateToAuditPersistenceGetAuditHistoryWhenHistoryFlagIsSet() {
// Given
when(persistence.getAuditHistory()).thenReturn(Collections.emptyList());
AuditListArgs args = new AuditListArgs(true, null, false);

// When
operation.execute(args);

// Then
verify(persistence, times(1)).getAuditHistory();
verify(persistence, never()).getAuditSnapshot();
operation = new AuditListOperation(auditReader);
}

@Test
@DisplayName("Should filter entries by since date")
void shouldFilterEntriesBySinceDate() {
// Given
LocalDateTime now = LocalDateTime.now();
LocalDateTime yesterday = now.minusDays(1);
LocalDateTime twoDaysAgo = now.minusDays(2);

AuditEntry oldEntry = createAuditEntryWithTime("exec-1", "change-1", twoDaysAgo);
AuditEntry newEntry = createAuditEntryWithTime("exec-2", "change-2", now);
List<AuditEntry> entries = Arrays.asList(oldEntry, newEntry);
when(persistence.getAuditSnapshot()).thenReturn(entries);

AuditListArgs args = new AuditListArgs(false, yesterday, false);

// When
AuditListResult result = operation.execute(args);

// Then
assertNotNull(result);
assertEquals(1, result.getAuditEntries().size());
assertEquals("change-2", result.getAuditEntries().get(0).getChangeId());
}

@Test
@DisplayName("Should set extended flag in result")
void shouldSetExtendedFlagInResult() {
// Given
when(persistence.getAuditSnapshot()).thenReturn(Collections.emptyList());
AuditListArgs args = new AuditListArgs(false, null, true);

// When
AuditListResult result = operation.execute(args);

// Then
assertTrue(result.isExtended());
}

private AuditEntry createAuditEntry(String executionId, String changeId) {
return createAuditEntryWithTime(executionId, changeId, LocalDateTime.now());
}

private AuditEntry createAuditEntryWithTime(String executionId, String changeId, LocalDateTime time) {
return new AuditEntry(
executionId,
"stage-1",
changeId,
"test-author",
time,
AuditEntry.Status.APPLIED,
AuditEntry.ChangeType.STANDARD_CODE,
"TestClass",
"apply",
null,
100L,
"localhost",
null,
false,
null
);
@DisplayName("Should reject execution as an enterprise-only feature")
void shouldRejectExecutionAsEnterpriseFeature() {
assertThrows(UnsupportedOperationException.class, () -> operation.execute(new AuditListArgs()));
verifyNoInteractions(auditReader);
}
}
Loading