Browse Source

SONAR-15144 - Audit Log Clean Up Job

tags/9.1.0.47736
belen-pruvost-sonarsource 2 years ago
parent
commit
b7dec8c521
17 changed files with 602 additions and 11 deletions
  1. 66
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditHousekeepingFrequencyHelper.java
  2. 63
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeStep.java
  3. 30
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskModule.java
  4. 84
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskProcessor.java
  5. 104
    0
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditHousekeepingFrequencyHelperTest.java
  6. 99
    0
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeStepTest.java
  7. 37
    0
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskModuleTest.java
  8. 72
    0
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskProcessorTest.java
  9. 2
    0
      server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
  10. 8
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditDao.java
  11. 5
    4
      server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditMapper.java
  12. 2
    1
      server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskTypes.java
  13. 15
    3
      server/sonar-db-dao/src/main/resources/org/sonar/db/audit/AuditMapper.xml
  14. 8
    1
      server/sonar-db-dao/src/test/java/org/sonar/db/audit/AuditDaoTest.java
  15. 2
    0
      server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
  16. 4
    0
      sonar-core/src/main/java/org/sonar/core/config/Frequency.java
  17. 1
    0
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 66
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditHousekeepingFrequencyHelper.java View File

@@ -0,0 +1,66 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.taskprocessor;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Optional;
import org.sonar.api.utils.System2;
import org.sonar.core.config.Frequency;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.property.PropertyDto;

import static org.sonar.core.config.PurgeConstants.AUDIT_HOUSEKEEPING_FREQUENCY;
import static org.sonar.core.config.PurgeProperties.DEFAULT_FREQUENCY;

public class AuditHousekeepingFrequencyHelper {
private final System2 system2;

public AuditHousekeepingFrequencyHelper(System2 system2) {
this.system2 = system2;
}

public PropertyDto getHouseKeepingFrequency(DbClient dbClient, DbSession dbSession) {
return Optional.ofNullable(dbClient.propertiesDao()
.selectGlobalProperty(dbSession, AUDIT_HOUSEKEEPING_FREQUENCY))
.orElse(defaultAuditHouseKeepingProperty());
}

public long getThresholdDate(String frequency) {
Optional<Frequency> housekeepingFrequency = Arrays.stream(Frequency.values())
.filter(f -> f.name().equalsIgnoreCase(frequency)).findFirst();
if (housekeepingFrequency.isEmpty()) {
throw new IllegalArgumentException("Unsupported frequency: " + frequency);
}

return Instant.ofEpochMilli(system2.now())
.minus(housekeepingFrequency.get().getDays(), ChronoUnit.DAYS)
.toEpochMilli();
}

private static PropertyDto defaultAuditHouseKeepingProperty() {
PropertyDto property = new PropertyDto();
property.setKey(AUDIT_HOUSEKEEPING_FREQUENCY);
property.setValue(DEFAULT_FREQUENCY);
return property;
}
}

+ 63
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeStep.java View File

@@ -0,0 +1,63 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.taskprocessor;

import java.util.Set;
import java.util.stream.Collectors;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.ce.task.step.ComputationStep;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.audit.AuditDto;
import org.sonar.db.property.PropertyDto;

public final class AuditPurgeStep implements ComputationStep {
private static final Logger LOG = Loggers.get(AuditPurgeStep.class);

private final AuditHousekeepingFrequencyHelper auditHousekeepingFrequencyHelper;
private final DbClient dbClient;

public AuditPurgeStep(AuditHousekeepingFrequencyHelper auditHousekeepingFrequencyHelper, DbClient dbClient) {
this.auditHousekeepingFrequencyHelper = auditHousekeepingFrequencyHelper;
this.dbClient = dbClient;
}

@Override
public void execute(Context context) {
try (DbSession dbSession = dbClient.openSession(false)) {
PropertyDto property = auditHousekeepingFrequencyHelper.getHouseKeepingFrequency(dbClient, dbSession);
long deleteBefore = auditHousekeepingFrequencyHelper.getThresholdDate(property.getValue());
Set<String> auditUuids = dbClient.auditDao()
.selectOlderThan(dbSession, deleteBefore)
.stream()
.map(AuditDto::getUuid)
.collect(Collectors.toSet());
LOG.info(String.format("%s audit logs to be deleted...", auditUuids.size()));
dbClient.auditDao().deleteByUuids(dbSession, auditUuids);
dbSession.commit();
}
}

@Override
public String getDescription() {
return "Purge Audit Logs";
}
}

