View Javadoc
1   /*
2    * Copyright (C) 2015, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.transport;
12  
13  import static org.junit.Assert.assertEquals;
14  import static org.junit.Assert.assertSame;
15  import static org.junit.Assert.fail;
16  
17  import java.io.IOException;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.eclipse.jgit.errors.TransportException;
22  import org.eclipse.jgit.internal.JGitText;
23  import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
24  import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
25  import org.eclipse.jgit.junit.TestRepository;
26  import org.eclipse.jgit.lib.NullProgressMonitor;
27  import org.eclipse.jgit.lib.ObjectId;
28  import org.eclipse.jgit.lib.Repository;
29  import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
30  import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
31  import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
32  import org.junit.After;
33  import org.junit.Before;
34  import org.junit.Test;
35  
36  public class AtomicPushTest {
37  	private URIish uri;
38  	private TestProtocol<Object> testProtocol;
39  	private Object ctx = new Object();
40  	private InMemoryRepository server;
41  	private InMemoryRepository client;
42  	private ObjectId commit1;
43  	private ObjectId commit2;
44  
45  	@Before
46  	public void setUp() throws Exception {
47  		server = newRepo("server");
48  		client = newRepo("client");
49  		testProtocol = new TestProtocol<>(
50  				null,
51  				new ReceivePackFactory<Object>() {
52  					@Override
53  					public ReceivePack create(Object req, Repository db)
54  							throws ServiceNotEnabledException,
55  							ServiceNotAuthorizedException {
56  						return new ReceivePack(db);
57  					}
58  				});
59  		uri = testProtocol.register(ctx, server);
60  
61  		try (TestRepository<?> clientRepo = new TestRepository<>(client)) {
62  			commit1 = clientRepo.commit().noFiles().message("test commit 1")
63  					.create();
64  			commit2 = clientRepo.commit().noFiles().message("test commit 2")
65  					.create();
66  		}
67  	}
68  
69  	@After
70  	public void tearDown() {
71  		Transport.unregister(testProtocol);
72  	}
73  
74  	private static InMemoryRepository newRepo(String name) {
75  		return new InMemoryRepository(new DfsRepositoryDescription(name));
76  	}
77  
78  	@Test
79  	public void pushNonAtomic() throws Exception {
80  		PushResult r;
81  		server.setPerformsAtomicTransactions(false);
82  		try (Transport tn = testProtocol.open(uri, client, "server")) {
83  			tn.setPushAtomic(false);
84  			r = tn.push(NullProgressMonitor.INSTANCE, commands());
85  		}
86  
87  		RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
88  		RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
89  		assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
90  		assertSame(
91  				RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
92  				two.getStatus());
93  	}
94  
95  	@Test
96  	public void pushAtomicClientGivesUpEarly() throws Exception {
97  		PushResult r;
98  		try (Transport tn = testProtocol.open(uri, client, "server")) {
99  			tn.setPushAtomic(true);
100 			r = tn.push(NullProgressMonitor.INSTANCE, commands());
101 		}
102 
103 		RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
104 		RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
105 		assertSame(
106 				RemoteRefUpdate.Status.REJECTED_OTHER_REASON,
107 				one.getStatus());
108 		assertSame(
109 				RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
110 				two.getStatus());
111 		assertEquals(JGitText.get().transactionAborted, one.getMessage());
112 	}
113 
114 	@Test
115 	public void pushAtomicDisabled() throws Exception {
116 		List<RemoteRefUpdate> cmds = new ArrayList<>();
117 		cmds.add(new RemoteRefUpdate(
118 				null, null,
119 				commit1, "refs/heads/one",
120 				true /* force update */,
121 				null /* no local tracking ref */,
122 				ObjectId.zeroId()));
123 		cmds.add(new RemoteRefUpdate(
124 				null, null,
125 				commit2, "refs/heads/two",
126 				true /* force update */,
127 				null /* no local tracking ref */,
128 				ObjectId.zeroId()));
129 
130 		server.setPerformsAtomicTransactions(false);
131 		try (Transport tn = testProtocol.open(uri, client, "server")) {
132 			tn.setPushAtomic(true);
133 			tn.push(NullProgressMonitor.INSTANCE, cmds);
134 			fail("did not throw TransportException");
135 		} catch (TransportException e) {
136 			assertEquals(
137 					uri + ": " + JGitText.get().atomicPushNotSupported,
138 					e.getMessage());
139 		}
140 	}
141 
142 	private List<RemoteRefUpdate> commands() throws IOException {
143 		List<RemoteRefUpdate> cmds = new ArrayList<>();
144 		cmds.add(new RemoteRefUpdate(
145 				null, null,
146 				commit1, "refs/heads/one",
147 				true /* force update */,
148 				null /* no local tracking ref */,
149 				ObjectId.zeroId()));
150 		cmds.add(new RemoteRefUpdate(
151 				null, null,
152 				commit2, "refs/heads/two",
153 				true /* force update */,
154 				null /* no local tracking ref */,
155 				commit1));
156 		return cmds;
157 	}
158 }