View Javadoc
1   /*
2    * Copyright (C) 2019, Google LLC. 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  package org.eclipse.jgit.transport;
11  
12  import static org.assertj.core.api.Assertions.assertThat;
13  import static org.assertj.core.api.Assertions.catchThrowableOfType;
14  
15  import java.io.IOException;
16  import java.util.Arrays;
17  import java.util.HashMap;
18  import java.util.Map;
19  
20  import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
21  import org.eclipse.jgit.errors.TransportException;
22  import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector;
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.Ref;
27  import org.eclipse.jgit.lib.Repository;
28  import org.eclipse.jgit.revwalk.RevBlob;
29  import org.eclipse.jgit.revwalk.RevCommit;
30  import org.eclipse.jgit.transport.UploadPack.RequestValidator;
31  import org.junit.Before;
32  import org.junit.Test;
33  
34  public abstract class RequestValidatorTestCase {
35  
36  	private RevCommit reachableCommit;
37  
38  	private RevCommit tipAdvertisedCommit;
39  
40  	private RevCommit tipUnadvertisedCommit;
41  
42  	private RevCommit unreachableCommit;
43  
44  	private RevBlob reachableBlob;
45  
46  	private RevBlob unreachableBlob;
47  
48  	private InMemoryRepository repo;
49  
50  	protected abstract RequestValidator createValidator();
51  
52  	@Before
53  	public void setUp() throws Exception {
54  		repo = new InMemoryRepository(new DfsRepositoryDescription());
55  		try (TestRepository<InMemoryRepository> git = new TestRepository<>(
56  				repo)) {
57  			reachableBlob = git.blob("foo");
58  			reachableCommit = git
59  					.commit(git.tree(git.file("foo", reachableBlob)));
60  			tipAdvertisedCommit = git.commit(reachableCommit);
61  			git.update("advertised", tipAdvertisedCommit);
62  
63  			tipUnadvertisedCommit = git.commit(reachableCommit);
64  			git.update("unadvertised", tipUnadvertisedCommit);
65  
66  			unreachableBlob = git.blob("unreachableFoo");
67  			unreachableCommit = git
68  					.commit(git.tree(git.file("foo", unreachableBlob)));
69  		}
70  	}
71  
72  	/**
73  	 * @return true if a commit reachable from a visible tip (but not directly
74  	 *         the tip) is valid
75  	 */
76  	protected abstract boolean isReachableCommitValid();
77  
78  	/** @return true if a commit not reachable from any tip is valid */
79  	protected abstract boolean isUnreachableCommitValid();
80  
81  	/**
82  	 * @return true if the commit directly pointed by an advertised ref is valid
83  	 */
84  	protected abstract boolean isAdvertisedTipValid();
85  
86  	/**
87  	 * @return true if the object directly pointed by a non-advertised ref is
88  	 *         valid
89  	 */
90  	protected abstract boolean isUnadvertisedTipCommitValid();
91  
92  	// UploadPack doesn't allow to ask for blobs when there is no
93  	// bitmap. Test both cases separately.
94  	/**
95  	 * @return true if a reachable blob is valid (and the repo has bitmaps)
96  	 */
97  	protected abstract boolean isReachableBlobValid_withBitmaps();
98  
99  	/**
100 	 * @return true if a reachable blob is valid (and the repo does NOT have
101 	 *         bitmaps)
102 	 */
103 	protected abstract boolean isReachableBlobValid_withoutBitmaps();
104 
105 	/**
106 	 * @return true if a blob unreachable from any tip is valid
107 	 */
108 	protected abstract boolean isUnreachableBlobValid();
109 
110 	@Test
111 	public void validateReachableCommitWithBitmaps() throws Throwable {
112 		ThrowingCallable c = () -> createValidator().checkWants(
113 				getUploadPack(getRepoWithBitmaps()),
114 				Arrays.asList(reachableCommit));
115 		if (!isReachableCommitValid()) {
116 			assertTransportException(c,
117 					"want " + reachableCommit.name() + " not valid");
118 			return;
119 		}
120 		c.call();
121 	}
122 
123 	@Test
124 	public void validateReachableCommitWithoutBitmaps() throws Throwable {
125 		ThrowingCallable c = () -> createValidator().checkWants(
126 				getUploadPack(getRepoWithoutBitmaps()),
127 				Arrays.asList(reachableCommit));
128 		if (!isReachableCommitValid()) {
129 			assertTransportException(c,
130 					"want " + reachableCommit.name() + " not valid");
131 			return;
132 		}
133 		c.call();
134 	}
135 
136 	@Test
137 	public void validateAdvertisedTipWithBitmaps() throws Throwable {
138 		ThrowingCallable c = () -> createValidator().checkWants(
139 				getUploadPack(getRepoWithBitmaps()),
140 				Arrays.asList(tipAdvertisedCommit));
141 		if (!isAdvertisedTipValid()) {
142 			assertTransportException(c,
143 					"want " + tipAdvertisedCommit.name() + " not valid");
144 			return;
145 		}
146 		c.call();
147 	}
148 
149 	@Test
150 	public void validateAdvertisedTipWithoutBitmaps() throws Throwable {
151 		ThrowingCallable c = () -> createValidator().checkWants(
152 				getUploadPack(getRepoWithoutBitmaps()),
153 				Arrays.asList(tipAdvertisedCommit));
154 		if (!isAdvertisedTipValid()) {
155 			assertTransportException(c,
156 					"want " + tipAdvertisedCommit.name() + " not valid");
157 			return;
158 		}
159 		c.call();
160 	}
161 
162 	@Test
163 	public void validateUnadvertisedTipWithBitmaps() throws Throwable {
164 		ThrowingCallable c = () -> createValidator().checkWants(
165 				getUploadPack(getRepoWithBitmaps()),
166 				Arrays.asList(tipUnadvertisedCommit));
167 		if (!isUnadvertisedTipCommitValid()) {
168 			assertTransportException(c,
169 					"want " + tipUnadvertisedCommit.name() + " not valid");
170 			return;
171 		}
172 		c.call();
173 	}
174 
175 	@Test
176 	public void validateUnadvertisedTipWithoutBitmaps() throws Throwable {
177 		ThrowingCallable c = () -> createValidator().checkWants(
178 				getUploadPack(getRepoWithoutBitmaps()),
179 				Arrays.asList(tipUnadvertisedCommit));
180 		if (!isUnadvertisedTipCommitValid()) {
181 			assertTransportException(c,
182 					"want " + tipUnadvertisedCommit.name() + " not valid");
183 			return;
184 		}
185 		c.call();
186 	}
187 
188 	@Test
189 	public void validateUnreachableCommitWithBitmaps() throws Throwable {
190 		ThrowingCallable c = () -> createValidator().checkWants(
191 				getUploadPack(getRepoWithBitmaps()),
192 				Arrays.asList(unreachableCommit));
193 		if (!isUnreachableCommitValid()) {
194 			assertTransportException(c,
195 					"want " + unreachableCommit.name() + " not valid");
196 			return;
197 		}
198 		c.call();
199 	}
200 
201 	@Test
202 	public void validateUnreachableCommitWithoutBitmaps() throws Throwable {
203 		ThrowingCallable c = () -> createValidator().checkWants(
204 				getUploadPack(getRepoWithoutBitmaps()),
205 				Arrays.asList(unreachableCommit));
206 		if (!isUnreachableCommitValid()) {
207 			assertTransportException(c,
208 					"want " + unreachableCommit.name() + " not valid");
209 			return;
210 		}
211 		c.call();
212 	}
213 
214 	@Test
215 	public void validateReachableBlobWithBitmaps() throws Throwable {
216 		ThrowingCallable c = () -> createValidator().checkWants(
217 				getUploadPack(getRepoWithBitmaps()),
218 				Arrays.asList(reachableBlob));
219 		if (!isReachableBlobValid_withBitmaps()) {
220 			assertTransportException(c,
221 					"want " + reachableBlob.name() + " not valid");
222 			return;
223 		}
224 		c.call();
225 	}
226 
227 	@Test
228 	public void validateReachableBlobWithoutBitmaps() throws Throwable {
229 		ThrowingCallable c = () -> createValidator().checkWants(
230 				getUploadPack(getRepoWithoutBitmaps()),
231 				Arrays.asList(reachableBlob));
232 		if (!isReachableBlobValid_withoutBitmaps()) {
233 			assertTransportException(c,
234 					"want " + reachableBlob.name() + " not valid");
235 			return;
236 		}
237 		c.call();
238 	}
239 
240 	@Test
241 	public void validateUnreachableBlobWithBitmaps() throws Throwable {
242 		ThrowingCallable c = () -> createValidator().checkWants(
243 				getUploadPack(getRepoWithBitmaps()),
244 				Arrays.asList(unreachableBlob));
245 		if (!isUnreachableBlobValid()) {
246 			assertTransportException(c,
247 					"want " + unreachableBlob.name() + " not valid");
248 			return;
249 		}
250 		c.call();
251 	}
252 
253 	@Test
254 	public void validateUnreachableBlobWithoutBitmaps() throws Throwable {
255 		ThrowingCallable c = () -> createValidator().checkWants(
256 				getUploadPack(getRepoWithoutBitmaps()),
257 				Arrays.asList(unreachableBlob));
258 		if (!isUnreachableBlobValid()) {
259 			assertTransportException(c,
260 					"want " + unreachableBlob.name() + " not valid");
261 			return;
262 		}
263 		c.call();
264 	}
265 
266 	private void assertTransportException(ThrowingCallable c,
267 			String messageContent) throws AssertionError {
268 		assertThat(catchThrowableOfType(c, TransportException.class))
269 				.hasMessageContaining(messageContent);
270 	}
271 
272 	private UploadPack getUploadPack(Repository repository) throws IOException {
273 		UploadPack uploadPack = new UploadPack(repository);
274 
275 		Ref advertisedRef = repo.getRefDatabase().findRef("advertised");
276 		Map<String, Ref> advertisedRefs = new HashMap<>();
277 		advertisedRefs.put(advertisedRef.getName(), advertisedRef);
278 
279 		uploadPack.setAdvertisedRefs(advertisedRefs);
280 		return uploadPack;
281 	}
282 
283 	private Repository getRepoWithBitmaps() throws IOException {
284 		new DfsGarbageCollector(repo).pack(null);
285 		repo.scanForRepoChanges();
286 		return repo;
287 	}
288 
289 	private Repository getRepoWithoutBitmaps() {
290 		return repo;
291 	}
292 }