Merge changes I30886e35,I4bdc9a71

* changes:
  Document all options of list projects endpoint
  Add acceptance tests for list projects endpoint
This commit is contained in:
David Pursehouse 2014-07-10 05:12:25 +00:00 committed by Gerrit Code Review
commit 4560488f1c
3 changed files with 418 additions and 21 deletions

View File

@ -52,22 +52,110 @@ by project name.
}
----
.Get all projects with their description
****
get::/projects/?d
****
[[project-options]]
==== Project Options
Branch(b)::
Limit the results to the projects having the specified branch and
include the sha1 of the branch in the results.
+
Get projects that have a 'master' branch:
+
.Request
----
GET /projects/?b=master HTTP/1.0
----
+
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json;charset=UTF-8
)]}'
{
"some-project": {
"id": "some-project",
"branches": {
"master": "c5ed9dfcbf002ca0e432d788dab6ca2387829ca7"
}
},
"some-other-project": {
"id": "some-other-project",
"branches": {
"master": "ef1c270142f9581ecf768f4193fc8f8a81102ec2"
}
},
}
----
Description(d)::
Include project description in the results.
+
Get all the projects with their description:
+
.Request
----
GET /projects/?d HTTP/1.0
----
+
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json;charset=UTF-8
)]}'
{
"some-project": {
"id": "some-project",
"description": "Description of some project."
},
"some-other-project": {
"id": "some-other-project",
"description": "Description of some other project."
}
},
}
----
Limit(n)::
Limit the number of projects to be included in the results.
+
Query the first project in the project list:
+
.Request
----
GET /projects/?n=1 HTTP/1.0
----
+
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json;charset=UTF-8
)]}'
{
"some-project": {
"id": "some-project"
}
}
----
[[suggest-projects]]
The `/projects/` URL also accepts a prefix string in the `p` parameter.
This limits the results to those projects that start with the specified
Prefix(p)::
Limit the results to those projects that start with the specified
prefix.
+
List all projects that start with `platform/`:
+
.Request
----
GET /projects/?p=platform%2F HTTP/1.0
----
+
.Response
----
HTTP/1.1 200 OK
@ -84,22 +172,118 @@ List all projects that start with `platform/`:
}
}
----
+
E.g. this feature can be used by suggestion client UI's to limit results.
The `/projects/` URL also accepts a limit integer in the `n` parameter.
This limits the results to show `n` projects.
Query the first 25 projects in project list.
Skip(S)::
Skip the given number of projects from the beginning of the list.
+
Query the second project in the project list:
+
.Request
----
GET /projects/?n=25 HTTP/1.0
GET /projects/?n=1&S=1 HTTP/1.0
----
+
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json;charset=UTF-8
)]}'
{
"some-other-project": {
"id": "some-other-project"
}
}
----
The `/projects/` URL also accepts a start integer in the `S` parameter.
The results will skip `S` projects from project list.
Query 25 projects starting from index 50.
Substring(m)::
Limit the results to those projects that match the specified substring.
+
List all projects that match substring `test/`:
+
.Request
----
GET /projects/?n=25&S=50 HTTP/1.0
GET /projects/?m=test%2F HTTP/1.0
----
+
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json;charset=UTF-8
)]}'
{
"test/some-project": {
"id": "test%2Fsome-project",
},
"some-path/test/some-other-project": {
"id": "some-path%2Ftest%2Fsome-other-project",
}
}
----
Tree(t)::
Get projects inheritance in a tree-like format. This option does
not work together with the branch option.
+
Get all the projects with tree option:
+
.Request
----
GET /projects/?t HTTP/1.0
----
+
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json;charset=UTF-8
)]}'
{
"All-Projects" {
"id": "All-Projects"
},
"child-project": {
"id": "child-project",
"parent":"parent-project"
},
"parent-project": {
"id": "parent-project",
"parent":"All-Projects"
}
}
----
Type(type)::
Get projects with specified type: ALL, CODE, PERMISSIONS.
+
Get all the projects of type 'PERMISSIONS':
+
.Request
----
GET /projects/?type=PERMISSIONS HTTP/1.0
----
+
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json;charset=UTF-8
)]}'
{
"All-Projects" {
"id": "All-Projects"
},
"some-parent-project": {
"id": "some-parent-project"
}
}
----
[[get-project]]

View File