+ 30
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskModule.java View File

@@ -0,0 +1,30 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.taskprocessor;

import org.sonar.core.platform.Module;

public class AuditPurgeTaskModule extends Module {

@Override
protected void configureModule() {
add(AuditPurgeTaskProcessor.class);
}
}

+ 84
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskProcessor.java View File

@@ -0,0 +1,84 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.taskprocessor;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.annotation.CheckForNull;
import org.sonar.ce.task.CeTask;
import org.sonar.ce.task.CeTaskResult;
import org.sonar.ce.task.container.TaskContainer;
import org.sonar.ce.task.container.TaskContainerImpl;
import org.sonar.ce.task.projectanalysis.step.AbstractComputationSteps;
import org.sonar.ce.task.step.ComputationStep;
import org.sonar.ce.task.step.ComputationStepExecutor;
import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.ContainerPopulator;

import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE;

public class AuditPurgeTaskProcessor implements CeTaskProcessor {
private static final Set<String> HANDLED_TYPES = Set.of(AUDIT_PURGE);

private final ComponentContainer ceEngineContainer;

public AuditPurgeTaskProcessor(ComponentContainer ceEngineContainer) {
this.ceEngineContainer = ceEngineContainer;
}

@Override
public Set<String> getHandledCeTaskTypes() {
return HANDLED_TYPES;
}

@CheckForNull
@Override
public CeTaskResult process(CeTask task) {
try (TaskContainer container = new TaskContainerImpl(ceEngineContainer, newContainerPopulator(task))) {
container.bootup();
container.getComponentByType(ComputationStepExecutor.class).execute();
}
return null;
}

static ContainerPopulator<TaskContainer> newContainerPopulator(CeTask task) {
return taskContainer -> {
taskContainer.add(task);
taskContainer.add(AuditHousekeepingFrequencyHelper.class);
taskContainer.add(AuditPurgeStep.class);
taskContainer.add(new AuditPurgeComputationSteps(taskContainer));
taskContainer.add(ComputationStepExecutor.class);
};
}

public static final class AuditPurgeComputationSteps extends AbstractComputationSteps {

public AuditPurgeComputationSteps(ContainerPopulator.Container container) {
super(container);
}

@Override
public List<Class<? extends ComputationStep>> orderedStepClasses() {
return Arrays.asList(AuditPurgeStep.class);
}
}
}

+ 104
- 0
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditHousekeepingFrequencyHelperTest.java View File

@@ -0,0 +1,104 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.taskprocessor;

import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
import org.sonar.core.config.Frequency;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.property.PropertiesDao;
import org.sonar.db.property.PropertyDto;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.core.config.PurgeConstants.AUDIT_HOUSEKEEPING_FREQUENCY;
import static org.sonar.core.config.PurgeProperties.DEFAULT_FREQUENCY;

