blob: 9a926ea3a2e44f5bb48437b6a54a6e2798204965 [file] [log] [blame]
// Copyright (C) 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.acceptance.api.project;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.GitUtil.fetch;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.ExtensionRegistry;
import com.google.gerrit.acceptance.ExtensionRegistry.Registration;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.RawInputUtil;
import com.google.gerrit.entities.LabelFunction;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.entities.SubmitRequirement;
import com.google.gerrit.entities.SubmitRequirementExpression;
import com.google.gerrit.extensions.api.changes.PublishChangeEditInput;
import com.google.gerrit.extensions.api.projects.ConfigInfo;
import com.google.gerrit.extensions.api.projects.ConfigInput;
import com.google.gerrit.extensions.api.projects.ConfigValue;
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.git.ObjectIds;
import com.google.gerrit.server.config.ProjectConfigEntry;
import com.google.gerrit.server.git.validators.ValidationMessage;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.GroupList;
import com.google.gerrit.server.project.LabelConfigValidator;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.inject.Inject;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
public class ProjectConfigIT extends AbstractDaemonTest {
private static final String INVALID_PRROJECT_CONFIG =
"[label \"Foo\"]\n"
// copyAllScoresOnTrivialRebase is deprecated and no longer allowed to be set
+ " copyAllScoresOnTrivialRebase = true";
@Inject private ProjectOperations projectOperations;
@Inject private ExtensionRegistry extensionRegistry;
@Test
public void noLabelValidationForNonRefsMetaConfigChange() throws Exception {
PushOneCommit.Result r =
createChange(
testRepo,
"refs/heads/master",
"Test Change",
ProjectConfig.PROJECT_CONFIG,
INVALID_PRROJECT_CONFIG,
/* topic= */ null);
r.assertOkStatus();
approve(r.getChangeId());
gApi.changes().id(r.getChangeId()).current().submit();
assertThat(gApi.changes().id(r.getChangeId()).get().status).isEqualTo(ChangeStatus.MERGED);
}
@Test
public void noLabelValidationForNoneProjectConfigChange() throws Exception {
fetchRefsMetaConfig();
PushOneCommit.Result r =
createChange(
testRepo,
RefNames.REFS_CONFIG,
"Test Change",
"foo.config",
INVALID_PRROJECT_CONFIG,
/* topic= */ null);
r.assertOkStatus();
approve(r.getChangeId());
gApi.changes().id(r.getChangeId()).current().submit();
assertThat(gApi.changes().id(r.getChangeId()).get().status).isEqualTo(ChangeStatus.MERGED);
}
@Test
public void validateNoIssues_push() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
"[label \"Foo\"]\n description = Foo Label");
PushOneCommit.Result r = push.to("refs/for/" + RefNames.REFS_CONFIG);
r.assertOkStatus();
approve(r.getChangeId());
gApi.changes().id(r.getChangeId()).current().submit();
assertThat(gApi.changes().id(r.getChangeId()).get().status).isEqualTo(ChangeStatus.MERGED);
}
@Test
public void validateNoIssues_createChangeApi() throws Exception {
ChangeInput changeInput = new ChangeInput();
changeInput.project = project.get();
changeInput.branch = RefNames.REFS_CONFIG;
changeInput.subject = "A change";
changeInput.status = ChangeStatus.NEW;
ChangeInfo changeInfo = gApi.changes().create(changeInput).get();
gApi.changes().id(changeInfo.id).edit().create();
gApi.changes()
.id(changeInfo.id)
.edit()
.modifyFile(
ProjectConfig.PROJECT_CONFIG,
RawInputUtil.create("[label \"Foo\"]\n description = Foo Label"));
PublishChangeEditInput publishInput = new PublishChangeEditInput();
gApi.changes().id(changeInfo.id).edit().publish(publishInput);
approve(changeInfo.id);
gApi.changes().id(changeInfo.id).current().submit();
assertThat(gApi.changes().id(changeInfo.id).get().status).isEqualTo(ChangeStatus.MERGED);
}
@Test
public void rejectSettingCopyAnyScore() throws Exception {
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ANY_SCORE, /* value= */ true, "is:ANY");
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ANY_SCORE, /* value= */ false, "is:ANY");
}
@Test
public void rejectCreatingLabelWithInvalidFunction() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
"[label \"Foo\"]\n function = INVALID");
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format("commit %s: invalid project configuration", abbreviateName(r.getCommit())));
r.assertMessage(
String.format(
"ERROR: commit %s: invalid project configuration:\n"
+ "ERROR: commit %s: project.config: Invalid function for label \"foo\"."
+ " Valid names are: NoBlock, NoOp, PatchSetLock",
abbreviateName(r.getCommit()), abbreviateName(r.getCommit())));
}
@Test
public void rejectCreatingLabelPermissionWithInvalidRange_minGreaterThanMax() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ImmutableMap.of(
ProjectConfig.PROJECT_CONFIG,
"[access \"refs/heads/*\"]\n label-Code-Review = 1..-1 group Registered-Users",
GroupList.FILE_NAME,
String.format("%s\tRegistered-Users", SystemGroupBackend.REGISTERED_USERS.get())));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format("commit %s: invalid project configuration", abbreviateName(r.getCommit())));
r.assertMessage(
String.format(
"ERROR: commit %s: invalid project configuration:\n"
+ "ERROR: commit %s: project.config: invalid rule in"
+ " access.refs/heads/*.label-Code-Review:"
+ " invalid range in rule: 1..-1 group Registered-Users",
abbreviateName(r.getCommit()), abbreviateName(r.getCommit())));
}
@Test
public void rejectCreatingLabelPermissionWithInvalidRange_minSetMaxMissing() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ImmutableMap.of(
ProjectConfig.PROJECT_CONFIG,
"[access \"refs/heads/*\"]\n label-Code-Review = -1.. group Registered-Users",
GroupList.FILE_NAME,
String.format("%s\tRegistered-Users", SystemGroupBackend.REGISTERED_USERS.get())));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format("commit %s: invalid project configuration", abbreviateName(r.getCommit())));
r.assertMessage(
String.format(
"ERROR: commit %s: invalid project configuration:\n"
+ "ERROR: commit %s: project.config: invalid rule in"
+ " access.refs/heads/*.label-Code-Review:"
+ " invalid range in rule: -1.. group Registered-Users",
abbreviateName(r.getCommit()), abbreviateName(r.getCommit())));
}
@Test
public void rejectCreatingLabelPermissionWithInvalidRange_maxSetMinMissing() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ImmutableMap.of(
ProjectConfig.PROJECT_CONFIG,
"[access \"refs/heads/*\"]\n label-Code-Review = ..1 group Registered-Users",
GroupList.FILE_NAME,
String.format("%s\tRegistered-Users", SystemGroupBackend.REGISTERED_USERS.get())));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format("commit %s: invalid project configuration", abbreviateName(r.getCommit())));
r.assertMessage(
String.format(
"ERROR: commit %s: invalid project configuration:\n"
+ "ERROR: commit %s: project.config: invalid rule in"
+ " access.refs/heads/*.label-Code-Review:"
+ " invalid range in rule: ..1 group Registered-Users",
abbreviateName(r.getCommit()), abbreviateName(r.getCommit())));
}
@Test
public void rejectSettingCopyMinScore() throws Exception {
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_MIN_SCORE, /* value= */ true, "is:MIN");
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_MIN_SCORE, /* value= */ false, "is:MIN");
}
@Test
public void rejectSettingCopyMaxScore() throws Exception {
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_MAX_SCORE, /* value= */ true, "is:MAX");
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_MAX_SCORE, /* value= */ false, "is:MAX");
}
@Test
public void rejectSettingCopyAllScoresIfNoChange() throws Exception {
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CHANGE,
/* value= */ true,
"changekind:NO_CHANGE");
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CHANGE,
/* value= */ false,
"changekind:NO_CHANGE");
}
@Test
public void rejectSettingCopyAllScoresIfNoCodeChange() throws Exception {
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE,
/* value= */ true,
"changekind:NO_CODE_CHANGE");
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE,
/* value= */ false,
"changekind:NO_CODE_CHANGE");
}
@Test
public void rejectSettingCopyAllScoresOnMergeFirstParentUpdate() throws Exception {
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE,
/* value= */ true,
"changekind:MERGE_FIRST_PARENT_UPDATE");
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE,
/* value= */ false,
"changekind:MERGE_FIRST_PARENT_UPDATE");
}
@Test
public void rejectSettingCopyAllScoresOnTrivialRebase() throws Exception {
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_TRIVIAL_REBASE,
/* value= */ true,
"changekind:TRIVIAL_REBASE");
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_TRIVIAL_REBASE,
/* value= */ false,
"changekind:TRIVIAL_REBASE");
}
@Test
public void rejectSettingCopyAllScoresIfListOfFilesDidNotChange() throws Exception {
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_LIST_OF_FILES_DID_NOT_CHANGE,
/* value= */ true,
"has:unchanged-files");
testRejectSettingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_LIST_OF_FILES_DID_NOT_CHANGE,
/* value= */ false,
"has:unchanged-files");
}
private void testRejectSettingLabelFlag(
String key, boolean value, String expectedPredicateSuggestion) throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
String.format("[label \"Foo\"]\n %s = %s", key, value));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format(
"invalid %s file in revision %s", ProjectConfig.PROJECT_CONFIG, r.getCommit().name()));
r.assertMessage(
String.format(
"ERROR: commit %s: Parameter 'label.Foo.%s' is deprecated and cannot be set,"
+ " use '%s' in 'label.Foo.copyCondition' instead.",
abbreviateName(r.getCommit()), key, expectedPredicateSuggestion));
}
@Test
public void rejectSettingCopyValues() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = 1\n %s = 2",
LabelConfigValidator.KEY_COPY_VALUE, LabelConfigValidator.KEY_COPY_VALUE));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format(
"invalid %s file in revision %s", ProjectConfig.PROJECT_CONFIG, r.getCommit().name()));
r.assertMessage(
String.format(
"ERROR: commit %s: Parameter 'label.Foo.%s' is deprecated and cannot be set,"
+ " use 'is:<copy-value>' in 'label.Foo.copyCondition' instead.",
abbreviateName(r.getCommit()), LabelConfigValidator.KEY_COPY_VALUE));
}
@Test
public void rejectChangingCopyAnyScore() throws Exception {
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ANY_SCORE, /* value= */ true, "is:ANY");
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ANY_SCORE, /* value= */ false, "is:ANY");
}
@Test
public void rejectChangingCopyMinScore() throws Exception {
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_MIN_SCORE, /* value= */ true, "is:MIN");
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_MIN_SCORE, /* value= */ false, "is:MIN");
}
@Test
public void rejectChangingCopyMaxScore() throws Exception {
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_MAX_SCORE, /* value= */ true, "is:MAX");
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_MAX_SCORE, /* value= */ false, "is:MAX");
}
@Test
public void rejectChangingCopyAllScoresIfNoChange() throws Exception {
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CHANGE,
/* value= */ true,
"changekind:NO_CHANGE");
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CHANGE,
/* value= */ false,
"changekind:NO_CHANGE");
}
@Test
public void rejectChangingCopyAllScoresIfNoCodeChange() throws Exception {
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE,
/* value= */ true,
"changekind:NO_CODE_CHANGE");
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE,
/* value= */ false,
"changekind:NO_CODE_CHANGE");
}
@Test
public void rejectChangingCopyAllScoresOnMergeFirstParentUpdate() throws Exception {
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE,
/* value= */ true,
"changekind:MERGE_FIRST_PARENT_UPDATE");
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE,
/* value= */ false,
"changekind:MERGE_FIRST_PARENT_UPDATE");
}
@Test
public void rejectChangingCopyAllScoresOnTrivialRebase() throws Exception {
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_TRIVIAL_REBASE,
/* value= */ true,
"changekind:TRIVIAL_REBASE");
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_TRIVIAL_REBASE,
/* value= */ false,
"changekind:TRIVIAL_REBASE");
}
@Test
public void rejectChangingCopyAllScoresIfListOfFilesDidNotChange() throws Exception {
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_LIST_OF_FILES_DID_NOT_CHANGE,
/* value= */ true,
"has:unchanged-files");
testRejectChangingLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_LIST_OF_FILES_DID_NOT_CHANGE,
/* value= */ false,
"has:unchanged-files");
}
private void testRejectChangingLabelFlag(
String key, boolean value, String expectedPredicateSuggestion) throws Exception {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG,
String.format("[label \"Foo\"]\n %s = %s", key, !value))
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
testRejectSettingLabelFlag(key, value, expectedPredicateSuggestion);
}
@Test
public void rejectChangingCopyValues() throws Exception {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = 1\n %s = 2",
LabelConfigValidator.KEY_COPY_VALUE, LabelConfigValidator.KEY_COPY_VALUE))
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = -1\n %s = -2",
LabelConfigValidator.KEY_COPY_VALUE, LabelConfigValidator.KEY_COPY_VALUE));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format(
"invalid %s file in revision %s", ProjectConfig.PROJECT_CONFIG, r.getCommit().name()));
r.assertMessage(
String.format(
"ERROR: commit %s: Parameter 'label.Foo.%s' is deprecated and cannot be set,"
+ " use 'is:<copy-value>' in 'label.Foo.copyCondition' instead.",
abbreviateName(r.getCommit()), LabelConfigValidator.KEY_COPY_VALUE));
}
@Test
public void rejectSubmitRequirement_duplicateDescriptionKeys() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
"[submit-requirement \"Foo\"]\n"
+ " description = description 1\n "
+ " submittableIf = label:Code-Review=MAX\n"
+ "[submit-requirement \"Foo\"]\n"
+ " description = description 2\n");
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format("commit %s: invalid project configuration", abbreviateName(r.getCommit())));
r.assertMessage(
String.format(
"ERROR: commit %s: project.config: multiple definitions of description"
+ " for submit requirement 'foo'",
abbreviateName(r.getCommit())));
}
@Test
public void pluginConfigs_neverWriteDefaultValueToConfigFile() throws Exception {
String projectConfig = projectOperations.project(project).getConfig().toText();
assertThat(projectConfig).doesNotContain("myPlugin");
ProjectConfigEntry entry = new ProjectConfigEntry("enabled", "true");
try (Registration ignored =
extensionRegistry.newRegistration().add(entry, "test-config-entry")) {
// Default value is populated in API response
ConfigInfo configInfo = gApi.projects().name(project.get()).config();
assertThat(configInfo.pluginConfig.get("myPlugin").get("test-config-entry").value)
.isEqualTo("true");
// Set an unrelated parameter
ConfigInput input = new ConfigInput();
input.description = "New description";
gApi.projects().name(project.get()).config(input);
// The project config does not contain a section for the plugin
projectConfig = projectOperations.project(project).getConfig().toText();
assertThat(projectConfig).doesNotContain("myPlugin");
assertThat(projectConfig).contains("New description");
// Set the plugin config to the default value. Set an unrelated setting on the side.
Map<String, ConfigValue> val = new HashMap<>();
input.pluginConfigValues = new HashMap<>();
input.pluginConfigValues.put("myPlugin", val);
val.put("test-config-entry", new ConfigValue("true"));
input.description = "New description2";
gApi.projects().name(project.get()).config(input);
// The project config does not contain a section for the plugin
projectConfig = projectOperations.project(project).getConfig().toText();
assertThat(projectConfig).doesNotContain("myPlugin");
assertThat(projectConfig).contains("New description2");
}
}
@Test
public void pluginConfigs_persistNonDefaultConfig() throws Exception {
String projectConfig = projectOperations.project(project).getConfig().toText();
assertThat(projectConfig).doesNotContain("myPlugin");
ProjectConfigEntry entry = new ProjectConfigEntry("enabled", "true");
try (Registration ignored =
extensionRegistry.newRegistration().add(entry, "test-config-entry")) {
// Default value is populated in API response
ConfigInfo configInfo = gApi.projects().name(project.get()).config();
assertThat(configInfo.pluginConfig.get("myPlugin").get("test-config-entry").value)
.isEqualTo("true");
// Change value to non-default
ConfigInput input = new ConfigInput();
input.pluginConfigValues = new HashMap<>();
Map<String, ConfigValue> val = new HashMap<>();
input.pluginConfigValues.put("myPlugin", val);
val.put("test-config-entry", new ConfigValue("false"));
gApi.projects().name(project.get()).config(input);
// API response serves new setting
configInfo = gApi.projects().name(project.get()).config();
assertThat(configInfo.pluginConfig.get("myPlugin").get("test-config-entry").value)
.isEqualTo("false");
// The project config contains a section for the plugin
projectConfig = projectOperations.project(project).getConfig().toText();
assertThat(projectConfig).contains("myPlugin");
}
}
@Test
public void pluginConfigs_canUnsetPluginSetting() throws Exception {
String projectConfig = projectOperations.project(project).getConfig().toText();
assertThat(projectConfig).doesNotContain("myPlugin");
ProjectConfigEntry entry = new ProjectConfigEntry("enabled", "true");
try (Registration ignored =
extensionRegistry.newRegistration().add(entry, "test-config-entry")) {
// Default value is populated in API response
ConfigInfo configInfo = gApi.projects().name(project.get()).config();
assertThat(configInfo.pluginConfig.get("myPlugin").get("test-config-entry").value)
.isEqualTo("true");
// Change value to non-default
ConfigInput input = new ConfigInput();
input.pluginConfigValues = new HashMap<>();
Map<String, ConfigValue> val = new HashMap<>();
input.pluginConfigValues.put("myPlugin", val);
val.put("test-config-entry", new ConfigValue("false"));
gApi.projects().name(project.get()).config(input);
// API response serves new setting
configInfo = gApi.projects().name(project.get()).config();
assertThat(configInfo.pluginConfig.get("myPlugin").get("test-config-entry").value)
.isEqualTo("false");
// The project config contains a section for the plugin
projectConfig = projectOperations.project(project).getConfig().toText();
assertThat(projectConfig).contains("myPlugin");
// Reset value to default
val.put("test-config-entry", new ConfigValue("true"));
gApi.projects().name(project.get()).config(input);
projectConfig = projectOperations.project(project).getConfig().toText();
assertThat(projectConfig).doesNotContain("myPlugin");
configInfo = gApi.projects().name(project.get()).config();
assertThat(configInfo.pluginConfig.get("myPlugin").get("test-config-entry").value)
.isEqualTo("true");
}
}
@Test
public void rejectSubmitRequirement_duplicateApplicableIfKeys() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
"[submit-requirement \"Foo\"]\n "
+ " applicableIf = is:true\n "
+ " submittableIf = label:Code-Review=MAX\n"
+ "[submit-requirement \"Foo\"]\n"
+ " applicableIf = is:false\n");
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format("commit %s: invalid project configuration", abbreviateName(r.getCommit())));
r.assertMessage(
String.format(
"ERROR: commit %s: project.config: multiple definitions of applicableif"
+ " for submit requirement 'foo'",
abbreviateName(r.getCommit())));
}
@Test
public void rejectSubmitRequirement_duplicateSubmittableIfKeys() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
"[submit-requirement \"Foo\"]\n"
+ " submittableIf = label:Code-Review=MAX\n"
+ "[submit-requirement \"Foo\"]\n"
+ " submittableIf = label:Code-Review=MIN\n");
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format("commit %s: invalid project configuration", abbreviateName(r.getCommit())));
r.assertMessage(
String.format(
"ERROR: commit %s: project.config: multiple definitions of submittableif"
+ " for submit requirement 'foo'",
abbreviateName(r.getCommit())));
}
@Test
public void rejectSubmitRequirement_duplicateOverrideIfKeys() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
"[submit-requirement \"Foo\"]\n"
+ " overrideIf = is:true\n "
+ " submittableIf = label:Code-Review=MAX\n"
+ "[submit-requirement \"Foo\"]\n"
+ " overrideIf = is:false\n");
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format("commit %s: invalid project configuration", abbreviateName(r.getCommit())));
r.assertMessage(
String.format(
"ERROR: commit %s: project.config: multiple definitions of overrideif"
+ " for submit requirement 'foo'",
abbreviateName(r.getCommit())));
}
@Test
public void rejectSubmitRequirement_duplicateCanOverrideInChildProjectsKey() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
"[submit-requirement \"Foo\"]\n"
+ " canOverrideInChildProjects = true\n"
+ " submittableIf = label:Code-Review=MAX\n"
+ "[submit-requirement \"Foo\"]\n "
+ " canOverrideInChildProjects = false\n");
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format("commit %s: invalid project configuration", abbreviateName(r.getCommit())));
r.assertMessage(
String.format(
"ERROR: commit %s: project.config: multiple definitions of canoverrideinchildprojects"
+ " for submit requirement 'foo'",
abbreviateName(r.getCommit())));
}
@Test
public void submitRequirementsAreParsed_forExistingDuplicateDefinitions() throws Exception {
// Duplicate submit requirement definitions are rejected on config change uploads. For setups
// already containing duplicate SR definitions, the server is able to parse the "submit
// requirements correctly"
RevCommit revision;
// Commit a change to the project config, bypassing server validation.
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
revision =
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG,
"[submit-requirement \"Foo\"]\n"
+ " canOverrideInChildProjects = true\n"
+ " submittableIf = label:Code-Review=MAX\n"
+ "[submit-requirement \"Foo\"]\n "
+ " canOverrideInChildProjects = false\n")
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
try (Repository git = repoManager.openRepository(project)) {
// Server is able to parse the config.
ProjectConfig cfg = projectConfigFactory.create(project);
cfg.load(git, revision);
// One of the two definitions takes precedence and overrides the other.
assertThat(cfg.getSubmitRequirementSections())
.containsExactly(
"Foo",
SubmitRequirement.builder()
.setName("Foo")
.setAllowOverrideInChildProjects(false)
.setSubmittabilityExpression(
SubmitRequirementExpression.create("label:Code-Review=MAX"))
.build());
}
}
@Test
public void testRejectChangingLabelFunction_toMaxWithBlock() throws Exception {
testChangingLabelFunction(
/* initialLabelFunction= */ LabelFunction.NO_BLOCK,
/* newLabelFunction= */ LabelFunction.MAX_WITH_BLOCK,
/* errorMessage= */ String.format(
"Value '%s' of 'label.foo.function' is not allowed and cannot be set."
+ " Label functions can only be set to {no_block, no_op, patch_set_lock}."
+ " Use submit requirements instead of label functions.",
LabelFunction.MAX_WITH_BLOCK.getFunctionName()));
}
@Test
public void testRejectChangingLabelFunction_toMaxNoBlock() throws Exception {
testChangingLabelFunction(
/* initialLabelFunction= */ LabelFunction.NO_BLOCK,
/* newLabelFunction= */ LabelFunction.MAX_NO_BLOCK,
/* errorMessage= */ String.format(
"Value '%s' of 'label.foo.function' is not allowed and cannot be set."
+ " Label functions can only be set to {no_block, no_op, patch_set_lock}."
+ " Use submit requirements instead of label functions.",
LabelFunction.MAX_NO_BLOCK.getFunctionName()));
}
@Test
public void testRejectChangingLabelFunction_toAnyWithBlock() throws Exception {
testChangingLabelFunction(
/* initialLabelFunction= */ LabelFunction.NO_BLOCK,
/* newLabelFunction= */ LabelFunction.ANY_WITH_BLOCK,
/* errorMessage= */ String.format(
"Value '%s' of 'label.foo.function' is not allowed and cannot be set."
+ " Label functions can only be set to {no_block, no_op, patch_set_lock}."
+ " Use submit requirements instead of label functions.",
LabelFunction.ANY_WITH_BLOCK.getFunctionName()));
}
@Test
public void testChangingLabelFunction_toNoBlock() throws Exception {
testChangingLabelFunction(
/* initialLabelFunction= */ LabelFunction.MAX_WITH_BLOCK,
/* newLabelFunction= */ LabelFunction.NO_BLOCK,
/* errorMessage= */ null);
}
@Test
public void testChangingLabelFunction_toNoOp() throws Exception {
testChangingLabelFunction(
/* initialLabelFunction= */ LabelFunction.MAX_WITH_BLOCK,
/* newLabelFunction= */ LabelFunction.NO_OP,
/* errorMessage= */ null);
}
@Test
public void testChangingLabelFunction_toPatchSetLock() throws Exception {
testChangingLabelFunction(
/* initialLabelFunction= */ LabelFunction.MAX_WITH_BLOCK,
/* newLabelFunction= */ LabelFunction.PATCH_SET_LOCK,
/* errorMessage= */ null);
}
@Test
public void testRejectRemovingLabelFunction() throws Exception {
testChangingLabelFunction(
/* initialLabelFunction= */ LabelFunction.MAX_WITH_BLOCK,
/* newLabelFunction= */ null,
/* errorMessage= */ String.format(
"Cannot delete '%s.%s.%s'."
+ " Label functions can only be set to {%s, %s, %s}."
+ " Use submit requirements instead of label functions.",
ProjectConfig.LABEL,
"Foo",
ProjectConfig.KEY_FUNCTION,
LabelFunction.NO_BLOCK,
LabelFunction.NO_OP,
LabelFunction.PATCH_SET_LOCK));
}
private void testChangingLabelFunction(
LabelFunction initialLabelFunction,
@Nullable LabelFunction newLabelFunction,
@Nullable String errorMessage)
throws Exception {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = %s\n",
ProjectConfig.KEY_FUNCTION, initialLabelFunction.getFunctionName()))
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
newLabelFunction == null
? "[label \"Foo\"]\n"
: String.format(
"[label \"Foo\"]\n %s = %s\n",
ProjectConfig.KEY_FUNCTION, newLabelFunction.getFunctionName()));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
if (errorMessage == null) {
r.assertOkStatus();
return;
}
r.assertErrorStatus(
String.format(
"invalid %s file in revision %s", ProjectConfig.PROJECT_CONFIG, r.getCommit().name()));
r.assertMessage(errorMessage);
}
@Test
public void unsetCopyAnyScore() throws Exception {
testUnsetLabelFlag(LabelConfigValidator.KEY_COPY_ANY_SCORE, /* previousValue= */ true);
testUnsetLabelFlag(LabelConfigValidator.KEY_COPY_ANY_SCORE, /* previousValue= */ false);
}
@Test
public void unsetCopyMinScore() throws Exception {
testUnsetLabelFlag(LabelConfigValidator.KEY_COPY_MIN_SCORE, /* previousValue= */ true);
testUnsetLabelFlag(LabelConfigValidator.KEY_COPY_MIN_SCORE, /* previousValue= */ false);
}
@Test
public void unsetCopyMaxScore() throws Exception {
testUnsetLabelFlag(LabelConfigValidator.KEY_COPY_MAX_SCORE, /* previousValue= */ true);
testUnsetLabelFlag(LabelConfigValidator.KEY_COPY_MAX_SCORE, /* previousValue= */ false);
}
@Test
public void unsetCopyAllScoresIfNoChange() throws Exception {
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CHANGE, /* previousValue= */ true);
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CHANGE, /* previousValue= */ false);
}
@Test
public void unsetCopyAllScoresIfNoCodeChange() throws Exception {
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE, /* previousValue= */ true);
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE, /* previousValue= */ false);
}
@Test
public void unsetCopyAllScoresOnMergeFirstParentUpdate() throws Exception {
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE,
/* previousValue= */ true);
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE,
/* previousValue= */ false);
}
@Test
public void unsetCopyAllScoresOnTrivialRebase() throws Exception {
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_TRIVIAL_REBASE, /* previousValue= */ true);
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_TRIVIAL_REBASE, /* previousValue= */ false);
}
@Test
public void unsetCopyAllScoresIfListOfFilesDidNotChange() throws Exception {
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_LIST_OF_FILES_DID_NOT_CHANGE,
/* previousValue= */ true);
testUnsetLabelFlag(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_LIST_OF_FILES_DID_NOT_CHANGE,
/* previousValue= */ false);
}
private void testUnsetLabelFlag(String key, boolean previousValue) throws Exception {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG,
String.format("[label \"Foo\"]\n %s = %s", key, previousValue))
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
String.format("[label \"Foo\"]\n otherKey = value"));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertOkStatus();
}
@Test
public void unsetCopyValues() throws Exception {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = 1\n %s = 2",
LabelConfigValidator.KEY_COPY_VALUE, LabelConfigValidator.KEY_COPY_VALUE))
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
String.format("[label \"Foo\"]\n otherKey = value"));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertOkStatus();
}
@Test
public void keepCopyAnyScoreUnchanged() throws Exception {
testKeepLabelFlagUnchanged(LabelConfigValidator.KEY_COPY_ANY_SCORE, /* value= */ true);
testKeepLabelFlagUnchanged(LabelConfigValidator.KEY_COPY_ANY_SCORE, /* value= */ false);
}
@Test
public void keepCopyMinScoreUnchanged() throws Exception {
testKeepLabelFlagUnchanged(LabelConfigValidator.KEY_COPY_MIN_SCORE, /* value= */ true);
testKeepLabelFlagUnchanged(LabelConfigValidator.KEY_COPY_MIN_SCORE, /* value= */ false);
}
@Test
public void keepCopyMaxScoreUnchanged() throws Exception {
testKeepLabelFlagUnchanged(LabelConfigValidator.KEY_COPY_MAX_SCORE, /* value= */ true);
testKeepLabelFlagUnchanged(LabelConfigValidator.KEY_COPY_MAX_SCORE, /* value= */ false);
}
@Test
public void keepCopyAllScoresIfNoChangeUnchanged() throws Exception {
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CHANGE, /* value= */ true);
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CHANGE, /* value= */ false);
}
@Test
public void keepCopyAllScoresIfNoCodeChangeUnchanged() throws Exception {
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE, /* value= */ true);
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE, /* value= */ false);
}
@Test
public void keepCopyAllScoresOnMergeFirstParentUpdateUnchanged() throws Exception {
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE, /* value= */ true);
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE, /* value= */ false);
}
@Test
public void keepCopyAllScoresOnTrivialRebaseUnchanged() throws Exception {
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_TRIVIAL_REBASE, /* value= */ true);
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_ON_TRIVIAL_REBASE, /* value= */ false);
}
@Test
public void keepCopyAllScoresIfListOfFilesDidNotChangeUnchanged() throws Exception {
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_LIST_OF_FILES_DID_NOT_CHANGE,
/* value= */ true);
testKeepLabelFlagUnchanged(
LabelConfigValidator.KEY_COPY_ALL_SCORES_IF_LIST_OF_FILES_DID_NOT_CHANGE,
/* value= */ false);
}
private void testKeepLabelFlagUnchanged(String key, boolean value) throws Exception {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG, String.format("[label \"Foo\"]\n %s = %s", key, value))
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
String.format("[label \"Foo\"]\n %s = %s\n otherKey = value", key, value));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertOkStatus();
}
@Test
public void keepCopyValuesUnchanged() throws Exception {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = 1\n %s = 2",
LabelConfigValidator.KEY_COPY_VALUE, LabelConfigValidator.KEY_COPY_VALUE))
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = 1\n %s = 2\n otherKey = value",
LabelConfigValidator.KEY_COPY_VALUE, LabelConfigValidator.KEY_COPY_VALUE));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertOkStatus();
}
@Test
public void keepCopyValuesUnchanged_differentOrder() throws Exception {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = 1\n %s = 2",
LabelConfigValidator.KEY_COPY_VALUE, LabelConfigValidator.KEY_COPY_VALUE))
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = 2\n %s = 1",
LabelConfigValidator.KEY_COPY_VALUE, LabelConfigValidator.KEY_COPY_VALUE));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertOkStatus();
}
@Test
public void rejectMultipleLabelFlags() throws Exception {
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = true\n %s = true",
LabelConfigValidator.KEY_COPY_MIN_SCORE, LabelConfigValidator.KEY_COPY_MAX_SCORE));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format(
"invalid %s file in revision %s", ProjectConfig.PROJECT_CONFIG, r.getCommit().name()));
r.assertMessage(
String.format(
"ERROR: commit %s: Parameter 'label.Foo.%s' is deprecated and cannot be set,"
+ " use 'is:MIN' in 'label.Foo.copyCondition' instead.",
abbreviateName(r.getCommit()), LabelConfigValidator.KEY_COPY_MIN_SCORE));
r.assertMessage(
String.format(
"ERROR: commit %s: Parameter 'label.Foo.%s' is deprecated and cannot be set,"
+ " use 'is:MAX' in 'label.Foo.copyCondition' instead.",
abbreviateName(r.getCommit()), LabelConfigValidator.KEY_COPY_MAX_SCORE));
}
@Test
public void testSettingCopyCondition() throws Exception {
testChangingCopyCondition(/* initialCopyCondition= */ null, /* newCopyCondition= */ "is:ANY");
}
@Test
public void testRejectNonParseableCopyCondition_badSyntax() throws Exception {
testChangingCopyConditionExpectError(
/* initialCopyCondition= */ "is:ANY",
/* newCopyCondition= */ ":",
/* errorMessage= */ "Cannot parse copy condition ':' of label Foo (parameter"
+ " 'label.Foo.copyCondition'): line 1:0 no viable alternative at input ':'");
}
@Test
public void testRejectNonParseableCopyCondition_unsupportedOperator() throws Exception {
testChangingCopyConditionExpectError(
/* initialCopyCondition= */ "is:ANY",
/* newCopyCondition= */ "foo:bar",
/* errorMessage= */ "Cannot parse copy condition 'foo:bar' of label Foo (parameter"
+ " 'label.Foo.copyCondition'): unsupported operator foo:bar");
}
@Test
public void testFixNonParseableCopyCondition() throws Exception {
testChangingCopyCondition(/* initialCopyCondition= */ ":", /* newCopyCondition= */ "is:ANY");
}
@Test
public void testChangingCopyCondition() throws Exception {
testChangingCopyCondition(
/* initialCopyCondition= */ "is:ANY", /* newCopyCondition= */ "is:MAX");
}
@Test
public void testDeletingCopyCondition() throws Exception {
testChangingCopyCondition(/* initialCopyCondition= */ "is:ANY", /* newCopyCondition= */ null);
}
@Test
public void testDeletingNonParseableCopyCondition() throws Exception {
testChangingCopyCondition(/* initialCopyCondition= */ ":", /* newCopyCondition= */ null);
}
@Test
public void testChangingNonParseableCopyCondition() throws Exception {
testChangingCopyConditionExpectWarning(
/* initialCopyCondition= */ ":",
/* newCopyCondition= */ ":foo",
/* warningMessage= */ "Cannot parse copy condition ':foo' of label Foo (parameter"
+ " 'label.Foo.copyCondition'): line 1:0 no viable alternative at input ':'");
}
private void testChangingCopyCondition(
String initialCopyCondition, @Nullable String newCopyCondition) throws Exception {
testChangingCopyCondition(
initialCopyCondition, newCopyCondition, /* type= */ null, /* message= */ null);
}
private void testChangingCopyConditionExpectError(
String initialCopyCondition, @Nullable String newCopyCondition, String errorMessage)
throws Exception {
testChangingCopyCondition(
initialCopyCondition, newCopyCondition, ValidationMessage.Type.ERROR, errorMessage);
}
private void testChangingCopyConditionExpectWarning(
String initialCopyCondition, @Nullable String newCopyCondition, String warningMessage)
throws Exception {
testChangingCopyCondition(
initialCopyCondition, newCopyCondition, ValidationMessage.Type.WARNING, warningMessage);
}
private void testChangingCopyCondition(
@Nullable String initialCopyCondition,
@Nullable String newCopyCondition,
@Nullable ValidationMessage.Type type,
@Nullable String message)
throws Exception {
if (initialCopyCondition != null) {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo
.branch(RefNames.REFS_CONFIG)
.commit()
.add(
ProjectConfig.PROJECT_CONFIG,
String.format(
"[label \"Foo\"]\n %s = %s\n",
ProjectConfig.KEY_COPY_CONDITION, initialCopyCondition))
.parent(projectOperations.project(project).getHead(RefNames.REFS_CONFIG))
.create();
}
}
fetchRefsMetaConfig();
PushOneCommit push =
pushFactory.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
newCopyCondition == null
? "[label \"Foo\"]\n"
: String.format(
"[label \"Foo\"]\n %s = %s\n",
ProjectConfig.KEY_COPY_CONDITION, newCopyCondition));
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
if (!ValidationMessage.Type.ERROR.equals(type)) {
r.assertOkStatus();
return;
}
r.assertErrorStatus(
String.format(
"invalid %s file in revision %s", ProjectConfig.PROJECT_CONFIG, r.getCommit().name()));
if (message != null) {
r.assertMessage(message);
}
}
@Test
public void validateLabelConfigInInitialCommit() throws Exception {
try (TestRepository<Repository> testRepo =
new TestRepository<>(repoManager.openRepository(project))) {
testRepo.delete(RefNames.REFS_CONFIG);
}
PushOneCommit push =
pushFactory
.create(
admin.newIdent(),
testRepo,
"Test Change",
ProjectConfig.PROJECT_CONFIG,
INVALID_PRROJECT_CONFIG)
.setParents(ImmutableList.of());
PushOneCommit.Result r = push.to(RefNames.REFS_CONFIG);
r.assertErrorStatus(
String.format(
"invalid %s file in revision %s", ProjectConfig.PROJECT_CONFIG, r.getCommit().name()));
}
private void fetchRefsMetaConfig() throws Exception {
fetch(testRepo, RefNames.REFS_CONFIG + ":" + RefNames.REFS_CONFIG);
testRepo.reset(RefNames.REFS_CONFIG);
}
private String abbreviateName(AnyObjectId id) throws Exception {
return ObjectIds.abbreviateName(id, testRepo.getRevWalk().getObjectReader());
}
}