]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-15143 created api/audit_logs/download endpoint
authorLukasz Jarocki <lukasz.jarocki@sonarsource.com>
Wed, 14 Jul 2021 13:54:51 +0000 (15:54 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 27 Jul 2021 20:03:02 +0000 (20:03 +0000)
server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/audit/AuditMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/audit/AuditDaoTest.java
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/audit/AuditDbTester.java [new file with mode: 0644]
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/audit/AuditTesting.java

index 5279b63575ba408d772623402fae1c47af4ee57c..7c2b2d679797c7eae3d7d61af6a982f55fec47d5 100644 (file)
  */
 package org.sonar.db.audit;
 
+import java.util.List;
 import org.sonar.api.utils.System2;
 import org.sonar.core.util.UuidFactory;
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
-
-import java.util.List;
+import org.sonar.db.Pagination;
 
 import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.MAX_SIZE;
 
@@ -45,23 +45,19 @@ public class AuditDao implements Dao {
     return dbSession.getMapper(AuditMapper.class);
   }
 
-  public List<AuditDto> selectAll(DbSession dbSession) {
-    return getMapper(dbSession).selectAll();
-  }
-
-  public List<AuditDto> selectByPeriod(DbSession dbSession, long beginning, long end) {
-    return getMapper(dbSession).selectByPeriod(beginning, end);
-  }
-
-  public List<AuditDto> selectIfBeforeSelectedDate(DbSession dbSession, long end) {
-    return getMapper(dbSession).selectIfBeforeSelectedDate(end);
+  public List<AuditDto> selectByPeriodPaginated(DbSession dbSession, long start, long end, int page) {
+    return getMapper(dbSession).selectByPeriodPaginated(start, end, Pagination.forPage(page).andSize(DEFAULT_PAGE_SIZE));
   }
 
   public void insert(DbSession dbSession, AuditDto auditDto) {
-    long now = system2.now();
-    auditDto.setUuid(uuidFactory.create());
-    auditDto.setCreatedAt(now);
-    if (auditDto.getNewValue().length() > MAX_SIZE) {
+    if (auditDto.getUuid() == null) {
+      auditDto.setUuid(uuidFactory.create());
+    }
+    if (auditDto.getCreatedAt() == 0) {
+      long now = system2.now();
+      auditDto.setCreatedAt(now);
+    }
+    if(auditDto.getNewValue().length() > MAX_SIZE) {
       auditDto.setNewValue(EXCEEDED_LENGTH);
     }
     getMapper(dbSession).insert(auditDto);
index 22c7ea2ef53e98e6189d75b893b4284d8ab23b71..f5a45d34ba672f70ca14a53fe534b5e332d6ed8d 100644 (file)
 package org.sonar.db.audit;
 
 import org.apache.ibatis.annotations.Param;
+import org.sonar.db.Pagination;
 
 import java.util.List;
 
 public interface AuditMapper {
 
-  List<AuditDto> selectAll();
-
-  List<AuditDto> selectByPeriod(@Param("start") long start, @Param("end") long end);
-
-  List<AuditDto> selectIfBeforeSelectedDate(@Param("end") long end);
-
   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);
+
 }
index 31ab08d8a714dbc9475219f72e5e7f14714633a6..a2a6347c333763645a0a6553a3e3e22ad405ce27 100644 (file)
     a.created_at as "createdAt"
   </sql>
 
-  <select id="selectAll" resultType="org.sonar.db.audit.AuditDto">
-    select <include refid="sqlColumns"/>
-    from
-      audits a
-  </select>
-
-  <select id="selectByPeriod" parameterType="map" resultType="org.sonar.db.audit.AuditDto">
-    select <include refid="sqlColumns"/>
-    from
-      audits a
-    where
-      a.created_at &gt; #{start, jdbcType=BIGINT} AND
-      a.created_at &lt; #{end, jdbcType=BIGINT}
-  </select>
-
-    <select id="selectIfBeforeSelectedDate" parameterType="map" resultType="org.sonar.db.audit.AuditDto">
-    select <include refid="sqlColumns"/>
-    from
-      audits a
+  <select id="selectByPeriodPaginated" parameterType="map" resultType="org.sonar.db.audit.AuditDto">
+    select <include refid="sqlColumns"/> from (
+      select
+        row_number() over(order by created_at, uuid) as row_number, *
+        from audits
+        where created_at &gt;= #{start} and created_at &lt; #{end}
+    ) as a
     where
-      a.created_at &gt; #{end, jdbcType=BIGINT}
+    a.row_number between #{pagination.startRowNumber,jdbcType=INTEGER} and #{pagination.endRowNumber,jdbcType=INTEGER}
+    order by a.row_number asc
   </select>
 
   <insert id="insert" parameterType="Map" useGeneratedKeys="false">
index fcde499416c9c21e6aeef0f39ecde4d9b74711d7..b338b23132d0f05d16b24281edbd216e5b639ea9 100644 (file)
@@ -23,110 +23,94 @@ import java.util.List;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.impl.utils.TestSystem2;
-import org.sonar.core.util.UuidFactory;
 import org.sonar.core.util.UuidFactoryImpl;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 
 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 import static org.sonar.db.audit.AuditDao.EXCEEDED_LENGTH;
 
 public class AuditDaoTest {
 
   private static final long NOW = 1000000L;
-  private static final String A_UUID = "SOME_UUID";
   private final TestSystem2 system2 = new TestSystem2().setNow(NOW);
   @Rule
   public final DbTester db = DbTester.create(system2);
   private final DbSession dbSession = db.getSession();
-  private final UuidFactory uuidFactory = mock(UuidFactory.class);
 
   private final AuditDao testAuditDao = new AuditDao(system2, UuidFactoryImpl.INSTANCE);
 
   @Test
-  public void selectAll_oneEntryInserted_returnThisEntry() {
-    AuditDao auditDaoDeterministicUUID = new AuditDao(system2, uuidFactory);
-    when(uuidFactory.create()).thenReturn(A_UUID);
-    AuditDto auditDto = AuditTesting.newAuditDto();
-    auditDaoDeterministicUUID.insert(dbSession, auditDto);
+  public void selectByPeriodPaginated_10001EntriesInserted_defaultPageSizeEntriesReturned() {
+    prepareRowsWithDeterministicCreatedAt(10001);
 
-    List<AuditDto> auditDtos = auditDaoDeterministicUUID.selectAll(dbSession);
+    List<AuditDto> auditDtos = testAuditDao.selectByPeriodPaginated(dbSession, 1, 20000, 1);
 
-    assertThat(auditDtos.size()).isEqualTo(1);
-    assertThat(auditDtos.get(0))
-      .extracting(AuditDto::getUuid, AuditDto::getUserLogin,
-        AuditDto::getUserUuid, AuditDto::getCategory,
-        AuditDto::getOperation, AuditDto::getNewValue,
-        AuditDto::getCreatedAt)
-      .containsExactly(A_UUID, auditDto.getUserLogin(),
-        auditDto.getUserUuid(), auditDto.getCategory(),
-        auditDto.getOperation(), auditDto.getNewValue(),
-        auditDto.getCreatedAt());
+    assertThat(auditDtos.size()).isEqualTo(10000);
   }
 
   @Test
-  public void selectAll_100EntriesInserted_100EntriesReturned() {
-    AuditDao auditDao = new AuditDao(system2, UuidFactoryImpl.INSTANCE);
-    for(int i=0; i<100; i++) {
-      AuditDto auditDto = AuditTesting.newAuditDto();
-      auditDto.setUuid(randomAlphanumeric(20));
-      auditDao.insert(dbSession, auditDto);
-    }
+  public void selectByPeriodPaginated_10001EntriesInserted_querySecondPageReturns1Item() {
+    prepareRowsWithDeterministicCreatedAt(10001);
 
-    List<AuditDto> auditDtos = auditDao.selectAll(dbSession);
+    List<AuditDto> auditDtos = testAuditDao.selectByPeriodPaginated(dbSession, 1, 20000, 2);
 
-    assertThat(auditDtos.size()).isEqualTo(100);
+    assertThat(auditDtos.size()).isEqualTo(1);
   }
 
   @Test
-  public void selectByPeriod_selectOneRowFromTheMiddle() {
-    prepareThreeRowsWithDeterministicCreatedAt();
+  public void deleteIfBeforeSelectedDate_deleteTwoRows() {
+    prepareRowsWithDeterministicCreatedAt(3);
 
-    List<AuditDto> auditDtos = testAuditDao.selectByPeriod(dbSession, 1, 3);
+    testAuditDao.deleteIfBeforeSelectedDate(dbSession, 2);
 
+    List<AuditDto> auditDtos = testAuditDao.selectByPeriodPaginated(dbSession, 1, 4, 1);
     assertThat(auditDtos.size()).isEqualTo(1);
-    assertThat(auditDtos.get(0).getCreatedAt()).isEqualTo(2);
   }
 
   @Test
-  public void selectByPeriod_selectOneRowFromTheEnd() {
-    prepareThreeRowsWithDeterministicCreatedAt();
+  public void selectByPeriodPaginated_100EntriesInserted_100EntriesReturned() {
+    prepareRowsWithDeterministicCreatedAt(100);
 
-    List<AuditDto> auditDtos = testAuditDao.selectByPeriod(dbSession, 2, 4);
+    List<AuditDto> auditDtos = testAuditDao.selectByPeriodPaginated(dbSession, 1, 101, 1);
 
-    assertThat(auditDtos.size()).isEqualTo(1);
-    assertThat(auditDtos.get(0).getCreatedAt()).isEqualTo(3);
+    assertThat(auditDtos.size()).isEqualTo(100);
   }
 
   @Test
-  public void selectByPeriod_selectAllRows() {
-    prepareThreeRowsWithDeterministicCreatedAt();
+  public void insert_doNotSetACreatedAtIfAlreadySet() {
+    AuditDto auditDto = AuditTesting.newAuditDto();
+    auditDto.setCreatedAt(1041375600000L);
 
-    List<AuditDto> auditDtos = testAuditDao.selectByPeriod(dbSession, 0, 4);
+    testAuditDao.insert(dbSession, auditDto);
 
-    assertThat(auditDtos.size()).isEqualTo(3);
+    List<AuditDto> auditDtos = testAuditDao.selectByPeriodPaginated(dbSession, 1041375500000L, 1041375700000L, 1);
+    AuditDto storedAuditDto = auditDtos.get(0);
+    assertThat(storedAuditDto.getCreatedAt()).isEqualTo(auditDto.getCreatedAt());
   }
 
   @Test
-  public void selectIfBeforeSelectedDate_select1Row() {
-    prepareThreeRowsWithDeterministicCreatedAt();
+  public void insert_setACreatedAtIfAlreadySet() {
+    AuditDto auditDto = AuditTesting.newAuditDto();
+    auditDto.setCreatedAt(0);
 
-    List<AuditDto> auditDtos = testAuditDao.selectIfBeforeSelectedDate(dbSession, 2);
+    testAuditDao.insert(dbSession, auditDto);
 
-    assertThat(auditDtos.size()).isEqualTo(1);
+    assertThat(auditDto.getCreatedAt()).isNotZero();
   }
 
   @Test
-  public void deleteIfBeforeSelectedDate_deleteTwoRows() {
-    prepareThreeRowsWithDeterministicCreatedAt();
+  public void insert_doNotSetAUUIDIfAlreadySet() {
+    AuditDto auditDto = AuditTesting.newAuditDto();
+    auditDto.setUuid("myuuid");
+    auditDto.setCreatedAt(1041375600000L);
 
-    testAuditDao.deleteIfBeforeSelectedDate(dbSession, 2);
+    testAuditDao.insert(dbSession, auditDto);
 
-    List<AuditDto> auditDtos = testAuditDao.selectAll(dbSession);
-    assertThat(auditDtos.size()).isEqualTo(1);
+    List<AuditDto> auditDtos = testAuditDao.selectByPeriodPaginated(dbSession, 1041375500000L, 1041375700000L, 1);
+    AuditDto storedAuditDto = auditDtos.get(0);
+    assertThat(storedAuditDto.getUuid()).isEqualTo(auditDto.getUuid());
   }
 
   @Test
@@ -140,10 +124,9 @@ public class AuditDaoTest {
     assertThat(auditDto.getNewValue()).isEqualTo(EXCEEDED_LENGTH);
   }
 
-  private void prepareThreeRowsWithDeterministicCreatedAt() {
-    for(int i=1; i<=3; i++) {
-      AuditDto auditDto = AuditTesting.newAuditDto();
-      system2.setNow(i);
+  private void prepareRowsWithDeterministicCreatedAt(int size) {
+    for (int i = 1; i <= size; i++) {
+      AuditDto auditDto = AuditTesting.newAuditDto(i);
       testAuditDao.insert(dbSession, auditDto);
     }
   }
index 8d795b2411c925049829fc7396f56802dd2d395a..b4733ef57be6e5f1aa210a98076383cfc6790d23 100644 (file)
@@ -34,6 +34,7 @@ import org.sonar.core.util.SequenceUuidFactory;
 import org.sonar.core.util.UuidFactory;
 import org.sonar.db.alm.integration.pat.AlmPatsDbTester;
 import org.sonar.db.almsettings.AlmSettingsDbTester;
+import org.sonar.db.audit.AuditDbTester;
 import org.sonar.db.audit.AuditPersister;
 import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ProjectLinkDbTester;
@@ -88,6 +89,7 @@ public class DbTester extends AbstractDbTester<TestDbImpl> {
   private final InternalComponentPropertyDbTester internalComponentPropertyTester;
   private final AlmSettingsDbTester almSettingsDbTester;
   private final AlmPatsDbTester almPatsDbtester;
+  private final AuditDbTester auditDbTester;
 
   private DbTester(System2 system2, @Nullable String schemaPath, AuditPersister auditPersister, MyBatisConfExtension... confExtensions) {
     super(TestDbImpl.create(schemaPath, confExtensions));
@@ -116,6 +118,7 @@ public class DbTester extends AbstractDbTester<TestDbImpl> {
     this.newCodePeriodTester = new NewCodePeriodDbTester(this);
     this.almSettingsDbTester = new AlmSettingsDbTester(this);
     this.almPatsDbtester = new AlmPatsDbTester(this);
+    this.auditDbTester = new AuditDbTester(this);
   }
 
   public static DbTester create() {
@@ -244,6 +247,10 @@ public class DbTester extends AbstractDbTester<TestDbImpl> {
     return almPatsDbtester;
   }
 
+  public AuditDbTester audits() {
+    return auditDbTester;
+  }
+
   @Override
   protected void after() {
     if (session != null) {
diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/audit/AuditDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/audit/AuditDbTester.java
new file mode 100644 (file)
index 0000000..2d34d32
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.db.audit;
+
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+
+public class AuditDbTester {
+
+  private final DbTester db;
+  private final DbClient dbClient;
+  private final DbSession dbSession;
+
+  public AuditDbTester(DbTester db) {
+    this.db = db;
+    this.dbClient = db.getDbClient();
+    this.dbSession = db.getSession();
+  }
+
+  public final void insertRandomAuditEntry(long createdAt) {
+    AuditDto auditDto = AuditTesting.newAuditDto(createdAt);
+    dbClient.auditDao().insert(dbSession, auditDto);
+    db.commit();
+  }
+}
index 094ae46db49fb48382d9edc660368d0f8d1f0887..1cc60162c32d29657f2cbc6a9344272abfd4146b 100644 (file)
@@ -28,14 +28,26 @@ public class AuditTesting {
   private static final Random random = new Random();
 
   public static AuditDto newAuditDto() {
+    return newAuditDto(random.nextLong(), "operation");
+  }
+
+  public static AuditDto newAuditDto(String operation) {
+    return newAuditDto(random.nextLong(), operation);
+  }
+
+  public static AuditDto newAuditDto(long createdAt) {
+    return newAuditDto(createdAt, "operation");
+  }
+
+  public static AuditDto newAuditDto(long createdAt, String operation) {
     AuditDto auditDto = new AuditDto();
     auditDto.setUuid(randomAlphanumeric(20));
     auditDto.setUserUuid(randomAlphanumeric(40));
     auditDto.setUserLogin(randomAlphanumeric(40));
-    auditDto.setNewValue(randomAlphanumeric(2000));
-    auditDto.setOperation("operation");
+    auditDto.setNewValue("{ \"someKey\": \"someValue\" }");
+    auditDto.setOperation(operation);
     auditDto.setCategory("category");
-    auditDto.setCreatedAt(random.nextLong());
+    auditDto.setCreatedAt(createdAt);
     return auditDto;
   }
 }