blob: c0f98b12be1afa5174c54aa1d4b386e1aec08039 [file] [log] [blame]
Dave Borowitzb7fd3f32014-05-01 12:31:25 -07001// Copyright (C) 2014 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.gitiles;
16
Dave Borowitzfde41fd2015-09-16 15:14:38 -040017import static com.google.common.truth.Truth.assertThat;
Dave Borowitz4f568702014-05-01 19:54:57 -070018import static java.nio.charset.StandardCharsets.UTF_8;
AJ Ross001ea9b2016-08-23 13:40:04 -070019import static javax.servlet.http.HttpServletResponse.SC_OK;
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070020
Dave Borowitz4f568702014-05-01 19:54:57 -070021import com.google.common.io.BaseEncoding;
AJ Ross001ea9b2016-08-23 13:40:04 -070022import com.google.common.net.HttpHeaders;
Andrew Bonventre199efc42017-05-10 13:57:39 -070023import com.google.gitiles.FileJsonData.File;
Dave Borowitz3c441502014-09-05 16:06:37 -070024import com.google.gitiles.TreeJsonData.Tree;
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070025import com.google.template.soy.data.SoyListData;
26import com.google.template.soy.data.restricted.StringData;
Dave Borowitz3b744b12016-08-19 16:11:10 -040027import java.util.List;
28import java.util.Map;
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070029import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
30import org.eclipse.jgit.dircache.DirCacheEntry;
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070031import org.eclipse.jgit.lib.FileMode;
32import org.eclipse.jgit.lib.ObjectId;
33import org.eclipse.jgit.revwalk.RevBlob;
Dave Borowitz2387b142014-05-02 16:56:27 -070034import org.eclipse.jgit.revwalk.RevCommit;
Dave Borowitz228f3572014-05-02 14:26:25 -070035import org.eclipse.jgit.revwalk.RevTree;
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070036import org.junit.Test;
Dave Borowitz3dc854f2014-11-04 16:19:37 -080037import org.junit.runner.RunWith;
38import org.junit.runners.JUnit4;
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070039
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070040/** Tests for {@PathServlet}. */
41@SuppressWarnings("unchecked")
Dave Borowitz3dc854f2014-11-04 16:19:37 -080042@RunWith(JUnit4.class)
Nodir Turakulov4bc26002015-08-18 18:24:37 -070043public class PathServletTest extends ServletTest {
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070044 @Test
45 public void rootTreeHtml() throws Exception {
46 repo.branch("master").commit().add("foo", "contents").create();
47
48 Map<String, ?> data = buildData("/repo/+/master/");
Dave Borowitzfde41fd2015-09-16 15:14:38 -040049 assertThat(data).containsEntry("type", "TREE");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070050 List<Map<String, ?>> entries = getTreeEntries(data);
Dave Borowitzfde41fd2015-09-16 15:14:38 -040051 assertThat(entries).hasSize(1);
52 assertThat(entries.get(0).get("name")).isEqualTo("foo");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070053 }
54
55 @Test
56 public void subTreeHtml() throws Exception {
Dave Borowitzcf38c032016-05-02 11:06:23 -040057 repo.branch("master")
58 .commit()
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070059 .add("foo/bar", "bar contents")
60 .add("baz", "baz contents")
61 .create();
62
63 Map<String, ?> data = buildData("/repo/+/master/");
Dave Borowitzfde41fd2015-09-16 15:14:38 -040064 assertThat(data).containsEntry("type", "TREE");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070065 List<Map<String, ?>> entries = getTreeEntries(data);
Dave Borowitzfde41fd2015-09-16 15:14:38 -040066 assertThat(entries).hasSize(2);
67 assertThat(entries.get(0).get("name")).isEqualTo("baz");
68 assertThat(entries.get(1).get("name")).isEqualTo("foo/");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070069
70 data = buildData("/repo/+/master/foo");
Dave Borowitzfde41fd2015-09-16 15:14:38 -040071 assertThat(data).containsEntry("type", "TREE");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070072 entries = getTreeEntries(data);
Dave Borowitzfde41fd2015-09-16 15:14:38 -040073 assertThat(entries).hasSize(1);
74 assertThat(entries.get(0).get("name")).isEqualTo("bar");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070075
76 data = buildData("/repo/+/master/foo/");
Dave Borowitzfde41fd2015-09-16 15:14:38 -040077 assertThat(data).containsEntry("type", "TREE");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070078 entries = getTreeEntries(data);
Dave Borowitzfde41fd2015-09-16 15:14:38 -040079 assertThat(entries).hasSize(1);
80 assertThat(entries.get(0).get("name")).isEqualTo("bar");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070081 }
82
83 @Test
84 public void fileHtml() throws Exception {
85 repo.branch("master").commit().add("foo", "foo\ncontents\n").create();
86
87 Map<String, ?> data = buildData("/repo/+/master/foo");
Dave Borowitzfde41fd2015-09-16 15:14:38 -040088 assertThat(data).containsEntry("type", "REGULAR_FILE");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070089
90 SoyListData lines = (SoyListData) getBlobData(data).get("lines");
Dave Borowitzfde41fd2015-09-16 15:14:38 -040091 assertThat(lines.length()).isEqualTo(2);
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070092
93 SoyListData spans = lines.getListData(0);
Dave Borowitzfde41fd2015-09-16 15:14:38 -040094 assertThat(spans.length()).isEqualTo(1);
95 assertThat(spans.getMapData(0).get("classes")).isEqualTo(StringData.forValue("pln"));
96 assertThat(spans.getMapData(0).get("text")).isEqualTo(StringData.forValue("foo"));
Dave Borowitzb7fd3f32014-05-01 12:31:25 -070097
98 spans = lines.getListData(1);
Dave Borowitzfde41fd2015-09-16 15:14:38 -040099 assertThat(spans.length()).isEqualTo(1);
100 assertThat(spans.getMapData(0).get("classes")).isEqualTo(StringData.forValue("pln"));
101 assertThat(spans.getMapData(0).get("text")).isEqualTo(StringData.forValue("contents"));
Dave Borowitzb7fd3f32014-05-01 12:31:25 -0700102 }
103
104 @Test
105 public void symlinkHtml() throws Exception {
106 final RevBlob link = repo.blob("foo");
Dave Borowitzcf38c032016-05-02 11:06:23 -0400107 repo.branch("master")
108 .commit()
109 .add("foo", "contents")
110 .edit(
111 new PathEdit("bar") {
112 @Override
113 public void apply(DirCacheEntry ent) {
114 ent.setFileMode(FileMode.SYMLINK);
115 ent.setObjectId(link);
116 }
117 })
118 .create();
Dave Borowitzb7fd3f32014-05-01 12:31:25 -0700119
120 Map<String, ?> data = buildData("/repo/+/master/bar");
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400121 assertThat(data).containsEntry("type", "SYMLINK");
122 assertThat(getBlobData(data)).containsEntry("target", "foo");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -0700123 }
124
125 @Test
126 public void gitlinkHtml() throws Exception {
Dave Borowitzcf38c032016-05-02 11:06:23 -0400127 String gitmodules =
128 "[submodule \"gitiles\"]\n"
129 + " path = gitiles\n"
130 + " url = https://gerrit.googlesource.com/gitiles\n";
Dave Borowitzb7fd3f32014-05-01 12:31:25 -0700131 final String gitilesSha = "2b2f34bba3c2be7e2506ce6b1f040949da350cf9";
Dave Borowitzcf38c032016-05-02 11:06:23 -0400132 repo.branch("master")
133 .commit()
134 .add(".gitmodules", gitmodules)
135 .edit(
136 new PathEdit("gitiles") {
137 @Override
138 public void apply(DirCacheEntry ent) {
139 ent.setFileMode(FileMode.GITLINK);
140 ent.setObjectId(ObjectId.fromString(gitilesSha));
141 }
142 })
143 .create();
Dave Borowitzb7fd3f32014-05-01 12:31:25 -0700144
145 Map<String, ?> data = buildData("/repo/+/master/gitiles");
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400146 assertThat(data).containsEntry("type", "GITLINK");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -0700147
148 Map<String, ?> linkData = getBlobData(data);
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400149 assertThat(linkData).containsEntry("sha", gitilesSha);
150 assertThat(linkData).containsEntry("remoteUrl", "https://gerrit.googlesource.com/gitiles");
151 assertThat(linkData).containsEntry("httpUrl", "https://gerrit.googlesource.com/gitiles");
Dave Borowitzb7fd3f32014-05-01 12:31:25 -0700152 }
153
Dave Borowitz4f568702014-05-01 19:54:57 -0700154 @Test
155 public void blobText() throws Exception {
156 repo.branch("master").commit().add("foo", "contents").create();
Nodir Turakulov4bc26002015-08-18 18:24:37 -0700157 String text = buildBlob("/repo/+/master/foo", "100644");
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400158 assertThat(text).isEqualTo("contents");
Dave Borowitz4f568702014-05-01 19:54:57 -0700159 }
160
161 @Test
Andrew Bonventre199efc42017-05-10 13:57:39 -0700162 public void fileJson() throws Exception {
163 RevBlob blob = repo.blob("contents");
164 repo.branch("master").commit().add("path/to/file", blob).create();
165
166 File file = buildJson(File.class, "/repo/+/master/path/to/file");
167
168 assertThat(file.id).isEqualTo(blob.name());
169 assertThat(file.repo).isEqualTo("repo");
170 assertThat(file.revision).isEqualTo("master");
171 assertThat(file.path).isEqualTo("path/to/file");
172 }
173
174 @Test
Dave Borowitz4f568702014-05-01 19:54:57 -0700175 public void symlinkText() throws Exception {
176 final RevBlob link = repo.blob("foo");
Dave Borowitzcf38c032016-05-02 11:06:23 -0400177 repo.branch("master")
178 .commit()
179 .edit(
180 new PathEdit("baz") {
181 @Override
182 public void apply(DirCacheEntry ent) {
183 ent.setFileMode(FileMode.SYMLINK);
184 ent.setObjectId(link);
185 }
186 })
187 .create();
Nodir Turakulov4bc26002015-08-18 18:24:37 -0700188 String text = buildBlob("/repo/+/master/baz", "120000");
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400189 assertThat(text).isEqualTo("foo");
Dave Borowitz228f3572014-05-02 14:26:25 -0700190 }
191
192 @Test
193 public void treeText() throws Exception {
194 RevBlob blob = repo.blob("contents");
195 RevTree tree = repo.tree(repo.file("foo/bar", blob));
196 repo.branch("master").commit().setTopLevelTree(tree).create();
197
198 String expected = "040000 tree " + repo.get(tree, "foo").name() + "\tfoo\n";
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400199 assertThat(buildBlob("/repo/+/master/", "040000")).isEqualTo(expected);
Dave Borowitz228f3572014-05-02 14:26:25 -0700200
201 expected = "100644 blob " + blob.name() + "\tbar\n";
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400202 assertThat(buildBlob("/repo/+/master/foo", "040000")).isEqualTo(expected);
203 assertThat(buildBlob("/repo/+/master/foo/", "040000")).isEqualTo(expected);
Dave Borowitz228f3572014-05-02 14:26:25 -0700204 }
205
206 @Test
207 public void treeTextEscaped() throws Exception {
208 RevBlob blob = repo.blob("contents");
209 repo.branch("master").commit().add("foo\nbar\rbaz", blob).create();
210
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400211 assertThat(buildBlob("/repo/+/master/", "040000"))
212 .isEqualTo("100644 blob " + blob.name() + "\t\"foo\\nbar\\rbaz\"\n");
Dave Borowitz4f568702014-05-01 19:54:57 -0700213 }
214
215 @Test
216 public void nonBlobText() throws Exception {
Dave Borowitzcf38c032016-05-02 11:06:23 -0400217 String gitmodules =
218 "[submodule \"gitiles\"]\n"
219 + " path = gitiles\n"
220 + " url = https://gerrit.googlesource.com/gitiles\n";
Dave Borowitz4f568702014-05-01 19:54:57 -0700221 final String gitilesSha = "2b2f34bba3c2be7e2506ce6b1f040949da350cf9";
Dave Borowitzcf38c032016-05-02 11:06:23 -0400222 repo.branch("master")
223 .commit()
Dave Borowitz4f568702014-05-01 19:54:57 -0700224 .add("foo/bar", "contents")
225 .add(".gitmodules", gitmodules)
Dave Borowitzcf38c032016-05-02 11:06:23 -0400226 .edit(
227 new PathEdit("gitiles") {
228 @Override
229 public void apply(DirCacheEntry ent) {
230 ent.setFileMode(FileMode.GITLINK);
231 ent.setObjectId(ObjectId.fromString(gitilesSha));
232 }
233 })
234 .create();
Dave Borowitz4f568702014-05-01 19:54:57 -0700235
Nodir Turakulov4bc26002015-08-18 18:24:37 -0700236 assertNotFound("/repo/+/master/nonexistent", "format=text");
237 assertNotFound("/repo/+/master/gitiles", "format=text");
Dave Borowitz4f568702014-05-01 19:54:57 -0700238 }
239
Dave Borowitz2387b142014-05-02 16:56:27 -0700240 @Test
Han-Wen Nienhuys8aefdb82016-05-02 16:49:35 +0200241 public void treeJsonSizes() throws Exception {
242 RevCommit c = repo.parseBody(repo.branch("master").commit().add("baz", "01234567").create());
243
244 Tree tree = buildJson(Tree.class, "/repo/+/master/", "long=1");
245
246 assertThat(tree.id).isEqualTo(c.getTree().name());
247 assertThat(tree.entries).hasSize(1);
248 assertThat(tree.entries.get(0).mode).isEqualTo(0100644);
249 assertThat(tree.entries.get(0).type).isEqualTo("blob");
250 assertThat(tree.entries.get(0).name).isEqualTo("baz");
251 assertThat(tree.entries.get(0).size).isEqualTo(8);
252 }
253
254 @Test
255 public void treeJsonLinkTarget() throws Exception {
256 final ObjectId targetID = repo.blob("target");
257 RevCommit c =
258 repo.parseBody(
259 repo.branch("master")
260 .commit()
261 .edit(
262 new PathEdit("link") {
263 @Override
264 public void apply(DirCacheEntry ent) {
265 ent.setFileMode(FileMode.SYMLINK);
266 ent.setObjectId(targetID);
267 }
268 })
269 .create());
270
271 Tree tree = buildJson(Tree.class, "/repo/+/master/", "long=1");
272
273 assertThat(tree.id).isEqualTo(c.getTree().name());
274 assertThat(tree.entries).hasSize(1);
275
276 TreeJsonData.Entry e = tree.entries.get(0);
277 assertThat(e.mode).isEqualTo(0120000);
278 assertThat(e.type).isEqualTo("blob");
279 assertThat(e.name).isEqualTo("link");
280 assertThat(e.id).isEqualTo(targetID.name());
281 assertThat(e.target).isEqualTo("target");
282 }
283
284 @Test
Han-Wen Nienhuys0dc93872016-05-03 15:21:42 +0200285 public void treeJsonRecursive() throws Exception {
286 RevCommit c =
287 repo.parseBody(
288 repo.branch("master")
289 .commit()
290 .add("foo/baz/bar/a", "bar contents")
291 .add("foo/baz/bar/b", "bar contents")
292 .add("baz", "baz contents")
293 .create());
294 Tree tree = buildJson(Tree.class, "/repo/+/master/", "recursive=1");
295
296 assertThat(tree.id).isEqualTo(c.getTree().name());
297 assertThat(tree.entries).hasSize(3);
298
299 assertThat(tree.entries.get(0).name).isEqualTo("baz");
300 assertThat(tree.entries.get(1).name).isEqualTo("foo/baz/bar/a");
301 assertThat(tree.entries.get(2).name).isEqualTo("foo/baz/bar/b");
302
303 tree = buildJson(Tree.class, "/repo/+/master/foo/baz", "recursive=1");
304
305 assertThat(tree.entries).hasSize(2);
306
307 assertThat(tree.entries.get(0).name).isEqualTo("bar/a");
308 assertThat(tree.entries.get(1).name).isEqualTo("bar/b");
309 }
310
311 @Test
Dave Borowitz2387b142014-05-02 16:56:27 -0700312 public void treeJson() throws Exception {
Dave Borowitzcf38c032016-05-02 11:06:23 -0400313 RevCommit c =
314 repo.parseBody(
315 repo.branch("master")
316 .commit()
317 .add("foo/bar", "bar contents")
318 .add("baz", "baz contents")
319 .create());
Dave Borowitz2387b142014-05-02 16:56:27 -0700320
Dave Borowitza774f592015-10-26 11:41:27 -0400321 Tree tree = buildJson(Tree.class, "/repo/+/master/");
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400322 assertThat(tree.id).isEqualTo(c.getTree().name());
323 assertThat(tree.entries).hasSize(2);
324 assertThat(tree.entries.get(0).mode).isEqualTo(0100644);
325 assertThat(tree.entries.get(0).type).isEqualTo("blob");
326 assertThat(tree.entries.get(0).id).isEqualTo(repo.get(c.getTree(), "baz").name());
327 assertThat(tree.entries.get(0).name).isEqualTo("baz");
328 assertThat(tree.entries.get(1).mode).isEqualTo(040000);
329 assertThat(tree.entries.get(1).type).isEqualTo("tree");
330 assertThat(tree.entries.get(1).id).isEqualTo(repo.get(c.getTree(), "foo").name());
331 assertThat(tree.entries.get(1).name).isEqualTo("foo");
Dave Borowitz2387b142014-05-02 16:56:27 -0700332
Dave Borowitza774f592015-10-26 11:41:27 -0400333 tree = buildJson(Tree.class, "/repo/+/master/foo");
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400334 assertThat(tree.id).isEqualTo(repo.get(c.getTree(), "foo").name());
335 assertThat(tree.entries).hasSize(1);
336 assertThat(tree.entries.get(0).mode).isEqualTo(0100644);
337 assertThat(tree.entries.get(0).type).isEqualTo("blob");
338 assertThat(tree.entries.get(0).id).isEqualTo(repo.get(c.getTree(), "foo/bar").name());
339 assertThat(tree.entries.get(0).name).isEqualTo("bar");
Dave Borowitz2387b142014-05-02 16:56:27 -0700340
Dave Borowitza774f592015-10-26 11:41:27 -0400341 tree = buildJson(Tree.class, "/repo/+/master/foo/");
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400342 assertThat(tree.id).isEqualTo(repo.get(c.getTree(), "foo").name());
343 assertThat(tree.entries).hasSize(1);
344 assertThat(tree.entries.get(0).mode).isEqualTo(0100644);
345 assertThat(tree.entries.get(0).type).isEqualTo("blob");
346 assertThat(tree.entries.get(0).id).isEqualTo(repo.get(c.getTree(), "foo/bar").name());
347 assertThat(tree.entries.get(0).name).isEqualTo("bar");
Dave Borowitz2387b142014-05-02 16:56:27 -0700348 }
349
AJ Ross001ea9b2016-08-23 13:40:04 -0700350 @Test
351 public void allowOrigin() throws Exception {
352 repo.branch("master").commit().add("foo", "contents").create();
353 FakeHttpServletResponse res = buildText("/repo/+/master/foo");
354 assertThat(res.getHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN))
355 .isEqualTo("http://localhost");
356 }
357
358 @Test
359 public void rejectOrigin() throws Exception {
360 repo.branch("master").commit().add("foo", "contents").create();
David Pursehouseccaa85d2017-05-30 10:47:27 +0900361 FakeHttpServletResponse res =
362 buildResponse("/repo/+/master/foo", "format=text", SC_OK, "http://notlocalhost");
AJ Ross001ea9b2016-08-23 13:40:04 -0700363 assertThat(res.getHeader(HttpHeaders.CONTENT_TYPE)).isEqualTo("text/plain");
David Pursehouseccaa85d2017-05-30 10:47:27 +0900364 assertThat(res.getHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo(null);
AJ Ross001ea9b2016-08-23 13:40:04 -0700365 }
366
Dave Borowitzb7fd3f32014-05-01 12:31:25 -0700367 private Map<String, ?> getBlobData(Map<String, ?> data) {
368 return ((Map<String, Map<String, ?>>) data).get("data");
369 }
370
371 private List<Map<String, ?>> getTreeEntries(Map<String, ?> data) {
372 return ((Map<String, List<Map<String, ?>>>) data.get("data")).get("entries");
373 }
374
Nodir Turakulov4bc26002015-08-18 18:24:37 -0700375 private String buildBlob(String path, String expectedMode) throws Exception {
376 FakeHttpServletResponse res = buildText(path);
Dave Borowitzfde41fd2015-09-16 15:14:38 -0400377 assertThat(res.getHeader(PathServlet.MODE_HEADER)).isEqualTo(expectedMode);
Nodir Turakulov4bc26002015-08-18 18:24:37 -0700378 String base64 = res.getActualBodyString();
379 return new String(BaseEncoding.base64().decode(base64), UTF_8);
Dave Borowitz228f3572014-05-02 14:26:25 -0700380 }
Dave Borowitzb7fd3f32014-05-01 12:31:25 -0700381}