@@ -700,6 +700,7 @@ subprojects { | |||
bbtImplementation 'org.sonarsource.orchestrator:sonar-orchestrator-junit4' | |||
bbtImplementation project(":sonar-testing-harness") | |||
bbtImplementation project(":private:it-common") | |||
bbtImplementation testFixtures(project(":sonar-ws")) | |||
} | |||
} | |||
@@ -118,7 +118,8 @@ public class EsJvmOptions extends JvmOptions<EsJvmOptions> { | |||
res.put("-Dlog4j2.disable.jmx=", "true"); | |||
res.put("-Dlog4j2.formatMsgNoLookups=", "true"); | |||
/* | |||
* Due to internationalization enhancements in JDK 9 Elasticsearch need to set the provider to COMPAT otherwise time/date | |||
* Due to internationalization enhancements in JDK 9 org.sonarqube.ws.tester.Elasticsearch need to set the provider to COMPAT otherwise | |||
* time/date | |||
* parsing will break in an incompatible way for some date patterns and locales. | |||
*/ | |||
res.put("-Djava.locale.providers=", "COMPAT"); |
@@ -20,15 +20,21 @@ dependencies { | |||
compileOnlyApi 'com.google.code.findbugs:jsr305' | |||
compileOnlyApi 'javax.annotation:javax.annotation-api' | |||
testImplementation 'com.squareup.okhttp3:mockwebserver' | |||
testImplementation 'com.squareup.okio:okio' | |||
testImplementation 'commons-io:commons-io' | |||
testImplementation 'commons-lang:commons-lang' | |||
testImplementation 'junit:junit' | |||
testImplementation 'org.assertj:assertj-core' | |||
testImplementation 'org.hamcrest:hamcrest-core' | |||
testImplementation 'org.mockito:mockito-core' | |||
testImplementation project(':sonar-testing-harness') | |||
testImplementation 'com.squareup.okhttp3:mockwebserver' | |||
testImplementation 'com.squareup.okio:okio' | |||
testImplementation 'commons-io:commons-io' | |||
testImplementation 'commons-lang:commons-lang' | |||
testImplementation 'junit:junit' | |||
testImplementation 'org.assertj:assertj-core' | |||
testImplementation 'org.hamcrest:hamcrest-core' | |||
testImplementation 'org.mockito:mockito-core' | |||
testImplementation project(':sonar-testing-harness') | |||
testFixturesApi 'junit:junit' | |||
testFixturesApi 'com.google.guava:guava' | |||
testFixturesApi 'org.assertj:assertj-core' | |||
testFixturesApi 'org.sonarsource.orchestrator:sonar-orchestrator-junit4' | |||
testFixturesApi 'commons-io:commons-io' | |||
} | |||
artifactoryPublish.skip = false |
@@ -0,0 +1,68 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* All rights reserved | |||
* mailto:info AT sonarsource DOT com | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import org.junit.rules.ExternalResource; | |||
import org.sonarqube.ws.AlmSettings; | |||
import org.sonarqube.ws.client.HttpException; | |||
import org.sonarqube.ws.client.almsettings.AlmSettingsService; | |||
import org.sonarqube.ws.client.almsettings.CreateGithubRequest; | |||
import org.sonarqube.ws.client.almsettings.DeleteRequest; | |||
public class AlmSettingsTester extends ExternalResource { | |||
private final TesterSession session; | |||
AlmSettingsTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
public void addGitHubAlmSettings(String key) { | |||
session.wsClient().almSettings().createGithub(new CreateGithubRequest() | |||
.setClientId("id1") | |||
.setAppId("app1") | |||
.setClientSecret("shhh") | |||
.setKey(key).setPrivateKey("PRIV") | |||
.setUrl("http://example.org")); | |||
} | |||
void deleteAll() { | |||
AlmSettingsService almSettingsService = session.wsClient().almSettings(); | |||
try { | |||
AlmSettings.ListDefinitionsWsResponse response = almSettingsService.listDefinitions(); | |||
response.getGithubList().forEach(e -> almSettingsService.delete(new DeleteRequest(e.getKey()))); | |||
response.getAzureList().forEach(e -> almSettingsService.delete(new DeleteRequest(e.getKey()))); | |||
response.getBitbucketList().forEach(e -> almSettingsService.delete(new DeleteRequest(e.getKey()))); | |||
response.getBitbucketcloudList().forEach(e -> almSettingsService.delete(new DeleteRequest(e.getKey()))); | |||
response.getGitlabList().forEach(e -> almSettingsService.delete(new DeleteRequest(e.getKey()))); | |||
} catch (HttpException e) { | |||
// If server is not at least a developer edition, the ws is not available, nothing to do | |||
if (e.code() == 404) { | |||
return; | |||
} | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,353 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import com.google.common.util.concurrent.Uninterruptibles; | |||
import com.google.gson.Gson; | |||
import java.util.List; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import java.util.function.Consumer; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.junit.rules.ExternalResource; | |||
import org.sonarqube.ws.Ce; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.applications.ApplicationsService; | |||
import org.sonarqube.ws.client.applications.CreateRequest; | |||
import org.sonarqube.ws.client.applications.DeleteRequest; | |||
import org.sonarqube.ws.client.applications.SearchProjectsRequest; | |||
import org.sonarqube.ws.client.applications.ShowRequest; | |||
import org.sonarqube.ws.client.applications.UpdateRequest; | |||
import org.sonarqube.ws.client.ce.ActivityStatusRequest; | |||
import org.sonarqube.ws.client.projects.ProjectsService; | |||
import org.sonarqube.ws.client.projects.SearchRequest; | |||
import static java.util.Arrays.stream; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class ApplicationTester extends ExternalResource { | |||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); | |||
private final TesterSession session; | |||
ApplicationTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
public ApplicationsService service() { | |||
return session.wsClient().applications(); | |||
} | |||
public void deleteAll() { | |||
ProjectsService service = session.wsClient().projects(); | |||
service.search(new SearchRequest().setQualifiers(singletonList("APP"))).getComponentsList() | |||
.forEach(p -> { | |||
waitForCeQueueEmpty(); | |||
session.wsClient().applications().delete(new DeleteRequest().setApplication(p.getKey())); | |||
}); | |||
waitForCeQueueEmpty(); | |||
org.sonarqube.ws.client.components.SearchRequest searchRequest = new org.sonarqube.ws.client.components.SearchRequest().setQualifiers(singletonList("APP")); | |||
assertThat(session.wsClient().components().search(searchRequest).getComponentsList()).isEmpty(); | |||
} | |||
public void updateName(String applicationKey, String name) { | |||
service().update(new UpdateRequest().setApplication(applicationKey).setName(name)); | |||
} | |||
public ApplicationTester waitForCeQueueEmpty() { | |||
Ce.ActivityStatusWsResponse status; | |||
boolean empty; | |||
do { | |||
status = session.wsClient().ce().activityStatus(new ActivityStatusRequest()); | |||
empty = status.getInProgress() + status.getPending() == 0; | |||
if (!empty) { | |||
Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); | |||
} | |||
} while (!empty); | |||
return this; | |||
} | |||
@SafeVarargs | |||
public final Application generate(Consumer<CreateRequest>... populators) { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
CreateRequest request = new CreateRequest() | |||
.setKey("applicationKey" + id) | |||
.setName("applicationName" + id) | |||
.setDescription("applicationDescription" + id); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
return CreateResponse.parse(session.wsClient().applications().create(request)).getApplication(); | |||
} | |||
public ShowResponse show(ShowRequest showRequest) { | |||
return ShowResponse.parse(session.wsClient().applications().show(showRequest)); | |||
} | |||
public void refresh() { | |||
session.wsClient().wsConnector().call(new PostRequest("/api/applications/refresh")).failIfNotSuccessful(); | |||
waitForCeQueueEmpty(); | |||
} | |||
public SearchProjectsResponse searchProjects(SearchProjectsRequest searchProjectsRequest) { | |||
return SearchProjectsResponse.parse(session.wsClient().applications().searchProjects(searchProjectsRequest)); | |||
} | |||
public static class CreateResponse { | |||
private final Application application; | |||
public CreateResponse(Application application) { | |||
this.application = application; | |||
} | |||
public Application getApplication() { | |||
return application; | |||
} | |||
public static CreateResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, CreateResponse.class); | |||
} | |||
} | |||
public static class ShowResponse { | |||
private final Application application; | |||
public ShowResponse(Application application) { | |||
this.application = application; | |||
} | |||
public Application getApplication() { | |||
return application; | |||
} | |||
public static ShowResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, ShowResponse.class); | |||
} | |||
} | |||
public static class SearchProjectsResponse { | |||
private final Paging paging; | |||
private final List<Project> projects; | |||
public SearchProjectsResponse(Paging paging, List<Project> projects) { | |||
this.paging = paging; | |||
this.projects = projects; | |||
} | |||
public Paging getPaging() { | |||
return paging; | |||
} | |||
public List<Project> getProjects() { | |||
return projects; | |||
} | |||
public static SearchProjectsResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, SearchProjectsResponse.class); | |||
} | |||
public static class Project { | |||
private final String key; | |||
private final String name; | |||
private final boolean enabled; | |||
private final boolean selected; | |||
public Project(String key, String name, boolean enabled, boolean selected) { | |||
this.key = key; | |||
this.name = name; | |||
this.enabled = enabled; | |||
this.selected = selected; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public boolean isEnabled() { | |||
return enabled; | |||
} | |||
public boolean isSelected() { | |||
return selected; | |||
} | |||
} | |||
} | |||
public static class Paging { | |||
public final int pageIndex; | |||
public final int pageSize; | |||
public final int total; | |||
public Paging(int pageIndex, int pageSize, int total) { | |||
this.pageIndex = pageIndex; | |||
this.pageSize = pageSize; | |||
this.total = total; | |||
} | |||
public int getPageIndex() { | |||
return pageIndex; | |||
} | |||
public int getPageSize() { | |||
return pageSize; | |||
} | |||
public int getTotal() { | |||
return total; | |||
} | |||
} | |||
public static class Application { | |||
private final String key; | |||
private final String branch; | |||
private final boolean isMain; | |||
private final String name; | |||
private final String description; | |||
private final String visibility; | |||
private final List<Project> projects; | |||
private final List<Application.Branch> branches; | |||
private final List<String> tags; | |||
public Application(String key, String branch, boolean isMain, String name, String description, String visibility, List<Project> projects, List<Branch> branches, | |||
List<String> tags) { | |||
this.key = key; | |||
this.branch = branch; | |||
this.isMain = isMain; | |||
this.name = name; | |||
this.description = description; | |||
this.visibility = visibility; | |||
this.projects = projects; | |||
this.branches = branches; | |||
this.tags = tags; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getBranch() { | |||
return branch; | |||
} | |||
public boolean isMain() { | |||
return isMain; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public String getDescription() { | |||
return description; | |||
} | |||
public String getVisibility() { | |||
return visibility; | |||
} | |||
public List<Application.Project> getProjects() { | |||
return projects; | |||
} | |||
public List<String> getTags() { | |||
return tags; | |||
} | |||
@CheckForNull | |||
public List<Application.Branch> getBranches() { | |||
return branches; | |||
} | |||
public static class Project { | |||
private final String key; | |||
private final String branch; | |||
private final Boolean isMain; | |||
private final String name; | |||
private final boolean enabled; | |||
private final Boolean selected; | |||
public Project(String key, String branch, @Nullable Boolean isMain, String name, boolean enabled, @Nullable Boolean selected) { | |||
this.key = key; | |||
this.branch = branch; | |||
this.isMain = isMain; | |||
this.name = name; | |||
this.enabled = enabled; | |||
this.selected = selected; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
@CheckForNull | |||
public String getBranch() { | |||
return branch; | |||
} | |||
@CheckForNull | |||
public Boolean isMain() { | |||
return isMain; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public boolean isEnabled() { | |||
return enabled; | |||
} | |||
@CheckForNull | |||
public Boolean isSelected() { | |||
return selected; | |||
} | |||
} | |||
public static class Branch { | |||
private final String name; | |||
private final boolean isMain; | |||
public Branch(String name, boolean isMain) { | |||
this.name = name; | |||
this.isMain = isMain; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public boolean isMain() { | |||
return isMain; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,84 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import java.io.IOException; | |||
import java.net.InetAddress; | |||
import okhttp3.MediaType; | |||
import okhttp3.OkHttpClient; | |||
import okhttp3.Request; | |||
import okhttp3.RequestBody; | |||
import okhttp3.Response; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
/** | |||
* Helper to directly access Elasticsearch. It requires the HTTP port | |||
* to be open. | |||
*/ | |||
public class Elasticsearch { | |||
private final int httpPort; | |||
public Elasticsearch(int httpPort) { | |||
this.httpPort = httpPort; | |||
} | |||
/** | |||
* Forbid indexing requests on the specified index. Index becomes read-only. | |||
*/ | |||
public void lockWrites(String index) throws IOException { | |||
putIndexSetting(httpPort, index, "blocks.write", "true"); | |||
} | |||
/** | |||
* Enable indexing requests on the specified index. | |||
* @see #lockWrites(String) | |||
*/ | |||
public void unlockWrites(String index) throws IOException { | |||
putIndexSetting(httpPort, index, "blocks.write", "false"); | |||
} | |||
public void makeYellow() throws IOException { | |||
putIndexSetting(httpPort, "issues", "number_of_replicas", "5"); | |||
} | |||
public void makeGreen() throws IOException { | |||
putIndexSetting(httpPort, "issues", "number_of_replicas", "0"); | |||
} | |||
private static void putIndexSetting(int searchHttpPort, String index, String key, String value) throws IOException { | |||
Request.Builder request = new Request.Builder() | |||
.url(baseUrl(searchHttpPort) + index + "/_settings") | |||
.put(RequestBody.create(MediaType.parse("application/json"), "{" + | |||
" \"index\" : {" + | |||
" \"" + key + "\" : \"" + value + "\"" + | |||
" }" + | |||
"}")); | |||
OkHttpClient okClient = new OkHttpClient.Builder().build(); | |||
try (Response response = okClient.newCall(request.build()).execute()) { | |||
assertThat(response.isSuccessful()).isTrue(); | |||
} | |||
} | |||
private static String baseUrl(int searchHttpPort) { | |||
return "http://" + InetAddress.getLoopbackAddress().getHostAddress() + ":" + searchHttpPort + "/"; | |||
} | |||
} |
@@ -0,0 +1,106 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import java.util.List; | |||
import java.util.Set; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import java.util.function.Consumer; | |||
import java.util.stream.Collectors; | |||
import org.assertj.core.api.Assertions; | |||
import org.sonarqube.ws.UserGroups; | |||
import org.sonarqube.ws.Users; | |||
import org.sonarqube.ws.Users.GroupsWsResponse.Group; | |||
import org.sonarqube.ws.client.usergroups.AddUserRequest; | |||
import org.sonarqube.ws.client.usergroups.CreateRequest; | |||
import org.sonarqube.ws.client.usergroups.DeleteRequest; | |||
import org.sonarqube.ws.client.usergroups.SearchRequest; | |||
import org.sonarqube.ws.client.users.GroupsRequest; | |||
import static java.util.Arrays.stream; | |||
public class GroupTester { | |||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); | |||
private final TesterSession session; | |||
GroupTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
@SafeVarargs | |||
public final UserGroups.Group generate(Consumer<CreateRequest>... populators) { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
CreateRequest request = new CreateRequest() | |||
.setName("Group" + id) | |||
.setDescription("Description " + id); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
return session.wsClient().userGroups().create(request).getGroup(); | |||
} | |||
public List<UserGroups.Group> getGroups(String partialGroupName) { | |||
SearchRequest searchRequest = new SearchRequest(); | |||
searchRequest.setQ(partialGroupName); | |||
return session.wsClient().userGroups().search(searchRequest).getGroupsList(); | |||
} | |||
public List<Group> getGroupsOfUser(String userLogin) { | |||
GroupsRequest request = new GroupsRequest().setLogin(userLogin); | |||
Users.GroupsWsResponse response = session.users().service().groups(request); | |||
return response.getGroupsList(); | |||
} | |||
public GroupTester addMemberToGroups(String userLogin, String... groups) { | |||
for (String group : groups) { | |||
AddUserRequest request = new AddUserRequest() | |||
.setLogin(userLogin) | |||
.setName(group); | |||
session.wsClient().userGroups().addUser(request); | |||
} | |||
return this; | |||
} | |||
public GroupTester assertThatUserIsOnlyMemberOf(String userLogin, String... expectedGroups) { | |||
Set<String> groups = getGroupsOfUser(userLogin).stream() | |||
.map(Group::getName) | |||
.collect(Collectors.toSet()); | |||
Assertions.assertThat(groups).containsExactlyInAnyOrder(expectedGroups); | |||
return this; | |||
} | |||
public GroupTester deleteAllGenerated() { | |||
List<String> allGroups = session.wsClient().userGroups().search(new SearchRequest()).getGroupsList().stream().map(UserGroups.Group::getName) | |||
.collect(Collectors.toList()); | |||
allGroups.stream() | |||
.filter(g -> g.matches("Group\\d+$")) | |||
.forEach(g -> session.wsClient().userGroups().delete(new DeleteRequest().setName(g))); | |||
return this; | |||
} | |||
public GroupTester delete(UserGroups.Group... groups) { | |||
List<String> allGroups = session.wsClient().userGroups().search(new SearchRequest()).getGroupsList().stream().map(UserGroups.Group::getName) | |||
.collect(Collectors.toList()); | |||
stream(groups) | |||
.filter(g -> allGroups.contains(g.getName())) | |||
.forEach(g -> session.wsClient().userGroups().delete(new DeleteRequest().setName(g.getName()))); | |||
return this; | |||
} | |||
} |
@@ -0,0 +1,105 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.function.Function; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.Stream; | |||
import javax.annotation.CheckForNull; | |||
import org.sonarqube.ws.Measures; | |||
import org.sonarqube.ws.Measures.Measure; | |||
import org.sonarqube.ws.client.measures.ComponentRequest; | |||
import static java.lang.Double.parseDouble; | |||
import static java.util.Collections.singletonList; | |||
public class MeasureTester { | |||
private final TesterSession session; | |||
MeasureTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
@CheckForNull | |||
public Measure getMeasure(String componentKey, String metricKey) { | |||
return getMeasuresByMetricKey(componentKey, metricKey).get(metricKey); | |||
} | |||
@CheckForNull | |||
public Double getMeasureAsDouble(String componentKey, String metricKey) { | |||
Measure measure = getMeasure(componentKey, metricKey); | |||
return (measure == null) ? null : parseDouble(measure.getValue()); | |||
} | |||
public Map<String, Measure> getMeasuresByMetricKey(String componentKey, String... metricKeys) { | |||
return getStreamMeasures(componentKey, metricKeys) | |||
.filter(Measure::hasValue) | |||
.collect(Collectors.toMap(Measure::getMetric, Function.identity())); | |||
} | |||
public Map<String, Double> getMeasuresAsDoubleByMetricKey(String componentKey, String... metricKeys) { | |||
return getStreamMeasures(componentKey, metricKeys) | |||
.filter(Measure::hasValue) | |||
.collect(Collectors.toMap(Measure::getMetric, measure -> parseDouble(measure.getValue()))); | |||
} | |||
private Stream<Measure> getStreamMeasures(String componentKey, String... metricKeys) { | |||
return session.wsClient().measures().component(new ComponentRequest() | |||
.setComponent(componentKey) | |||
.setMetricKeys(Arrays.asList(metricKeys))) | |||
.getComponent().getMeasuresList() | |||
.stream(); | |||
} | |||
@CheckForNull | |||
public Measure getMeasureWithVariation(String componentKey, String metricKey) { | |||
Measures.ComponentWsResponse response = session.wsClient().measures().component(new ComponentRequest() | |||
.setComponent(componentKey) | |||
.setMetricKeys(singletonList(metricKey)) | |||
.setAdditionalFields(singletonList("period"))); | |||
List<Measure> measures = response.getComponent().getMeasuresList(); | |||
return measures.size() == 1 ? measures.get(0) : null; | |||
} | |||
@CheckForNull | |||
public Map<String, Measure> getMeasuresWithVariationsByMetricKey(String componentKey, String... metricKeys) { | |||
return session.wsClient().measures().component(new ComponentRequest() | |||
.setComponent(componentKey) | |||
.setMetricKeys(Arrays.asList(metricKeys)) | |||
.setAdditionalFields(singletonList("period"))).getComponent().getMeasuresList() | |||
.stream() | |||
.collect(Collectors.toMap(Measure::getMetric, Function.identity())); | |||
} | |||
/** | |||
* Return leak period value | |||
*/ | |||
@CheckForNull | |||
public Double getLeakPeriodValue(String componentKey, String metricKey) { | |||
Measures.PeriodValue periodsValue = getMeasureWithVariation(componentKey, metricKey).getPeriod(); | |||
return parseDouble(periodsValue.getValue()); | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import javax.annotation.Nullable; | |||
import org.sonarqube.ws.NewCodePeriods; | |||
import org.sonarqube.ws.client.newcodeperiods.NewCodePeriodsService; | |||
import org.sonarqube.ws.client.newcodeperiods.SetRequest; | |||
import org.sonarqube.ws.client.newcodeperiods.ShowRequest; | |||
import org.sonarqube.ws.client.newcodeperiods.UnsetRequest; | |||
public class NewCodePeriodTester { | |||
private final TesterSession session; | |||
NewCodePeriodTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
public NewCodePeriodsService service() { | |||
return session.wsClient().newCodePeriods(); | |||
} | |||
public void setGlobal(String type, @Nullable String value) { | |||
set(null, null, type, value); | |||
} | |||
public void set(@Nullable String projectKey, @Nullable String branchKey, String type, @Nullable String value) { | |||
session.wsClient().newCodePeriods().set(new SetRequest() | |||
.setProject(projectKey) | |||
.setBranch(branchKey) | |||
.setType(type) | |||
.setValue(value)); | |||
} | |||
public void unset(@Nullable String projectKey, @Nullable String branchKey) { | |||
session.wsClient().newCodePeriods().unset(new UnsetRequest() | |||
.setProject(projectKey) | |||
.setBranch(branchKey)); | |||
} | |||
public NewCodePeriods.ShowWSResponse show(@Nullable String projectKey, @Nullable String branchKey) { | |||
return session.wsClient().newCodePeriods().show(new ShowRequest() | |||
.setProject(projectKey) | |||
.setBranch(branchKey)); | |||
} | |||
} |
@@ -0,0 +1,128 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import java.util.function.Consumer; | |||
import org.sonarqube.ws.Permissions.PermissionTemplate; | |||
import org.sonarqube.ws.Permissions.SearchTemplatesWsResponse.TemplateIdQualifier; | |||
import org.sonarqube.ws.Projects.CreateWsResponse.Project; | |||
import org.sonarqube.ws.Users; | |||
import org.sonarqube.ws.client.permissions.AddGroupRequest; | |||
import org.sonarqube.ws.client.permissions.AddGroupToTemplateRequest; | |||
import org.sonarqube.ws.client.permissions.AddProjectCreatorToTemplateRequest; | |||
import org.sonarqube.ws.client.permissions.AddUserRequest; | |||
import org.sonarqube.ws.client.permissions.AddUserToTemplateRequest; | |||
import org.sonarqube.ws.client.permissions.ApplyTemplateRequest; | |||
import org.sonarqube.ws.client.permissions.CreateTemplateRequest; | |||
import org.sonarqube.ws.client.permissions.PermissionsService; | |||
import org.sonarqube.ws.client.permissions.SearchTemplatesRequest; | |||
import org.sonarqube.ws.client.permissions.SetDefaultTemplateRequest; | |||
import static com.sonar.orchestrator.container.Server.ADMIN_LOGIN; | |||
import static java.util.Arrays.stream; | |||
public class PermissionTester { | |||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); | |||
private final TesterSession session; | |||
PermissionTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
@SafeVarargs | |||
public final PermissionTemplate generateTemplate(Consumer<CreateTemplateRequest>... populators) { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
String name = "template" + id; | |||
CreateTemplateRequest request = new CreateTemplateRequest() | |||
.setName(name); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
PermissionTemplate template = service().createTemplate(request).getPermissionTemplate(); | |||
// Give browse and admin permissions to admin in order to allow admin wsclient to perform any operation on created projects | |||
addUserToTemplate(ADMIN_LOGIN, template, "user"); | |||
addUserToTemplate(ADMIN_LOGIN, template, "admin"); | |||
return template; | |||
} | |||
public void addUserToTemplate(Users.CreateWsResponse.User user, PermissionTemplate template, String permission) { | |||
addUserToTemplate(user.getLogin(), template, permission); | |||
} | |||
public void addUserToTemplate(String login, PermissionTemplate template, String permission) { | |||
service().addUserToTemplate(new AddUserToTemplateRequest() | |||
.setLogin(login) | |||
.setTemplateName(template.getName()) | |||
.setPermission(permission)); | |||
} | |||
public void addGroup(String groupName, String permission) { | |||
service().addGroup(new AddGroupRequest().setGroupName(groupName).setPermission(permission)); | |||
} | |||
public void addUser(String login, String permission) { | |||
service().addUser(new AddUserRequest().setLogin(login).setPermission(permission)); | |||
} | |||
public void addGroupToTemplate(String groupName, PermissionTemplate template, String permission) { | |||
service().addGroupToTemplate(new AddGroupToTemplateRequest() | |||
.setGroupName(groupName) | |||
.setTemplateName(template.getName()) | |||
.setPermission(permission)); | |||
} | |||
public void addCreatorToTemplate(PermissionTemplate template, String permission) { | |||
this.service().addProjectCreatorToTemplate( | |||
new AddProjectCreatorToTemplateRequest() | |||
.setPermission(permission) | |||
.setTemplateId(template.getId())); | |||
} | |||
public void applyTemplate(PermissionTemplate template, Project project) { | |||
service().applyTemplate( | |||
new ApplyTemplateRequest() | |||
.setTemplateName(template.getName()) | |||
.setProjectKey(project.getKey())); | |||
} | |||
public TemplateIdQualifier getDefaultTemplateForProject() { | |||
return service().searchTemplates(new SearchTemplatesRequest()).getDefaultTemplatesList() | |||
.stream() | |||
.filter(t -> t.getQualifier().equals("TRK")) | |||
.findFirst() | |||
.orElseThrow(() -> { | |||
throw new IllegalStateException("Cannot find default template for project"); | |||
}); | |||
} | |||
public void setDefaultTemplate(TemplateIdQualifier template) { | |||
service().setDefaultTemplate(new SetDefaultTemplateRequest().setTemplateId(template.getTemplateId())); | |||
} | |||
public void setDefaultTemplate(PermissionTemplate template) { | |||
service().setDefaultTemplate(new SetDefaultTemplateRequest().setTemplateId(template.getId())); | |||
} | |||
public PermissionsService service() { | |||
return session.wsClient().permissions(); | |||
} | |||
} |
@@ -0,0 +1,101 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import java.util.function.Consumer; | |||
import javax.annotation.Nullable; | |||
import org.sonarqube.ws.Components; | |||
import org.sonarqube.ws.Projects; | |||
import org.sonarqube.ws.client.HttpException; | |||
import org.sonarqube.ws.client.WsResponse; | |||
import org.sonarqube.ws.client.components.ShowRequest; | |||
import org.sonarqube.ws.client.projects.CreateRequest; | |||
import org.sonarqube.ws.client.projects.DeleteRequest; | |||
import org.sonarqube.ws.client.projects.ExportFindingsRequest; | |||
import org.sonarqube.ws.client.projects.ProjectsService; | |||
import org.sonarqube.ws.client.projects.SearchRequest; | |||
import static java.util.Arrays.stream; | |||
import static java.util.Collections.singletonList; | |||
public class ProjectTester { | |||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); | |||
private final TesterSession session; | |||
ProjectTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
void deleteAll() { | |||
ProjectsService service = session.wsClient().projects(); | |||
service.search(new SearchRequest().setQualifiers(singletonList("TRK"))).getComponentsList().forEach(p -> service.delete(new DeleteRequest().setProject(p.getKey()))); | |||
} | |||
public ProjectsService service() { | |||
return session.wsClient().projects(); | |||
} | |||
public WsResponse exportFindings(String projectKey, @Nullable String branchKey) { | |||
ProjectsService service = session.wsClient().projects(); | |||
return service.exportFindings(new ExportFindingsRequest(projectKey, branchKey)); | |||
} | |||
@SafeVarargs | |||
public final Projects.CreateWsResponse.Project provision(Consumer<CreateRequest>... populators) { | |||
String key = generateKey(); | |||
CreateRequest request = new CreateRequest() | |||
.setProject(key) | |||
.setName("Name " + key); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
return session.wsClient().projects().create(request).getProject(); | |||
} | |||
public Components.Component getComponent(String componentKey) { | |||
try { | |||
return session.wsClient().components().show(new ShowRequest().setComponent((componentKey))).getComponent(); | |||
} catch (org.sonarqube.ws.client.HttpException e) { | |||
if (e.code() == 404) { | |||
return null; | |||
} | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
public boolean exists(String projectKey) { | |||
try { | |||
Components.ShowWsResponse response = session.wsClient().components().show(new ShowRequest().setComponent(projectKey)); | |||
return response.getComponent() != null; | |||
} catch (HttpException e) { | |||
if (e.code() == 404) { | |||
return false; | |||
} | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
public String generateKey() { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
return "key" + id; | |||
} | |||
} |
@@ -0,0 +1,126 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import com.google.gson.Gson; | |||
import com.google.gson.annotations.SerializedName; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import java.util.function.Consumer; | |||
import java.util.stream.Collectors; | |||
import org.sonarqube.ws.Projects.CreateWsResponse.Project; | |||
import org.sonarqube.ws.client.qualitygates.CreateRequest; | |||
import org.sonarqube.ws.client.qualitygates.DestroyRequest; | |||
import org.sonarqube.ws.client.qualitygates.ListRequest; | |||
import org.sonarqube.ws.client.qualitygates.QualitygatesService; | |||
import org.sonarqube.ws.client.qualitygates.SelectRequest; | |||
import org.sonarqube.ws.client.qualitygates.SetAsDefaultRequest; | |||
import static java.util.Arrays.stream; | |||
import static org.sonarqube.ws.Qualitygates.CreateResponse; | |||
import static org.sonarqube.ws.Qualitygates.ListWsResponse; | |||
public class QGateTester { | |||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); | |||
private final TesterSession session; | |||
QGateTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
public QualitygatesService service() { | |||
return session.wsClient().qualitygates(); | |||
} | |||
void deleteAll() { | |||
List<ListWsResponse.QualityGate> builtInQualityGates = session.wsClient().qualitygates().list(new ListRequest()).getQualitygatesList().stream() | |||
.filter(ListWsResponse.QualityGate::getIsBuiltIn) | |||
.collect(Collectors.toList()); | |||
if (builtInQualityGates.size() == 1) { | |||
session.wsClient().qualitygates().setAsDefault(new SetAsDefaultRequest().setName(builtInQualityGates.get(0).getName())); | |||
} | |||
session.wsClient().qualitygates().list(new ListRequest()).getQualitygatesList().stream() | |||
.filter(qualityGate -> !qualityGate.getIsDefault()) | |||
.filter(qualityGate -> !qualityGate.getIsBuiltIn()) | |||
.forEach(qualityGate -> session.wsClient().qualitygates().destroy(new DestroyRequest().setName(qualityGate.getName()))); | |||
} | |||
@SafeVarargs | |||
public final CreateResponse generate(Consumer<CreateRequest>... populators) { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
CreateRequest request = new CreateRequest() | |||
.setName("QualityGate " + id); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
return session.wsClient().qualitygates().create(request); | |||
} | |||
public void associateProject(CreateResponse qualityGate, Project project) { | |||
service().select(new SelectRequest() | |||
.setGateName(qualityGate.getName()) | |||
.setProjectKey(project.getKey())); | |||
} | |||
public static class ListResponse { | |||
@SerializedName("default") | |||
private final String defaultQGate; | |||
@SerializedName("qualitygates") | |||
private final List<QGate> qualityGates = new ArrayList<>(); | |||
public ListResponse(String defaultQGate) { | |||
this.defaultQGate = defaultQGate; | |||
} | |||
public List<QGate> getQualityGates() { | |||
return qualityGates; | |||
} | |||
public String getDefault() { | |||
return defaultQGate; | |||
} | |||
public static ListResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, ListResponse.class); | |||
} | |||
public static class QGate { | |||
@SerializedName("id") | |||
private final String id; | |||
@SerializedName("name") | |||
private final String name; | |||
public QGate(String id, String name) { | |||
this.id = id; | |||
this.name = name; | |||
} | |||
public String getId() { | |||
return id; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,63 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* All rights reserved | |||
* mailto:info AT sonarsource DOT com | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import com.google.common.base.Joiner; | |||
import com.google.common.base.Preconditions; | |||
public class QModelTester { | |||
private static final String DEV_COST_PROPERTY = "sonar.technicalDebt.developmentCost"; | |||
private static final String RATING_GRID_PROPERTY = "sonar.technicalDebt.ratingGrid"; | |||
private static final String DEV_COST_LANGUAGE_PROPERTY = "languageSpecificParameters"; | |||
private static final String DEV_COST_LANGUAGE_NAME_PROPERTY = DEV_COST_LANGUAGE_PROPERTY + ".0.language"; | |||
private static final String DEV_COST_LANGUAGE_COST_PROPERTY = DEV_COST_LANGUAGE_PROPERTY + ".0.man_days"; | |||
private static final Joiner COMMA_JOINER = Joiner.on(","); | |||
private final TesterSession session; | |||
QModelTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
public void updateDevelopmentCost(int developmentCost) { | |||
session.settings().setGlobalSettings(DEV_COST_PROPERTY, Integer.toString(developmentCost)); | |||
} | |||
public void updateLanguageDevelopmentCost(String language, int developmentCost) { | |||
session.settings().setGlobalSettings(DEV_COST_LANGUAGE_PROPERTY, "0"); | |||
session.settings().setGlobalSettings(DEV_COST_LANGUAGE_NAME_PROPERTY, language); | |||
session.settings().setGlobalSettings(DEV_COST_LANGUAGE_COST_PROPERTY, Integer.toString(developmentCost)); | |||
} | |||
public void updateRatingGrid(Double... ratingGrid) { | |||
Preconditions.checkState(ratingGrid.length == 4, "Rating grid must contains 4 values"); | |||
session.settings().setGlobalSettings(RATING_GRID_PROPERTY, COMMA_JOINER.join(ratingGrid)); | |||
} | |||
public void reset() { | |||
session.settings().resetSettings(DEV_COST_LANGUAGE_PROPERTY, DEV_COST_LANGUAGE_NAME_PROPERTY, DEV_COST_LANGUAGE_COST_PROPERTY, RATING_GRID_PROPERTY, DEV_COST_PROPERTY); | |||
} | |||
} |
@@ -0,0 +1,136 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* All rights reserved | |||
* mailto:info AT sonarsource DOT com | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import java.util.List; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import java.util.function.Consumer; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Nullable; | |||
import org.sonarqube.ws.Projects.CreateWsResponse.Project; | |||
import org.sonarqube.ws.Qualityprofiles; | |||
import org.sonarqube.ws.Qualityprofiles.CreateWsResponse.QualityProfile; | |||
import org.sonarqube.ws.client.qualityprofiles.ActivateRuleRequest; | |||
import org.sonarqube.ws.client.qualityprofiles.AddProjectRequest; | |||
import org.sonarqube.ws.client.qualityprofiles.CreateRequest; | |||
import org.sonarqube.ws.client.qualityprofiles.DeactivateRuleRequest; | |||
import org.sonarqube.ws.client.qualityprofiles.DeleteRequest; | |||
import org.sonarqube.ws.client.qualityprofiles.QualityprofilesService; | |||
import org.sonarqube.ws.client.qualityprofiles.SearchRequest; | |||
import static java.util.Arrays.stream; | |||
public class QProfileTester { | |||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); | |||
private final TesterSession session; | |||
QProfileTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
public QualityprofilesService service() { | |||
return session.wsClient().qualityprofiles(); | |||
} | |||
void deleteAll() { | |||
List<Qualityprofiles.SearchWsResponse.QualityProfile> qualityProfiles = session.wsClient().qualityprofiles().search(new SearchRequest()).getProfilesList().stream() | |||
.filter(qp -> !qp.getIsDefault()) | |||
.filter(qp -> !qp.getIsBuiltIn()) | |||
.filter(qp -> qp.getParentKey() == null || qp.getParentKey().equals("")) | |||
.collect(Collectors.toList()); | |||
qualityProfiles.forEach( | |||
qp -> session.wsClient().qualityprofiles().delete(new DeleteRequest().setQualityProfile(qp.getName()).setLanguage(qp.getLanguage()))); | |||
} | |||
@SafeVarargs | |||
public final QualityProfile createXooProfile(Consumer<CreateRequest>... populators) { | |||
CreateRequest request = new CreateRequest() | |||
.setLanguage("xoo") | |||
.setName(generateName()); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
return service().create(request).getProfile(); | |||
} | |||
public QProfileTester activateRule(QualityProfile profile, String ruleKey) { | |||
return activateRule(profile.getKey(), ruleKey); | |||
} | |||
public QProfileTester activateRule(String profileKey, String ruleKey) { | |||
ActivateRuleRequest request = new ActivateRuleRequest() | |||
.setKey(profileKey) | |||
.setRule(ruleKey); | |||
service().activateRule(request); | |||
return this; | |||
} | |||
public QProfileTester activateRule(QualityProfile profile, String ruleKey, String severity, List<String> params) { | |||
return activateRule(profile.getKey(), ruleKey, severity, params); | |||
} | |||
public QProfileTester activateRule(QualityProfile profile, String ruleKey, String severity) { | |||
return activateRule(profile.getKey(), ruleKey, severity, null); | |||
} | |||
public QProfileTester activateRule(String profileKey, String ruleKey, String severity) { | |||
return activateRule(profileKey, ruleKey, severity, null); | |||
} | |||
public QProfileTester activateRule(String profileKey, String ruleKey, String severity, @Nullable List<String> params) { | |||
service().activateRule(new ActivateRuleRequest() | |||
.setKey(profileKey) | |||
.setRule(ruleKey) | |||
.setSeverity(severity) | |||
.setParams(params)); | |||
return this; | |||
} | |||
public QProfileTester deactivateRule(QualityProfile profile, String ruleKey) { | |||
service().deactivateRule(new DeactivateRuleRequest().setKey(profile.getKey()).setRule(ruleKey)); | |||
return this; | |||
} | |||
public QProfileTester assignQProfileToProject(QualityProfile profile, Project project) { | |||
return assignQProfileToProject(profile, project.getKey()); | |||
} | |||
public QProfileTester assignQProfileToProject(QualityProfile profile, String projectKey) { | |||
return assignQProfileToProject(profile.getName(), profile.getLanguage(), projectKey); | |||
} | |||
public QProfileTester assignQProfileToProject(String profileName, String profileLanguage, String projectKey) { | |||
service().addProject(new AddProjectRequest() | |||
.setProject(projectKey) | |||
.setQualityProfile(profileName) | |||
.setLanguage(profileLanguage)); | |||
return this; | |||
} | |||
public String generateName() { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
return "Profile" + id; | |||
} | |||
} |
@@ -0,0 +1,114 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import com.google.common.collect.ImmutableSet; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.Stream; | |||
import javax.annotation.Nullable; | |||
import org.sonarqube.ws.Settings; | |||
import org.sonarqube.ws.Settings.Setting; | |||
import org.sonarqube.ws.client.settings.ListDefinitionsRequest; | |||
import org.sonarqube.ws.client.settings.ResetRequest; | |||
import org.sonarqube.ws.client.settings.SetRequest; | |||
import org.sonarqube.ws.client.settings.SettingsService; | |||
import org.sonarqube.ws.client.settings.ValuesRequest; | |||
import static java.util.Arrays.asList; | |||
public class SettingTester { | |||
private static final Set<String> EMAIL_SETTINGS = ImmutableSet.of("email.smtp_host.secured", "email.smtp_port.secured", "email.smtp_secure_connection.secured", | |||
"email.smtp_username.secured", "email.smtp_password.secured", "email.from", "email.prefix"); | |||
private final TesterSession session; | |||
SettingTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
public SettingsService service() { | |||
return session.wsClient().settings(); | |||
} | |||
public void deleteAll() { | |||
List<String> settingKeys = Stream.concat( | |||
session.wsClient().settings().listDefinitions(new ListDefinitionsRequest()).getDefinitionsList() | |||
.stream() | |||
.filter(def -> def.getType() != Settings.Type.LICENSE) | |||
.map(Settings.Definition::getKey) | |||
.filter(key -> !key.equals(Tester.FORCE_AUTHENTICATION_PROPERTY_NAME)), | |||
EMAIL_SETTINGS.stream()) | |||
.collect(Collectors.toList()); | |||
session.wsClient().settings().reset(new ResetRequest().setKeys(settingKeys)); | |||
} | |||
public void resetSettings(String... keys) { | |||
session.wsClient().settings().reset(new ResetRequest().setKeys(asList(keys))); | |||
} | |||
public List<Setting> getGlobalSettings(String... keys) { | |||
return session.wsClient().settings().values(new ValuesRequest().setKeys(asList(keys))) | |||
.getSettingsList(); | |||
} | |||
public void resetProjectSettings(String projectKey, String... keys) { | |||
session.wsClient().settings().reset(new ResetRequest().setComponent(projectKey).setKeys(asList(keys))); | |||
} | |||
public void setGlobalSetting(String key, @Nullable String value) { | |||
setSetting(null, key, value); | |||
} | |||
public void setMultiValuesGlobalSetting(String key, String... values) { | |||
session.wsClient().settings().set(new SetRequest() | |||
.setKey(key) | |||
.setValues(Arrays.asList(values)) | |||
.setComponent(null)); | |||
} | |||
public void setGlobalSettings(String... keyValues) { | |||
for (int i = 0; i < keyValues.length; i += 2) { | |||
setSetting(null, keyValues[i], keyValues[i + 1]); | |||
} | |||
} | |||
public void setProjectSetting(String componentKey, String key, @Nullable String value) { | |||
setSetting(componentKey, key, value); | |||
} | |||
public void setProjectSettings(String componentKey, String... properties) { | |||
for (int i = 0; i < properties.length; i += 2) { | |||
setSetting(componentKey, properties[i], properties[i + 1]); | |||
} | |||
} | |||
private void setSetting(@Nullable String componentKey, String key, @Nullable String value) { | |||
if (value == null) { | |||
session.wsClient().settings().reset(new ResetRequest().setKeys(asList(key)).setComponent(componentKey)); | |||
} else { | |||
session.wsClient().settings().set(new SetRequest().setKey(key).setValue(value).setComponent(componentKey)); | |||
} | |||
} | |||
} |
@@ -0,0 +1,403 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import com.google.common.base.Preconditions; | |||
import com.sonar.orchestrator.container.Edition; | |||
import com.sonar.orchestrator.container.Server; | |||
import com.sonar.orchestrator.junit4.OrchestratorRule; | |||
import java.sql.Connection; | |||
import java.sql.PreparedStatement; | |||
import java.sql.SQLException; | |||
import java.util.List; | |||
import java.util.function.Consumer; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Nullable; | |||
import org.junit.rules.ExternalResource; | |||
import org.sonarqube.ws.Ce; | |||
import org.sonarqube.ws.client.HttpConnector; | |||
import org.sonarqube.ws.client.WsClient; | |||
import org.sonarqube.ws.client.WsClientFactories; | |||
import org.sonarqube.ws.client.ce.ActivityRequest; | |||
import static com.sonar.orchestrator.container.Edition.DEVELOPER; | |||
import static com.sonar.orchestrator.container.Edition.ENTERPRISE; | |||
import static java.lang.String.format; | |||
import static java.util.Arrays.stream; | |||
import static org.sonarqube.ws.client.HttpConnector.DEFAULT_READ_TIMEOUT_MILLISECONDS; | |||
/** | |||
* This JUnit rule wraps an {@link OrchestratorRule} instance and provides : | |||
* <ul> | |||
* <li>clean-up of users between tests</li> | |||
* <li>clean-up of session when opening a browser (cookies, local storage)</li> | |||
* <li>quick access to {@link WsClient} instances</li> | |||
* <li>clean-up of defined settings. Properties that are not defined by a plugin are not reset.</li> | |||
* <li>helpers to generate users</li> | |||
* </ul> | |||
* <p> | |||
* Recommendation is to define a {@code @Rule} instance. If not possible, then | |||
* {@code @ClassRule} must be used through a {@link org.junit.rules.RuleChain} | |||
* around {@link OrchestratorRule}. | |||
* <p> | |||
* Not supported: | |||
* <ul> | |||
* <li>clean-up global settings</li> | |||
* <li>clean-up system administrators/roots</li> | |||
* <li>clean-up the properties that are not defined (no PropertyDefinition)</li> | |||
* </ul> | |||
*/ | |||
public class Tester extends ExternalResource implements TesterSession { | |||
static final String FORCE_AUTHENTICATION_PROPERTY_NAME = "sonar.forceAuthentication"; | |||
private final OrchestratorRule orchestrator; | |||
private boolean enableForceAuthentication = false; | |||
private Elasticsearch elasticsearch = null; | |||
// initialized in #before() | |||
private boolean beforeCalled = false; | |||
private TesterSession rootSession; | |||
private final int readTimeoutMilliseconds; | |||
public Tester(OrchestratorRule orchestrator) { | |||
this(orchestrator, DEFAULT_READ_TIMEOUT_MILLISECONDS); | |||
} | |||
public Tester(OrchestratorRule orchestrator, int readTimeoutMilliseconds) { | |||
this.orchestrator = orchestrator; | |||
this.readTimeoutMilliseconds = readTimeoutMilliseconds; | |||
} | |||
public Tester enableForceAuthentication() { | |||
verifyNotStarted(); | |||
enableForceAuthentication = true; | |||
return this; | |||
} | |||
@Override | |||
public void before() { | |||
verifyNotStarted(); | |||
rootSession = new TesterSessionImpl(orchestrator, | |||
httpConnectorBuilder -> httpConnectorBuilder.readTimeoutMilliseconds(readTimeoutMilliseconds), | |||
httpConnectorBuilder -> httpConnectorBuilder.credentials("admin", "admin")); | |||
setForceAuthentication(enableForceAuthentication); | |||
beforeCalled = true; | |||
} | |||
@Override | |||
public void after() { | |||
waitForCeTasksToFinish(); | |||
deactivateScim(); | |||
users().deleteAll(); | |||
projects().deleteAll(); | |||
settings().deleteAll(); | |||
qGates().deleteAll(); | |||
qProfiles().deleteAll(); | |||
webhooks().deleteAllGlobal(); | |||
almSettings().deleteAll(); | |||
groups().deleteAllGenerated(); | |||
Edition edition = orchestrator.getDistribution().getEdition(); | |||
if (edition.equals(ENTERPRISE)) { | |||
applications().deleteAll(); | |||
views().deleteAll(); | |||
applications().deleteAll(); | |||
} else if (edition.equals(DEVELOPER)) { | |||
applications().deleteAll(); | |||
} | |||
setForceAuthentication(enableForceAuthentication); | |||
} | |||
public void deactivateScim() { | |||
try (Connection connection = orchestrator.getDatabase().openConnection(); | |||
PreparedStatement preparedStatement = connection.prepareStatement("delete from internal_properties where kee = ?")) { | |||
preparedStatement.setString(1, "sonar.scim.enabled"); | |||
preparedStatement.execute(); | |||
} catch (SQLException e) { | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
private void setForceAuthentication(boolean enableForceAuthentication) { | |||
String serverProperty = orchestrator.getDistribution().getServerProperty(FORCE_AUTHENTICATION_PROPERTY_NAME); | |||
if (serverProperty != null) { | |||
Preconditions.checkArgument(enableForceAuthentication == Boolean.parseBoolean(serverProperty), | |||
"This test was expecting to have authentication configured, but server property configuration has mismatched."); | |||
return; | |||
} | |||
if (enableForceAuthentication) { | |||
settings().resetSettings(FORCE_AUTHENTICATION_PROPERTY_NAME); | |||
} else { | |||
settings().setGlobalSetting(FORCE_AUTHENTICATION_PROPERTY_NAME, Boolean.toString(false)); | |||
} | |||
} | |||
private void waitForCeTasksToFinish() { | |||
// Let's try to wait for 30s for in progress or pending tasks to finish | |||
int counter = 60; | |||
while (counter > 0 && | |||
wsClient().ce().activity(new ActivityRequest().setStatus(List.of("PENDING", "IN_PROGRESS"))).getTasksCount() != 0) { | |||
counter--; | |||
try { | |||
Thread.sleep(500); | |||
} catch (InterruptedException e) { | |||
Thread.currentThread().interrupt(); | |||
break; | |||
} | |||
} | |||
Ce.ActivityResponse activity = wsClient().ce().activity(new ActivityRequest().setStatus(List.of("PENDING", "IN_PROGRESS"))); | |||
if (activity.getTasksCount() != 0) { | |||
throw new IllegalStateException(format("Waiting for 30 seconds for tasks to finish but there are still ce tasks : %n %s", | |||
activity.getTasksList().stream() | |||
.map(t -> format("analysisId: [%s] type: [%s] componentName: [%s]", t.getAnalysisId(), t.getType(), t.getComponentName())) | |||
.collect(Collectors.joining("\n")))); | |||
} | |||
} | |||
public TesterSession asAnonymous() { | |||
return as(null, null); | |||
} | |||
public TesterSession as(String login) { | |||
return as(login, login); | |||
} | |||
public TesterSession as(String login, String password) { | |||
verifyStarted(); | |||
return new TesterSessionImpl(orchestrator, login, password); | |||
} | |||
public TesterSession withSystemPassCode(String systemPassCode) { | |||
verifyStarted(); | |||
return new TesterSessionImpl(orchestrator, systemPassCode); | |||
} | |||
public Elasticsearch elasticsearch() { | |||
if (elasticsearch != null) { | |||
return elasticsearch; | |||
} | |||
elasticsearch = new Elasticsearch(orchestrator.getServer().getSearchPort()); | |||
return elasticsearch; | |||
} | |||
private void verifyNotStarted() { | |||
if (beforeCalled) { | |||
throw new IllegalStateException("org.sonarqube.ws.tester.Tester should not be already started"); | |||
} | |||
} | |||
private void verifyStarted() { | |||
if (!beforeCalled) { | |||
throw new IllegalStateException("org.sonarqube.ws.tester.Tester is not started yet"); | |||
} | |||
} | |||
/** | |||
* Web service client configured with root access | |||
*/ | |||
@Override | |||
public WsClient wsClient() { | |||
verifyStarted(); | |||
return rootSession.wsClient(); | |||
} | |||
@Override | |||
public GroupTester groups() { | |||
return rootSession.groups(); | |||
} | |||
@Override | |||
public ProjectTester projects() { | |||
return rootSession.projects(); | |||
} | |||
@Override | |||
public QModelTester qModel() { | |||
return rootSession.qModel(); | |||
} | |||
@Override | |||
public QProfileTester qProfiles() { | |||
return rootSession.qProfiles(); | |||
} | |||
@Override | |||
public UserTester users() { | |||
return rootSession.users(); | |||
} | |||
@Override | |||
public SettingTester settings() { | |||
return rootSession.settings(); | |||
} | |||
@Override | |||
public NewCodePeriodTester newCodePeriods() { | |||
return rootSession.newCodePeriods(); | |||
} | |||
@Override | |||
public QGateTester qGates() { | |||
return rootSession.qGates(); | |||
} | |||
@Override | |||
public WebhookTester webhooks() { | |||
return rootSession.webhooks(); | |||
} | |||
@Override | |||
public PermissionTester permissions() { | |||
return rootSession.permissions(); | |||
} | |||
@Override | |||
public ViewTester views() { | |||
return rootSession.views(); | |||
} | |||
@Override | |||
public ApplicationTester applications() { | |||
return rootSession.applications(); | |||
} | |||
@Override | |||
public MeasureTester measures() { | |||
return rootSession.measures(); | |||
} | |||
@Override | |||
public AlmSettingsTester almSettings() { | |||
return rootSession.almSettings(); | |||
} | |||
private static class TesterSessionImpl implements TesterSession { | |||
private final WsClient client; | |||
private TesterSessionImpl(OrchestratorRule orchestrator, @Nullable String login, @Nullable String password) { | |||
Server server = orchestrator.getServer(); | |||
this.client = WsClientFactories.getDefault().newClient(HttpConnector.newBuilder() | |||
.url(server.getUrl()) | |||
.credentials(login, password) | |||
.build()); | |||
} | |||
private TesterSessionImpl(OrchestratorRule orchestrator, @Nullable String systemPassCode) { | |||
Server server = orchestrator.getServer(); | |||
this.client = WsClientFactories.getDefault().newClient(HttpConnector.newBuilder() | |||
.systemPassCode(systemPassCode) | |||
.url(server.getUrl()) | |||
.build()); | |||
} | |||
private TesterSessionImpl(OrchestratorRule orchestrator, Consumer<HttpConnector.Builder>... httpConnectorPopulators) { | |||
Server server = orchestrator.getServer(); | |||
HttpConnector.Builder httpConnectorBuilder = HttpConnector.newBuilder() | |||
.url(server.getUrl()); | |||
stream(httpConnectorPopulators).forEach(populator -> populator.accept(httpConnectorBuilder)); | |||
this.client = WsClientFactories.getDefault().newClient(httpConnectorBuilder.build()); | |||
} | |||
@Override | |||
public WsClient wsClient() { | |||
return client; | |||
} | |||
@Override | |||
public GroupTester groups() { | |||
return new GroupTester(this); | |||
} | |||
@Override | |||
public ProjectTester projects() { | |||
return new ProjectTester(this); | |||
} | |||
@Override | |||
public QModelTester qModel() { | |||
return new QModelTester(this); | |||
} | |||
@Override | |||
public QProfileTester qProfiles() { | |||
return new QProfileTester(this); | |||
} | |||
@Override | |||
public UserTester users() { | |||
return new UserTester(this); | |||
} | |||
@Override | |||
public SettingTester settings() { | |||
return new SettingTester(this); | |||
} | |||
@Override | |||
public NewCodePeriodTester newCodePeriods() { | |||
return new NewCodePeriodTester(this); | |||
} | |||
@Override | |||
public QGateTester qGates() { | |||
return new QGateTester(this); | |||
} | |||
@Override | |||
public WebhookTester webhooks() { | |||
return new WebhookTester(this); | |||
} | |||
@Override | |||
public PermissionTester permissions() { | |||
return new PermissionTester(this); | |||
} | |||
@Override | |||
public ViewTester views() { | |||
return new ViewTester(this); | |||
} | |||
@Override | |||
public ApplicationTester applications() { | |||
return new ApplicationTester(this); | |||
} | |||
@Override | |||
public MeasureTester measures() { | |||
return new MeasureTester(this); | |||
} | |||
@Override | |||
public AlmSettingsTester almSettings() { | |||
return new AlmSettingsTester(this); | |||
} | |||
} | |||
} |
@@ -0,0 +1,56 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import org.sonarqube.ws.client.WsClient; | |||
public interface TesterSession { | |||
WsClient wsClient(); | |||
GroupTester groups(); | |||
ProjectTester projects(); | |||
QModelTester qModel(); | |||
QProfileTester qProfiles(); | |||
UserTester users(); | |||
SettingTester settings(); | |||
NewCodePeriodTester newCodePeriods(); | |||
QGateTester qGates(); | |||
WebhookTester webhooks(); | |||
PermissionTester permissions(); | |||
ViewTester views(); | |||
ApplicationTester applications(); | |||
MeasureTester measures(); | |||
AlmSettingsTester almSettings(); | |||
} |
@@ -0,0 +1,218 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import com.google.common.collect.MoreCollectors; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import java.util.function.Consumer; | |||
import java.util.function.Predicate; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Nullable; | |||
import org.sonarqube.ws.UserTokens; | |||
import org.sonarqube.ws.Users; | |||
import org.sonarqube.ws.Users.CreateWsResponse.User; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.WsResponse; | |||
import org.sonarqube.ws.client.usergroups.AddUserRequest; | |||
import org.sonarqube.ws.client.users.ChangePasswordRequest; | |||
import org.sonarqube.ws.client.users.CreateRequest; | |||
import org.sonarqube.ws.client.users.SearchRequest; | |||
import org.sonarqube.ws.client.users.UpdateIdentityProviderRequest; | |||
import org.sonarqube.ws.client.users.UpdateRequest; | |||
import org.sonarqube.ws.client.users.UsersService; | |||
import org.sonarqube.ws.client.usertokens.GenerateRequest; | |||
import static java.util.Arrays.stream; | |||
public class UserTester { | |||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); | |||
private final TesterSession session; | |||
UserTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
void deleteAll() { | |||
session.wsClient().users().search(new SearchRequest()).getUsersList() | |||
.stream() | |||
.filter(u -> !"admin".equals(u.getLogin())) | |||
.forEach(u -> { | |||
PostRequest request = new PostRequest("api/users/deactivate").setParam("login", u.getLogin()); | |||
try (final WsResponse response = session.wsClient().wsConnector().call(request)) { | |||
response.failIfNotSuccessful(); | |||
} | |||
}); | |||
} | |||
public final String generateToken(String login) { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
String name = "token" + id; | |||
session.wsClient().userTokens().generate(new GenerateRequest().setLogin(login).setName(name)); | |||
return name; | |||
} | |||
public final String generateToken(String login, String type, @Nullable String projectKey) { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
String name = "token" + id; | |||
UserTokens.GenerateWsResponse response = session.wsClient().userTokens() | |||
.generate(new GenerateRequest().setLogin(login).setName(name).setType(type).setProjectKey(projectKey)); | |||
return response.getToken(); | |||
} | |||
public final String generateToken(String login, Consumer<GenerateRequest>... populators) { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
String name = "token" + id; | |||
GenerateRequest generateRequest = new GenerateRequest() | |||
.setName(name) | |||
.setLogin(login); | |||
stream(populators).forEach(p -> p.accept(generateRequest)); | |||
UserTokens.GenerateWsResponse response = session.wsClient().userTokens() | |||
.generate(generateRequest); | |||
return response.getToken(); | |||
} | |||
@SafeVarargs | |||
public final User generate(Consumer<CreateRequest>... populators) { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
String login = "login" + id; | |||
CreateRequest request = new CreateRequest() | |||
.setLogin(login) | |||
.setPassword(login) | |||
.setName("name" + id) | |||
.setEmail(id + "@test.com"); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
return service().create(request).getUser(); | |||
} | |||
@SafeVarargs | |||
public final User generateApplicationCreator(Consumer<CreateRequest>... populators) { | |||
User u = generate(populators); | |||
session.wsClient().permissions().addUser( | |||
new org.sonarqube.ws.client.permissions.AddUserRequest() | |||
.setLogin(u.getLogin()) | |||
.setPermission("applicationcreator")); | |||
return u; | |||
} | |||
@SafeVarargs | |||
public final User generatePortfolioCreator(Consumer<CreateRequest>... populators) { | |||
User u = generate(populators); | |||
session.wsClient().permissions().addUser( | |||
new org.sonarqube.ws.client.permissions.AddUserRequest() | |||
.setLogin(u.getLogin()) | |||
.setPermission("portfoliocreator")); | |||
return u; | |||
} | |||
/** | |||
* For standalone mode only | |||
*/ | |||
@SafeVarargs | |||
public final User generateAdministrator(Consumer<CreateRequest>... populators) { | |||
User user = generate(populators); | |||
session.wsClient().permissions().addUser(new org.sonarqube.ws.client.permissions.AddUserRequest().setLogin(user.getLogin()).setPermission("admin")); | |||
session.wsClient().userGroups().addUser(new AddUserRequest().setLogin(user.getLogin()).setName("sonar-administrators")); | |||
return user; | |||
} | |||
public UsersService service() { | |||
return session.wsClient().users(); | |||
} | |||
public Optional<Users.SearchWsResponse.User> getByExternalLogin(String externalLogin) { | |||
return getAllUsers().stream() | |||
.filter(user -> user.getExternalIdentity().equals(externalLogin)) | |||
.collect(MoreCollectors.toOptional()); | |||
} | |||
public List<Users.SearchWsResponse.User> getAllUsers() { | |||
return service().search(new SearchRequest()).getUsersList(); | |||
} | |||
public Optional<Users.SearchWsResponse.User> getDeactivatedUserByExternalLogin(String externalLogin) { | |||
return getAllDeactivatedUsers().stream() | |||
.filter(user -> user.getExternalIdentity().equals(externalLogin)) | |||
.collect(MoreCollectors.toOptional()); | |||
} | |||
public List<Users.SearchWsResponse.User> getAllDeactivatedUsers() { | |||
return service().search(new SearchRequest().setDeactivated(true)).getUsersList(); | |||
} | |||
public Optional<Users.SearchWsResponse.User> getByLogin(String login) { | |||
return queryForUser(login, t -> t.getLogin().equals(login)); | |||
} | |||
public Optional<Users.SearchWsResponse.User> getByEmail(String email) { | |||
return queryForUser(email, t -> t.getEmail().equals(email)); | |||
} | |||
public Optional<Users.SearchWsResponse.User> getByName(String name) { | |||
return queryForUser(name, t -> t.getName().equals(name)); | |||
} | |||
public void changePassword(String login, String previousPassword, String newPassword) { | |||
service().changePassword(new ChangePasswordRequest().setLogin(login).setPreviousPassword(previousPassword).setPassword(newPassword)); | |||
} | |||
private Optional<Users.SearchWsResponse.User> queryForUser(String login, Predicate<Users.SearchWsResponse.User> predicate) { | |||
List<Users.SearchWsResponse.User> users = session.wsClient().users().search(new SearchRequest().setQ(login)).getUsersList().stream() | |||
.filter(predicate).collect(Collectors.toList()); | |||
if (users.size() == 1) { | |||
return Optional.of(users.get(0)); | |||
} | |||
return Optional.empty(); | |||
} | |||
public final String generateLogin() { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
return "login" + id; | |||
} | |||
public final String generateProviderId() { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
return "providerId" + id; | |||
} | |||
public final String generateEmail() { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
return "email" + id + "@test.com"; | |||
} | |||
public void updateIdentityProvider(String login, String externalProvider, @Nullable String externalIdentity) { | |||
session.wsClient().users().updateIdentityProvider( | |||
new UpdateIdentityProviderRequest() | |||
.setLogin(login) | |||
.setNewExternalProvider(externalProvider) | |||
.setNewExternalIdentity(externalIdentity)); | |||
} | |||
public void update(String login, Consumer<UpdateRequest>... updaters) { | |||
UpdateRequest updateRequest = new UpdateRequest(); | |||
updateRequest.setLogin(login); | |||
stream(updaters).forEach(p -> p.accept(updateRequest)); | |||
session.wsClient().users().update(updateRequest); | |||
} | |||
} |
@@ -0,0 +1,517 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import com.google.common.util.concurrent.Uninterruptibles; | |||
import com.google.gson.Gson; | |||
import java.util.List; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import java.util.function.Consumer; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.junit.rules.ExternalResource; | |||
import org.sonarqube.ws.Ce; | |||
import org.sonarqube.ws.Projects.CreateWsResponse.Project; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.ce.ActivityStatusRequest; | |||
import org.sonarqube.ws.client.projects.ProjectsService; | |||
import org.sonarqube.ws.client.projects.SearchRequest; | |||
import org.sonarqube.ws.client.views.CreateRequest; | |||
import org.sonarqube.ws.client.views.DeleteRequest; | |||
import org.sonarqube.ws.client.views.ProjectsRequest; | |||
import org.sonarqube.ws.client.views.RefreshRequest; | |||
import org.sonarqube.ws.client.views.ShowRequest; | |||
import org.sonarqube.ws.client.views.ViewsService; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Arrays.stream; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class ViewTester extends ExternalResource { | |||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); | |||
private final TesterSession session; | |||
ViewTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
public ViewsService service() { | |||
return session.wsClient().views(); | |||
} | |||
public void deleteAll() { | |||
ProjectsService service = session.wsClient().projects(); | |||
service.search(new SearchRequest().setQualifiers(asList("VW"))).getComponentsList() | |||
.forEach(p -> { | |||
waitForCeQueueEmpty(); | |||
session.wsClient().views().delete(new DeleteRequest().setKey(p.getKey())); | |||
}); | |||
waitForCeQueueEmpty(); | |||
org.sonarqube.ws.client.components.SearchRequest searchRequest = new org.sonarqube.ws.client.components.SearchRequest().setQualifiers(asList("VW", "SVW")); | |||
assertThat(session.wsClient().components().search(searchRequest).getComponentsList()).isEmpty(); | |||
assertNotViewInDef(); | |||
} | |||
@SafeVarargs | |||
public final CreateRequest generate(Consumer<CreateRequest>... populators) { | |||
String key = generateKey(); | |||
CreateRequest request = new CreateRequest() | |||
.setKey(key) | |||
.setName("Name " + key) | |||
.setDescription("Description " + key); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
service().create(request); | |||
return request; | |||
} | |||
@SafeVarargs | |||
public final String createSubPortfolio(String parentKey, Consumer<CreateRequest>... populators) { | |||
String key = generateKey(); | |||
CreateRequest request = new CreateRequest() | |||
.setParent(parentKey) | |||
.setKey(key) | |||
.setName("Sub view name " + key) | |||
.setDescription("Sub view description " + key); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
service().create(request); | |||
return request.getKey(); | |||
} | |||
public void addProject(String viewKey, Project project) { | |||
addProject(viewKey, project.getKey()); | |||
} | |||
public void addProject(String viewKey, String projectKey) { | |||
session.wsClient().wsConnector().call( | |||
new PostRequest("/api/views/add_project") | |||
.setParam("key", viewKey) | |||
.setParam("project", projectKey)) | |||
.failIfNotSuccessful(); | |||
} | |||
public void addProjectBranch(String viewKey, String projectKey, String branch) { | |||
session.wsClient().wsConnector().call( | |||
new PostRequest("/api/views/add_project_branch") | |||
.setParam("key", viewKey) | |||
.setParam("project", projectKey) | |||
.setParam("branch", branch)) | |||
.failIfNotSuccessful(); | |||
} | |||
public AddLocalReferenceResponse addPortfolio(String key, String portfolioRefKey) { | |||
return AddLocalReferenceResponse.parse(session.wsClient().wsConnector().call( | |||
new PostRequest("/api/views/add_portfolio") | |||
.setParam("portfolio", key) | |||
.setParam("reference", portfolioRefKey)) | |||
.failIfNotSuccessful().content()); | |||
} | |||
public MoveResponse move(String key, String destinationKey) { | |||
return MoveResponse.parse(session.wsClient().wsConnector().call( | |||
new PostRequest("/api/views/move") | |||
.setParam("key", key) | |||
.setParam("destination", destinationKey)) | |||
.failIfNotSuccessful().content()); | |||
} | |||
public String generateKey() { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
return "viewKey" + id; | |||
} | |||
public void refresh() { | |||
service().refresh(new RefreshRequest()); | |||
waitForCeQueueEmpty(); | |||
} | |||
public ViewTester waitForCeQueueEmpty() { | |||
Ce.ActivityStatusWsResponse status; | |||
boolean empty; | |||
do { | |||
status = session.wsClient().ce().activityStatus(new ActivityStatusRequest()); | |||
empty = status.getInProgress() + status.getPending() == 0; | |||
if (!empty) { | |||
Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); | |||
} | |||
} while (!empty); | |||
return this; | |||
} | |||
public ListResponse list() { | |||
return ListResponse.parse(service().list()); | |||
} | |||
public ShowResponse show(ShowRequest showRequest) { | |||
return ShowResponse.parse(service().show(showRequest)); | |||
} | |||
public ProjectsResponse projects(ProjectsRequest request) { | |||
return ProjectsResponse.parse(service().projects(request)); | |||
} | |||
public SearchResponse search(org.sonarqube.ws.client.views.SearchRequest searchRequest) { | |||
return SearchResponse.parse(service().search(searchRequest)); | |||
} | |||
private void assertNotViewInDef() { | |||
assertThat(ListResponse.parse(service().list()).getViews()).isEmpty(); | |||
} | |||
public static class ShowResponse { | |||
private final String key; | |||
private final String name; | |||
private final String desc; | |||
private final String qualifier; | |||
private final String selectionMode; | |||
private final String regexp; | |||
private final List<SelectedProject> selectedProjects; | |||
private final List<SubView> subViews; | |||
private final List<String> tags; | |||
public ShowResponse(String key, String name, String desc, String qualifier, String selectionMode, String regexp, | |||
List<SelectedProject> selectedProjects, @Nullable List<SubView> subViews, List<String> tags) { | |||
this.key = key; | |||
this.name = name; | |||
this.desc = desc; | |||
this.qualifier = qualifier; | |||
this.selectionMode = selectionMode; | |||
this.regexp = regexp; | |||
this.selectedProjects = selectedProjects; | |||
this.subViews = subViews; | |||
this.tags = tags; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public String getDesc() { | |||
return desc; | |||
} | |||
public String getQualifier() { | |||
return qualifier; | |||
} | |||
public List<SelectedProject> getSelectedProjects() { | |||
return selectedProjects; | |||
} | |||
public String getSelectionMode() { | |||
return selectionMode; | |||
} | |||
public String getRegexp() { | |||
return regexp; | |||
} | |||
public List<String> getTags() { | |||
return tags; | |||
} | |||
@CheckForNull | |||
public List<SubView> getSubViews() { | |||
return subViews; | |||
} | |||
public static ShowResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, ShowResponse.class); | |||
} | |||
public static class SelectedProject { | |||
private final String projectKey; | |||
private final List<String> selectedBranches; | |||
public SelectedProject(String projectKey, List<String> selectedBranches) { | |||
this.projectKey = projectKey; | |||
this.selectedBranches = selectedBranches; | |||
} | |||
public String getProjectKey() { | |||
return projectKey; | |||
} | |||
public List<String> getSelectedBranches() { | |||
return selectedBranches; | |||
} | |||
} | |||
public static class SubView { | |||
private final String key; | |||
private final String name; | |||
private final String desc; | |||
private final String selectionMode; | |||
private final String originalKey; | |||
private final String manual_measure_key; | |||
private final String manual_measure_value; | |||
private final List<SubView> subViews; | |||
public SubView(String key, String name, String desc, String selectionMode, String originalKey, String manual_measure_key, String manual_measure_value, | |||
List<SubView> subViews) { | |||
this.key = key; | |||
this.name = name; | |||
this.desc = desc; | |||
this.selectionMode = selectionMode; | |||
this.originalKey = originalKey; | |||
this.manual_measure_key = manual_measure_key; | |||
this.manual_measure_value = manual_measure_value; | |||
this.subViews = subViews; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public String getDesc() { | |||
return desc; | |||
} | |||
public String getSelectionMode() { | |||
return selectionMode; | |||
} | |||
public String getOriginalKey() { | |||
return originalKey; | |||
} | |||
public String getManual_measure_key() { | |||
return manual_measure_key; | |||
} | |||
public String getManual_measure_value() { | |||
return manual_measure_value; | |||
} | |||
public List<SubView> getSubViews() { | |||
return subViews; | |||
} | |||
} | |||
} | |||
public static class ListResponse { | |||
private List<View> views; | |||
private ListResponse(List<View> views) { | |||
this.views = views; | |||
} | |||
public List<View> getViews() { | |||
return views; | |||
} | |||
public static ListResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, ListResponse.class); | |||
} | |||
public static class View { | |||
private final String key; | |||
private final String name; | |||
private final String qualifier; | |||
private View(String key, String name, String qualifier) { | |||
this.key = key; | |||
this.name = name; | |||
this.qualifier = qualifier; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public String getQualifier() { | |||
return qualifier; | |||
} | |||
public static View parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, View.class); | |||
} | |||
} | |||
} | |||
public static class AddLocalReferenceResponse { | |||
private final String key; | |||
private final String name; | |||
public AddLocalReferenceResponse(String key, String name) { | |||
this.key = key; | |||
this.name = name; | |||
} | |||
public static AddLocalReferenceResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, AddLocalReferenceResponse.class); | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
} | |||
public static class ProjectsResponse { | |||
private List<Project> results; | |||
private boolean more; | |||
public ProjectsResponse(List<Project> results, boolean more) { | |||
this.results = results; | |||
this.more = more; | |||
} | |||
public List<Project> getProjects() { | |||
return results; | |||
} | |||
public boolean isMore() { | |||
return more; | |||
} | |||
public static ProjectsResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, ProjectsResponse.class); | |||
} | |||
public static class Project { | |||
private final String key; | |||
private final String name; | |||
private final boolean selected; | |||
private final boolean enabled; | |||
private Project(String key, String name, boolean selected, boolean enabled) { | |||
this.key = key; | |||
this.name = name; | |||
this.selected = selected; | |||
this.enabled = enabled; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public boolean isSelected() { | |||
return selected; | |||
} | |||
public boolean isEnabled() { | |||
return enabled; | |||
} | |||
} | |||
} | |||
public static class SearchResponse { | |||
private List<Component> components; | |||
private SearchResponse(List<Component> components) { | |||
this.components = components; | |||
} | |||
public List<Component> getComponents() { | |||
return components; | |||
} | |||
public static SearchResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, SearchResponse.class); | |||
} | |||
public static class Component { | |||
private final String key; | |||
private final String name; | |||
private final String qualifier; | |||
private Component(String key, String name, String qualifier) { | |||
this.key = key; | |||
this.name = name; | |||
this.qualifier = qualifier; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public String getQualifier() { | |||
return qualifier; | |||
} | |||
public static Component parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, Component.class); | |||
} | |||
} | |||
} | |||
public static class MoveResponse { | |||
private final String key; | |||
private final String name; | |||
public MoveResponse(String key, String name) { | |||
this.key = key; | |||
this.name = name; | |||
} | |||
public static MoveResponse parse(String json) { | |||
Gson gson = new Gson(); | |||
return gson.fromJson(json, MoveResponse.class); | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
} | |||
} |
@@ -0,0 +1,107 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.tester; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
import java.util.function.Consumer; | |||
import javax.annotation.Nullable; | |||
import org.assertj.core.api.Assertions; | |||
import org.sonarqube.ws.Projects.CreateWsResponse.Project; | |||
import org.sonarqube.ws.Webhooks.CreateWsResponse.Webhook; | |||
import org.sonarqube.ws.Webhooks.Delivery; | |||
import org.sonarqube.ws.client.webhooks.CreateRequest; | |||
import org.sonarqube.ws.client.webhooks.DeleteRequest; | |||
import org.sonarqube.ws.client.webhooks.DeliveriesRequest; | |||
import org.sonarqube.ws.client.webhooks.DeliveryRequest; | |||
import org.sonarqube.ws.client.webhooks.ListRequest; | |||
import org.sonarqube.ws.client.webhooks.WebhooksService; | |||
import static java.util.Arrays.stream; | |||
import static java.util.Objects.requireNonNull; | |||
public class WebhookTester { | |||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); | |||
private final TesterSession session; | |||
WebhookTester(TesterSession session) { | |||
this.session = session; | |||
} | |||
public WebhooksService service() { | |||
return session.wsClient().webhooks(); | |||
} | |||
@SafeVarargs | |||
public final Webhook generate(Consumer<CreateRequest>... populators) { | |||
return generate(null, populators); | |||
} | |||
@SafeVarargs | |||
public final Webhook generate( | |||
@Nullable Project project, | |||
Consumer<CreateRequest>... populators) { | |||
int id = ID_GENERATOR.getAndIncrement(); | |||
CreateRequest request = new CreateRequest() | |||
.setName("Webhook " + id) | |||
.setUrl("https://webhook-" + id) | |||
.setProject(project != null ? project.getKey() : null); | |||
stream(populators).forEach(p -> p.accept(request)); | |||
return service().create(request).getWebhook(); | |||
} | |||
public void deleteAllGlobal() { | |||
service().list(new ListRequest()).getWebhooksList().forEach(p -> service().delete(new DeleteRequest().setWebhook(p.getKey()))); | |||
} | |||
public List<Delivery> getPersistedDeliveries(Project project) { | |||
DeliveriesRequest deliveriesReq = new DeliveriesRequest().setComponentKey(project.getKey()); | |||
return service().deliveries(deliveriesReq).getDeliveriesList(); | |||
} | |||
public Delivery getPersistedDeliveryByName(Project project, String webhookName) { | |||
List<Delivery> deliveries = getPersistedDeliveries(project); | |||
Optional<Delivery> delivery = deliveries.stream().filter(d -> d.getName().equals(webhookName)).findFirst(); | |||
Assertions.assertThat(delivery).isPresent(); | |||
return delivery.get(); | |||
} | |||
public Delivery getDetailOfPersistedDelivery(Delivery delivery) { | |||
Delivery detail = service().delivery(new DeliveryRequest().setDeliveryId(delivery.getId())).getDelivery(); | |||
return requireNonNull(detail); | |||
} | |||
public void assertThatPersistedDeliveryIsValid(Delivery delivery, @Nullable Project project, @Nullable String url) { | |||
Assertions.assertThat(delivery.getId()).isNotEmpty(); | |||
Assertions.assertThat(delivery.getName()).isNotEmpty(); | |||
Assertions.assertThat(delivery.hasSuccess()).isTrue(); | |||
Assertions.assertThat(delivery.getHttpStatus()).isGreaterThanOrEqualTo(200); | |||
Assertions.assertThat(delivery.getDurationMs()).isGreaterThanOrEqualTo(0); | |||
Assertions.assertThat(delivery.getAt()).isNotEmpty(); | |||
if (project != null) { | |||
Assertions.assertThat(delivery.getComponentKey()).isEqualTo(project.getKey()); | |||
} | |||
if (url != null) { | |||
Assertions.assertThat(delivery.getUrl()).startsWith(url); | |||
} | |||
} | |||
} |