]> source.dussan.org Git - sonarqube.git/commitdiff
WS api/projects/projects/provisioned list the provisioned projects - SONAR-6526
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 8 May 2015 10:05:06 +0000 (12:05 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Mon, 11 May 2015 15:31:37 +0000 (17:31 +0200)
21 files changed:
server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectsWs.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/ProvisionedProjectsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java
server/sonar-server/src/main/java/org/sonar/server/language/ws/ListAction.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/RepositoriesAction.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/TagsAction.java
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsListAction.java
server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java
server/sonar-server/src/main/resources/org/sonar/server/component/ws/projects-example-provisioned.json [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/ProvisionedProjectsActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/BaseStepTest.java
server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/delete-result.xml
server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/select_provisioned_projects.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/shared.xml
server/sonar-server/src/test/resources/org/sonar/server/component/ws/ProvisionedProjectsActionTest/all-projects.json [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java
sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml

index bd85204aaa6b2ddc3486ecb0988c586d86c589f2..96d3eb0ab44e36e7d3ac5a0f8c1b6237dbba52b0 100644 (file)
@@ -21,6 +21,8 @@
 package org.sonar.server.component.db;
 
 import com.google.common.base.Function;
+import org.apache.ibatis.session.RowBounds;
+import org.sonar.api.ServerComponent;
 import org.sonar.api.ServerSide;
 import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.resources.Scopes;
@@ -33,13 +35,17 @@ import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.DaoUtils;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.db.BaseDao;
+import org.sonar.server.es.SearchOptions;
 import org.sonar.server.exceptions.NotFoundException;
 
 import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @since 4.3
@@ -173,4 +179,21 @@ public class ComponentDao extends BaseDao<ComponentMapper, ComponentDto, String>
     return mapper(session).selectProjectsFromView("%." + viewUuid + ".%", projectViewUuid);
   }
 
+  public List<ComponentDto> selectProvisionedProjects(DbSession session, SearchOptions searchOptions, @Nullable String query) {
+    Map<String, String> parameters = new HashMap<>();
+    parameters.put("qualifier", Qualifiers.PROJECT);
+    if (query != null) {
+      parameters.put("query", "%" + query + "%");
+    }
+    return mapper(session).selectProvisionedProjects(parameters, new RowBounds(searchOptions.getOffset(), searchOptions.getLimit()));
+  }
+
+  public int countProvisionedProjects(DbSession session, @Nullable String query) {
+    Map<String, String> parameters = new HashMap<>();
+    parameters.put("qualifier", Qualifiers.PROJECT);
+    if (query != null) {
+      parameters.put("query", "%" + query + "%");
+    }
+    return mapper(session).countProvisionedProjects(parameters);
+  }
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectsAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectsAction.java
new file mode 100644 (file)
index 0000000..ddbe535
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.component.ws;
+
+import org.sonar.server.ws.WsAction;
+
+public interface ProjectsAction extends WsAction {
+  // marker interface
+}
index a4a06570cf2aec14a3952f3483709bba26f70969..4b99a290d58466e3696847de1eb1a5c4a25c80f9 100644 (file)
@@ -25,6 +25,11 @@ import org.sonar.api.server.ws.RailsHandler;
 import org.sonar.api.server.ws.WebService;
 
 public class ProjectsWs implements WebService {
+  private final ProjectsAction[] actions;
+
+  public ProjectsWs(ProjectsAction... actions) {
+    this.actions = actions;
+  }
 
   @Override
   public void define(Context context) {
@@ -36,6 +41,10 @@ public class ProjectsWs implements WebService {
     defineCreateAction(controller);
     defineDestroyAction(controller);
 
+    for (ProjectsAction action : actions) {
+      action.define(controller);
+    }
+
     controller.done();
   }
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProvisionedProjectsAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProvisionedProjectsAction.java
new file mode 100644 (file)
index 0000000..cbc15b8
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.component.ws;
+
+import com.google.common.io.Resources;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.user.UserSession;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+public class ProvisionedProjectsAction implements ProjectsAction {
+  private final DbClient dbClient;
+
+  private static final List<String> POSSIBLE_FIELDS = Arrays.asList("uuid", "key", "name", "creationDate");
+
+  public ProvisionedProjectsAction(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller
+      .createAction("provisioned")
+      .setDescription(
+        "Get the list of provisioned projects.<br /> " +
+          "Require admin role.")
+      .setSince("5.2")
+      .setResponseExample(Resources.getResource(getClass(), "projects-example-provisioned.json"))
+      .setHandler(this)
+      .addPagingParams(100)
+      .addFieldsParam(POSSIBLE_FIELDS);
+
+    action
+      .createParam(Param.TEXT_QUERY)
+      .setDescription("UTF-8 search query")
+      .setExampleValue("sonar");
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    UserSession.get().checkGlobalPermission(UserRole.ADMIN, "You need admin rights.");
+    SearchOptions options = new SearchOptions().setPage(
+      request.mandatoryParamAsInt(Param.PAGE),
+      request.mandatoryParamAsInt(Param.PAGE_SIZE)
+    );
+    List<String> desiredFields = desiredFields(request);
+    String query = request.param(Param.TEXT_QUERY);
+
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      List<ComponentDto> projects = dbClient.componentDao().selectProvisionedProjects(dbSession, options, query);
+      int nbOfProjects = dbClient.componentDao().countProvisionedProjects(dbSession, query);
+      JsonWriter json = response.newJsonWriter().beginObject();
+      writeProjects(projects, json, desiredFields);
+      options.writeJson(json, nbOfProjects);
+      json.endObject().close();
+    } finally {
+      MyBatis.closeQuietly(dbSession);
+    }
+  }
+
+  private void writeProjects(List<ComponentDto> projects, JsonWriter json, List<String> desiredFields) {
+    json.name("projects");
+    json.beginArray();
+    for (ComponentDto project : projects) {
+      json.beginObject();
+      json.prop("uuid", project.uuid());
+      writeIfNeeded(json, "key", project.key(), desiredFields);
+      writeIfNeeded(json, "name", project.name(), desiredFields);
+      writeIfNeeded(json, "creationDate", project.getCreatedAt(), desiredFields);
+      json.endObject();
+    }
+    json.endArray();
+  }
+
+  private void writeIfNeeded(JsonWriter json, String fieldName, String value, List<String> desiredFields) {
+    if (desiredFields.contains(fieldName)) {
+      json.prop(fieldName, value);
+    }
+  }
+
+  private void writeIfNeeded(JsonWriter json, String fieldName, Date date, List<String> desiredFields) {
+    if (desiredFields.contains(fieldName)) {
+      json.propDateTime(fieldName, date);
+    }
+  }
+
+  private List<String> desiredFields(Request request) {
+    List<String> desiredFields = request.paramAsStrings(Param.FIELDS);
+    if (desiredFields == null) {
+      desiredFields = POSSIBLE_FIELDS;
+    }
+
+    return desiredFields;
+  }
+}
index 8096dc5dd62095d3098e66e00676d19b15b85cc9..880d8ac9e8a3ae42374bd6fc9e7ede62fc30801e 100644 (file)
@@ -24,6 +24,7 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.server.issue.IssueService;
 
@@ -37,8 +38,8 @@ public class AuthorsAction implements BaseIssuesWsAction {
 
   @Override
   public void handle(Request request, Response response) throws Exception {
-    String query = request.param(WebService.Param.TEXT_QUERY);
-    int pageSize = request.mandatoryParamAsInt(WebService.Param.PAGE_SIZE);
+    String query = request.param(Param.TEXT_QUERY);
+    int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
 
     JsonWriter json = response.newJsonWriter()
       .beginObject()
@@ -60,10 +61,10 @@ public class AuthorsAction implements BaseIssuesWsAction {
       .setResponseExample(Resources.getResource(this.getClass(), "example-authors.json"))
       .setHandler(this);
 
-    action.createParam(WebService.Param.TEXT_QUERY)
+    action.createParam(Param.TEXT_QUERY)
       .setDescription("A pattern to match SCM accounts against")
       .setExampleValue("luke");
-    action.createParam(WebService.Param.PAGE_SIZE)
+    action.createParam(Param.PAGE_SIZE)
       .setDescription("The size of the list to return")
       .setExampleValue("25")
       .setDefaultValue("10");
index fcd4326e48ce97c99242d5e82ba2a5c0da49730d..d8c80e868fe3f746b7bc52cb59c1ac56303e276b 100644 (file)
@@ -29,6 +29,7 @@ import org.sonar.api.server.ws.RequestHandler;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.text.JsonWriter;
 
 import javax.annotation.Nullable;
@@ -52,7 +53,7 @@ public class ListAction implements RequestHandler {
 
   @Override
   public void handle(Request request, Response response) throws Exception {
-    String query = request.param("q");
+    String query = request.param(Param.TEXT_QUERY);
     int pageSize = request.mandatoryParamAsInt("ps");
 
     JsonWriter json = response.newJsonWriter().beginObject().name("languages").beginArray();
@@ -84,7 +85,7 @@ public class ListAction implements RequestHandler {
       .setHandler(this)
       .setResponseExample(Resources.getResource(getClass(), "example-list.json"));
 
-    action.createParam("q")
+    action.createParam(Param.TEXT_QUERY)
       .setDescription("A pattern to match language keys/names against")
       .setExampleValue("java");
     action.createParam("ps")
index 4c76a9e1fef217391173ebcd1c54ba67bde31cf1..4fb3c1fbf8adaa5a86913154c66fb002f8c89117 100644 (file)
@@ -104,6 +104,7 @@ import org.sonar.server.component.ws.ComponentAppAction;
 import org.sonar.server.component.ws.ComponentsWs;
 import org.sonar.server.component.ws.EventsWs;
 import org.sonar.server.component.ws.ProjectsWs;
+import org.sonar.server.component.ws.ProvisionedProjectsAction;
 import org.sonar.server.component.ws.ResourcesWs;
 import org.sonar.server.computation.ComputationThreadLauncher;
 import org.sonar.server.computation.ReportQueue;
@@ -795,6 +796,7 @@ class ServerComponents {
     pico.addSingleton(org.sonar.server.component.ws.SearchAction.class);
     pico.addSingleton(EventsWs.class);
     pico.addSingleton(ComponentCleanerService.class);
+    pico.addSingleton(ProvisionedProjectsAction.class);
 
     // views
     pico.addSingleton(ViewIndexDefinition.class);
index 8a2adbbd562f0e06b5611d73b7eb587e8ff0a5cb..87f2b89e75514d68df2b2f37682fb6fcb6b34dd1 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.server.rule.RuleRepositories;
 import org.sonar.server.rule.RuleRepositories.Repository;
@@ -53,7 +54,7 @@ public class RepositoriesAction implements RulesAction {
 
   @Override
   public void handle(Request request, Response response) throws Exception {
-    String query = request.param("q");
+    String query = request.param(Param.TEXT_QUERY);
     String languageKey = request.param(LANGUAGE);
     int pageSize = request.mandatoryParamAsInt("ps");
 
@@ -102,7 +103,7 @@ public class RepositoriesAction implements RulesAction {
       .setHandler(this)
       .setResponseExample(Resources.getResource(getClass(), "example-repositories.json"));
 
-    action.createParam("q")
+    action.createParam(Param.TEXT_QUERY)
       .setDescription("A pattern to match repository keys/names against")
       .setExampleValue("squid");
     action.createParam(LANGUAGE)
index 4d20919f6ada7bb1f1a69b80837fa940bb794578..cec1677167152496c72ea1ab2752b6e28e6b9da5 100644 (file)
@@ -24,6 +24,7 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.server.rule.RuleService;
 
@@ -46,7 +47,7 @@ public class TagsAction implements RulesAction {
       .setHandler(this)
       .setResponseExample(Resources.getResource(getClass(), "example-tags.json"));
 
-    action.createParam("q")
+    action.createParam(Param.TEXT_QUERY)
       .setDescription("A pattern to match tags against")
       .setExampleValue("misra");
     action.createParam("ps")
@@ -57,7 +58,7 @@ public class TagsAction implements RulesAction {
 
   @Override
   public void handle(Request request, Response response) {
-    String query = request.param("q");
+    String query = request.param(Param.TEXT_QUERY);
     int pageSize = request.mandatoryParamAsInt("ps");
     Set<String> tags = service.listTags(query, pageSize);
     JsonWriter json = response.newJsonWriter().beginObject();
index ffd502d92a4facbd5235153b56e173e7d4b4c3a9..0a65137ecf7012d07e2ef685c1eb237d6759c489 100644 (file)
@@ -114,7 +114,7 @@ public class TestsListAction implements TestAction {
     SearchOptions searchOptions = new SearchOptions().setPage(
       request.mandatoryParamAsInt(WebService.Param.PAGE),
       request.mandatoryParamAsInt(WebService.Param.PAGE_SIZE)
-      );
+    );
 
     DbSession dbSession = dbClient.openSession(false);
     SearchResult<TestDoc> tests;
index 7030d7363ba9dac591d75bfd3cd41aae0e5cebbb..996488ec57d0c367c997ede0de3471453df7d728 100644 (file)
@@ -24,6 +24,7 @@ import com.google.common.collect.ImmutableSet;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.server.es.SearchOptions;
 import org.sonar.server.es.SearchResult;
@@ -37,8 +38,6 @@ import java.util.Set;
 
 public class SearchAction implements BaseUsersWsAction {
 
-  private static final String PARAM_QUERY = "q";
-
   private static final String FIELD_LOGIN = "login";
   private static final String FIELD_NAME = "name";
   private static final String FIELD_EMAIL = "email";
@@ -61,16 +60,16 @@ public class SearchAction implements BaseUsersWsAction {
     action.addFieldsParam(FIELDS);
     action.addPagingParams(50);
 
-    action.createParam(PARAM_QUERY)
+    action.createParam(Param.TEXT_QUERY)
       .setDescription("Filter on login or name.");
   }
 
   @Override
   public void handle(Request request, Response response) throws Exception {
     SearchOptions options = new SearchOptions()
-      .setPage(request.mandatoryParamAsInt(WebService.Param.PAGE), request.mandatoryParamAsInt(WebService.Param.PAGE_SIZE));
-    List<String> fields = request.paramAsStrings(WebService.Param.FIELDS);
-    SearchResult<UserDoc> result = userIndex.search(request.param(PARAM_QUERY), options);
+      .setPage(request.mandatoryParamAsInt(Param.PAGE), request.mandatoryParamAsInt(Param.PAGE_SIZE));
+    List<String> fields = request.paramAsStrings(Param.FIELDS);
+    SearchResult<UserDoc> result = userIndex.search(request.param(Param.TEXT_QUERY), options);
 
     JsonWriter json = response.newJsonWriter().beginObject();
     options.writeJson(json, result.getTotal());
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/component/ws/projects-example-provisioned.json b/server/sonar-server/src/main/resources/org/sonar/server/component/ws/projects-example-provisioned.json
new file mode 100644 (file)
index 0000000..4bb9f84
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "projects": [
+    {
+      "uuid": "ce4c03d6-430f-40a9-b777-ad877c00aa4d",
+      "key": "org.apache.hbas:hbase",
+      "name": "HBase",
+      "creationDate": "2015-03-04T23:03:44+0100"
+    },
+    {
+      "uuid": "c526ef20-131b-4486-9357-063fa64b5079",
+      "key": "com.microsoft.roslyn:roslyn",
+      "name": "Roslyn",
+      "creationDate": "2013-03-04T23:03:44+0100"
+    }
+  ],
+  "total": 2,
+  "p": 1,
+  "ps": 100
+}
index a7b643f7905bd3bc9aad78fc164f361512940c4a..ff3d0b1fecbb6b4483c22bba9f21012fb08c2248 100644 (file)
@@ -23,13 +23,15 @@ package org.sonar.server.component.db;
 import org.apache.ibatis.exceptions.PersistenceException;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.ClassRule;
 import org.junit.Test;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.System2;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.component.FilePathWithHashDto;
-import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.es.SearchOptions;
 import org.sonar.server.exceptions.NotFoundException;
 
 import java.util.Collections;
@@ -41,19 +43,21 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-public class ComponentDaoTest extends AbstractDaoTestCase {
+public class ComponentDaoTest {
 
-  DbSession session;
-
-  ComponentDao dao;
+  ComponentDao sut;
 
+  @ClassRule
+  public static DbTester db = new DbTester();
+  DbSession session;
   System2 system2;
 
+
   @Before
   public void createDao() {
-    session = getMyBatis().openSession(false);
+    session = db.myBatis().openSession(false);
     system2 = mock(System2.class);
-    dao = new ComponentDao(system2);
+    sut = new ComponentDao(system2);
   }
 
   @After
@@ -63,9 +67,9 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void get_by_uuid() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    ComponentDto result = dao.getNullableByUuid(session, "KLMN");
+    ComponentDto result = sut.getNullableByUuid(session, "KLMN");
     assertThat(result).isNotNull();
     assertThat(result.uuid()).isEqualTo("KLMN");
     assertThat(result.moduleUuid()).isEqualTo("EFGH");
@@ -82,11 +86,15 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
     assertThat(result.getCopyResourceId()).isNull();
   }
 
+  private void loadBasicDataInDatabase() {
+    db.prepareDbUnit(getClass(), "shared.xml");
+  }
+
   @Test
   public void get_by_uuid_on_technical_project_copy() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    ComponentDto result = dao.getNullableByUuid(session, "STUV");
+    ComponentDto result = sut.getNullableByUuid(session, "STUV");
     assertThat(result).isNotNull();
     assertThat(result.uuid()).isEqualTo("STUV");
     assertThat(result.moduleUuid()).isEqualTo("OPQR");
@@ -105,25 +113,25 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void get_by_uuid_on_disabled_component() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    ComponentDto result = dao.getNullableByUuid(session, "DCBA");
+    ComponentDto result = sut.getNullableByUuid(session, "DCBA");
     assertThat(result).isNotNull();
     assertThat(result.isEnabled()).isFalse();
   }
 
   @Test(expected = NotFoundException.class)
   public void fail_to_get_by_uuid_when_component_not_found() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    dao.getByUuid(session, "unknown");
+    sut.getByUuid(session, "unknown");
   }
 
   @Test
   public void get_by_key() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    ComponentDto result = dao.getNullableByKey(session, "org.struts:struts-core:src/org/struts/RequestContext.java");
+    ComponentDto result = sut.getNullableByKey(session, "org.struts:struts-core:src/org/struts/RequestContext.java");
     assertThat(result).isNotNull();
     assertThat(result.key()).isEqualTo("org.struts:struts-core:src/org/struts/RequestContext.java");
     assertThat(result.path()).isEqualTo("src/org/struts/RequestContext.java");
@@ -134,23 +142,23 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
     assertThat(result.language()).isEqualTo("java");
     assertThat(result.parentProjectId()).isEqualTo(2);
 
-    assertThat(dao.getNullableByKey(session, "unknown")).isNull();
+    assertThat(sut.getNullableByKey(session, "unknown")).isNull();
   }
 
   @Test
   public void get_by_key_on_disabled_component() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    ComponentDto result = dao.getNullableByKey(session, "org.disabled.project");
+    ComponentDto result = sut.getNullableByKey(session, "org.disabled.project");
     assertThat(result).isNotNull();
     assertThat(result.isEnabled()).isFalse();
   }
 
   @Test
   public void get_by_key_on_a_root_project() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    ComponentDto result = dao.getNullableByKey(session, "org.struts:struts");
+    ComponentDto result = sut.getNullableByKey(session, "org.struts:struts");
     assertThat(result).isNotNull();
     assertThat(result.key()).isEqualTo("org.struts:struts");
     assertThat(result.deprecatedKey()).isEqualTo("org.struts:struts");
@@ -166,9 +174,9 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void get_by_keys() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    List<ComponentDto> results = dao.getByKeys(session, "org.struts:struts-core:src/org/struts/RequestContext.java");
+    List<ComponentDto> results = sut.getByKeys(session, "org.struts:struts-core:src/org/struts/RequestContext.java");
     assertThat(results).hasSize(1);
 
     ComponentDto result = results.get(0);
@@ -182,14 +190,14 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
     assertThat(result.language()).isEqualTo("java");
     assertThat(result.parentProjectId()).isEqualTo(2);
 
-    assertThat(dao.getByKeys(session, "unknown")).isEmpty();
+    assertThat(sut.getByKeys(session, "unknown")).isEmpty();
   }
 
   @Test
   public void get_by_ids() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    List<ComponentDto> results = dao.getByIds(session, newArrayList(4L));
+    List<ComponentDto> results = sut.getByIds(session, newArrayList(4L));
     assertThat(results).hasSize(1);
 
     ComponentDto result = results.get(0);
@@ -203,14 +211,14 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
     assertThat(result.language()).isEqualTo("java");
     assertThat(result.parentProjectId()).isEqualTo(2);
 
-    assertThat(dao.getByIds(session, newArrayList(555L))).isEmpty();
+    assertThat(sut.getByIds(session, newArrayList(555L))).isEmpty();
   }
 
   @Test
   public void get_by_uuids() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    List<ComponentDto> results = dao.getByUuids(session, newArrayList("KLMN"));
+    List<ComponentDto> results = sut.getByUuids(session, newArrayList("KLMN"));
     assertThat(results).hasSize(1);
 
     ComponentDto result = results.get(0);
@@ -228,14 +236,14 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
     assertThat(result.scope()).isEqualTo("FIL");
     assertThat(result.language()).isEqualTo("java");
 
-    assertThat(dao.getByUuids(session, newArrayList("unknown"))).isEmpty();
+    assertThat(sut.getByUuids(session, newArrayList("unknown"))).isEmpty();
   }
 
   @Test
   public void get_by_uuids_on_removed_components() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    List<ComponentDto> results = dao.getByUuids(session, newArrayList("DCBA"));
+    List<ComponentDto> results = sut.getByUuids(session, newArrayList("DCBA"));
     assertThat(results).hasSize(1);
 
     ComponentDto result = results.get(0);
@@ -245,201 +253,201 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void select_existing_uuids() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    List<String> results = dao.selectExistingUuids(session, newArrayList("KLMN"));
+    List<String> results = sut.selectExistingUuids(session, newArrayList("KLMN"));
     assertThat(results).containsOnly("KLMN");
 
-    assertThat(dao.selectExistingUuids(session, newArrayList("KLMN", "unknown"))).hasSize(1);
-    assertThat(dao.selectExistingUuids(session, newArrayList("unknown"))).isEmpty();
+    assertThat(sut.selectExistingUuids(session, newArrayList("KLMN", "unknown"))).hasSize(1);
+    assertThat(sut.selectExistingUuids(session, newArrayList("unknown"))).isEmpty();
   }
 
   @Test
   public void get_by_id() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    assertThat(dao.getById(4L, session)).isNotNull();
+    assertThat(sut.getById(4L, session)).isNotNull();
   }
 
   @Test
   public void get_by_id_on_disabled_component() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    ComponentDto result = dao.getNullableById(10L, session);
+    ComponentDto result = sut.getNullableById(10L, session);
     assertThat(result).isNotNull();
     assertThat(result.isEnabled()).isFalse();
   }
 
   @Test(expected = NotFoundException.class)
   public void fail_to_get_by_id_when_project_not_found() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    dao.getById(111L, session);
+    sut.getById(111L, session);
   }
 
   @Test
   public void get_nullable_by_id() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    assertThat(dao.getNullableById(4L, session)).isNotNull();
-    assertThat(dao.getNullableById(111L, session)).isNull();
+    assertThat(sut.getNullableById(4L, session)).isNotNull();
+    assertThat(sut.getNullableById(111L, session)).isNull();
   }
 
   @Test
   public void count_by_id() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    assertThat(dao.existsById(4L, session)).isTrue();
-    assertThat(dao.existsById(111L, session)).isFalse();
+    assertThat(sut.existsById(4L, session)).isTrue();
+    assertThat(sut.existsById(111L, session)).isFalse();
   }
 
   @Test
   public void find_modules_by_project() {
-    setupData("multi-modules");
+    db.prepareDbUnit(getClass(), "multi-modules.xml");
 
-    List<ComponentDto> results = dao.findModulesByProject("org.struts:struts", session);
+    List<ComponentDto> results = sut.findModulesByProject("org.struts:struts", session);
     assertThat(results).hasSize(1);
     assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts-core");
 
-    results = dao.findModulesByProject("org.struts:struts-core", session);
+    results = sut.findModulesByProject("org.struts:struts-core", session);
     assertThat(results).hasSize(1);
     assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts-data");
 
-    assertThat(dao.findModulesByProject("org.struts:struts-data", session)).isEmpty();
+    assertThat(sut.findModulesByProject("org.struts:struts-data", session)).isEmpty();
 
-    assertThat(dao.findModulesByProject("unknown", session)).isEmpty();
+    assertThat(sut.findModulesByProject("unknown", session)).isEmpty();
   }
 
   @Test
   public void find_sub_projects_by_component_keys() {
-    setupData("multi-modules");
+    db.prepareDbUnit(getClass(), "multi-modules.xml");
 
     // Sub project of a file
-    List<ComponentDto> results = dao.findSubProjectsByComponentUuids(session, newArrayList("HIJK"));
+    List<ComponentDto> results = sut.findSubProjectsByComponentUuids(session, newArrayList("HIJK"));
     assertThat(results).hasSize(1);
     assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts-data");
 
     // Sub project of a directory
-    results = dao.findSubProjectsByComponentUuids(session, newArrayList("GHIJ"));
+    results = sut.findSubProjectsByComponentUuids(session, newArrayList("GHIJ"));
     assertThat(results).hasSize(1);
     assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts-data");
 
     // Sub project of a sub module
-    results = dao.findSubProjectsByComponentUuids(session, newArrayList("FGHI"));
+    results = sut.findSubProjectsByComponentUuids(session, newArrayList("FGHI"));
     assertThat(results).hasSize(1);
     assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts");
 
     // Sub project of a module
-    results = dao.findSubProjectsByComponentUuids(session, newArrayList("EFGH"));
+    results = sut.findSubProjectsByComponentUuids(session, newArrayList("EFGH"));
     assertThat(results).hasSize(1);
     assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts");
 
     // Sub project of a project
-    assertThat(dao.findSubProjectsByComponentUuids(session, newArrayList("ABCD"))).isEmpty();
+    assertThat(sut.findSubProjectsByComponentUuids(session, newArrayList("ABCD"))).isEmpty();
 
     // SUb projects of a component and a sub module
-    assertThat(dao.findSubProjectsByComponentUuids(session, newArrayList("HIJK", "FGHI"))).hasSize(2);
+    assertThat(sut.findSubProjectsByComponentUuids(session, newArrayList("HIJK", "FGHI"))).hasSize(2);
 
-    assertThat(dao.findSubProjectsByComponentUuids(session, newArrayList("unknown"))).isEmpty();
+    assertThat(sut.findSubProjectsByComponentUuids(session, newArrayList("unknown"))).isEmpty();
 
-    assertThat(dao.findSubProjectsByComponentUuids(session, Collections.<String>emptyList())).isEmpty();
+    assertThat(sut.findSubProjectsByComponentUuids(session, Collections.<String>emptyList())).isEmpty();
   }
 
   @Test
   public void select_enabled_modules_tree() {
-    setupData("multi-modules");
+    db.prepareDbUnit(getClass(), "multi-modules.xml");
 
     // From root project
-    List<ComponentDto> modules = dao.selectEnabledDescendantModules(session, "ABCD");
+    List<ComponentDto> modules = sut.selectEnabledDescendantModules(session, "ABCD");
     assertThat(modules).extracting("uuid").containsOnly("ABCD", "EFGH", "FGHI");
 
     // From module
-    modules = dao.selectEnabledDescendantModules(session, "EFGH");
+    modules = sut.selectEnabledDescendantModules(session, "EFGH");
     assertThat(modules).extracting("uuid").containsOnly("EFGH", "FGHI");
 
     // From sub module
-    modules = dao.selectEnabledDescendantModules(session, "FGHI");
+    modules = sut.selectEnabledDescendantModules(session, "FGHI");
     assertThat(modules).extracting("uuid").containsOnly("FGHI");
 
     // Folder
-    assertThat(dao.selectEnabledDescendantModules(session, "GHIJ")).isEmpty();
-    assertThat(dao.selectEnabledDescendantModules(session, "unknown")).isEmpty();
+    assertThat(sut.selectEnabledDescendantModules(session, "GHIJ")).isEmpty();
+    assertThat(sut.selectEnabledDescendantModules(session, "unknown")).isEmpty();
   }
 
   @Test
   public void select_all_modules_tree() {
-    setupData("multi-modules");
+    db.prepareDbUnit(getClass(), "multi-modules.xml");
 
     // From root project, disabled sub module is returned
-    List<ComponentDto> modules = dao.selectDescendantModules(session, "ABCD");
+    List<ComponentDto> modules = sut.selectDescendantModules(session, "ABCD");
     assertThat(modules).extracting("uuid").containsOnly("ABCD", "EFGH", "FGHI", "IHGF");
 
     // From module, disabled sub module is returned
-    modules = dao.selectDescendantModules(session, "EFGH");
+    modules = sut.selectDescendantModules(session, "EFGH");
     assertThat(modules).extracting("uuid").containsOnly("EFGH", "FGHI", "IHGF");
 
     // From removed sub module -> should not be returned
-    assertThat(dao.selectDescendantModules(session, "IHGF")).isEmpty();
+    assertThat(sut.selectDescendantModules(session, "IHGF")).isEmpty();
   }
 
   @Test
   public void select_enabled_module_files_tree_from_module() {
-    setupData("select_module_files_tree");
+    db.prepareDbUnit(getClass(), "select_module_files_tree.xml");
 
     // From root project
-    List<FilePathWithHashDto> files = dao.selectEnabledDescendantFiles(session, "ABCD");
+    List<FilePathWithHashDto> files = sut.selectEnabledDescendantFiles(session, "ABCD");
     assertThat(files).extracting("uuid").containsOnly("EFGHI", "HIJK");
     assertThat(files).extracting("moduleUuid").containsOnly("EFGH", "FGHI");
     assertThat(files).extracting("srcHash").containsOnly("srcEFGHI", "srcHIJK");
     assertThat(files).extracting("path").containsOnly("src/org/struts/pom.xml", "src/org/struts/RequestContext.java");
 
     // From module
-    files = dao.selectEnabledDescendantFiles(session, "EFGH");
+    files = sut.selectEnabledDescendantFiles(session, "EFGH");
     assertThat(files).extracting("uuid").containsOnly("EFGHI", "HIJK");
     assertThat(files).extracting("moduleUuid").containsOnly("EFGH", "FGHI");
     assertThat(files).extracting("srcHash").containsOnly("srcEFGHI", "srcHIJK");
     assertThat(files).extracting("path").containsOnly("src/org/struts/pom.xml", "src/org/struts/RequestContext.java");
 
     // From sub module
-    files = dao.selectEnabledDescendantFiles(session, "FGHI");
+    files = sut.selectEnabledDescendantFiles(session, "FGHI");
     assertThat(files).extracting("uuid").containsOnly("HIJK");
     assertThat(files).extracting("moduleUuid").containsOnly("FGHI");
     assertThat(files).extracting("srcHash").containsOnly("srcHIJK");
     assertThat(files).extracting("path").containsOnly("src/org/struts/RequestContext.java");
 
     // From directory
-    assertThat(dao.selectEnabledDescendantFiles(session, "GHIJ")).isEmpty();
+    assertThat(sut.selectEnabledDescendantFiles(session, "GHIJ")).isEmpty();
 
-    assertThat(dao.selectEnabledDescendantFiles(session, "unknown")).isEmpty();
+    assertThat(sut.selectEnabledDescendantFiles(session, "unknown")).isEmpty();
   }
 
   @Test
   public void select_enabled_module_files_tree_from_project() {
-    setupData("select_module_files_tree");
+    db.prepareDbUnit(getClass(), "select_module_files_tree.xml");
 
     // From root project
-    List<FilePathWithHashDto> files = dao.selectEnabledFilesFromProject(session, "ABCD");
+    List<FilePathWithHashDto> files = sut.selectEnabledFilesFromProject(session, "ABCD");
     assertThat(files).extracting("uuid").containsOnly("EFGHI", "HIJK");
     assertThat(files).extracting("moduleUuid").containsOnly("EFGH", "FGHI");
     assertThat(files).extracting("srcHash").containsOnly("srcEFGHI", "srcHIJK");
     assertThat(files).extracting("path").containsOnly("src/org/struts/pom.xml", "src/org/struts/RequestContext.java");
 
     // From module
-    assertThat(dao.selectEnabledFilesFromProject(session, "EFGH")).isEmpty();
+    assertThat(sut.selectEnabledFilesFromProject(session, "EFGH")).isEmpty();
 
     // From sub module
-    assertThat(dao.selectEnabledFilesFromProject(session, "FGHI")).isEmpty();
+    assertThat(sut.selectEnabledFilesFromProject(session, "FGHI")).isEmpty();
 
     // From directory
-    assertThat(dao.selectEnabledFilesFromProject(session, "GHIJ")).isEmpty();
+    assertThat(sut.selectEnabledFilesFromProject(session, "GHIJ")).isEmpty();
 
-    assertThat(dao.selectEnabledFilesFromProject(session, "unknown")).isEmpty();
+    assertThat(sut.selectEnabledFilesFromProject(session, "unknown")).isEmpty();
   }
 
   @Test
   public void insert() {
     when(system2.now()).thenReturn(DateUtils.parseDate("2014-06-18").getTime());
-    setupData("empty");
+    db.prepareDbUnit(getClass(), "empty.xml");
 
     ComponentDto componentDto = new ComponentDto()
       .setId(1L)
@@ -460,17 +468,17 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
       .setEnabled(true)
       .setAuthorizationUpdatedAt(123456789L);
 
-    dao.insert(session, componentDto);
+    sut.insert(session, componentDto);
     session.commit();
 
     assertThat(componentDto.getId()).isNotNull();
-    checkTables("insert", "projects");
+    db.assertDbUnit(getClass(), "insert-result.xml", "projects");
   }
 
   @Test
   public void insert_disabled_component() {
     when(system2.now()).thenReturn(DateUtils.parseDate("2014-06-18").getTime());
-    setupData("empty");
+    db.prepareDbUnit(getClass(), "empty.xml");
 
     ComponentDto componentDto = new ComponentDto()
       .setId(1L)
@@ -489,62 +497,82 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
       .setEnabled(false)
       .setAuthorizationUpdatedAt(123456789L);
 
-    dao.insert(session, componentDto);
+    sut.insert(session, componentDto);
     session.commit();
 
     assertThat(componentDto.getId()).isNotNull();
-    checkTables("insert_disabled_component", "projects");
+    db.assertDbUnit(getClass(), "insert_disabled_component-result.xml", "projects");
   }
 
   @Test(expected = IllegalStateException.class)
   public void update() {
-    dao.update(session, new ComponentDto()
-      .setId(1L)
-      .setKey("org.struts:struts-core:src/org/struts/RequestContext.java")
-      );
+    sut.update(session, new ComponentDto()
+        .setId(1L)
+        .setKey("org.struts:struts-core:src/org/struts/RequestContext.java")
+    );
   }
 
   @Test
   public void delete() {
-    setupData("shared");
+    loadBasicDataInDatabase();
 
-    dao.delete(session, new ComponentDto()
-      .setId(1L)
-      .setKey("org.struts:struts-core:src/org/struts/RequestContext.java")
-      );
+    sut.delete(session, new ComponentDto()
+        .setId(1L)
+        .setKey("org.struts:struts-core:src/org/struts/RequestContext.java")
+    );
     session.commit();
 
-    checkTable("delete", "projects");
+    db.assertDbUnit(getClass(), "delete-result.xml", "projects");
   }
 
   @Test
   public void find_project_uuids() {
-    setupData("find_project_uuids");
+    db.prepareDbUnit(getClass(), "find_project_uuids.xml");
 
-    assertThat(dao.findProjectUuids(session)).containsExactly("ABCD");
+    assertThat(sut.findProjectUuids(session)).containsExactly("ABCD");
   }
 
   @Test(expected = PersistenceException.class)
   public void synchronize_after() {
-    dao.synchronizeAfter(session, new Date(0L));
+    sut.synchronizeAfter(session, new Date(0L));
   }
 
   @Test
   public void select_views_and_sub_views() {
-    setupData("shared_views");
+    db.prepareDbUnit(getClass(), "shared_views.xml");
 
-    assertThat(dao.selectAllViewsAndSubViews(session)).extracting("uuid").containsOnly("ABCD", "EFGH", "FGHI", "IJKL");
-    assertThat(dao.selectAllViewsAndSubViews(session)).extracting("projectUuid").containsOnly("ABCD", "EFGH", "IJKL");
+    assertThat(sut.selectAllViewsAndSubViews(session)).extracting("uuid").containsOnly("ABCD", "EFGH", "FGHI", "IJKL");
+    assertThat(sut.selectAllViewsAndSubViews(session)).extracting("projectUuid").containsOnly("ABCD", "EFGH", "IJKL");
   }
 
   @Test
   public void select_projects_from_view() {
-    setupData("shared_views");
+    db.prepareDbUnit(getClass(), "shared_views.xml");
+
+    assertThat(sut.selectProjectsFromView(session, "ABCD", "ABCD")).containsOnly("JKLM");
+    assertThat(sut.selectProjectsFromView(session, "EFGH", "EFGH")).containsOnly("KLMN", "JKLM");
+    assertThat(sut.selectProjectsFromView(session, "FGHI", "EFGH")).containsOnly("JKLM");
+    assertThat(sut.selectProjectsFromView(session, "IJKL", "IJKL")).isEmpty();
+    assertThat(sut.selectProjectsFromView(session, "Unknown", "Unknown")).isEmpty();
+  }
+
+  @Test
+  public void select_provisioned_projects() {
+    db.prepareDbUnit(getClass(), "select_provisioned_projects.xml");
+
+    List<ComponentDto> result = sut.selectProvisionedProjects(session, new SearchOptions(), null);
+    ComponentDto project = result.get(0);
+
+    assertThat(result).hasSize(1);
+    assertThat(project.getKey()).isEqualTo("org.provisioned.project");
+  }
+
+  @Test
+  public void count_provisioned_projects() {
+    db.prepareDbUnit(getClass(), "select_provisioned_projects.xml");
+
+    int numberOfProjects = sut.countProvisionedProjects(session, null);
 
-    assertThat(dao.selectProjectsFromView(session, "ABCD", "ABCD")).containsOnly("JKLM");
-    assertThat(dao.selectProjectsFromView(session, "EFGH", "EFGH")).containsOnly("KLMN", "JKLM");
-    assertThat(dao.selectProjectsFromView(session, "FGHI", "EFGH")).containsOnly("JKLM");
-    assertThat(dao.selectProjectsFromView(session, "IJKL", "IJKL")).isEmpty();
-    assertThat(dao.selectProjectsFromView(session, "Unknown", "Unknown")).isEmpty();
+    assertThat(numberOfProjects).isEqualTo(1);
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProvisionedProjectsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProvisionedProjectsActionTest.java
new file mode 100644 (file)
index 0000000..2707055
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.component.ws;
+
+import com.google.common.io.Resources;
+import org.apache.commons.lang.StringUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.component.SnapshotTesting;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.component.db.SnapshotDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.ws.WsTester;
+import org.sonar.test.JsonAssert;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProvisionedProjectsActionTest {
+
+  @ClassRule
+  public static DbTester db = new DbTester();
+
+  WsTester ws;
+  DbClient dbClient;
+  DbSession dbSession;
+  ComponentDao componentDao;
+
+  @After
+  public void tearDown() throws Exception {
+    dbSession.close();
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    dbClient = new DbClient(db.database(), db.myBatis(), new ComponentDao(), new SnapshotDao(System2.INSTANCE));
+    dbSession = dbClient.openSession(false);
+    componentDao = dbClient.componentDao();
+    db.truncateTables();
+    ws = new WsTester(new ProjectsWs(new ProvisionedProjectsAction(dbClient)));
+  }
+
+  @Test
+  public void all_provisioned_projects_without_analyzed_projects() throws Exception {
+    MockUserSession.set().setGlobalPermissions(UserRole.ADMIN);
+    ComponentDto analyzedProject = ComponentTesting.newProjectDto("analyzed-uuid-1");
+    componentDao.insert(dbSession, newProvisionedProject("1"), newProvisionedProject("2"));
+    analyzedProject = componentDao.insert(dbSession, analyzedProject);
+    SnapshotDto snapshot = SnapshotTesting.createForProject(analyzedProject);
+    dbClient.snapshotDao().insert(dbSession, snapshot);
+    dbSession.commit();
+
+    WsTester.TestRequest request = ws.newGetRequest("api/projects", "provisioned");
+
+    request.execute().assertJson(getClass(), "all-projects.json");
+  }
+
+  @Test
+  public void provisioned_projects_with_correct_paginated() throws Exception {
+    MockUserSession.set().setGlobalPermissions(UserRole.ADMIN);
+    for (int i = 1; i <= 10; i++) {
+      componentDao.insert(dbSession, newProvisionedProject(String.valueOf(i)));
+    }
+    dbSession.commit();
+
+    WsTester.TestRequest request = ws.newGetRequest("api/projects", "provisioned")
+      .setParam(Param.PAGE, "3")
+      .setParam(Param.PAGE_SIZE, "4");
+
+    String jsonOutput = request.execute().outputAsString();
+
+    assertThat(StringUtils.countMatches(jsonOutput, "provisioned-uuid-")).isEqualTo(2);
+  }
+
+  @Test
+  public void provisioned_projects_with_desired_fields() throws Exception {
+    MockUserSession.set().setGlobalPermissions(UserRole.ADMIN);
+    componentDao.insert(dbSession, newProvisionedProject("1"));
+    dbSession.commit();
+
+    String jsonOutput = ws.newGetRequest("api/projects", "provisioned")
+      .setParam(Param.FIELDS, "key")
+      .execute().outputAsString();
+
+    assertThat(jsonOutput).contains("uuid", "key")
+      .doesNotContain("name")
+      .doesNotContain("creationDate");
+  }
+
+  @Test
+  public void provisioned_projects_with_query() throws Exception {
+    MockUserSession.set().setGlobalPermissions(UserRole.ADMIN);
+    componentDao.insert(dbSession, newProvisionedProject("1"), newProvisionedProject("2"));
+    dbSession.commit();
+
+    String jsonOutput = ws.newGetRequest("api/projects", "provisioned")
+      .setParam(Param.TEXT_QUERY, "provisioned-name-2")
+      .execute().outputAsString();
+
+    assertThat(jsonOutput)
+      .contains("provisioned-name-2", "provisioned-uuid-2")
+      .doesNotContain("provisioned-uuid-1");
+    assertThat(componentDao.countProvisionedProjects(dbSession, "name-2")).isEqualTo(1);
+    assertThat(componentDao.countProvisionedProjects(dbSession, "key-2")).isEqualTo(1);
+    assertThat(componentDao.countProvisionedProjects(dbSession, "visioned-name-")).isEqualTo(2);
+  }
+
+  private static ComponentDto newProvisionedProject(String id) {
+    return ComponentTesting
+      .newProjectDto("provisioned-uuid-" + id)
+      .setName("provisioned-name-" + id)
+      .setKey("provisioned-key-" + id);
+  }
+
+  @Test
+  public void provisioned_projects_as_defined_in_the_example() throws Exception {
+    MockUserSession.set().setGlobalPermissions(UserRole.ADMIN);
+    ComponentDto hBaseProject = ComponentTesting.newProjectDto("ce4c03d6-430f-40a9-b777-ad877c00aa4d")
+      .setKey("org.apache.hbas:hbase")
+      .setName("HBase")
+      .setCreatedAt(DateUtils.parseDateTime("2015-03-04T23:03:44+0100"));
+    ComponentDto roslynProject = ComponentTesting.newProjectDto("c526ef20-131b-4486-9357-063fa64b5079")
+      .setKey("com.microsoft.roslyn:roslyn")
+      .setName("Roslyn")
+      .setCreatedAt(DateUtils.parseDateTime("2013-03-04T23:03:44+0100"));
+    componentDao.insert(dbSession, hBaseProject, roslynProject);
+    dbSession.commit();
+
+    WsTester.Result result = ws.newGetRequest("api/projects", "provisioned").execute();
+
+    JsonAssert.assertJson(result.outputAsString()).isSimilarTo(Resources.getResource(getClass(), "projects-example-provisioned.json"));
+  }
+}
index adc3e316086887994f134c342bc0bc825bb5782b..224a8316a39d170ae241a8b50bb65e51afbc1382 100644 (file)
@@ -36,6 +36,5 @@ public abstract class BaseStepTest {
     assertThat(step().toString()).isNotEmpty();
     assertThat(step().getDescription()).isNotEmpty();
     assertThat(step().supportedProjectQualifiers().length).isGreaterThan(0);
-
   }
 }
index 2547c1eb70781320a5154d4f92cddc607314331a..45814a6cbe7bdf7237338aa1658d9498ec01deb5 100644 (file)
@@ -86,7 +86,7 @@
             uuid="OPQR" project_uuid="OPQR" module_uuid="[null]" module_uuid_path=".OPQR."
             description="the description" long_name="Anakin Skywalker"
             enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
-  <projects id="12" project_id="11" root_id="11" scope="PRJ" qualifier="DEV_PRJ" kee="DEV:anakin@skywalker.name:org.struts:struts" name="Apache Struts"
+  <projects id="12"  root_id="11" scope="PRJ" qualifier="DEV_PRJ" kee="DEV:anakin@skywalker.name:org.struts:struts" name="Apache Struts"
             uuid="STUV" project_uuid="OPQR" module_uuid="OPQR" module_uuid_path=".OPQR."
             description="the description" long_name="Apache Struts"
             enabled="[true]" language="[null]" copy_resource_id="1" person_id="11" path="[null]" authorization_updated_at="123456789" />
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/select_provisioned_projects.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/select_provisioned_projects.xml
new file mode 100644 (file)
index 0000000..7d13578
--- /dev/null
@@ -0,0 +1,100 @@
+<dataset>
+
+  <!-- Struts projects is authorized for all user -->
+  <group_roles id="1" group_id="[null]" resource_id="1" role="user"/>
+
+  <!-- Provisioned project -->
+  <projects id="42" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.provisioned.project" name="Provisioned Project"
+            uuid="PPAA" project_uuid="PPAA" module_uuid="[null]" module_uuid_path="."
+            description="the description" long_name="Provisioned Project"
+            enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
+
+  <!-- root project -->
+  <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" deprecated_kee="org.struts:struts" name="Struts"
+            uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
+  <snapshots id="1" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+             status="P" islast="[true]" purge_status="[null]"
+             period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+             period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+             period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             depth="[null]" scope="PRJ" qualifier="TRK" created_at="1228222680000" build_date="1228222680000"
+             version="[null]" path=""/>
+  <snapshots id="10" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+             status="P" islast="[false]" purge_status="[null]"
+             period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+             period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+             period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             depth="[null]" scope="PRJ" qualifier="TRK" created_at="1228136280000" build_date="1228136280000"
+             version="[null]" path=""/>
+
+  <!-- module -->
+  <projects id="2" root_id="1" kee="org.struts:struts-core" name="Struts Core"
+            uuid="EFGH" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD.EFGH."
+            scope="PRJ" qualifier="BRC" long_name="Struts Core"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]" />
+  <snapshots id="2" project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
+             status="P" islast="[true]" purge_status="[null]"
+             period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+             period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+             period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             depth="[null]" scope="PRJ" qualifier="BRC" created_at="1228222680000" build_date="1228222680000"
+             version="[null]" path="1."/>
+
+  <!-- directory -->
+  <projects long_name="org.struts" id="3" scope="DIR" qualifier="DIR" kee="org.struts:struts-core:src/org/struts"
+            uuid="GHIJ" project_uuid="ABCD" module_uuid="EFGH" module_uuid_path=".ABCD.EFGH."
+            name="src/org/struts" root_id="2"
+            description="[null]"
+            enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="src/org/struts" authorization_updated_at="[null]" />
+  <snapshots id="3" project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
+             status="P" islast="[true]" purge_status="[null]"
+             period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+             period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+             period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             depth="[null]" scope="DIR" qualifier="PAC" created_at="1228222680000" build_date="1228222680000"
+             version="[null]" path="1.2."/>
+
+  <!-- file -->
+  <projects long_name="org.struts.RequestContext" id="4" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:src/org/struts/RequestContext.java"
+            uuid="KLMN" project_uuid="ABCD" module_uuid="EFGH" module_uuid_path=".ABCD.EFGH."
+            name="RequestContext.java" root_id="2"
+            description="[null]"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java" authorization_updated_at="[null]" />
+
+  <snapshots id="4" project_id="4" parent_snapshot_id="3" root_project_id="1" root_snapshot_id="1"
+             status="P" islast="[true]" purge_status="[null]"
+             period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+             period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+             period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+             period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             depth="[null]" scope="FIL" qualifier="CLA" created_at="1228222680000" build_date="1228222680000"
+             version="[null]" path="1.2.3."/>
+
+  <!-- Disabled projects -->
+  <projects id="10" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.disabled.project" name="Disabled Project"
+            uuid="DCBA" project_uuid="DCBA" module_uuid="[null]" module_uuid_path="."
+            description="the description" long_name="Disabled project"
+            enabled="[false]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
+
+  <!-- Developer and technical project copy -->
+  <projects id="11" root_id="[null]" scope="PRJ" qualifier="DEV" kee="DEV:anakin@skywalker.name" name="Anakin Skywalker"
+            uuid="OPQR" project_uuid="OPQR" module_uuid="[null]" module_uuid_path=".OPQR."
+            description="the description" long_name="Anakin Skywalker"
+            enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
+  <projects id="12" root_id="11" scope="PRJ" qualifier="DEV_PRJ" kee="DEV:anakin@skywalker.name:org.struts:struts" name="Apache Struts"
+            uuid="STUV" project_uuid="OPQR" module_uuid="OPQR" module_uuid_path=".OPQR."
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="[null]" copy_resource_id="1" person_id="11" path="[null]" authorization_updated_at="123456789" />
+
+</dataset>
index 70b0af093df84620a4b9e075d19cf353c12deda8..91b28bfa466651d54de1b76c708d7dce8ff6b821 100644 (file)
@@ -87,7 +87,7 @@
             uuid="OPQR" project_uuid="OPQR" module_uuid="[null]" module_uuid_path=".OPQR."
             description="the description" long_name="Anakin Skywalker"
             enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
-  <projects id="12" project_id="11" root_id="11" scope="PRJ" qualifier="DEV_PRJ" kee="DEV:anakin@skywalker.name:org.struts:struts" name="Apache Struts"
+  <projects id="12"  root_id="11" scope="PRJ" qualifier="DEV_PRJ" kee="DEV:anakin@skywalker.name:org.struts:struts" name="Apache Struts"
             uuid="STUV" project_uuid="OPQR" module_uuid="OPQR" module_uuid_path=".OPQR."
             description="the description" long_name="Apache Struts"
             enabled="[true]" language="[null]" copy_resource_id="1" person_id="11" path="[null]" authorization_updated_at="123456789" />
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/ws/ProvisionedProjectsActionTest/all-projects.json b/server/sonar-server/src/test/resources/org/sonar/server/component/ws/ProvisionedProjectsActionTest/all-projects.json
new file mode 100644 (file)
index 0000000..3fc3e56
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "projects":[
+    {
+      "uuid":"provisioned-uuid-1",
+      "key":"provisioned-key-1",
+      "name":"provisioned-name-1"
+    },
+    {
+      "uuid":"provisioned-uuid-2",
+      "key":"provisioned-key-2",
+      "name":"provisioned-name-2"
+    }
+  ]
+}
index cfbfb4291b372759cadba7b8850e190d0d5f60be..6ed690b97d6e475acfc718f27cac2b3a3c3da3e8 100644 (file)
@@ -21,6 +21,7 @@
 package org.sonar.core.component.db;
 
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.session.RowBounds;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.component.FilePathWithHashDto;
 import org.sonar.core.component.UuidWithProjectUuidDto;
@@ -29,6 +30,7 @@ import javax.annotation.CheckForNull;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @since 4.3
@@ -101,4 +103,8 @@ public interface ComponentMapper {
   void insert(ComponentDto rule);
 
   void deleteByKey(String key);
+
+  List<ComponentDto> selectProvisionedProjects(Map<String, String> parameters, RowBounds rowBounds);
+
+  int countProvisionedProjects(Map<String, String> parameters);
 }
index 7c5430038ece96f1cc6adc6e89943d6836c6f161..84c011c08f2ba9f9ad7d1f0994f14cac8880db68 100644 (file)
     delete from projects where kee=#{key}
   </delete>
 
-</mapper>
+  <select id="selectProvisionedProjects" parameterType="map" resultType="Component">
+    select <include refid="componentColumns"/>
+    from projects p
+    <include refid="provisionClauses"/>
+  </select>
 
+  <select id="countProvisionedProjects" parameterType="map" resultType="int">
+    select count(p.id)
+    from projects p
+    <include refid="provisionClauses"/>
+  </select>
+
+  <sql id="provisionClauses">
+    left join snapshots s on s.project_id=p.id
+    where
+    s.id is null
+    and p.enabled=${_true}
+    and p.qualifier=#{qualifier}
+    and p.copy_resource_id is null
+    <if test="query!=null">
+      and (
+      p.name like #{query}
+      or p.kee like #{query}
+      )
+    </if>
+  </sql>
+</mapper>