@RunWith(DataProviderRunner.class)
public class AuditHousekeepingFrequencyHelperTest {
private static final long NOW = 10_000_000_000L;

private final DbClient dbClient = mock(DbClient.class);
private final DbSession dbSession = mock(DbSession.class);
private final PropertiesDao propertiesDao = mock(PropertiesDao.class);
private final System2 system2 = new TestSystem2().setNow(NOW);
private final AuditHousekeepingFrequencyHelper underTest = new AuditHousekeepingFrequencyHelper(system2);

@Test
@UseDataProvider("frequencyOptions")
public void getThresholdDate(Frequency frequency) {
long result = underTest.getThresholdDate(frequency.getDescription());


long expected = Instant.ofEpochMilli(system2.now())
.minus(frequency.getDays(), ChronoUnit.DAYS)
.toEpochMilli();

assertThat(result).isEqualTo(expected);
}

@Test
public void getThresholdDateForUnknownFrequencyFails() {
assertThatThrownBy(() -> underTest.getThresholdDate("Lalala"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Unsupported frequency: Lalala");
}

@Test
public void getHouseKeepingFrequency() {
String value = "Weekly";
PropertyDto propertyDto = new PropertyDto().setKey(AUDIT_HOUSEKEEPING_FREQUENCY).setValue(value);
when(dbClient.propertiesDao()).thenReturn(propertiesDao);
when(propertiesDao
.selectGlobalProperty(dbSession, AUDIT_HOUSEKEEPING_FREQUENCY))
.thenReturn(propertyDto);
assertThat(underTest.getHouseKeepingFrequency(dbClient, dbSession).getValue()).isEqualTo(value);
}

@Test
public void getDefaultHouseKeepingFrequencyWhenNotSet() {
when(dbClient.propertiesDao()).thenReturn(propertiesDao);
when(propertiesDao
.selectGlobalProperty(dbSession, AUDIT_HOUSEKEEPING_FREQUENCY))
.thenReturn(null);
assertThat(underTest.getHouseKeepingFrequency(dbClient, dbSession).getValue())
.isEqualTo(DEFAULT_FREQUENCY);
}

@DataProvider
public static Object[][] frequencyOptions() {
return new Object[][] {
{Frequency.WEEKLY},
{Frequency.MONTHLY},
{Frequency.TRIMESTRIAL},
{Frequency.YEARLY}
};
}
}

+ 99
- 0
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeStepTest.java View File

@@ -0,0 +1,99 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.taskprocessor;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.audit.AuditDto;
import org.sonar.db.audit.AuditTesting;
import org.sonar.db.property.PropertyDto;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.core.config.Frequency.MONTHLY;
import static org.sonar.core.config.PurgeConstants.AUDIT_HOUSEKEEPING_FREQUENCY;

public class AuditPurgeStepTest {
private final static long NOW = 1_400_000_000_000L;
private final static long BEFORE = 1_300_000_000_000L;
private final static long LATER = 1_500_000_000_000L;
private final static ZonedDateTime thresholdDate = Instant.ofEpochMilli(NOW)
.atZone(ZoneId.systemDefault());
private final static PropertyDto FREQUENCY_PROPERTY = new PropertyDto()
.setKey(AUDIT_HOUSEKEEPING_FREQUENCY)
.setValue(MONTHLY.name());

@Rule
public final DbTester dbTester = DbTester.create(System2.INSTANCE);

private final DbClient dbClient = dbTester.getDbClient();

private final System2 system2 = new System2();

@Rule
public final DbTester db = DbTester.create(system2);

private final AuditHousekeepingFrequencyHelper auditHousekeepingFrequencyHelper = mock(AuditHousekeepingFrequencyHelper.class);

private final AuditPurgeStep underTest = new AuditPurgeStep(auditHousekeepingFrequencyHelper, dbClient);

@Before
public void setUp() {
when(auditHousekeepingFrequencyHelper.getHouseKeepingFrequency(any(), any())).thenReturn(FREQUENCY_PROPERTY);
when(auditHousekeepingFrequencyHelper.getThresholdDate(anyString())).thenReturn(NOW);
}

@Test
public void executeDeletesOlderAudits() {
prepareRowsWithDeterministicCreatedAt();
assertThat(dbClient.auditDao().selectOlderThan(db.getSession(), LATER + 1)).hasSize(3);

underTest.execute(() -> null);

assertThat(dbClient.auditDao().selectOlderThan(db.getSession(), LATER + 1)).hasSize(2);
}

@Test
public void getDescription() {
assertThat(underTest.getDescription()).isEqualTo("Purge Audit Logs");
}

private void prepareRowsWithDeterministicCreatedAt() {
insertAudit(BEFORE);
insertAudit(NOW);
insertAudit(LATER);
db.getSession().commit();
}

private void insertAudit(long timestamp) {
AuditDto auditDto = AuditTesting.newAuditDto(timestamp);
dbClient.auditDao().insert(db.getSession(), auditDto);
}
}

+ 37
- 0
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskModuleTest.java View File

@@ -0,0 +1,37 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.taskprocessor;

import org.junit.Test;
import org.sonar.core.platform.ComponentContainer;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;

public class AuditPurgeTaskModuleTest {

@Test
public void verifyCountOfAddedComponents() {
ComponentContainer container = new ComponentContainer();
new AuditPurgeTaskModule().configure(container);
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 1);
}

}

+ 72
- 0
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskProcessorTest.java View File

@@ -0,0 +1,72 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.taskprocessor;

import java.util.List;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.mockito.Mockito;
import org.sonar.ce.task.CeTask;
import org.sonar.ce.task.container.TaskContainer;
import org.sonar.ce.task.step.ComputationStep;
import org.sonar.core.platform.ComponentContainer;

import static org.mockito.ArgumentMatchers.any;
import static org.sonar.ce.task.projectanalysis.taskprocessor.AuditPurgeTaskProcessor.AuditPurgeComputationSteps;
import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE;

public class AuditPurgeTaskProcessorTest {

private ComponentContainer ceEngineContainer = Mockito.mock(ComponentContainer.class);

private AuditPurgeTaskProcessor underTest = new AuditPurgeTaskProcessor(ceEngineContainer);
private TaskContainer container = Mockito.spy(TaskContainer.class);

@Test
public void getHandledCeTaskTypes() {
Assertions.assertThat(underTest.getHandledCeTaskTypes()).containsExactly(AUDIT_PURGE);
}

@Test(expected = NullPointerException.class)
public void processThrowsNPEIfCeTaskIsNull() {
underTest.process(null);
}

@Test
public void newContainerPopulator() {
CeTask task = new CeTask.Builder()
.setUuid("TASK_UUID")
.setType("Type")
.build();

AuditPurgeTaskProcessor.newContainerPopulator(task).populateContainer(container);
Mockito.verify(container, Mockito.times(5)).add(any());
}

@Test
public void orderedStepClasses(){
AuditPurgeComputationSteps auditPurgeComputationSteps = new AuditPurgeComputationSteps(null);

List<Class<? extends ComputationStep>> steps = auditPurgeComputationSteps.orderedStepClasses();

Assertions.assertThat(steps).containsExactly(AuditPurgeStep.class);
}

}

+ 2
- 0
server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java View File

@@ -63,6 +63,7 @@ import org.sonar.ce.task.projectanalysis.ProjectAnalysisTaskModule;
import org.sonar.ce.task.projectanalysis.analysis.ProjectConfigurationFactory;
import org.sonar.ce.task.projectanalysis.issue.AdHocRuleCreator;
import org.sonar.ce.task.projectanalysis.notification.ReportAnalysisFailureNotificationModule;
import org.sonar.ce.task.projectanalysis.taskprocessor.AuditPurgeTaskModule;
import org.sonar.ce.task.projectanalysis.taskprocessor.IssueSyncTaskModule;
import org.sonar.ce.taskprocessor.CeProcessingScheduler;
import org.sonar.ce.taskprocessor.CeTaskProcessorModule;
@@ -433,6 +434,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
CeTaskCommonsModule.class,
ProjectAnalysisTaskModule.class,
IssueSyncTaskModule.class,
AuditPurgeTaskModule.class,
CeTaskProcessorModule.class,
OfficialDistribution.class,


+ 8
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditDao.java View File

@@ -20,12 +20,14 @@
package org.sonar.db.audit;

import java.util.List;
import java.util.Set;
import org.sonar.api.utils.System2;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
import org.sonar.db.Pagination;

import static org.sonar.db.DatabaseUtils.executeLargeUpdates;
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.MAX_SIZE;

public class AuditDao implements Dao {
@@ -63,7 +65,11 @@ public class AuditDao implements Dao {
getMapper(dbSession).insert(auditDto);
}

public void deleteIfBeforeSelectedDate(DbSession dbSession, long timestamp) {
getMapper(dbSession).deleteIfBeforeSelectedDate(timestamp);
public List<AuditDto> selectOlderThan(DbSession dbSession, long beforeTimestamp) {
return getMapper(dbSession).selectOlderThan(beforeTimestamp);
}

public void deleteByUuids(DbSession dbSession, Set<String> uuids) {
executeLargeUpdates(uuids, getMapper(dbSession)::deleteByUuids);
}
}

+ 5
- 4
server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditMapper.java View File

@@ -19,19 +19,20 @@
*/
package org.sonar.db.audit;

import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.sonar.db.Pagination;

import java.util.List;

public interface AuditMapper {

void insert(@Param("dto") AuditDto auditDto);

void delete(@Param("uuids") List<String> uuids);

void deleteIfBeforeSelectedDate(@Param("timestamp") long timestamp);

List<AuditDto> selectByPeriodPaginated(@Param("start")long start, @Param("end") long end, @Param("pagination") Pagination pagination);

List<AuditDto> selectOlderThan(@Param("beforeTimestamp") long beforeTimestamp);

void deleteByUuids(@Param("uuids") List<String> uuids);

}

+ 2
- 1
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskTypes.java View File

@@ -21,8 +21,9 @@ package org.sonar.db.ce;

public final class CeTaskTypes {
public static final String REPORT = "REPORT";
public static final String AUDIT_PURGE = "AUDIT_PURGE";
public static final String BRANCH_ISSUE_SYNC = "ISSUE_SYNC";
public static final String REPORT = "REPORT";

private CeTaskTypes() {
// only statics

+ 15
- 3
server/sonar-db-dao/src/main/resources/org/sonar/db/audit/AuditMapper.xml View File

@@ -47,10 +47,22 @@
)
</insert>

<delete id="deleteIfBeforeSelectedDate">
delete from audits
<select id="selectOlderThan" parameterType="long" resultType="org.sonar.db.audit.AuditDto">
select
<include refid="sqlColumns"/>
from audits a
where
created_at &lt;= #{timestamp,jdbcType=BIGINT}
a.created_at &lt; #{beforeTimestamp,jdbcType=BIGINT}
</select>

<delete id="deleteByUuids" parameterType="string">
delete
from audits
where
uuid in
<foreach collection="uuids" open="(" close=")" item="uuid" separator=",">
#{uuid,jdbcType=VARCHAR}
</foreach>
</delete>

</mapper>

+ 8
- 1
server/sonar-db-dao/src/test/java/org/sonar/db/audit/AuditDaoTest.java View File

@@ -20,6 +20,8 @@
package org.sonar.db.audit;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.impl.utils.TestSystem2;
@@ -63,7 +65,12 @@ public class AuditDaoTest {
public void deleteIfBeforeSelectedDate_deleteTwoRows() {
prepareRowsWithDeterministicCreatedAt(3);

testAuditDao.deleteIfBeforeSelectedDate(dbSession, 2);
Set<String> auditUuids = testAuditDao.selectOlderThan(dbSession, 3)
.stream()
.map(AuditDto::getUuid)
.collect(Collectors.toSet());

testAuditDao.deleteByUuids(dbSession, auditUuids);

List<AuditDto> auditDtos = testAuditDao.selectByPeriodPaginated(dbSession, 1, 4, 1);
assertThat(auditDtos.size()).isEqualTo(1);

+ 2
- 0
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java View File

@@ -39,6 +39,7 @@ import org.sonar.auth.gitlab.GitLabModule;
import org.sonar.auth.ldap.LdapModule;
import org.sonar.auth.saml.SamlModule;
import org.sonar.ce.task.projectanalysis.notification.ReportAnalysisFailureNotificationModule;
import org.sonar.ce.task.projectanalysis.taskprocessor.AuditPurgeTaskProcessor;
import org.sonar.ce.task.projectanalysis.taskprocessor.IssueSyncTaskProcessor;
import org.sonar.ce.task.projectanalysis.taskprocessor.ReportTaskProcessor;
import org.sonar.core.component.DefaultResourceTypes;
@@ -523,6 +524,7 @@ public class PlatformLevel4 extends PlatformLevel {
CeWsModule.class,
ReportTaskProcessor.class,
IssueSyncTaskProcessor.class,
AuditPurgeTaskProcessor.class,

// SonarSource editions
PlatformEditionProvider.class,

+ 4
- 0
sonar-core/src/main/java/org/sonar/core/config/Frequency.java View File

@@ -32,6 +32,10 @@ public enum Frequency {
return this.description;
}

public int getDays() {
return this.days;
}

Frequency(String description, int days) {
this.description = description;
this.days = days;

+ 1
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -2862,6 +2862,7 @@ background_task.type.ISSUE_SYNC=Project Data Reload
background_task.type.APP_REFRESH=Recomputation
background_task.type.PROJECT_EXPORT=Project Export
background_task.type.PROJECT_IMPORT=Project Import
background_task.type.AUDIT_PURGE=Audit Log Purge

background_tasks.page=Background Tasks
background_tasks.page.description=This page allows monitoring of the queue of tasks running asynchronously on the server. It also gives access to the history of finished tasks and their status. Analysis report processing is the most common kind of background task.

Loading…
Cancel
Save