]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8450 Extract logic to get qgate from project in QualityGateFinder
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 5 Dec 2016 16:41:10 +0000 (17:41 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 6 Dec 2016 10:48:59 +0000 (11:48 +0100)
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateFinder.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/GetByProjectAction.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateFinderTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/GetByProjectActionTest.java
sonar-db/src/test/java/org/sonar/db/DbTester.java
sonar-db/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java

diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateFinder.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateFinder.java
new file mode 100644 (file)
index 0000000..1d670ad
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.server.qualitygate;
+
+import java.util.Optional;
+import javax.annotation.CheckForNull;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.server.exceptions.NotFoundException;
+
+import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPERTY;
+
+public class QualityGateFinder {
+
+  private final DbClient dbClient;
+
+  public QualityGateFinder(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  /**
+   * Return effective quality gate of a project.
+   *
+   * It will first try to get the quality gate explicitly defined on a project, if none it will try to return default quality gate.
+   * As it's possible to have no default quality gate, this method can return {@link Optional#empty()}
+   */
+  public Optional<QualityGateData> getQualityGate(DbSession dbSession, long componentId) {
+    Optional<Long> qualityGateId = dbClient.projectQgateAssociationDao().selectQGateIdByComponentId(dbSession, componentId);
+    if (qualityGateId.isPresent()) {
+      return Optional.of(new QualityGateData(selectOrFailById(dbSession, qualityGateId.get()), false));
+    } else {
+      QualityGateDto defaultQualityGate = getDefault(dbSession);
+      if (defaultQualityGate == null) {
+        return Optional.empty();
+      }
+      return Optional.of(new QualityGateData(defaultQualityGate, true));
+    }
+  }
+
+  @CheckForNull
+  private QualityGateDto getDefault(DbSession dbSession) {
+    Long defaultId = getDefaultId(dbSession);
+    if (defaultId == null) {
+      return null;
+    }
+    return selectOrFailById(dbSession, defaultId);
+  }
+
+  private QualityGateDto selectOrFailById(DbSession dbSession, long qualityGateId) {
+    QualityGateDto qualityGateDto = dbClient.qualityGateDao().selectById(dbSession, qualityGateId);
+    if (qualityGateDto == null) {
+      throw new NotFoundException(String.format("No quality gate has been found for id %s", qualityGateId));
+    }
+    return qualityGateDto;
+  }
+
+  @CheckForNull
+  private Long getDefaultId(DbSession dbSession) {
+    PropertyDto defaultQgate = dbClient.propertiesDao().selectGlobalProperty(dbSession, SONAR_QUALITYGATE_PROPERTY);
+    if (defaultQgate == null || isBlank(defaultQgate.getValue())) {
+      // For the moment, it's possible to have no default quality gate, but it will change with SONAR-8507
+      return null;
+    }
+    return Long.valueOf(defaultQgate.getValue());
+  }
+
+  public static class QualityGateData {
+    private final QualityGateDto qualityGate;
+    private final boolean isDefault;
+
+    private QualityGateData(QualityGateDto qualityGate, boolean isDefault) {
+      this.qualityGate = qualityGate;
+      this.isDefault = isDefault;
+    }
+
+    public QualityGateDto getQualityGate() {
+      return qualityGate;
+    }
+
+    public boolean isDefault() {
+      return isDefault;
+    }
+  }
+}
index c2a225eec0ec43c28a2656d6590d81f57b693ffa..896eaa64c6969334b2896208ca6c028a50dca984 100644 (file)
@@ -48,6 +48,7 @@ public class QualityGateModule extends Module {
       QualityGateUpdater.class,
       QualityGateConditionsUpdater.class,
       QgateProjectFinder.class,
+      QualityGateFinder.class,
       // WS
       QualityGatesWs.class,
       ListAction.class,
index c51422284ad5eed9457a333d2c38bab8cc0cab10..977e9120e9c5ca0495ad067214456e4b03d7a8df 100644 (file)
@@ -31,7 +31,8 @@ import org.sonar.db.component.ComponentDto;
 import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.component.ComponentFinder.ParamNames;
-import org.sonar.server.qualitygate.QualityGates;
+import org.sonar.server.qualitygate.QualityGateFinder;
+import org.sonar.server.qualitygate.QualityGateFinder.QualityGateData;
 import org.sonar.server.user.UserSession;
 import org.sonarqube.ws.WsQualityGates.GetByProjectWsResponse;
 
@@ -47,13 +48,13 @@ public class GetByProjectAction implements QualityGatesWsAction {
   private final UserSession userSession;
   private final DbClient dbClient;
   private final ComponentFinder componentFinder;
-  private final QualityGates qualityGates;
+  private final QualityGateFinder qualityGateFinder;
 
-  public GetByProjectAction(UserSession userSession, DbClient dbClient, ComponentFinder componentFinder, QualityGates qualityGates) {
+  public GetByProjectAction(UserSession userSession, DbClient dbClient, ComponentFinder componentFinder, QualityGateFinder qualityGateFinder) {
     this.userSession = userSession;
     this.dbClient = dbClient;
     this.componentFinder = componentFinder;
-    this.qualityGates = qualityGates;
+    this.qualityGateFinder = qualityGateFinder;
   }
 
   @Override
@@ -80,7 +81,7 @@ public class GetByProjectAction implements QualityGatesWsAction {
     DbSession dbSession = dbClient.openSession(false);
     try {
       ComponentDto project = getProject(dbSession, request.param(PARAM_PROJECT_ID), request.param(PARAM_PROJECT_KEY));
-      QualityGateData data = getQualityGate(dbSession, project.getId());
+      Optional<QualityGateData> data = qualityGateFinder.getQualityGate(dbSession, project.getId());
 
       writeProtobuf(buildResponse(data), request, response);
     } finally {
@@ -99,37 +100,20 @@ public class GetByProjectAction implements QualityGatesWsAction {
     return project;
   }
 
-  private static GetByProjectWsResponse buildResponse(QualityGateData data) {
-    if (!data.qualityGate.isPresent()) {
+  private static GetByProjectWsResponse buildResponse(Optional<QualityGateData> data) {
+    if (!data.isPresent()) {
       return GetByProjectWsResponse.getDefaultInstance();
     }
 
-    QualityGateDto qualityGate = data.qualityGate.get();
+    QualityGateDto qualityGate = data.get().getQualityGate();
     GetByProjectWsResponse.Builder response = GetByProjectWsResponse.newBuilder();
 
     response.getQualityGateBuilder()
       .setId(String.valueOf(qualityGate.getId()))
       .setName(qualityGate.getName())
-      .setDefault(data.isDefault);
+      .setDefault(data.get().isDefault());
 
     return response.build();
   }
 
-  private QualityGateData getQualityGate(DbSession dbSession, long componentId) {
-    Optional<Long> qualityGateId = dbClient.projectQgateAssociationDao().selectQGateIdByComponentId(dbSession, componentId);
-
-    return qualityGateId.isPresent()
-      ? new QualityGateData(Optional.ofNullable(dbClient.qualityGateDao().selectById(dbSession, qualityGateId.get())), false)
-      : new QualityGateData(Optional.ofNullable(qualityGates.getDefault()), true);
-  }
-
-  private static class QualityGateData {
-    private final Optional<QualityGateDto> qualityGate;
-    private final boolean isDefault;
-
-    private QualityGateData(Optional<QualityGateDto> qualityGate, boolean isDefault) {
-      this.qualityGate = qualityGate;
-      this.isDefault = isDefault;
-    }
-  }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateFinderTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateFinderTest.java
new file mode 100644 (file)
index 0000000..9826a19
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.server.qualitygate;
+
+import java.util.Optional;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.server.exceptions.NotFoundException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+
+public class QualityGateFinderTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  private DbSession dbSession = dbTester.getSession();
+
+  private QualityGateFinder underTest = new QualityGateFinder(dbTester.getDbClient());
+
+  @Test
+  public void return_default_quality_gate_for_project() {
+    ComponentDto project = dbTester.components().insertComponent(newProjectDto());
+    QualityGateDto dbQualityGate = dbTester.qualityGates().createDefaultQualityGate("Sonar way");
+
+    Optional<QualityGateFinder.QualityGateData> result = underTest.getQualityGate(dbSession, project.getId());
+
+    assertThat(result).isPresent();
+    assertThat(result.get().getQualityGate().getId()).isEqualTo(dbQualityGate.getId());
+    assertThat(result.get().isDefault()).isTrue();
+  }
+
+  @Test
+  public void return_project_quality_gate_over_default() {
+    ComponentDto project = dbTester.components().insertComponent(newProjectDto());
+    dbTester.qualityGates().createDefaultQualityGate("Sonar way");
+    QualityGateDto dbQualityGate = dbTester.qualityGates().insertQualityGate("My team QG");
+    dbTester.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
+
+    Optional<QualityGateFinder.QualityGateData> result = underTest.getQualityGate(dbSession, project.getId());
+
+    assertThat(result).isPresent();
+    assertThat(result.get().getQualityGate().getId()).isEqualTo(dbQualityGate.getId());
+    assertThat(result.get().isDefault()).isFalse();
+  }
+
+  @Test
+  public void return_nothing_when_no_default_qgate_and_no_qgate_defined_for_project() {
+    ComponentDto project = dbTester.components().insertComponent(newProjectDto());
+
+    Optional<QualityGateFinder.QualityGateData> result = underTest.getQualityGate(dbSession, project.getId());
+
+    assertThat(result).isNotPresent();
+  }
+
+  @Test
+  public void fail_when_default_qgate_defined_in_properties_does_not_exists() throws Exception {
+    ComponentDto project = dbTester.components().insertComponent(newProjectDto());
+    QualityGateDto dbQualityGate = dbTester.qualityGates().createDefaultQualityGate("Sonar way");
+    dbTester.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);
+
+    expectedException.expect(NotFoundException.class);
+    underTest.getQualityGate(dbSession, project.getId());
+  }
+
+  @Test
+  public void fail_when_project_qgate_defined_in_properties_does_not_exists() throws Exception {
+    ComponentDto project = dbTester.components().insertComponent(newProjectDto());
+    QualityGateDto dbQualityGate = dbTester.qualityGates().insertQualityGate("My team QG");
+    dbTester.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
+    dbTester.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);
+
+    expectedException.expect(NotFoundException.class);
+    underTest.getQualityGate(dbSession, project.getId());
+  }
+}
index bb8ad41e8b7d4c3bd542f823a0c8df240a0b0414..6d1b2c1b592a0fbae9fa2d261514cc94dc635115 100644 (file)
@@ -30,6 +30,6 @@ public class QualityGateModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new QualityGateModule().configure(container);
-    assertThat(container.size()).isEqualTo(22 + 2);
+    assertThat(container.size()).isEqualTo(23 + 2);
   }
 }
index d07e2cec6f90c6c517c6fffa89b282d7e5df564d..57cae11cdc54e80acfa5ecc9f9e75224a4e0e827 100644 (file)
@@ -26,7 +26,6 @@ import javax.annotation.Nullable;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.api.measures.MetricFinder;
 import org.sonar.api.utils.System2;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.permission.GlobalPermissions;
@@ -40,9 +39,8 @@ import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.qualitygate.QualityGates;
+import org.sonar.server.qualitygate.QualityGateFinder;
 import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.user.UserSession;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
 import org.sonarqube.ws.MediaTypes;
@@ -51,7 +49,6 @@ import org.sonarqube.ws.WsQualityGates.GetByProjectWsResponse;
 
 import static com.google.common.base.Throwables.propagate;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
 import static org.sonar.db.component.ComponentTesting.newProjectDto;
 import static org.sonar.test.JsonAssert.assertJson;
 import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID;
@@ -69,8 +66,7 @@ public class GetByProjectActionTest {
   DbSession dbSession = db.getSession();
 
   private WsActionTester ws = new WsActionTester(
-    new GetByProjectAction(userSession, dbClient, new ComponentFinder(dbClient),
-      new QualityGates(dbClient, mock(MetricFinder.class), mock(UserSession.class))));
+    new GetByProjectAction(userSession, dbClient, new ComponentFinder(dbClient), new QualityGateFinder(dbClient)));
 
   @Test
   public void json_example() {
index 2f0e95ec461c4d131f52c8a022c191d9c6ec3037..e3fde30440333cba93dcbd19a5d7da678606d990 100644 (file)
@@ -69,6 +69,7 @@ import org.sonar.db.organization.OrganizationDbTester;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.organization.OrganizationTesting;
 import org.sonar.db.permission.template.PermissionTemplateDbTester;
+import org.sonar.db.qualitygate.QualityGateDbTester;
 import org.sonar.db.user.RootFlagAssertions;
 import org.sonar.db.user.UserDbTester;
 
@@ -100,6 +101,7 @@ public class DbTester extends ExternalResource {
   private final ComponentDbTester componentTester;
   private final OrganizationDbTester organizationTester;
   private final PermissionTemplateDbTester permissionTemplateTester;
+  private final QualityGateDbTester qualityGateDbTester;
   private final RootFlagAssertions rootFlagAssertions;
 
   private DbTester(System2 system2, @Nullable String schemaPath) {
@@ -110,6 +112,7 @@ public class DbTester extends ExternalResource {
     this.componentTester = new ComponentDbTester(this);
     this.organizationTester = new OrganizationDbTester(this);
     this.permissionTemplateTester = new PermissionTemplateDbTester(this);
+    this.qualityGateDbTester = new QualityGateDbTester(this);
     this.rootFlagAssertions = new RootFlagAssertions(this);
   }
 
@@ -182,6 +185,10 @@ public class DbTester extends ExternalResource {
     return permissionTemplateTester;
   }
 
+  public QualityGateDbTester qualityGates() {
+    return qualityGateDbTester;
+  }
+
   public RootFlagAssertions rootFlag() {
     return rootFlagAssertions;
   }
index 5f61358b9a7ff9ce592b6e4ce11b13a37b269613..d088ec564748d2c57c7f31175748fbc4c21d2890 100644 (file)
@@ -22,6 +22,8 @@ package org.sonar.db.qualitygate;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.property.PropertyDto;
 
 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
 
@@ -46,4 +48,25 @@ public class QualityGateDbTester {
     db.commit();
     return updatedUser;
   }
+
+  public void associateProjectToQualityGate(ComponentDto component, QualityGateDto qualityGate) {
+    dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto()
+      .setKey("sonar.qualitygate")
+      .setResourceId(component.getId())
+      .setValue(String.valueOf(qualityGate.getId())));
+    db.commit();
+  }
+
+  public QualityGateDto createDefaultQualityGate(String qualityGateName) {
+    QualityGateDto defaultQGate = insertQualityGate(qualityGateName);
+    setDefaultQualityGate(defaultQGate);
+    return defaultQGate;
+  }
+
+  public void setDefaultQualityGate(QualityGateDto qualityGate) {
+    dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto()
+      .setKey("sonar.qualitygate")
+      .setValue(String.valueOf(qualityGate.getId())));
+    db.commit();
+  }
 }