| /******************************************************************************* |
| * Copyright (C) 2010, 2012 Mathias Kinzler <mathias.kinzler@sap.com> 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 |
| *******************************************************************************/ |
| package org.eclipse.egit.core.test.op; |
| |
| 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 static org.junit.Assert.fail; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.ILog; |
| import org.eclipse.core.runtime.ILogListener; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.egit.core.Activator; |
| import org.eclipse.egit.core.op.AddToIndexOperation; |
| import org.eclipse.egit.core.op.BranchOperation; |
| import org.eclipse.egit.core.op.CloneOperation; |
| import org.eclipse.egit.core.op.CommitOperation; |
| import org.eclipse.egit.core.op.PushOperation; |
| import org.eclipse.egit.core.op.PushOperationResult; |
| import org.eclipse.egit.core.op.PushOperationSpecification; |
| import org.eclipse.egit.core.test.DualRepositoryTestCase; |
| import org.eclipse.egit.core.test.TestRepository; |
| import org.eclipse.egit.core.test.TestUtils; |
| import org.eclipse.jgit.lib.Constants; |
| import org.eclipse.jgit.lib.ObjectId; |
| import org.eclipse.jgit.lib.RefUpdate; |
| import org.eclipse.jgit.lib.Repository; |
| import org.eclipse.jgit.revwalk.RevCommit; |
| import org.eclipse.jgit.transport.PushResult; |
| import org.eclipse.jgit.transport.RemoteRefUpdate; |
| import org.eclipse.jgit.transport.RemoteRefUpdate.Status; |
| import org.eclipse.jgit.transport.URIish; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class PushOperationTest extends DualRepositoryTestCase { |
| |
| |
| private static final String INVALID_URI = "invalid-uri"; |
| |
| File workdir; |
| |
| File workdir2; |
| |
| String projectName = "PushTest"; |
| |
| /** |
| * Set up repository1 with branch "master", create some project and commit |
| * it; then clone into repository2; finally create a branch "test" on top of |
| * "master" in repository2 |
| * |
| * @throws Exception |
| */ |
| @Before |
| public void setUp() throws Exception { |
| |
| workdir = testUtils.createTempDir("Repository1"); |
| workdir2 = testUtils.createTempDir("Repository2"); |
| |
| repository1 = new TestRepository(new File(workdir, Constants.DOT_GIT)); |
| |
| // now we create a project in repo1 |
| IProject project = testUtils.createProjectInLocalFileSystem(workdir, |
| projectName); |
| testUtils.addFileToProject(project, "folder1/file1.txt", "Hello world"); |
| |
| repository1.connect(project); |
| repository1.trackAllFiles(project); |
| repository1.commit("Initial commit"); |
| |
| // let's get rid of the project |
| project.delete(false, false, null); |
| |
| // let's clone repository1 to repository2 |
| URIish uri = repository1.getUri(); |
| CloneOperation clop = new CloneOperation(uri, true, null, workdir2, |
| "refs/heads/master", "origin", 0); |
| clop.run(null); |
| |
| Repository repo2 = Activator.getDefault().getRepositoryCache().lookupRepository(new File(workdir2, |
| Constants.DOT_GIT)); |
| repository2 = new TestRepository(repo2); |
| // we push to branch "test" of repository2 |
| RefUpdate createBranch = repository2.getRepository().updateRef( |
| "refs/heads/test"); |
| createBranch.setNewObjectId(repository2.getRepository().resolve( |
| "refs/heads/master")); |
| createBranch.update(); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| repository1.dispose(); |
| repository2.dispose(); |
| repository1 = null; |
| repository2 = null; |
| testUtils.deleteTempDirs(); |
| } |
| |
| /** |
| * Push from repository1 "master" into "test" of repository2. |
| * |
| * @throws Exception |
| */ |
| @Test |
| public void testPush() throws Exception { |
| |
| // push from repository1 to repository2 |
| PushOperation pop = createPushOperation(); |
| pop.run(new NullProgressMonitor()); |
| assertEquals(Status.UP_TO_DATE, getStatus(pop.getOperationResult())); |
| |
| // let's add a new file to the project shared with repository1 |
| IProject proj = importProject(repository1, projectName); |
| ArrayList<IFile> files = new ArrayList<IFile>(); |
| IFile newFile = testUtils.addFileToProject(proj, "folder2/file2.txt", |
| "New file"); |
| files.add(newFile); |
| IFile[] fileArr = files.toArray(new IFile[files.size()]); |
| |
| AddToIndexOperation trop = new AddToIndexOperation(files); |
| trop.execute(null); |
| CommitOperation cop = new CommitOperation(fileArr, files, TestUtils.AUTHOR, |
| TestUtils.COMMITTER, "Added file"); |
| cop.execute(null); |
| |
| proj.delete(false, false, null); |
| |
| pop = createPushOperation(); |
| pop.run(null); |
| assertEquals(Status.OK, getStatus(pop.getOperationResult())); |
| |
| try { |
| // assert that we cannot run this again |
| pop.run(null); |
| fail("Expected Exception not thrown"); |
| } catch (IllegalStateException e) { |
| // expected |
| } |
| |
| pop = createPushOperation(); |
| pop.run(null); |
| assertEquals(Status.UP_TO_DATE, getStatus(pop.getOperationResult())); |
| |
| String newFilePath = newFile.getFullPath().toOSString(); |
| |
| File testFile = new File(workdir2, newFilePath); |
| assertFalse(testFile.exists()); |
| testFile = new File(workdir, newFilePath); |
| assertTrue(testFile.exists()); |
| |
| // check out test and verify the file is there |
| BranchOperation bop = new BranchOperation(repository2.getRepository(), |
| "refs/heads/test"); |
| bop.execute(null); |
| testFile = new File(workdir2, newFilePath); |
| assertTrue(testFile.exists()); |
| } |
| |
| /** |
| * An invalid URI should yield an operation result with an error message |
| * and the exception should be logged |
| * |
| * @throws Exception |
| */ |
| @Test |
| public void testInvalidUriDuringPush() throws Exception { |
| ILog log = Activator.getDefault().getLog(); |
| LogListener listener = new LogListener(); |
| log.addLogListener(listener); |
| |
| PushOperation pop = createInvalidPushOperation(); |
| pop.run(new NullProgressMonitor()); |
| PushOperationResult result = pop.getOperationResult(); |
| String errorMessage = result.getErrorMessage(new URIish(INVALID_URI)); |
| assertNotNull(errorMessage); |
| assertTrue(errorMessage.contains(INVALID_URI)); |
| |
| assertTrue(listener.loggedSomething()); |
| assertTrue(listener.loggedException()); |
| |
| } |
| |
| private PushOperation createInvalidPushOperation() throws Exception { |
| // set up push with invalid URI to provoke an exception |
| PushOperationSpecification spec = new PushOperationSpecification(); |
| // the remote is invalid |
| URIish remote = new URIish(INVALID_URI); |
| // update master upon master |
| Repository local = repository1.getRepository(); |
| RemoteRefUpdate update = new RemoteRefUpdate(local, "HEAD", "refs/heads/test", |
| false, null, null); |
| spec.addURIRefUpdates(remote, Collections.singletonList(update)); |
| // now we can construct the push operation |
| PushOperation pop = new PushOperation(local, spec, false, 0); |
| return pop; |
| } |
| |
| private static final class LogListener implements ILogListener { |
| private boolean loggedSomething = false; |
| private boolean loggedException = false; |
| |
| public void logging(IStatus status, String plugin) { |
| loggedSomething = true; |
| loggedException = status.getException() != null; |
| } |
| |
| public boolean loggedSomething() { |
| return loggedSomething; |
| } |
| |
| public boolean loggedException() { |
| return loggedException; |
| } |
| |
| } |
| |
| /** |
| * We should get an {@link IllegalStateException} if we run |
| * getOperationResult before run() |
| * |
| * @throws Exception |
| */ |
| @Test |
| public void testIllegalStateExceptionOnGetResultWithoutRun() |
| throws Exception { |
| // push from repository1 to repository2 |
| PushOperation pop = createPushOperation(); |
| try { |
| pop.getOperationResult(); |
| fail("Expected Exception not thrown"); |
| } catch (IllegalStateException e) { |
| // expected |
| } |
| } |
| |
| /** |
| * We should get an {@link IllegalStateException} if the spec was re-used |
| * |
| * @throws Exception |
| */ |
| @Test |
| public void testPushWithReusedSpec() throws Exception { |
| |
| PushOperationSpecification spec = new PushOperationSpecification(); |
| // the remote is repo2 |
| URIish remote = repository2.getUri(); |
| // update master upon master |
| List<RemoteRefUpdate> refUpdates = new ArrayList<RemoteRefUpdate>(); |
| RemoteRefUpdate update = new RemoteRefUpdate(repository1 |
| .getRepository(), "HEAD", "refs/heads/test", false, null, null); |
| refUpdates.add(update); |
| spec.addURIRefUpdates(remote, refUpdates); |
| |
| PushOperation pop = new PushOperation(repository1.getRepository(), |
| spec, false, 0); |
| pop.run(null); |
| |
| pop = new PushOperation(repository1.getRepository(), spec, false, 0); |
| try { |
| pop.run(null); |
| fail("Expected Exception not thrown"); |
| } catch (IllegalStateException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testUpdateTrackingBranchIfSpecifiedInRemoteRefUpdate() throws Exception { |
| // Commit on repository 2 |
| IProject project = importProject(repository2, projectName); |
| RevCommit commit = repository2.addAndCommit(project, new File(workdir2, "test.txt"), "Commit in repository 2"); |
| project.delete(false, false, null); |
| |
| // We want to push from repository 2 to 1 (because repository 2 already |
| // has tracking set up) |
| URIish remote = repository1.getUri(); |
| String trackingRef = "refs/remotes/origin/master"; |
| RemoteRefUpdate update = new RemoteRefUpdate( |
| repository2.getRepository(), "HEAD", "refs/heads/master", false, |
| trackingRef, null); |
| PushOperationSpecification spec = new PushOperationSpecification(); |
| spec.addURIRefUpdates(remote, Arrays.asList(update)); |
| |
| PushOperation push = new PushOperation(repository2.getRepository(), |
| spec, false, 0); |
| push.run(null); |
| |
| PushOperationResult result = push.getOperationResult(); |
| PushResult pushResult = result.getPushResult(remote); |
| assertNotNull("Expected result to have tracking ref update", pushResult.getTrackingRefUpdate(trackingRef)); |
| |
| ObjectId trackingId = repository2.getRepository().resolve(trackingRef); |
| assertEquals("Expected tracking branch to be updated", commit.getId(), trackingId); |
| } |
| |
| private Status getStatus(PushOperationResult operationResult) { |
| URIish uri = operationResult.getURIs().iterator().next(); |
| return operationResult.getPushResult(uri).getRemoteUpdates().iterator() |
| .next().getStatus(); |
| } |
| |
| private PushOperation createPushOperation() throws Exception { |
| // set up push from repository1 to repository2 |
| // we cannot re-use the RemoteRefUpdate!!! |
| PushOperationSpecification spec = new PushOperationSpecification(); |
| // the remote is repo2 |
| URIish remote = new URIish("file:///" |
| + repository2.getRepository().getDirectory().toString()); |
| // update master upon master |
| List<RemoteRefUpdate> refUpdates = new ArrayList<RemoteRefUpdate>(); |
| RemoteRefUpdate update = new RemoteRefUpdate(repository1 |
| .getRepository(), "HEAD", "refs/heads/test", false, null, null); |
| refUpdates.add(update); |
| spec.addURIRefUpdates(remote, refUpdates); |
| // now we can construct the push operation |
| PushOperation pop = new PushOperation(repository1.getRepository(), |
| spec, false, 0); |
| return pop; |
| } |
| |
| } |