blob: cae8fecc055806e693f6960a683a4a8c928462b8 [file] [log] [blame]
// Copyright (C) 2011 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.git;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import com.google.common.collect.Iterables;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.ContributorAgreement;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.project.CommentLinkInfoImpl;
import com.google.gwtorm.client.KeyUtil;
import com.google.gwtorm.server.StandardKeyEncoder;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.util.RawParseUtils;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class ProjectConfigTest extends LocalDiskRepositoryTestCase {
private static final String LABEL_SCORES_CONFIG =
" copyMinScore = "
+ !LabelType.DEF_COPY_MIN_SCORE
+ "\n" //
+ " copyMaxScore = "
+ !LabelType.DEF_COPY_MAX_SCORE
+ "\n" //
+ " copyAllScoresOnMergeFirstParentUpdate = "
+ !LabelType.DEF_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE
+ "\n" //
+ " copyAllScoresOnTrivialRebase = "
+ !LabelType.DEF_COPY_ALL_SCORES_ON_TRIVIAL_REBASE
+ "\n" //
+ " copyAllScoresIfNoCodeChange = "
+ !LabelType.DEF_COPY_ALL_SCORES_IF_NO_CODE_CHANGE
+ "\n" //
+ " copyAllScoresIfNoChange = "
+ !LabelType.DEF_COPY_ALL_SCORES_IF_NO_CHANGE
+ "\n";
private final GroupReference developers =
new GroupReference(new AccountGroup.UUID("X"), "Developers");
private final GroupReference staff = new GroupReference(new AccountGroup.UUID("Y"), "Staff");
private Repository db;
private TestRepository<Repository> util;
@BeforeClass
public static void setUpOnce() {
KeyUtil.setEncoderImpl(new StandardKeyEncoder());
}
@Override
@Before
public void setUp() throws Exception {
super.setUp();
db = createBareRepository();
util = new TestRepository<>(db);
}
@Test
public void readConfig() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[access \"refs/heads/*\"]\n" //
+ " exclusiveGroupPermissions = read submit create\n" //
+ " submit = group Developers\n" //
+ " push = group Developers\n" //
+ " read = group Developers\n" //
+ "[accounts]\n" //
+ " sameGroupVisibility = deny group Developers\n" //
+ " sameGroupVisibility = block group Staff\n" //
+ "[contributor-agreement \"Individual\"]\n" //
+ " description = A simple description\n" //
+ " accepted = group Developers\n" //
+ " accepted = group Staff\n" //
+ " autoVerify = group Developers\n" //
+ " agreementUrl = http://www.example.com/agree\n")) //
));
ProjectConfig cfg = read(rev);
assertThat(cfg.getAccountsSection().getSameGroupVisibility()).hasSize(2);
ContributorAgreement ca = cfg.getContributorAgreement("Individual");
assertThat(ca.getName()).isEqualTo("Individual");
assertThat(ca.getDescription()).isEqualTo("A simple description");
assertThat(ca.getAgreementUrl()).isEqualTo("http://www.example.com/agree");
assertThat(ca.getAccepted()).hasSize(2);
assertThat(ca.getAccepted().get(0).getGroup()).isEqualTo(developers);
assertThat(ca.getAccepted().get(1).getGroup().getName()).isEqualTo("Staff");
assertThat(ca.getAutoVerify().getName()).isEqualTo("Developers");
AccessSection section = cfg.getAccessSection("refs/heads/*");
assertThat(section).isNotNull();
assertThat(cfg.getAccessSection("refs/*")).isNull();
Permission create = section.getPermission(Permission.CREATE);
Permission submit = section.getPermission(Permission.SUBMIT);
Permission read = section.getPermission(Permission.READ);
Permission push = section.getPermission(Permission.PUSH);
assertThat(create.getExclusiveGroup()).isTrue();
assertThat(submit.getExclusiveGroup()).isTrue();
assertThat(read.getExclusiveGroup()).isTrue();
assertThat(push.getExclusiveGroup()).isFalse();
}
@Test
public void readConfigLabelDefaultValue() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[label \"CustomLabel\"]\n" //
+ " value = -1 Negative\n" //
+ " value = 0 No Score\n" //
+ " value = 1 Positive\n")) //
));
ProjectConfig cfg = read(rev);
Map<String, LabelType> labels = cfg.getLabelSections();
Short dv = labels.entrySet().iterator().next().getValue().getDefaultValue();
assertThat((int) dv).isEqualTo(0);
}
@Test
public void readConfigLabelDefaultValueInRange() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[label \"CustomLabel\"]\n" //
+ " value = -1 Negative\n" //
+ " value = 0 No Score\n" //
+ " value = 1 Positive\n" //
+ " defaultValue = -1\n")) //
));
ProjectConfig cfg = read(rev);
Map<String, LabelType> labels = cfg.getLabelSections();
Short dv = labels.entrySet().iterator().next().getValue().getDefaultValue();
assertThat((int) dv).isEqualTo(-1);
}
@Test
public void readConfigLabelDefaultValueNotInRange() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[label \"CustomLabel\"]\n" //
+ " value = -1 Negative\n" //
+ " value = 0 No Score\n" //
+ " value = 1 Positive\n" //
+ " defaultValue = -2\n")) //
));
ProjectConfig cfg = read(rev);
assertThat(cfg.getValidationErrors()).hasSize(1);
assertThat(Iterables.getOnlyElement(cfg.getValidationErrors()).getMessage())
.isEqualTo("project.config: Invalid defaultValue \"-2\" for label \"CustomLabel\"");
}
@Test
public void readConfigLabelScores() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[label \"CustomLabel\"]\n" //
+ LABEL_SCORES_CONFIG)) //
));
ProjectConfig cfg = read(rev);
Map<String, LabelType> labels = cfg.getLabelSections();
LabelType type = labels.entrySet().iterator().next().getValue();
assertThat(type.isCopyMinScore()).isNotEqualTo(LabelType.DEF_COPY_MIN_SCORE);
assertThat(type.isCopyMaxScore()).isNotEqualTo(LabelType.DEF_COPY_MAX_SCORE);
assertThat(type.isCopyAllScoresOnMergeFirstParentUpdate())
.isNotEqualTo(LabelType.DEF_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE);
assertThat(type.isCopyAllScoresOnTrivialRebase())
.isNotEqualTo(LabelType.DEF_COPY_ALL_SCORES_ON_TRIVIAL_REBASE);
assertThat(type.isCopyAllScoresIfNoCodeChange())
.isNotEqualTo(LabelType.DEF_COPY_ALL_SCORES_IF_NO_CODE_CHANGE);
assertThat(type.isCopyAllScoresIfNoChange())
.isNotEqualTo(LabelType.DEF_COPY_ALL_SCORES_IF_NO_CHANGE);
}
@Test
public void editConfig() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[access \"refs/heads/*\"]\n" //
+ " exclusiveGroupPermissions = read submit\n" //
+ " submit = group Developers\n" //
+ " upload = group Developers\n" //
+ " read = group Developers\n" //
+ "[accounts]\n" //
+ " sameGroupVisibility = deny group Developers\n" //
+ " sameGroupVisibility = block group Staff\n" //
+ "[contributor-agreement \"Individual\"]\n" //
+ " description = A simple description\n" //
+ " accepted = group Developers\n" //
+ " autoVerify = group Developers\n" //
+ " agreementUrl = http://www.example.com/agree\n" //
+ "[label \"CustomLabel\"]\n" //
+ LABEL_SCORES_CONFIG)) //
));
update(rev);
ProjectConfig cfg = read(rev);
AccessSection section = cfg.getAccessSection("refs/heads/*");
cfg.getAccountsSection()
.setSameGroupVisibility(Collections.singletonList(new PermissionRule(cfg.resolve(staff))));
Permission submit = section.getPermission(Permission.SUBMIT);
submit.add(new PermissionRule(cfg.resolve(staff)));
ContributorAgreement ca = cfg.getContributorAgreement("Individual");
ca.setAccepted(Collections.singletonList(new PermissionRule(cfg.resolve(staff))));
ca.setAutoVerify(null);
ca.setDescription("A new description");
rev = commit(cfg);
assertThat(text(rev, "project.config"))
.isEqualTo(
"" //
+ "[access \"refs/heads/*\"]\n" //
+ " exclusiveGroupPermissions = read submit\n" //
+ " submit = group Developers\n" //
+ "\tsubmit = group Staff\n" //
+ " upload = group Developers\n" //
+ " read = group Developers\n" //
+ "[accounts]\n" //
+ " sameGroupVisibility = group Staff\n" //
+ "[contributor-agreement \"Individual\"]\n" //
+ " description = A new description\n" //
+ " accepted = group Staff\n" //
+ " agreementUrl = http://www.example.com/agree\n"
+ "[label \"CustomLabel\"]\n" //
+ LABEL_SCORES_CONFIG
+ "\tfunction = MaxWithBlock\n" // label gets this function when it is created
+ "\tdefaultValue = 0\n"); // label gets this value when it is created
}
@Test
public void editConfigMissingGroupTableEntry() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[access \"refs/heads/*\"]\n" //
+ " exclusiveGroupPermissions = read submit\n" //
+ " submit = group People Who Can Submit\n" //
+ " upload = group Developers\n" //
+ " read = group Developers\n")) //
));
update(rev);
ProjectConfig cfg = read(rev);
AccessSection section = cfg.getAccessSection("refs/heads/*");
Permission submit = section.getPermission(Permission.SUBMIT);
submit.add(new PermissionRule(cfg.resolve(staff)));
rev = commit(cfg);
assertThat(text(rev, "project.config"))
.isEqualTo(
"" //
+ "[access \"refs/heads/*\"]\n" //
+ " exclusiveGroupPermissions = read submit\n" //
+ " submit = group People Who Can Submit\n" //
+ "\tsubmit = group Staff\n" //
+ " upload = group Developers\n" //
+ " read = group Developers\n");
}
@Test
public void readExistingPluginConfig() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file(
"project.config",
util.blob(
"" //
+ "[plugin \"somePlugin\"]\n" //
+ " key1 = value1\n" //
+ " key2 = value2a\n"
+ " key2 = value2b\n")) //
));
update(rev);
ProjectConfig cfg = read(rev);
PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
assertThat(pluginCfg.getNames()).hasSize(2);
assertThat(pluginCfg.getString("key1")).isEqualTo("value1");
assertThat(pluginCfg.getStringList(("key2"))).isEqualTo(new String[] {"value2a", "value2b"});
}
@Test
public void readUnexistingPluginConfig() throws Exception {
ProjectConfig cfg = new ProjectConfig(new Project.NameKey("test"));
cfg.load(db);
PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
assertThat(pluginCfg.getNames()).isEmpty();
}
@Test
public void editPluginConfig() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file(
"project.config",
util.blob(
"" //
+ "[plugin \"somePlugin\"]\n" //
+ " key1 = value1\n" //
+ " key2 = value2a\n" //
+ " key2 = value2b\n")) //
));
update(rev);
ProjectConfig cfg = read(rev);
PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
pluginCfg.setString("key1", "updatedValue1");
pluginCfg.setStringList("key2", Arrays.asList("updatedValue2a", "updatedValue2b"));
rev = commit(cfg);
assertThat(text(rev, "project.config"))
.isEqualTo(
"" //
+ "[plugin \"somePlugin\"]\n" //
+ "\tkey1 = updatedValue1\n" //
+ "\tkey2 = updatedValue2a\n" //
+ "\tkey2 = updatedValue2b\n");
}
@Test
public void readPluginConfigGroupReference() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[plugin \"somePlugin\"]\n" //
+ "key1 = "
+ developers.toConfigValue()
+ "\n")) //
));
update(rev);
ProjectConfig cfg = read(rev);
PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
assertThat(pluginCfg.getNames()).hasSize(1);
assertThat(pluginCfg.getGroupReference("key1")).isEqualTo(developers);
}
@Test
public void readPluginConfigGroupReferenceNotInGroupsFile() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[plugin \"somePlugin\"]\n" //
+ "key1 = "
+ staff.toConfigValue()
+ "\n")) //
));
update(rev);
ProjectConfig cfg = read(rev);
assertThat(cfg.getValidationErrors()).hasSize(1);
assertThat(Iterables.getOnlyElement(cfg.getValidationErrors()).getMessage())
.isEqualTo(
"project.config: group \"" + staff.getName() + "\" not in " + GroupList.FILE_NAME);
}
@Test
public void editPluginConfigGroupReference() throws Exception {
RevCommit rev =
util.commit(
util.tree( //
util.file("groups", util.blob(group(developers))), //
util.file(
"project.config",
util.blob(
"" //
+ "[plugin \"somePlugin\"]\n" //
+ "key1 = "
+ developers.toConfigValue()
+ "\n")) //
));
update(rev);
ProjectConfig cfg = read(rev);
PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
assertThat(pluginCfg.getNames()).hasSize(1);
assertThat(pluginCfg.getGroupReference("key1")).isEqualTo(developers);
pluginCfg.setGroupReference("key1", staff);
rev = commit(cfg);
assertThat(text(rev, "project.config"))
.isEqualTo(
"" //
+ "[plugin \"somePlugin\"]\n" //
+ "\tkey1 = "
+ staff.toConfigValue()
+ "\n");
assertThat(text(rev, "groups"))
.isEqualTo(
"# UUID\tGroup Name\n" //
+ "#\n" //
+ staff.getUUID().get()
+ " \t"
+ staff.getName()
+ "\n");
}
@Test
public void addCommentLink() throws Exception {
RevCommit rev = util.commit().create();
update(rev);
ProjectConfig cfg = read(rev);
CommentLinkInfoImpl cm = new CommentLinkInfoImpl("Test", "abc.*", null, "<a>link</a>", true);
cfg.addCommentLinkSection(cm);
rev = commit(cfg);
assertThat(text(rev, "project.config"))
.isEqualTo("[commentlink \"Test\"]\n\tmatch = abc.*\n\thtml = <a>link</a>\n");
}
private ProjectConfig read(RevCommit rev) throws IOException, ConfigInvalidException {
ProjectConfig cfg = new ProjectConfig(new Project.NameKey("test"));
cfg.load(db, rev);
return cfg;
}
private RevCommit commit(ProjectConfig cfg)
throws IOException, MissingObjectException, IncorrectObjectTypeException {
try (MetaDataUpdate md =
new MetaDataUpdate(GitReferenceUpdated.DISABLED, cfg.getProject().getNameKey(), db)) {
util.tick(5);
util.setAuthorAndCommitter(md.getCommitBuilder());
md.setMessage("Edit\n");
cfg.commit(md);
Ref ref = db.exactRef(RefNames.REFS_CONFIG);
return util.getRevWalk().parseCommit(ref.getObjectId());
}
}
private void update(RevCommit rev) throws Exception {
RefUpdate u = db.updateRef(RefNames.REFS_CONFIG);
u.disableRefLog();
u.setNewObjectId(rev);
Result result = u.forceUpdate();
assertWithMessage("Cannot update ref for test: " + result)
.that(result)
.isAnyOf(Result.FAST_FORWARD, Result.FORCED, Result.NEW, Result.NO_CHANGE);
}
private String text(RevCommit rev, String path) throws Exception {
RevObject blob = util.get(rev.getTree(), path);
byte[] data = db.open(blob).getCachedBytes(Integer.MAX_VALUE);
return RawParseUtils.decode(data);
}
private static String group(GroupReference g) {
return g.getUUID().get() + "\t" + g.getName() + "\n";
}
}