| // Copyright (C) 2017 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.googlesource.gerrit.plugins.findowners; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block; |
| import static com.google.gerrit.entities.RefNames.REFS_CONFIG; |
| import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| |
| import com.google.gerrit.acceptance.LightweightPluginDaemonTest; |
| import com.google.gerrit.acceptance.PushOneCommit; |
| import com.google.gerrit.acceptance.RestResponse; |
| import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; |
| import com.google.gerrit.common.data.Permission; |
| import com.google.gerrit.entities.BranchNameKey; |
| import com.google.gerrit.entities.Project; |
| import com.google.gerrit.entities.RefNames; |
| import com.google.gerrit.extensions.api.changes.SubmitInput; |
| import com.google.gerrit.extensions.api.projects.BranchApi; |
| import com.google.gerrit.extensions.client.ChangeStatus; |
| import com.google.gerrit.extensions.common.ChangeInfo; |
| import com.google.gerrit.extensions.common.ChangeInput; |
| import com.google.gerrit.server.account.Emails; |
| import com.google.gerrit.server.patch.PatchListCache; |
| import com.google.gerrit.server.permissions.PermissionBackend; |
| import com.google.inject.Inject; |
| import org.eclipse.jgit.lib.ObjectLoader; |
| import org.eclipse.jgit.revwalk.RevObject; |
| import org.eclipse.jgit.revwalk.RevTree; |
| import org.eclipse.jgit.revwalk.RevWalk; |
| import org.eclipse.jgit.transport.RefSpec; |
| import org.eclipse.jgit.treewalk.TreeWalk; |
| import org.eclipse.jgit.treewalk.filter.PathFilterGroup; |
| import org.junit.Before; |
| |
| /** Abstract base class for find-owners plugin integration tests. */ |
| public abstract class FindOwners extends LightweightPluginDaemonTest { |
| |
| @Inject protected Emails emails; |
| @Inject protected PermissionBackend permissionBackend; |
| @Inject protected ProjectOperations projectOperations; |
| @Inject protected PatchListCache patchListCache; |
| |
| protected static final String PLUGIN_NAME = "find-owners"; |
| protected Config config; |
| |
| @Before |
| public void setConfig() { |
| config = new Config(pluginConfig, null, null, null, null); |
| } |
| |
| protected String oneOwnerList(String email) { |
| return "owners:[ " + ownerJson(email) + " ]"; |
| } |
| |
| protected String ownerJson(String email) { |
| return "{ email:" + email + ", weights:[ 1, 0, 0 ] }"; |
| } |
| |
| protected String ownerJson(String email, int w1, int w2, int w3) { |
| return "{ email:" + email + ", weights:[ " + w1 + ", " + w2 + ", " + w3 + " ] }"; |
| } |
| |
| protected ChangeInfo newChangeInfo(String subject) throws Exception { |
| ChangeInput in = new ChangeInput(); |
| in.project = project.get(); |
| in.branch = "master"; |
| in.subject = subject; |
| in.topic = ""; |
| in.status = ChangeStatus.NEW; |
| return gApi.changes().create(in).get(); |
| } |
| |
| protected String getFindOwnersResponse(ChangeInfo info) throws Exception { |
| return filteredJson( |
| userRestSession.get("/changes/" + info._number + "/revisions/1/" + PLUGIN_NAME)); |
| } |
| |
| protected String getOwnersResponse(ChangeInfo info) throws Exception { |
| return filteredJson(userRestSession.get("/changes/" + info._number + "/owners")); |
| } |
| |
| protected String getOwnersResponse(PushOneCommit.Result change) throws Exception { |
| return filteredJson(userRestSession.get("/changes/" + change.getChangeId() + "/owners")); |
| } |
| |
| protected String getOwnersDebugResponse(PushOneCommit.Result change) throws Exception { |
| return filteredJson( |
| userRestSession.get("/changes/" + change.getChangeId() + "/owners?debug=1")); |
| } |
| |
| protected void approveSubmit(PushOneCommit.Result change) throws Exception { |
| approve(change.getChangeId()); |
| gApi.changes().id(change.getChangeId()).current().submit(new SubmitInput()); |
| } |
| |
| protected PushOneCommit.Result addFile(String subject, String file, String content) |
| throws Exception { |
| PushOneCommit.Result c = createChange(subject, file, content); |
| approveSubmit(c); |
| return c; |
| } |
| |
| protected void switchProject(Project.NameKey p) throws Exception { |
| project = p; |
| testRepo = cloneProject(project); |
| } |
| |
| protected void blockRead(Project.NameKey p) throws Exception { |
| projectOperations |
| .project(p) |
| .forUpdate() |
| .add(block(Permission.READ).ref("refs/heads/master").group(REGISTERED_USERS)) |
| .update(); |
| } |
| |
| protected org.eclipse.jgit.lib.Config readProjectConfig() throws Exception { |
| git().fetch().setRefSpecs(new RefSpec(REFS_CONFIG + ":" + REFS_CONFIG)).call(); |
| testRepo.reset(RefNames.REFS_CONFIG); |
| RevWalk rw = testRepo.getRevWalk(); |
| RevTree tree = rw.parseTree(testRepo.getRepository().resolve("HEAD")); |
| |
| try (TreeWalk treeWalk = new TreeWalk(rw.getObjectReader())) { |
| treeWalk.setFilter(PathFilterGroup.createFromStrings("project.config")); |
| treeWalk.reset(tree); |
| boolean hasProjectConfig = treeWalk.next(); |
| if (!hasProjectConfig) { |
| return new org.eclipse.jgit.lib.Config(); |
| } |
| } |
| |
| RevObject obj = rw.parseAny(testRepo.get(tree, "project.config")); |
| ObjectLoader loader = rw.getObjectReader().open(obj); |
| String text = new String(loader.getCachedBytes(), UTF_8); |
| org.eclipse.jgit.lib.Config cfg = new org.eclipse.jgit.lib.Config(); |
| cfg.fromText(text); |
| return cfg; |
| } |
| |
| protected void setProjectConfig(String var, String value) throws Exception { |
| org.eclipse.jgit.lib.Config cfg = readProjectConfig(); |
| cfg.setString("plugin", PLUGIN_NAME, var, value); |
| assertThat(cfg.getString("plugin", PLUGIN_NAME, var)).isEqualTo(value); |
| PushOneCommit.Result commit = |
| pushFactory |
| .create( |
| admin.newIdent(), // normal user cannot change refs/meta/config |
| testRepo, |
| "Update project config", |
| "project.config", |
| cfg.toText()) |
| .to("refs/for/" + REFS_CONFIG); |
| commit.assertOkStatus(); |
| approveSubmit(commit); |
| testRepo = cloneProject(project); // reset the testRepo after cfg change |
| } |
| |
| protected int checkApproval(PushOneCommit.Result r) throws Exception { |
| Project.NameKey project = r.getChange().project(); |
| Cache cache = getCache().init(0, 0); |
| OwnersDb db = |
| cache.get( |
| true, |
| null, |
| projectCache.get(project), |
| accountCache, |
| emails, |
| repoManager, |
| r.getChange(), |
| 1); |
| Checker c = |
| new Checker( |
| accountCache, |
| patchListCache, |
| repoManager, |
| emails, |
| pluginConfig, |
| null, |
| r.getChange(), |
| 1); |
| return c.findApproval(db); |
| } |
| |
| // To simplify test case code, the REST API returned JSON string is filtered to |
| // remove '\t', ' ' and '"', but replace "\\\"" with '"', |
| // replace '\n' with space, remove "owner_revision:*" and "HostName:*", |
| // and replace some unicode with simple characters. |
| protected static String filteredJson(String json) { |
| return json.replaceAll("[\t ]", "") |
| .replace("\\\"", "\t") |
| .replace("\"", "") |
| .replace('\t', '"') |
| .replace('\n', ' ') |
| .replaceAll("owner_revision:[^ ]* ", "") |
| .replaceAll("HostName:[^ ]*, ", "") |
| .replace("\\u0027", "'") |
| .replace("\\u003d", "=") |
| .replace("\\u003e", ">"); |
| } |
| |
| protected static String filteredJson(RestResponse response) throws Exception { |
| return filteredJson(response.getEntityContent()); |
| } |
| |
| protected String myProjectName(String test, String project) { |
| return this.getClass().getName() + "_" + test + "_" + project; |
| } |
| |
| protected String idProject(String test, String project) { |
| return idProject(myProjectName(test, project)); |
| } |
| |
| protected String idProject(String name) { |
| // Expected string of "id": "name",, |
| return "\"id\": \"" + name + "\","; |
| } |
| |
| protected static void verifyRestResult( |
| RestResult result, int voteLevel, int patchset, int changeNumber, boolean addDebugMsg) |
| throws Exception { |
| assertThat(result.minOwnerVoteLevel).isEqualTo(voteLevel); |
| assertThat(result.patchset).isEqualTo(patchset); |
| assertThat(result.change).isEqualTo(changeNumber); |
| assertThat(result.addDebugMsg).isEqualTo(addDebugMsg); |
| if (addDebugMsg) { |
| assertThat(result.dbgmsgs).isNotNull(); |
| } else { |
| assertThat(result.dbgmsgs).isNull(); |
| } |
| } |
| |
| protected BranchApi createBranch(String branch) throws Exception { |
| return createBranch(BranchNameKey.create(project, branch)); |
| } |
| |
| protected PushOneCommit.Result createChangeInBranch( |
| String branch, String subject, String fileName, String content) throws Exception { |
| PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo, subject, fileName, content); |
| return push.to("refs/for/" + branch); |
| } |
| |
| protected Project.NameKey newProject(String name) { |
| return newProject(name, Project.nameKey("All-Projects")); |
| } |
| |
| protected Project.NameKey newProject(String name, Project.NameKey parent) { |
| return projectOperations.newProject().parent(parent).name(name).create(); |
| } |
| |
| protected String projectOwnersFileName(Project.NameKey name) { |
| // This function is called repeatedly in ConfigIT without recreating config. |
| // So, here we recreate config, to get the latest owners file name. |
| setConfig(); |
| return config.getOwnersFileName(projectCache.get(name), null); |
| } |
| |
| protected Cache getCache() { |
| return Cache.getInstance(config, repoManager); |
| } |
| } |