@ -0,0 +1,211 @@
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.acceptance.rest.project;
import static com.google.gerrit.acceptance.GitUtil.createProject;
import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertProjects;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
import com.jcraft.jsch.JSchException;
import org.apache.http.HttpStatus;
import org.junit.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
public class ListProjectsIT extends AbstractDaemonTest {
@Inject
private AllProjectsName allProjects;
@Inject
private AllUsersName allUsers;
@Test
public void listProjects() throws IOException, JSchException {
Project.NameKey someProject = new Project.NameKey("some-project");
createProject(sshSession, someProject.get());
RestResponse r = GET("/projects/");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
Map<String, ProjectInfo> result = toProjectInfoMap(r);
assertProjects(Arrays.asList(allUsers, someProject, project),
result.values());
}
@Test
public void listProjectsWithBranch() throws IOException, JSchException {
RestResponse r = GET("/projects/?b=master");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
Map<String, ProjectInfo> result = toProjectInfoMap(r);
assertNotNull(result.get(project.get()));
assertNotNull(result.get(project.get()).branches);
assertEquals(1, result.get(project.get()).branches.size());
assertNotNull(result.get(project.get()).branches.get("master"));
}
@Test
public void listProjectWithDescription() throws RestApiException, IOException {
ProjectInput projectInput = new ProjectInput();
projectInput.name = "some-project";
projectInput.description = "Description of some-project";
gApi.projects().name(projectInput.name).create(projectInput);
// description not be included in the results by default.
RestResponse r = GET("/projects/");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
Map<String, ProjectInfo> result = toProjectInfoMap(r);
assertNotNull(result.get(projectInput.name));
assertNull(result.get(projectInput.name).description);
r = GET("/projects/?d");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
result = toProjectInfoMap(r);
assertNotNull(result.get(projectInput.name));
assertEquals(projectInput.description,
result.get(projectInput.name).description);
}
@Test
public void listProjectsWithLimit() throws IOException, JSchException {
for (int i = 0; i < 5; i++) {
createProject(sshSession, new Project.NameKey("someProject" + i).get());
}
RestResponse r = GET("/projects/");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
Map<String, ProjectInfo> result = toProjectInfoMap(r);
assertEquals(7, result.size()); // 5 plus 2 existing projects: p and
// All-Users
r = GET("/projects/?n=2");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
result = toProjectInfoMap(r);
assertEquals(2, result.size());
}
@Test
public void listProjectsWithPrefix() throws IOException, JSchException {
Project.NameKey someProject = new Project.NameKey("some-project");
createProject(sshSession, someProject.get());
Project.NameKey someOtherProject =
new Project.NameKey("some-other-project");
createProject(sshSession, someOtherProject.get());
Project.NameKey projectAwesome = new Project.NameKey("project-awesome");
createProject(sshSession, projectAwesome.get());
RestResponse r = GET("/projects/?p=some");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
Map<String, ProjectInfo> result = toProjectInfoMap(r);
assertProjects(Arrays.asList(someProject, someOtherProject),
result.values());
}
@Test
public void listProjectsWithSkip() throws IOException, JSchException {
for (int i = 0; i < 5; i++) {
createProject(sshSession, new Project.NameKey("someProject" + i).get());
}
RestResponse r = GET("/projects/");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
Map<String, ProjectInfo> result = toProjectInfoMap(r);
assertEquals(7, result.size()); // 5 plus 2 existing projects: p and
// All-Users
r = GET("/projects/?S=6");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
result = toProjectInfoMap(r);
assertEquals(1, result.size());
}
@Test
public void listProjectsWithSubstring() throws IOException, JSchException {
Project.NameKey someProject = new Project.NameKey("some-project");
createProject(sshSession, someProject.get());
Project.NameKey someOtherProject =
new Project.NameKey("some-other-project");
createProject(sshSession, someOtherProject.get());
Project.NameKey projectAwesome = new Project.NameKey("project-awesome");
createProject(sshSession, projectAwesome.get());
RestResponse r = GET("/projects/?m=some");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
Map<String, ProjectInfo> result = toProjectInfoMap(r);
assertProjects(
Arrays.asList(someProject, someOtherProject, projectAwesome),
result.values());
}
@Test
public void listProjectsWithTree() throws IOException, JSchException {
Project.NameKey someParentProject =
new Project.NameKey("some-parent-project");
createProject(sshSession, someParentProject.get());
Project.NameKey someChildProject =
new Project.NameKey("some-child-project");
createProject(sshSession, someChildProject.get(), someParentProject);
RestResponse r = GET("/projects/?tree");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
Map<String, ProjectInfo> result = toProjectInfoMap(r);
assertNotNull(result.get(someChildProject.get()));
assertEquals(someParentProject.get(),
result.get(someChildProject.get()).parent);
}
@Test
public void listProjectWithType() throws RestApiException, IOException {
RestResponse r = GET("/projects/?type=PERMISSIONS");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
Map<String, ProjectInfo> result = toProjectInfoMap(r);
assertEquals(1, result.size());
assertNotNull(result.get(allProjects.get()));
r = GET("/projects/?type=ALL");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
result = toProjectInfoMap(r);
assertEquals(3, result.size());
assertProjects(Arrays.asList(allProjects, allUsers, project),
result.values());
}
private static Map<String, ProjectInfo> toProjectInfoMap(RestResponse r)
throws IOException {
Map<String, ProjectInfo> result =
newGson().fromJson(r.getReader(),
new TypeToken<Map<String, ProjectInfo>>() {}.getType());
return result;
}
private RestResponse GET(String endpoint) throws IOException {
return adminSession.get(endpoint);
}
}

View File

@ -27,18 +27,20 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.project.ProjectState;
import java.util.List;
import java.util.Collection;
import java.util.Set;
public class ProjectAssert {
public static void assertProjects(Iterable<Project.NameKey> expected,
List<ProjectInfo> actual) {
Collection<ProjectInfo> actual) {
for (final Project.NameKey p : expected) {
ProjectInfo info = Iterables.find(actual, new Predicate<ProjectInfo>() {
@Override
public boolean apply(ProjectInfo info) {
return new Project.NameKey(info.name).equals(p);
// 'name' is not set if returned in a map, use the id instead.
return new Project.NameKey(info.name != null ? info.name : Url
.decode(info.id)).equals(p);
}}, null);
assertNotNull("missing project: " + p, info);
actual.remove(info);