Add tests for reviewing and submitting refs/meta/config changes
Change-Id: I51b699e0a4dc32b96e228629319b682f566c553c
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConfigChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConfigChangeIT.java
new file mode 100644
index 0000000..c78231b
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConfigChangeIT.java
@@ -0,0 +1,153 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.rest.change;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.fail;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.TestProjectInput;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
+import com.google.gerrit.extensions.client.ChangeStatus;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.project.Util;
+
+import org.eclipse.jgit.lib.Config;
+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.junit.Before;
+import org.junit.Test;
+
+public class ConfigChangeIT extends AbstractDaemonTest {
+ @Before
+ public void setUp() throws Exception {
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ Util.allow(cfg, Permission.OWNER, REGISTERED_USERS, "refs/*");
+ Util.allow(
+ cfg, Permission.PUSH, REGISTERED_USERS, "refs/for/refs/meta/config");
+ Util.allow(cfg, Permission.SUBMIT, REGISTERED_USERS, "refs/meta/config");
+ saveProjectConfig(project, cfg);
+
+ setApiUser(user);
+ fetchRefsMetaConfig();
+ }
+
+ @Test
+ @TestProjectInput(cloneAs = "user")
+ public void updateProjectConfig() throws Exception {
+ Config cfg = readProjectConfig();
+ assertThat(cfg.getString("project", null, "description")).isNull();
+ String desc = "new project description";
+ cfg.setString("project", null, "description", desc);
+
+ PushOneCommit.Result r = createConfigChange(cfg);
+ String id = r.getChangeId();
+
+ gApi.changes().id(id).current().review(ReviewInput.approve());
+ gApi.changes().id(id).current().submit();
+
+ assertThat(gApi.changes().id(id).info().status)
+ .isEqualTo(ChangeStatus.MERGED);
+ assertThat(gApi.projects().name(project.get()).get().description)
+ .isEqualTo(desc);
+ fetchRefsMetaConfig();
+ assertThat(readProjectConfig().getString("project", null, "description"))
+ .isEqualTo(desc);
+ }
+
+ @Test
+ @TestProjectInput(cloneAs = "user")
+ public void onlyAdminMayUpdateProjectParent() throws Exception {
+ setApiUser(admin);
+ ProjectInput parent = new ProjectInput();
+ parent.name = name("parent");
+ parent.permissionsOnly = true;
+ gApi.projects().create(parent);
+
+ setApiUser(user);
+ Config cfg = readProjectConfig();
+ assertThat(cfg.getString("access", null, "inheritFrom"))
+ .isAnyOf(null, allProjects.get());
+ cfg.setString("access", null, "inheritFrom", parent.name);
+
+ PushOneCommit.Result r = createConfigChange(cfg);
+ String id = r.getChangeId();
+
+ gApi.changes().id(id).current().review(ReviewInput.approve());
+ try {
+ gApi.changes().id(id).current().submit();
+ fail("expected submit to fail");
+ } catch (ResourceConflictException e) {
+ assertThat(e).hasMessage(
+ "Cannot merge " + r.getCommit().name() + "\n"
+ + "Change contains a project configuration that changes the parent"
+ + " project.\n"
+ + "The change must be submitted by a Gerrit administrator.");
+ }
+
+ assertThat(gApi.projects().name(project.get()).get().parent)
+ .isEqualTo(allProjects.get());
+ fetchRefsMetaConfig();
+ assertThat(readProjectConfig().getString("access", null, "inheritFrom"))
+ .isAnyOf(null, allProjects.get());
+
+ setApiUser(admin);
+ gApi.changes().id(id).current().submit();
+ assertThat(gApi.changes().id(id).info().status)
+ .isEqualTo(ChangeStatus.MERGED);
+ assertThat(gApi.projects().name(project.get()).get().parent)
+ .isEqualTo(parent.name);
+ fetchRefsMetaConfig();
+ assertThat(readProjectConfig().getString("access", null, "inheritFrom"))
+ .isEqualTo(parent.name);
+ }
+
+ private void fetchRefsMetaConfig() throws Exception {
+ git().fetch().setRefSpecs(new RefSpec("refs/meta/config:refs/meta/config"))
+ .call();
+ testRepo.reset("refs/meta/config");
+ }
+
+ private Config readProjectConfig() throws Exception {
+ RevWalk rw = testRepo.getRevWalk();
+ RevTree tree = rw.parseTree(testRepo.getRepository().resolve("HEAD"));
+ RevObject obj = rw.parseAny(testRepo.get(tree, "project.config"));
+ ObjectLoader loader = rw.getObjectReader().open(obj);
+ String text = new String(loader.getCachedBytes(), UTF_8);
+ Config cfg = new Config();
+ cfg.fromText(text);
+ return cfg;
+ }
+
+ private PushOneCommit.Result createConfigChange(Config cfg) throws Exception {
+ PushOneCommit.Result r = pushFactory.create(
+ db, user.getIdent(), testRepo,
+ "Update project config",
+ "project.config",
+ cfg.toText())
+ .to("refs/for/refs/meta/config");
+ r.assertOkStatus();
+ return r;
+ }
+}