Implement delete for audit log wrapper

This fixes errors when deleting configurations.
The error occured during "unmirror" in the mirror plugin.

Committed-by: Eduard Heimbuch <eduard.heimbuch@cloudogu.com>
Co-authored-by: René Pfeuffer <rene.pfeuffer@cloudogu.com>
This commit is contained in:
Rene Pfeuffer
2023-06-08 10:30:37 +02:00
parent 86b8be9f17
commit 5c505457bb
3 changed files with 58 additions and 6 deletions

View File

@@ -0,0 +1,2 @@
- type: fixed
description: Implement delete for audit log wrapper

View File

@@ -32,6 +32,7 @@ import sonia.scm.store.StoreDecoratorFactory;
import java.util.Optional;
import java.util.Set;
import static com.google.common.base.MoreObjects.firstNonNull;
import static java.util.Collections.emptySet;
public class AuditLogConfigurationStoreDecorator<T> implements ConfigurationStore<T> {
@@ -48,29 +49,58 @@ public class AuditLogConfigurationStoreDecorator<T> implements ConfigurationStor
this.context = context;
}
@Override
public T get() {
return delegate.get();
}
@Override
public void set(T object) {
if (!shouldBeIgnored(object)) {
if (shouldAudit(object)) {
auditors.forEach(s -> s.createEntry(createEntryCreationContext(object)));
}
delegate.set(object);
}
@Override
public void delete() {
if (shouldAudit(get())) {
auditors.forEach(s -> s.createEntry(createEntryDeletionContext()));
}
delegate.delete();
}
private EntryCreationContext<T> createEntryCreationContext(T object) {
String repositoryId = context.getStoreParameters().getRepositoryId();
return createContext(context.getStoreParameters().getRepositoryId(), get(), object);
}
private EntryCreationContext<T> createEntryDeletionContext() {
return createContext(context.getStoreParameters().getRepositoryId(), get(), null);
}
private EntryCreationContext<T> createContext(String repositoryId, T oldObject, T newObject) {
if (!Strings.isNullOrEmpty(repositoryId)) {
String name = repositoryDAO.get(repositoryId).getNamespaceAndName().toString();
return new EntryCreationContext<>(object, get(), name, getRepositoryLabels(object));
return new EntryCreationContext<>(
newObject,
oldObject,
name,
getRepositoryLabels(firstNonNull(newObject, oldObject))
);
} else {
return new EntryCreationContext<>(object, get(), "", shouldUseStoreNameAsLabel(object) ? Set.of(context.getStoreParameters().getName()) : emptySet());
return new EntryCreationContext<>(
newObject,
oldObject,
shouldUseStoreNameAsLabel(firstNonNull(newObject, oldObject)) ? Set.of(context.getStoreParameters().getName()) : emptySet()
);
}
}
private boolean shouldBeIgnored(T object) {
return getAnnotation(object).map(AuditEntry::ignore).orElse(false);
private boolean shouldAudit(T object) {
return getAnnotation(object)
.map(AuditEntry::ignore)
.map(b -> !b)
.orElse(true);
}
private Set<String> getRepositoryLabels(T object) {

View File

@@ -58,6 +58,7 @@ class AuditLogConfigurationStoreDecoratorTest {
@Mock
private StoreDecoratorFactory.Context storeContext;
@Mock
@SuppressWarnings("rawtypes")
private TypedStoreParameters parameters;
private AuditLogConfigurationStoreDecorator<Object> decorator;
@@ -71,6 +72,7 @@ class AuditLogConfigurationStoreDecoratorTest {
class WithAuditableEntries {
@BeforeEach
@SuppressWarnings("unchecked")
void setUpStoreContext() {
when(storeContext.getStoreParameters()).thenReturn(parameters);
lenient().when(parameters.getName()).thenReturn("hog");
@@ -93,6 +95,24 @@ class AuditLogConfigurationStoreDecoratorTest {
));
}
@Test
void shouldCallAuditorForDeletedEntry() {
SimpleEntry oldEntry = new SimpleEntry();
when(delegate.get()).thenReturn(oldEntry);
decorator.delete();
verify(auditor).createEntry(argThat(
context -> {
assertThat(context.getEntity()).isEmpty();
assertThat(context.getAdditionalLabels()).contains("hog");
assertThat(context.getObject()).isNull();
assertThat(context.getOldObject()).isSameAs(oldEntry);
return true;
}
));
}
@Test
void shouldCallAuditorForAdditionalLabelEntry() {
Object entry = new ExtraLabelEntry();