org.eclipse.orion.server.tests.servlets.git.GitPushTest.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.orion.server.tests.servlets.git.GitPushTest.java

Source

/*******************************************************************************
 * Copyright (c) 2011, 2012 IBM Corporation and others 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 * IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.orion.server.tests.servlets.git;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import com.meterware.httpunit.*;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URI;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.MergeResult.MergeStatus;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.orion.internal.server.core.IOUtilities;
import org.eclipse.orion.internal.server.servlets.ProtocolConstants;
import org.eclipse.orion.server.core.ServerStatus;
import org.eclipse.orion.server.git.GitConstants;
import org.json.*;
import org.junit.*;
import org.junit.Test;

public class GitPushTest extends GitTest {

    @BeforeClass
    public static void prepareSsh() {
        readSshProperties();
    }

    @Test
    public void testPushNoBody() throws Exception {
        // clone a repo
        URI workspaceLocation = createWorkspace(getMethodName());
        String workspaceId = workspaceIdFromLocation(workspaceLocation);
        JSONObject project = createProjectOrLink(workspaceLocation, getMethodName(), null);
        IPath clonePath = getClonePath(workspaceId, project);
        clone(clonePath);

        // get project metadata
        WebRequest request = getGetRequest(project.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        WebResponse response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project = new JSONObject(response.getText());

        JSONObject gitSection = project.getJSONObject(GitConstants.KEY_GIT);
        String gitRemoteUri = gitSection.getString(GitConstants.KEY_REMOTE);

        // get remote branch location
        JSONObject remoteBranch = getRemoteBranch(gitRemoteUri, 1, 0, Constants.MASTER);
        String remoteBranchLocation = remoteBranch.getString(ProtocolConstants.KEY_LOCATION);

        // push with no body
        request = getPostGitRemoteRequest(remoteBranchLocation, null, false, false);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_BAD_REQUEST, response.getResponseCode());
    }

    @Test
    public void testPushHead() throws Exception {
        URI workspaceLocation = createWorkspace(getMethodName());
        String workspaceId = workspaceIdFromLocation(workspaceLocation);

        // clone1
        JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName() + "1", null);
        IPath clonePath1 = getClonePath(workspaceId, project1);
        clone(clonePath1);

        // get project1 metadata
        WebRequest request = getGetRequest(project1.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        WebResponse response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project1 = new JSONObject(response.getText());

        JSONObject gitSection1 = project1.getJSONObject(GitConstants.KEY_GIT);
        String gitRemoteUri1 = gitSection1.getString(GitConstants.KEY_REMOTE);
        String gitHeadUri1 = gitSection1.getString(GitConstants.KEY_HEAD);

        // clone2
        JSONObject project2 = createProjectOrLink(workspaceLocation, getMethodName() + "2", null);
        IPath clonePath2 = getClonePath(workspaceId, project2);
        clone(clonePath2);

        // get project2 metadata
        request = getGetRequest(project2.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project2 = new JSONObject(response.getText());
        JSONObject gitSection2 = project2.getJSONObject(GitConstants.KEY_GIT);
        String gitRemoteUri2 = gitSection2.getString(GitConstants.KEY_REMOTE);
        String gitHeadUri2 = gitSection2.getString(GitConstants.KEY_HEAD);

        // clone1: list remotes
        request = GitRemoteTest.getGetGitRemoteRequest(gitRemoteUri1);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        JSONObject remotes = new JSONObject(response.getText());
        JSONArray remotesArray = remotes.getJSONArray(ProtocolConstants.KEY_CHILDREN);
        assertEquals(1, remotesArray.length());
        JSONObject remote = remotesArray.getJSONObject(0);
        assertNotNull(remote);
        assertEquals(Constants.DEFAULT_REMOTE_NAME, remote.getString(ProtocolConstants.KEY_NAME));

        // clone1: change
        JSONObject testTxt1 = getChild(project1, "test.txt");
        modifyFile(testTxt1, "incoming change");

        addFile(testTxt1);

        // clone1: commit
        request = GitCommitTest.getPostGitCommitRequest(gitHeadUri1, "incoming change commit", false);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // clone1: push
        ServerStatus pushStatus = push(gitRemoteUri1, 1, 0, Constants.MASTER, Constants.HEAD, false);
        assertEquals(true, pushStatus.isOK());

        // clone2: get remote branch location
        JSONObject remoteBranch = getRemoteBranch(gitRemoteUri2, 1, 0, Constants.MASTER);
        String remoteBranchLocation2 = remoteBranch.getString(ProtocolConstants.KEY_LOCATION);

        // clone2: fetch
        fetch(remoteBranchLocation2);

        // clone2: get remote details
        JSONObject remoteBranch2 = getRemoteBranch(gitRemoteUri2, 1, 0, Constants.MASTER);
        String newRefId2 = remoteBranch2.getString(ProtocolConstants.KEY_ID);

        // clone2: merge into HEAD, "git merge origin/master"
        gitHeadUri2 = remoteBranch2.getString(GitConstants.KEY_HEAD);
        JSONObject merge = merge(gitHeadUri2, newRefId2);
        MergeStatus mergeResult = MergeStatus.valueOf(merge.getString(GitConstants.KEY_RESULT));
        assertEquals(MergeStatus.FAST_FORWARD, mergeResult);

        // clone2: assert change from clone1 is in place
        JSONObject testTxt2 = getChild(project2, "test.txt");
        request = getGetRequest(testTxt2.getString(ProtocolConstants.KEY_LOCATION));
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        assertEquals("incoming change", response.getText());
    }

    @Test
    public void testPushHeadSshWithPrivateKeyPassphrase() throws Exception {
        Assume.assumeTrue(sshRepo2 != null);
        Assume.assumeTrue(knownHosts2 != null);
        Assume.assumeTrue(privateKey != null);
        Assume.assumeTrue(passphrase != null);

        URI workspaceLocation = createWorkspace(getMethodName());
        String workspaceId = workspaceIdFromLocation(workspaceLocation);
        URIish uri = new URIish(sshRepo2);

        // clone1: create
        JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName() + "1", null);
        IPath clonePath = getClonePath(workspaceId, project1);

        WebRequest request = new PostGitCloneRequest().setURIish(uri).setFilePath(clonePath)
                .setKnownHosts(knownHosts2).setPrivateKey(privateKey).setPublicKey(publicKey)
                .setPassphrase(passphrase).getWebRequest();
        String cloneContentLocation1 = clone(request);

        // clone1: get project/folder metadata
        request = getGetRequest(cloneContentLocation1);
        WebResponse response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project1 = new JSONObject(response.getText());

        // clone1: get git links
        JSONObject gitSection1 = project1.getJSONObject(GitConstants.KEY_GIT);
        String gitRemoteUri1 = gitSection1.optString(GitConstants.KEY_REMOTE);
        String gitIndexUri1 = gitSection1.optString(GitConstants.KEY_INDEX);
        String gitHeadUri1 = gitSection1.optString(GitConstants.KEY_HEAD);

        // clone2: create
        JSONObject project2 = createProjectOrLink(workspaceLocation, getMethodName() + "2", null);
        clonePath = getClonePath(workspaceId, project2);
        request = new PostGitCloneRequest().setURIish(uri).setFilePath(clonePath).setKnownHosts(knownHosts2)
                .setPrivateKey(privateKey).setPublicKey(publicKey).setPassphrase(passphrase).getWebRequest();
        String cloneContentLocation2 = clone(request);

        // clone2: get project/folder metadata
        request = getGetRequest(cloneContentLocation2);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project2 = new JSONObject(response.getText());

        // clone2: get git links
        JSONObject gitSection2 = project2.getJSONObject(GitConstants.KEY_GIT);
        String gitRemoteUri2 = gitSection2.getString(GitConstants.KEY_REMOTE);
        String gitCommitUri2 = gitSection2.getString(GitConstants.KEY_COMMIT);

        // clone1: list remotes
        request = GitRemoteTest.getGetGitRemoteRequest(gitRemoteUri1);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        JSONObject remotes = new JSONObject(response.getText());
        JSONArray remotesArray = remotes.getJSONArray(ProtocolConstants.KEY_CHILDREN);
        assertEquals(1, remotesArray.length());
        JSONObject remote = remotesArray.getJSONObject(0);
        assertNotNull(remote);
        assertEquals(Constants.DEFAULT_REMOTE_NAME, remote.getString(ProtocolConstants.KEY_NAME));

        // clone1: change
        JSONObject testTxt1 = getChild(project1, "test.txt");
        modifyFile(testTxt1, "incoming change");

        // clone1: add
        request = GitAddTest.getPutGitIndexRequest(gitIndexUri1);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // clone1: commit
        request = GitCommitTest.getPostGitCommitRequest(gitHeadUri1, "incoming change commit", false);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // clone1: push
        ServerStatus pushStatus = push(gitRemoteUri1, 1, 0, Constants.MASTER, Constants.HEAD, false, null,
                knownHosts2, privateKey, publicKey, passphrase, true);
        assertEquals(true, pushStatus.isOK());

        // clone2: get remote branch location
        JSONObject remoteBranch = getRemoteBranch(gitRemoteUri2, 1, 0, Constants.MASTER);
        String remoteBranchLocation2 = remoteBranch.getString(ProtocolConstants.KEY_LOCATION);

        // clone2: fetch
        fetch(remoteBranchLocation2, null, knownHosts2, privateKey, publicKey, passphrase, true);

        // clone2: get remote details
        JSONObject remoteBranch2 = getRemoteBranch(gitRemoteUri2, 1, 0, Constants.MASTER);
        String newRefId2 = remoteBranch2.getString(ProtocolConstants.KEY_ID);

        // clone2: merge into HEAD, "git merge origin/master"
        gitCommitUri2 = remoteBranch2.getString(GitConstants.KEY_HEAD);
        JSONObject merge = merge(gitCommitUri2, newRefId2);
        MergeStatus mergeResult = MergeStatus.valueOf(merge.getString(GitConstants.KEY_RESULT));
        assertEquals(MergeStatus.FAST_FORWARD, mergeResult);

        // clone2: assert change from clone1 is in place
        JSONObject testTxt2 = getChild(project2, "test.txt");
        request = getGetRequest(testTxt2.getString(ProtocolConstants.KEY_LOCATION));
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        assertEquals("incoming change", response.getText());
    }

    @Test
    public void testPushBranch() throws Exception {
        URI workspaceLocation = createWorkspace(getMethodName());
        String workspaceId = workspaceIdFromLocation(workspaceLocation);

        // clone1: create
        JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName() + "1", null);
        IPath clonePath1 = getClonePath(workspaceId, project1);
        JSONObject clone1 = clone(clonePath1);
        String cloneLocation1 = clone1.getString(ProtocolConstants.KEY_LOCATION);
        String branchesLocation1 = clone1.getString(GitConstants.KEY_BRANCH);

        // get project1 metadata
        WebRequest request = getGetRequest(project1.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        WebResponse response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project1 = new JSONObject(response.getText());
        JSONObject gitSection1 = project1.optJSONObject(GitConstants.KEY_GIT);
        assertNotNull(gitSection1);
        String gitIndexUri1 = gitSection1.getString(GitConstants.KEY_INDEX);
        String gitHeadUri1 = gitSection1.getString(GitConstants.KEY_HEAD);

        // clone1: branch 'a'
        response = branch(branchesLocation1, "a");
        JSONObject branch = new JSONObject(response.getText());

        checkoutBranch(cloneLocation1, "a");

        // clone1: change
        JSONObject testTxt1 = getChild(project1, "test.txt");
        modifyFile(testTxt1, "branch 'a' change");

        // clone1: add
        request = GitAddTest.getPutGitIndexRequest(gitIndexUri1);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // clone1: commit
        request = GitCommitTest.getPostGitCommitRequest(gitHeadUri1, "incoming branch 'a' commit", false);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // clone1: push by remote branch
        JSONArray remoteBranchLocations = branch.getJSONArray(GitConstants.KEY_REMOTE);
        assertEquals(1, remoteBranchLocations.length());
        String remoteBranchLocation = remoteBranchLocations.getJSONObject(0)
                .getJSONArray(ProtocolConstants.KEY_CHILDREN).getJSONObject(0)
                .getString(ProtocolConstants.KEY_LOCATION);
        ServerStatus pushStatus = push(remoteBranchLocation, Constants.HEAD, false);
        assertTrue(pushStatus.isOK());

        // clone1: get the remote branch name
        request = getGetRequest(remoteBranchLocation);
        response = webConversation.getResponse(request);
        JSONObject remoteBranch1 = new JSONObject(response.getText());
        String remoteBranchName1 = remoteBranch1.getString(ProtocolConstants.KEY_NAME);

        // clone2
        JSONObject project2 = createProjectOrLink(workspaceLocation, getMethodName() + "2", null);
        IPath clonePath2 = getClonePath(workspaceId, project2);
        JSONObject clone2 = clone(clonePath2);
        String cloneLocation2 = clone2.getString(ProtocolConstants.KEY_LOCATION);
        String branchesLocation2 = clone2.getString(GitConstants.KEY_BRANCH);

        // get project2 metadata
        request = getGetRequest(project2.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project2 = new JSONObject(response.getText());
        JSONObject gitSection2 = project2.optJSONObject(GitConstants.KEY_GIT);
        assertNotNull(gitSection2);

        // create a local branch 'a' tracking remoteBranchName1 and checkout 'a'
        response = branch(branchesLocation2, "a", remoteBranchName1);
        assertEquals(HttpURLConnection.HTTP_CREATED, response.getResponseCode());
        response = checkoutBranch(cloneLocation2, "a");
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        JSONObject testTxt2 = getChild(project2, "test.txt");
        request = getGetRequest(testTxt2.getString(ProtocolConstants.KEY_LOCATION));
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        assertEquals("branch 'a' change", response.getText());
    }

    @Test
    public void testPushToDelete() throws Exception {
        URI workspaceLocation = createWorkspace(getMethodName());
        IPath[][] clonePaths = createTestClonePairs(workspaceLocation);

        for (IPath[] clonePath : clonePaths) {
            // clone 1
            JSONObject clone1 = clone(clonePath[0]);
            String cloneLocation1 = clone1.getString(ProtocolConstants.KEY_LOCATION);
            String contentLocation1 = clone1.getString(ProtocolConstants.KEY_CONTENT_LOCATION);
            String branchesLocation1 = clone1.getString(GitConstants.KEY_BRANCH);

            // clone 1 - get project1 metadata
            WebRequest request = getGetRequest(contentLocation1);
            WebResponse response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            JSONObject project1 = new JSONObject(response.getText());
            JSONObject gitSection1 = project1.getJSONObject(GitConstants.KEY_GIT);
            String gitRemoteUri1 = gitSection1.getString(GitConstants.KEY_REMOTE);
            String gitIndexUri1 = gitSection1.getString(GitConstants.KEY_INDEX);
            String gitHeadUri1 = gitSection1.getString(GitConstants.KEY_HEAD);

            // clone 1 - create branch "a"
            response = branch(branchesLocation1, "a");
            JSONObject newBranch = new JSONObject(response.getText());
            JSONArray remoteBranchLocations1 = newBranch.getJSONArray(GitConstants.KEY_REMOTE);
            assertEquals(1, remoteBranchLocations1.length());

            // clone 1 - checkout "a"
            final String newBranchName = "a";
            response = checkoutBranch(cloneLocation1, newBranchName);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

            // clone 1 - change
            JSONObject testTxt1 = getChild(project1, "test.txt");
            modifyFile(testTxt1, "clone1 change");

            // clone 1 - add
            request = GitAddTest.getPutGitIndexRequest(gitIndexUri1);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

            // clone 1 - commit
            request = GitCommitTest.getPostGitCommitRequest(gitHeadUri1, "clone1 change commit", false);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

            // clone 1 - push "a"
            int i = 0;
            String remoteBranchName = remoteBranchLocations1.getJSONObject(0)
                    .getJSONArray(ProtocolConstants.KEY_CHILDREN).getJSONObject(i)
                    .getString(ProtocolConstants.KEY_NAME);
            if (!remoteBranchName.equals("origin/a")) {
                i = 1;
                remoteBranchName = remoteBranchLocations1.getJSONObject(0)
                        .getJSONArray(ProtocolConstants.KEY_CHILDREN).getJSONObject(i)
                        .getString(ProtocolConstants.KEY_NAME);
            }
            assertEquals("origin/a", remoteBranchName);
            String remoteBranchLocation1 = remoteBranchLocations1.getJSONObject(0)
                    .getJSONArray(ProtocolConstants.KEY_CHILDREN).getJSONObject(i)
                    .getString(ProtocolConstants.KEY_LOCATION);
            ServerStatus pushStatus = push(remoteBranchLocation1, Constants.HEAD, false);
            assertEquals(true, pushStatus.isOK());

            // clone 1 - list remote branches - expect 2
            JSONObject remote1 = getRemote(gitRemoteUri1, 1, 0, Constants.DEFAULT_REMOTE_NAME);
            String remoteLocation1 = remote1.getString(ProtocolConstants.KEY_LOCATION);

            request = GitRemoteTest.getGetGitRemoteRequest(remoteLocation1);
            response = webConversation.getResponse(request);
            ServerStatus status = waitForTask(response);
            assertTrue(status.toString(), status.isOK());
            remote1 = status.getJsonData();
            JSONArray refsArray = remote1.getJSONArray(ProtocolConstants.KEY_CHILDREN);
            assertEquals(2, refsArray.length());
            JSONObject ref = refsArray.getJSONObject(0);
            assertEquals(Constants.R_REMOTES + Constants.DEFAULT_REMOTE_NAME + "/" + newBranchName,
                    ref.getString(ProtocolConstants.KEY_FULL_NAME));
            ref = refsArray.getJSONObject(1);
            assertEquals(Constants.R_REMOTES + Constants.DEFAULT_REMOTE_NAME + "/" + Constants.MASTER,
                    ref.getString(ProtocolConstants.KEY_FULL_NAME));

            // clone 2 
            JSONObject clone2 = clone(clonePath[1]);
            String cloneLocation2 = clone2.getString(ProtocolConstants.KEY_LOCATION);
            String contentLocation2 = clone2.getString(ProtocolConstants.KEY_CONTENT_LOCATION);

            // clone 2 - get project2 metadata
            request = getGetRequest(contentLocation2);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            JSONObject project2 = new JSONObject(response.getText());
            JSONObject gitSection2 = project2.getJSONObject(GitConstants.KEY_GIT);
            String gitRemoteUri2 = gitSection2.getString(GitConstants.KEY_REMOTE);

            // clone 2 - check if the branch "a" is available
            JSONObject remote2 = getRemote(gitRemoteUri2, 1, 0, Constants.DEFAULT_REMOTE_NAME);
            String remoteLocation2 = remote2.getString(ProtocolConstants.KEY_LOCATION);

            request = GitRemoteTest.getGetGitRemoteRequest(remoteLocation2);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            remote2 = new JSONObject(response.getText());
            refsArray = remote2.getJSONArray(ProtocolConstants.KEY_CHILDREN);
            assertEquals(2, refsArray.length());
            ref = refsArray.getJSONObject(0);
            assertEquals(Constants.R_REMOTES + Constants.DEFAULT_REMOTE_NAME + "/" + Constants.MASTER,
                    ref.getString(ProtocolConstants.KEY_FULL_NAME));
            ref = refsArray.getJSONObject(1);
            assertEquals(Constants.R_REMOTES + Constants.DEFAULT_REMOTE_NAME + "/" + newBranchName,
                    ref.getString(ProtocolConstants.KEY_FULL_NAME));
            String remoteBranchLocation2 = ref.getString(ProtocolConstants.KEY_LOCATION);

            // clone 2 - checkout branch "a"
            response = checkoutBranch(cloneLocation2, newBranchName);

            // clone 1 - delete remote branch "a"
            push(remoteBranchLocation1, "", false, false);

            // clone 1 - list remote branches - expect 1
            request = GitRemoteTest.getGetGitRemoteRequest(remoteLocation1);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            remote1 = new JSONObject(response.getText());
            refsArray = remote1.getJSONArray(ProtocolConstants.KEY_CHILDREN);
            assertEquals(1, refsArray.length());
            ref = refsArray.getJSONObject(0);
            assertEquals(Constants.R_REMOTES + Constants.DEFAULT_REMOTE_NAME + "/" + Constants.MASTER,
                    ref.getString(ProtocolConstants.KEY_FULL_NAME));

            // clone 2 - fetch
            request = GitFetchTest.getPostGitRemoteRequest(remoteBranchLocation2, true, false);
            response = webConversation.getResponse(request);
            status = waitForTask(response);
            assertFalse(status.toString(), status.isOK());

            // clone 2 - fetch task should fail
            JSONObject statusJson = status.toJSON();
            JSONObject result = statusJson.has("Result") ? statusJson.getJSONObject("Result") : statusJson;
            assertEquals("Error", result.getString("Severity"));
        }
    }

    @Test
    public void testPushFromLog() throws Exception {
        // clone a repo
        URI workspaceLocation = createWorkspace(getMethodName());
        String workspaceId = workspaceIdFromLocation(workspaceLocation);
        JSONObject project = createProjectOrLink(workspaceLocation, getMethodName(), null);
        IPath clonePath = getClonePath(workspaceId, project);
        clone(clonePath);

        // get project metadata
        WebRequest request = getGetRequest(project.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        WebResponse response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project = new JSONObject(response.getText());

        JSONObject gitSection = project.getJSONObject(GitConstants.KEY_GIT);
        String gitIndexUri = gitSection.getString(GitConstants.KEY_INDEX);
        String gitHeadUri = gitSection.getString(GitConstants.KEY_HEAD);

        // log
        JSONArray commitsArray = log(gitHeadUri);
        assertEquals(1, commitsArray.length());

        // change
        JSONObject testTxt = getChild(project, "test.txt");
        modifyFile(testTxt, "incoming change");

        // add
        request = GitAddTest.getPutGitIndexRequest(gitIndexUri);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // commit
        request = GitCommitTest.getPostGitCommitRequest(gitHeadUri, "incoming change commit", false);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // log again
        JSONObject logResponse = logObject(gitHeadUri);
        assertEquals(2, logResponse.getJSONArray(ProtocolConstants.KEY_CHILDREN).length());

        JSONObject toRefBranch = logResponse.getJSONObject(GitConstants.KEY_LOG_TO_REF);
        JSONArray remoteLocations = toRefBranch.getJSONArray(GitConstants.KEY_REMOTE);
        assertEquals(1, remoteLocations.length());
        String remoteBranchLocation = remoteLocations.getJSONObject(0).getJSONArray(ProtocolConstants.KEY_CHILDREN)
                .getJSONObject(0).getString(ProtocolConstants.KEY_LOCATION);

        // push
        request = getPostGitRemoteRequest(remoteBranchLocation, Constants.HEAD, false, false);
        response = webConversation.getResponse(request);
        ServerStatus status = waitForTask(response);
        assertTrue(status.toString(), status.isOK());
    }

    @Test
    public void testPushRejected() throws Exception {
        URI workspaceLocation = createWorkspace(getMethodName());
        String workspaceId = workspaceIdFromLocation(workspaceLocation);

        // clone1
        JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName() + "1", null);
        IPath clonePath1 = getClonePath(workspaceId, project1);
        clone(clonePath1);

        // get project1 metadata
        WebRequest request = getGetRequest(project1.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        WebResponse response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project1 = new JSONObject(response.getText());
        JSONObject gitSection1 = project1.optJSONObject(GitConstants.KEY_GIT);
        assertNotNull(gitSection1);
        String gitRemoteUri1 = gitSection1.optString(GitConstants.KEY_REMOTE);
        String gitIndexUri1 = gitSection1.optString(GitConstants.KEY_INDEX);
        String gitHeadUri1 = gitSection1.optString(GitConstants.KEY_HEAD);

        // clone2
        JSONObject project2 = createProjectOrLink(workspaceLocation, getMethodName() + "2", null);
        IPath clonePath2 = getClonePath(workspaceId, project2);
        clone(clonePath2);

        // get project2 metadata
        request = getGetRequest(project2.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project2 = new JSONObject(response.getText());
        JSONObject gitSection2 = project2.optJSONObject(GitConstants.KEY_GIT);
        assertNotNull(gitSection2);
        String gitRemoteUri2 = gitSection2.getString(GitConstants.KEY_REMOTE);
        String gitIndexUri2 = gitSection2.getString(GitConstants.KEY_INDEX);
        String gitHeadUri2 = gitSection2.getString(GitConstants.KEY_HEAD);

        // clone1: change
        JSONObject testTxt1 = getChild(project1, "test.txt");
        modifyFile(testTxt1, "clone1 change");

        // clone1: add
        request = GitAddTest.getPutGitIndexRequest(gitIndexUri1);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // clone1: commit
        request = GitCommitTest.getPostGitCommitRequest(gitHeadUri1, "clone1 change commit", false);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // clone1: push
        ServerStatus pushStatus = push(gitRemoteUri1, 1, 0, Constants.MASTER, Constants.HEAD, false);
        assertEquals(true, pushStatus.isOK());

        // clone2: change
        JSONObject testTxt2 = getChild(project2, "test.txt");
        modifyFile(testTxt2, "clone2 change");

        // clone2: add
        request = GitAddTest.getPutGitIndexRequest(gitIndexUri2);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // clone2: commit
        request = GitCommitTest.getPostGitCommitRequest(gitHeadUri2, "clone2 change commit", false);
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

        // clone2: push
        pushStatus = push(gitRemoteUri2, 1, 0, Constants.MASTER, Constants.HEAD, false);
        assertEquals(IStatus.WARNING, pushStatus.getSeverity());

        Status pushResult = Status.valueOf(pushStatus.getMessage());
        assertEquals(Status.REJECTED_NONFASTFORWARD, pushResult);
    }

    @Test
    public void testPushRemoteRejected() throws Exception {
        // clone a repo
        URI workspaceLocation = createWorkspace(getMethodName());
        String workspaceId = workspaceIdFromLocation(workspaceLocation);
        JSONObject project = createProjectOrLink(workspaceLocation, getMethodName(), null);
        IPath clonePath = getClonePath(workspaceId, project);
        clone(clonePath);

        // get project metadata
        WebRequest request = getGetRequest(project.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        WebResponse response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project = new JSONObject(response.getText());

        JSONObject gitSection = project.getJSONObject(GitConstants.KEY_GIT);
        String gitRemoteUri = gitSection.getString(GitConstants.KEY_REMOTE);

        // 1st commit
        JSONObject testTxt = getChild(project, "test.txt");
        modifyFile(testTxt, "1st change");
        addFile(testTxt);
        commitFile(testTxt, "1st change commit", false);

        // push
        ServerStatus pushStatus = push(gitRemoteUri, 1, 0, Constants.MASTER, Constants.HEAD, false);
        assertEquals(IStatus.OK, pushStatus.getSeverity());

        // 2nd commit
        modifyFile(testTxt, "2nd change");
        addFile(testTxt);
        commitFile(testTxt, "2nd change commit", false);

        FileUtils.delete(new File(gitDir, Constants.DOT_GIT + "/objects/pack/"), FileUtils.RECURSIVE);

        pushStatus = push(gitRemoteUri, 1, 0, Constants.MASTER, Constants.HEAD, false);
        assertEquals(IStatus.WARNING, pushStatus.getSeverity());
        Status pushResult = Status.valueOf(pushStatus.getMessage());
        assertEquals(Status.REJECTED_OTHER_REASON, pushResult);
        JSONObject jsonResult = pushStatus.toJSON();
        if (jsonResult.has("JsonData")) {
            jsonResult = jsonResult.getJSONObject("JsonData");
        }
        assertTrue(jsonResult.toString(), jsonResult.has("DetailedMessage"));
        assertTrue(jsonResult.getString("DetailedMessage"),
                jsonResult.getString("DetailedMessage").matches("^object [\\da-f]+ missing$"));
    }

    @Test
    public void testForcedPush() throws Exception {
        // overwrite system settings, allow forced pushes, see bug 371881
        StoredConfig cfg = db.getConfig();
        cfg.setBoolean("receive", null, "denyNonFastforwards", false);
        cfg.save();

        URI workspaceLocation = createWorkspace(getMethodName());
        IPath[][] clonePaths = createTestClonePairs(workspaceLocation);

        for (IPath[] clonePath : clonePaths) {
            // clone1
            String contentLocation1 = clone(clonePath[0]).getString(ProtocolConstants.KEY_CONTENT_LOCATION);

            // get project1 metadata
            WebRequest request = getGetRequest(contentLocation1);
            WebResponse response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            JSONObject project1 = new JSONObject(response.getText());
            JSONObject gitSection1 = project1.getJSONObject(GitConstants.KEY_GIT);
            String gitRemoteUri1 = gitSection1.getString(GitConstants.KEY_REMOTE);
            String gitIndexUri1 = gitSection1.getString(GitConstants.KEY_INDEX);
            String gitHeadUri1 = gitSection1.getString(GitConstants.KEY_HEAD);

            // clone2
            String contentLocation2 = clone(clonePath[1]).getString(ProtocolConstants.KEY_CONTENT_LOCATION);

            // get project2 metadata
            request = getGetRequest(contentLocation2);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            JSONObject project2 = new JSONObject(response.getText());
            JSONObject gitSection2 = project2.getJSONObject(GitConstants.KEY_GIT);
            String gitRemoteUri2 = gitSection2.getString(GitConstants.KEY_REMOTE);
            String gitIndexUri2 = gitSection2.getString(GitConstants.KEY_INDEX);
            String gitHeadUri2 = gitSection2.getString(GitConstants.KEY_HEAD);

            // clone1: change
            JSONObject testTxt1 = getChild(project1, "test.txt");
            modifyFile(testTxt1, "clone1 change");

            // clone1: add
            request = GitAddTest.getPutGitIndexRequest(gitIndexUri1);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

            // clone1: commit
            request = GitCommitTest.getPostGitCommitRequest(gitHeadUri1, "clone1 change commit", false);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

            // clone1: push
            ServerStatus pushStatus = push(gitRemoteUri1, 1, 0, Constants.MASTER, Constants.HEAD, false);
            assertEquals(true, pushStatus.isOK());

            // clone2: change
            JSONObject testTxt2 = getChild(project2, "test.txt");
            modifyFile(testTxt2, "clone2 change");

            // clone2: add
            request = GitAddTest.getPutGitIndexRequest(gitIndexUri2);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

            // clone2: commit
            request = GitCommitTest.getPostGitCommitRequest(gitHeadUri2, "clone2 change commit", false);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

            // clone2: push
            pushStatus = push(gitRemoteUri2, 1, 0, Constants.MASTER, Constants.HEAD, false);
            assertEquals(IStatus.WARNING, pushStatus.getSeverity());
            Status pushResult = Status.valueOf(pushStatus.getMessage());
            assertEquals(Status.REJECTED_NONFASTFORWARD, pushResult);

            // clone2: forced push
            pushStatus = push(gitRemoteUri2, 1, 0, Constants.MASTER, Constants.HEAD, false, true);
            assertTrue(pushStatus.toJSON().toString(), pushStatus.isOK());
        }
    }

    @Test
    public void testPushTags() throws Exception {
        URI workspaceLocation = createWorkspace(getMethodName());
        String workspaceId = workspaceIdFromLocation(workspaceLocation);

        // clone1
        JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName() + "1", null);
        IPath clonePath1 = getClonePath(workspaceId, project1);
        clone(clonePath1);

        // get project1 metadata
        WebRequest request = getGetRequest(project1.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        WebResponse response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project1 = new JSONObject(response.getText());

        JSONObject gitSection1 = project1.optJSONObject(GitConstants.KEY_GIT);
        assertNotNull(gitSection1);
        String gitRemoteUri1 = gitSection1.optString(GitConstants.KEY_REMOTE);
        String gitTagUri1 = gitSection1.optString(GitConstants.KEY_TAG);

        // clone2
        JSONObject project2 = createProjectOrLink(workspaceLocation, getMethodName() + "2", null);
        IPath clonePath2 = getClonePath(workspaceId, project2);
        clone(clonePath2);

        // get project2 metadata
        request = getGetRequest(project2.getString(ProtocolConstants.KEY_CONTENT_LOCATION));
        response = webConversation.getResponse(request);
        assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
        project2 = new JSONObject(response.getText());

        JSONObject gitSection2 = project2.getJSONObject(GitConstants.KEY_GIT);
        String gitRemoteUri2 = gitSection2.getString(GitConstants.KEY_REMOTE);
        String gitHeadUri2 = gitSection2.getString(GitConstants.KEY_HEAD);
        String gitTagUri2 = gitSection2.getString(GitConstants.KEY_TAG);

        // clone1: tag HEAD with 'tag'
        tag(gitTagUri1, "tag", Constants.HEAD);

        ServerStatus pushStatus = push(gitRemoteUri1, 1, 0, Constants.MASTER, Constants.HEAD, true);
        assertEquals(true, pushStatus.isOK());

        // clone2: list tags
        JSONArray tags = listTags(gitTagUri2);
        assertEquals(0, tags.length());

        // clone2: fetch + merge
        JSONObject remoteBranch = getRemoteBranch(gitRemoteUri2, 1, 0, Constants.MASTER);
        String remoteBranchLocation2 = remoteBranch.getString(ProtocolConstants.KEY_LOCATION);
        fetch(remoteBranchLocation2);
        String id = remoteBranch.getString(ProtocolConstants.KEY_ID);
        merge(gitHeadUri2, id);

        // clone2: list tags again
        tags = listTags(gitTagUri2);
        assertEquals(1, tags.length());
    }

    @Test
    public void testPushNewBranchToSecondaryRemote() throws Exception {
        // see bug 353557
        URI workspaceLocation = createWorkspace(getMethodName());
        IPath[] clonePaths = createTestProjects(workspaceLocation);
        String workspaceId = workspaceIdFromLocation(workspaceLocation);

        for (int i = 0; i < clonePaths.length; i++) {
            IPath clonePath = clonePaths[i];
            // clone a  repo
            JSONObject clone = clone(clonePath);
            String cloneContentLocation = clone.getString(ProtocolConstants.KEY_CONTENT_LOCATION);
            String cloneLocation = clone.getString(ProtocolConstants.KEY_LOCATION);
            String branchesLocation = clone.getString(GitConstants.KEY_BRANCH);

            // get project/folder metadata
            WebRequest request = getGetRequest(cloneContentLocation);
            WebResponse response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            JSONObject folder = new JSONObject(response.getText());

            String remotesLocation = clone.getString(GitConstants.KEY_REMOTE);
            // expect only origin
            getRemote(remotesLocation, 1, 0, Constants.DEFAULT_REMOTE_NAME);

            // create secondary repository
            IPath randomLocation = AllGitTests.getRandomLocation();
            randomLocation = randomLocation.addTrailingSeparator().append(Constants.DOT_GIT);
            File dotGitDir = randomLocation.toFile().getCanonicalFile();
            Repository db2 = FileRepositoryBuilder.create(dotGitDir);
            assertFalse(dotGitDir.exists());
            db2.create(false /* non bare */);

            // dummy commit to start off master branch
            File dummyFile = new File(dotGitDir.getParentFile(), "test.txt");
            dummyFile.createNewFile();
            createFile(dummyFile.toURI(), "dummy");
            Git git2 = new Git(db2);
            git2.add().addFilepattern(".").call();
            git2.commit().setMessage("dummy commit").call();

            // create remote
            response = addRemote(remotesLocation, "secondary", dotGitDir.getParentFile().toURL().toString());
            String secondaryRemoteLocation = response.getHeaderField(ProtocolConstants.HEADER_LOCATION);
            assertNotNull(secondaryRemoteLocation);

            // list remotes
            request = getGetRequest(remotesLocation);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            JSONObject remotes = new JSONObject(response.getText());
            JSONArray remotesArray = remotes.getJSONArray(ProtocolConstants.KEY_CHILDREN);
            // expect origin and new remote
            assertEquals(2, remotesArray.length());

            // create branch, checkout
            response = branch(branchesLocation, "branch");
            JSONObject branch = new JSONObject(response.getText());
            checkoutBranch(cloneLocation, "branch");

            // modify, add, commit
            JSONObject testTxt = getChild(folder, "test.txt");
            modifyFile(testTxt, "branch change");
            addFile(testTxt);
            commitFile(testTxt, "branch commit", false);

            // push the new branch
            JSONArray remoteBranchLocations = branch.getJSONArray(GitConstants.KEY_REMOTE);
            assertEquals(2, remoteBranchLocations.length());
            String remoteBranchLocation = null;
            if (remoteBranchLocations.getJSONObject(0).getString(ProtocolConstants.KEY_NAME).equals("secondary")) {
                remoteBranchLocation = remoteBranchLocations.getJSONObject(0)
                        .getJSONArray(ProtocolConstants.KEY_CHILDREN).getJSONObject(0)
                        .getString(ProtocolConstants.KEY_LOCATION);
            } else if (remoteBranchLocations.getJSONObject(1).getString(ProtocolConstants.KEY_NAME)
                    .equals("secondary")) {
                remoteBranchLocation = remoteBranchLocations.getJSONObject(1)
                        .getJSONArray(ProtocolConstants.KEY_CHILDREN).getJSONObject(0)
                        .getString(ProtocolConstants.KEY_LOCATION);
            }
            assertNotNull(remoteBranchLocation);
            ServerStatus pushStatus = push(remoteBranchLocation, Constants.HEAD, false);
            assertTrue(pushStatus.isOK());

            // see bug 354144
            request = getGetRequest(branch.getString(ProtocolConstants.KEY_LOCATION));
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            branch = new JSONObject(response.getText());
            remoteBranchLocations = branch.getJSONArray(GitConstants.KEY_REMOTE);
            // now, there should be only one remote branch returned
            assertEquals(1, remoteBranchLocations.length());
            assertEquals("secondary", remoteBranchLocations.getJSONObject(0).getString(ProtocolConstants.KEY_NAME));
            assertEquals("secondary/branch",
                    remoteBranchLocations.getJSONObject(0).getJSONArray(ProtocolConstants.KEY_CHILDREN)
                            .getJSONObject(0).getString(ProtocolConstants.KEY_NAME));

            // clone the secondary branch and check if the new branch is there
            JSONObject secondProject = createProjectOrLink(workspaceLocation, getMethodName() + "-second-" + i,
                    null);
            IPath secondClonePath = getClonePath(workspaceId, secondProject);
            URIish uri = new URIish(dotGitDir.getParentFile().toURI().toURL());
            JSONObject clone2 = clone(uri, null, secondClonePath, null, null, null);
            String cloneLocation2 = clone2.getString(ProtocolConstants.KEY_LOCATION);
            String branchesLocation2 = clone2.getString(GitConstants.KEY_BRANCH);

            String remotesLocation2 = clone2.getString(GitConstants.KEY_REMOTE);
            // expecting two branches, second named "branch"
            JSONObject remoteBranch2 = getRemoteBranch(remotesLocation2, 2, 1, "branch");
            String remoteBranchName2 = remoteBranch2.getString(ProtocolConstants.KEY_NAME);

            // create tracking branch and check it out
            response = branch(branchesLocation2, null /* deduct from the remote branch name */, remoteBranchName2);
            JSONObject branch2 = new JSONObject(response.getText());
            response = checkoutBranch(cloneLocation2, branch2.getString(ProtocolConstants.KEY_NAME));
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());

            // check file content
            String cloneContentLocation2 = clone2.getString(ProtocolConstants.KEY_CONTENT_LOCATION);
            request = getGetRequest(cloneContentLocation2);
            response = webConversation.getResponse(request);
            assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
            JSONObject folder2 = new JSONObject(response.getText());
            JSONObject testTxt2 = getChild(folder2, "test.txt");
            assertEquals("branch change", getFileContent(testTxt2));
        }
    }

    static WebRequest getPostGitRemoteRequest(String location, String srcRef, boolean tags, boolean force)
            throws JSONException, UnsupportedEncodingException {
        String requestURI = toAbsoluteURI(location);
        JSONObject body = new JSONObject();
        if (srcRef != null)
            body.put(GitConstants.KEY_PUSH_SRC_REF, srcRef);
        body.put(GitConstants.KEY_PUSH_TAGS, tags);
        body.put(GitConstants.KEY_FORCE, force);
        WebRequest request = new PostMethodWebRequest(requestURI, IOUtilities.toInputStream(body.toString()),
                "UTF-8");
        request.setHeaderField(ProtocolConstants.HEADER_ORION_VERSION, "1");
        setAuthentication(request);
        return request;
    }

    static WebRequest getPostGitRemoteRequest(String location, String srcRef, boolean tags, boolean force,
            String name, String kh, byte[] privk, byte[] pubk, byte[] p)
            throws JSONException, UnsupportedEncodingException {
        String requestURI = toAbsoluteURI(location);
        JSONObject body = new JSONObject();

        body.put(ProtocolConstants.KEY_NAME, name);
        if (kh != null)
            body.put(GitConstants.KEY_KNOWN_HOSTS, kh);
        if (privk != null)
            body.put(GitConstants.KEY_PRIVATE_KEY, new String(privk));
        if (pubk != null)
            body.put(GitConstants.KEY_PUBLIC_KEY, new String(pubk));
        if (p != null)
            body.put(GitConstants.KEY_PASSPHRASE, new String(p));

        if (srcRef != null)
            body.put(GitConstants.KEY_PUSH_SRC_REF, srcRef);
        body.put(GitConstants.KEY_PUSH_TAGS, tags);
        body.put(GitConstants.KEY_FORCE, force);
        WebRequest request = new PostMethodWebRequest(requestURI, IOUtilities.toInputStream(body.toString()),
                "UTF-8");
        request.setHeaderField(ProtocolConstants.HEADER_ORION_VERSION, "1");
        setAuthentication(request);
        return request;
    }
}