Add IT test
Change-Id: I28300bd3e1a606b99f1f902eccc691f8681900d8
diff --git a/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProjectIT.java b/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProjectIT.java
new file mode 100644
index 0000000..af3ff0d
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/deleteproject/DeleteProjectIT.java
@@ -0,0 +1,324 @@
+// Copyright (C) 2018 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.deleteproject;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.GitUtil.pushHead;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.MoreObjects;
+import com.google.gerrit.acceptance.GerritConfig;
+import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.acceptance.UseLocalDisk;
+import com.google.gerrit.acceptance.UseSsh;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.client.ProjectState;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.googlesource.gerrit.plugins.deleteproject.DeleteProject.Input;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+import org.apache.commons.io.FileUtils;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PushResult;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
+import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+@UseSsh
+@TestPlugin(
+ name = "delete-project",
+ sysModule = "com.googlesource.gerrit.plugins.deleteproject.Module",
+ sshModule = "com.googlesource.gerrit.plugins.deleteproject.SshModule",
+ httpModule = "com.googlesource.gerrit.plugins.deleteproject.HttpModule")
+public class DeleteProjectIT extends LightweightPluginDaemonTest {
+
+ private static final String PLUGIN = "delete-project";
+ private static final String ARCHIVE_FOLDER = "archiveFolder";
+ private static final String PARENT_FOLDER = "parentFolder";
+
+ private File archiveFolder;
+ private File projectDir;
+
+ @Before
+ public void setUpArchiveFolder() throws IOException {
+ archiveFolder = Files.createDirectories(Paths.get(ARCHIVE_FOLDER)).toFile();
+ projectDir = verifyProjectRepoExists(project);
+ }
+
+ @After
+ public void removeArchiveFolder() {
+ FileUtils.deleteQuietly(archiveFolder);
+ }
+
+ @Test
+ @UseLocalDisk
+ public void testHttpDeleteProjectForce() throws Exception {
+ RestResponse r = httpDeleteProjectHelper(true);
+ r.assertNoContent();
+ assertThat(projectDir.exists()).isFalse();
+ }
+
+ @Test
+ @UseLocalDisk
+ public void testHttpDeleteProjectNotForce() throws Exception {
+ createChange();
+ RestResponse r = httpDeleteProjectHelper(false);
+ r.assertConflict();
+ assertThat(projectDir.exists()).isTrue();
+ }
+
+ @Test
+ @UseLocalDisk
+ public void testHttpDeleteProjectWithWatches() throws Exception {
+ watch(project.get(), null);
+ RestResponse r = httpDeleteProjectHelper(true);
+ r.assertNoContent();
+ assertThat(projectDir.exists()).isFalse();
+ }
+
+ @Test
+ @UseLocalDisk
+ public void testSshDeleteProjectWithoutOptions() throws Exception {
+ createChange();
+ String cmd = Joiner.on(" ").join(PLUGIN, "delete", project.get());
+ String expected =
+ String.format(
+ "Really delete '%s'?\n"
+ + "This is an operation which permanently deletes data. This cannot be undone!\n"
+ + "If you are sure you wish to delete this project, re-run with the --yes-really-delete flag.\n\n",
+ project.get());
+ adminSshSession.exec(cmd);
+
+ assertThat(projectDir.exists()).isTrue();
+ assertThat(adminSshSession.getError()).isEqualTo(expected);
+ }
+
+ @Test
+ @UseLocalDisk
+ public void testSshDeleteProjYesReallyDelete() throws Exception {
+ createChange();
+ String cmd = createDeleteCommand(project.get());
+ String expected =
+ String.format(
+ "Project '%s' has open changes. - To really delete '%s', re-run with the --force flag.%n",
+ project.get(), project.get());
+ adminSshSession.exec(cmd);
+
+ assertThat(projectDir.exists()).isTrue();
+ assertThat(adminSshSession.getError()).isEqualTo(expected);
+ }
+
+ @Test
+ @UseLocalDisk
+ public void testSshDeleteProjYesReallyDeleteForce() throws Exception {
+ createChange();
+ String cmd = createDeleteCommand("--force", project.get());
+ adminSshSession.exec(cmd);
+ assertThat(adminSshSession.getError()).isNull();
+ assertThat(projectDir.exists()).isFalse();
+ }
+
+ @Test
+ @UseLocalDisk
+ @GerritConfig(name = "plugin.delete-project.enablePreserveOption", value = "true")
+ public void testSshDeleteProjPreserveGitRepoEnabled() throws Exception {
+ String cmd = createDeleteCommand("--preserve-git-repository", project.get());
+ adminSshSession.exec(cmd);
+
+ assertThat(adminSshSession.getError()).isNull();
+ assertThat(projectDir.exists()).isTrue();
+ }
+
+ @Test
+ @UseLocalDisk
+ @GerritConfig(name = "plugin.delete-project.enablePreserveOption", value = "false")
+ public void testSshDeleteProjPreserveGitRepoNotEnabled() throws Exception {
+ String cmd = createDeleteCommand("--preserve-git-repository", project.get());
+ adminSshSession.exec(cmd);
+ String expected =
+ "Given the enablePreserveOption is configured to be false, "
+ + "the --preserve-git-repository option is not allowed.\n"
+ + "Please remove this option and retry.\n";
+ assertThat(adminSshSession.getError()).isEqualTo(expected);
+ assertThat(projectDir.exists()).isTrue();
+ }
+
+ @Test
+ @UseLocalDisk
+ @GerritConfig(name = "plugin.delete-project.hideProjectOnPreserve", value = "true")
+ public void testSshHideProject() throws Exception {
+ String cmd = createDeleteCommand("--preserve-git-repository", project.get());
+ adminSshSession.exec(cmd);
+
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ ProjectState state = cfg.getProject().getState();
+
+ assertThat(state).isEqualTo(ProjectState.HIDDEN);
+ assertThat(adminSshSession.getError()).isNull();
+ assertThat(projectDir.exists()).isTrue();
+ }
+
+ @Test
+ @UseLocalDisk
+ public void testDeleteProjWithChildren() throws Exception {
+ String childrenString = createProject("foo", project, true).get();
+ verifyProjectRepoExists(Project.NameKey.parse(childrenString));
+
+ String cmd = createDeleteCommand(project.get());
+ adminSshSession.exec(cmd);
+ assertThat(adminSshSession.getError())
+ .isEqualTo(
+ "fatal: Cannot delete project because it has children: " + childrenString + "\n");
+ assertThat(projectDir.exists()).isTrue();
+ }
+
+ @Test
+ @UseLocalDisk
+ public void testDeleteAllProject() throws Exception {
+ String name = allProjects.get();
+ String cmd = createDeleteCommand(name);
+ adminSshSession.exec(cmd);
+
+ assertThat(adminSshSession.getError())
+ .isEqualTo("fatal: Cannot delete project because it is protected against deletion" + "\n");
+ }
+
+ @Test
+ @UseLocalDisk
+ @GerritConfig(name = "plugin.delete-project.allowDeletionOfReposWithTags", value = "false")
+ public void testDeleteProjWithTags() throws Exception {
+ grant(Permission.CREATE, project, "refs/tags/*", false, REGISTERED_USERS);
+ pushTagOldCommitNotForce(Status.OK);
+
+ String cmd = createDeleteCommand(project.get());
+ adminSshSession.exec(cmd);
+ assertThat(adminSshSession.getError())
+ .isEqualTo("fatal: Project " + project.get() + " has tags" + "\n");
+ assertThat(projectDir.exists()).isTrue();
+ }
+
+ @Test
+ @UseLocalDisk
+ @GerritConfig(name = "plugin.delete-project.archiveDeletedRepos", value = "true")
+ @GerritConfig(name = "plugin.delete-project.archiveFolder", value = ARCHIVE_FOLDER)
+ public void testArchiveProject() throws Exception {
+ assertThat(archiveFolder.exists()).isTrue();
+ assertThat(isEmpty(archiveFolder.toPath())).isTrue();
+
+ String cmd = createDeleteCommand(project.get());
+ adminSshSession.exec(cmd);
+
+ assertThat(adminSshSession.getError()).isNull();
+ assertThat(isEmpty(archiveFolder.toPath())).isFalse();
+ assertThat(containsDeletedProject(archiveFolder.toPath(), project.get())).isTrue();
+ assertThat(projectDir.exists()).isFalse();
+ }
+
+ @Test
+ @UseLocalDisk
+ @GerritConfig(name = "plugin.delete-project.archiveDeletedRepos", value = "true")
+ @GerritConfig(name = "plugin.delete-project.archiveFolder", value = ARCHIVE_FOLDER)
+ public void testDeleteAndArchiveProjectWithParentFolder() throws Exception {
+ assertThat(archiveFolder.exists()).isTrue();
+ assertThat(isEmpty(archiveFolder.toPath())).isTrue();
+
+ String name = "pj1";
+ String projectName = createProject(name).get();
+ File projectDir = verifyProjectRepoExists(Project.NameKey.parse(projectName));
+
+ Path parentFolder = projectDir.toPath().getParent().resolve(PARENT_FOLDER).resolve(projectName);
+ parentFolder.toFile().mkdirs();
+ assertThat(parentFolder.toFile().exists()).isTrue();
+ assertThat(isEmpty(parentFolder)).isTrue();
+
+ Files.move(projectDir.toPath(), parentFolder, REPLACE_EXISTING);
+ assertThat(parentFolder.toFile().exists()).isTrue();
+ assertThat(isEmpty(parentFolder)).isFalse();
+
+ String cmd = createDeleteCommand(PARENT_FOLDER + "/" + projectName);
+ adminSshSession.exec(cmd);
+
+ assertThat(adminSshSession.getError()).isNull();
+ assertThat(isEmpty(archiveFolder.toPath())).isFalse();
+ assertThat(containsDeletedProject(archiveFolder.toPath().resolve(PARENT_FOLDER), name))
+ .isTrue();
+ assertThat(projectDir.exists()).isFalse();
+
+ assertThat(parentFolder.toFile().exists()).isFalse();
+ }
+
+ private File verifyProjectRepoExists(Project.NameKey name) throws IOException {
+ File projectDir;
+ try (Repository projectRepo = repoManager.openRepository(name)) {
+ projectDir = projectRepo.getDirectory();
+ }
+ assertThat(projectDir.exists()).isTrue();
+ return projectDir;
+ }
+
+ private RestResponse httpDeleteProjectHelper(boolean force) throws Exception {
+ setApiUser(user);
+ sender.clear();
+ String endPoint = "/projects/" + project.get() + "/delete-project~delete";
+ Input i = new Input();
+ i.force = force;
+
+ return adminRestSession.post(endPoint, i);
+ }
+
+ private String createDeleteCommand(String cmd, String... params) {
+ return Joiner.on(" ")
+ .join(PLUGIN, "delete", "--yes-really-delete", cmd, Joiner.on(" ").join(params));
+ }
+
+ private String pushTagOldCommitNotForce(Status expectedStatus) throws Exception {
+ testRepo = cloneProject(project, user);
+ commitBuilder().ident(user.getIdent()).message("subject (" + System.nanoTime() + ")").create();
+ String tagName = MoreObjects.firstNonNull(null, "v1_" + System.nanoTime());
+
+ grant(Permission.SUBMIT, project, "refs/for/refs/heads/master", false, REGISTERED_USERS);
+ pushHead(testRepo, "refs/for/master%submit");
+
+ String tagRef = RefNames.REFS_TAGS + tagName;
+ PushResult r = pushHead(testRepo, tagRef, false, false);
+ RemoteRefUpdate refUpdate = r.getRemoteUpdate(tagRef);
+ assertThat(refUpdate.getStatus()).named("LIGHTWEIGHT").isEqualTo(expectedStatus);
+ return tagName;
+ }
+
+ private boolean isEmpty(Path dir) throws IOException {
+ try (Stream<Path> dirStream = Files.list(dir)) {
+ return !dirStream.iterator().hasNext();
+ }
+ }
+
+ private boolean containsDeletedProject(Path dir, String projectName) throws IOException {
+ try (Stream<Path> dirStream = Files.list(dir)) {
+ return dirStream.anyMatch(d -> d.toString().contains(projectName));
+ }
+ }
+}