/*******************************************************************************
 * Copyright (c) 2011, 2014 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 java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;

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.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
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.metastore.SimpleMetaStore;
import org.eclipse.orion.server.core.IOUtilities;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.eclipse.orion.server.core.ServerStatus;
import org.eclipse.orion.server.git.GitConstants;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;

import com.meterware.httpunit.PostMethodWebRequest;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;

public class GitPushTest extends GitTest {

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

	@Test
	public void testPushNoBody() throws Exception {
		// clone a repo
		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		String workspaceId = workspaceIdFromLocation(workspaceLocation);
		JSONObject project = createProjectOrLink(workspaceLocation, getMethodName().concat("Project"), 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 {
		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		String workspaceId = workspaceIdFromLocation(workspaceLocation);

		// clone1
		JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName().concat("Project1"), 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().concat("Project2"), 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);

		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		String workspaceId = workspaceIdFromLocation(workspaceLocation);
		URIish uri = new URIish(sshRepo2);

		// clone1: create
		JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName().concat("Project1"), 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().concat("Project2"), 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 {
		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		String workspaceId = workspaceIdFromLocation(workspaceLocation);

		// clone1: create
		JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName().concat("Project1"), 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);
		assertTrue(remoteBranchLocations.length() >= 1);
		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().concat("Project2"), 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 {
		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		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);
			assertTrue(remoteBranchLocations1.length() >= 1);

			// 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
		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		String workspaceId = workspaceIdFromLocation(workspaceLocation);
		JSONObject project = createProjectOrLink(workspaceLocation, getMethodName().concat("Project"), 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 {
		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		String workspaceId = workspaceIdFromLocation(workspaceLocation);

		// clone1
		JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName().concat("Project1"), 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().concat("Project2"), 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);
		JSONObject jo = pushStatus.getJsonData();
		assertEquals("Error", jo.get("Severity"));

		JSONArray up = (JSONArray) jo.get("Updates");
		assertEquals(1, up.length());

		Status pushResult = Status.valueOf((String) ((JSONObject) up.get(0)).get("Result"));
		assertEquals(Status.REJECTED_NONFASTFORWARD, pushResult);
	}

	@Test
	public void testPushRemoteRejected() throws Exception {
		// clone a repo
		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		String workspaceId = workspaceIdFromLocation(workspaceLocation);
		JSONObject project = createProjectOrLink(workspaceLocation, getMethodName().concat("Project"), 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);
		JSONObject jo = pushStatus.getJsonData();

		JSONArray up = (JSONArray) jo.get("Updates");
		assertEquals(1, up.length());

		assertEquals("Error", jo.get("Severity"));
		Status pushResult = Status.valueOf((String) ((JSONObject) up.get(0)).get("Result"));
		assertEquals(Status.REJECTED_OTHER_REASON, pushResult);

		assertTrue(((JSONObject) up.get(0)).getString("Message"), ((JSONObject) up.get(0)).getString("Message").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();

		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		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);
			JSONObject jo = pushStatus.getJsonData();

			JSONArray up = (JSONArray) jo.get("Updates");
			assertEquals(1, up.length());

			assertEquals("Error", jo.get("Severity"));
			Status pushResult = Status.valueOf((String) ((JSONObject) up.get(0)).get("Result"));
			assertEquals(Status.REJECTED_NONFASTFORWARD, pushResult);

			// clone2: forced push
			pushStatus = push(gitRemoteUri2, 1, 0, Constants.MASTER, Constants.HEAD, false, true);
			jo = pushStatus.getJsonData();
			up = (JSONArray) jo.get("Updates");
			assertEquals(1, up.length());
			assertEquals("OK", ((JSONObject) up.get(0)).get("Result"));
		}
	}

	@Test
	public void testPushTags() throws Exception {
		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		String workspaceId = workspaceIdFromLocation(workspaceLocation);

		// clone1
		JSONObject project1 = createProjectOrLink(workspaceLocation, getMethodName().concat("Project1"), 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().concat("Project2"), 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
		createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
		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 = createTempDir();
			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 */);
			toClose.add(db2);

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

			// create remote
			response = addRemote(remotesLocation, "secondary", dotGitDir.getParentFile().toURI().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
			assertTrue(remoteBranchLocations.length() >= 1);
			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().concat("-second-").concat(Integer.toString(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;
	}
}