blob: c0f98b12be1afa5174c54aa1d4b386e1aec08039 [file] [log] [blame]
// Copyright (C) 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gitiles;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import com.google.common.io.BaseEncoding;
import com.google.common.net.HttpHeaders;
import com.google.gitiles.FileJsonData.File;
import com.google.gitiles.TreeJsonData.Tree;
import com.google.template.soy.data.SoyListData;
import com.google.template.soy.data.restricted.StringData;
import java.util.List;
import java.util.Map;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@PathServlet}. */
@SuppressWarnings("unchecked")
@RunWith(JUnit4.class)
public class PathServletTest extends ServletTest {
@Test
public void rootTreeHtml() throws Exception {
repo.branch("master").commit().add("foo", "contents").create();
Map<String, ?> data = buildData("/repo/+/master/");
assertThat(data).containsEntry("type", "TREE");
List<Map<String, ?>> entries = getTreeEntries(data);
assertThat(entries).hasSize(1);
assertThat(entries.get(0).get("name")).isEqualTo("foo");
}
@Test
public void subTreeHtml() throws Exception {
repo.branch("master")
.commit()
.add("foo/bar", "bar contents")
.add("baz", "baz contents")
.create();
Map<String, ?> data = buildData("/repo/+/master/");
assertThat(data).containsEntry("type", "TREE");
List<Map<String, ?>> entries = getTreeEntries(data);
assertThat(entries).hasSize(2);
assertThat(entries.get(0).get("name")).isEqualTo("baz");
assertThat(entries.get(1).get("name")).isEqualTo("foo/");
data = buildData("/repo/+/master/foo");
assertThat(data).containsEntry("type", "TREE");
entries = getTreeEntries(data);
assertThat(entries).hasSize(1);
assertThat(entries.get(0).get("name")).isEqualTo("bar");
data = buildData("/repo/+/master/foo/");
assertThat(data).containsEntry("type", "TREE");
entries = getTreeEntries(data);
assertThat(entries).hasSize(1);
assertThat(entries.get(0).get("name")).isEqualTo("bar");
}
@Test
public void fileHtml() throws Exception {
repo.branch("master").commit().add("foo", "foo\ncontents\n").create();
Map<String, ?> data = buildData("/repo/+/master/foo");
assertThat(data).containsEntry("type", "REGULAR_FILE");
SoyListData lines = (SoyListData) getBlobData(data).get("lines");
assertThat(lines.length()).isEqualTo(2);
SoyListData spans = lines.getListData(0);
assertThat(spans.length()).isEqualTo(1);
assertThat(spans.getMapData(0).get("classes")).isEqualTo(StringData.forValue("pln"));
assertThat(spans.getMapData(0).get("text")).isEqualTo(StringData.forValue("foo"));
spans = lines.getListData(1);
assertThat(spans.length()).isEqualTo(1);
assertThat(spans.getMapData(0).get("classes")).isEqualTo(StringData.forValue("pln"));
assertThat(spans.getMapData(0).get("text")).isEqualTo(StringData.forValue("contents"));
}
@Test
public void symlinkHtml() throws Exception {
final RevBlob link = repo.blob("foo");
repo.branch("master")
.commit()
.add("foo", "contents")
.edit(
new PathEdit("bar") {
@Override
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.SYMLINK);
ent.setObjectId(link);
}
})
.create();
Map<String, ?> data = buildData("/repo/+/master/bar");
assertThat(data).containsEntry("type", "SYMLINK");
assertThat(getBlobData(data)).containsEntry("target", "foo");
}
@Test
public void gitlinkHtml() throws Exception {
String gitmodules =
"[submodule \"gitiles\"]\n"
+ " path = gitiles\n"
+ " url = https://gerrit.googlesource.com/gitiles\n";
final String gitilesSha = "2b2f34bba3c2be7e2506ce6b1f040949da350cf9";
repo.branch("master")
.commit()
.add(".gitmodules", gitmodules)
.edit(
new PathEdit("gitiles") {
@Override
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(ObjectId.fromString(gitilesSha));
}
})
.create();
Map<String, ?> data = buildData("/repo/+/master/gitiles");
assertThat(data).containsEntry("type", "GITLINK");
Map<String, ?> linkData = getBlobData(data);
assertThat(linkData).containsEntry("sha", gitilesSha);
assertThat(linkData).containsEntry("remoteUrl", "https://gerrit.googlesource.com/gitiles");
assertThat(linkData).containsEntry("httpUrl", "https://gerrit.googlesource.com/gitiles");
}
@Test
public void blobText() throws Exception {
repo.branch("master").commit().add("foo", "contents").create();
String text = buildBlob("/repo/+/master/foo", "100644");
assertThat(text).isEqualTo("contents");
}
@Test
public void fileJson() throws Exception {
RevBlob blob = repo.blob("contents");
repo.branch("master").commit().add("path/to/file", blob).create();
File file = buildJson(File.class, "/repo/+/master/path/to/file");
assertThat(file.id).isEqualTo(blob.name());
assertThat(file.repo).isEqualTo("repo");
assertThat(file.revision).isEqualTo("master");
assertThat(file.path).isEqualTo("path/to/file");
}
@Test
public void symlinkText() throws Exception {
final RevBlob link = repo.blob("foo");
repo.branch("master")
.commit()
.edit(
new PathEdit("baz") {
@Override
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.SYMLINK);
ent.setObjectId(link);
}
})
.create();
String text = buildBlob("/repo/+/master/baz", "120000");
assertThat(text).isEqualTo("foo");
}
@Test
public void treeText() throws Exception {
RevBlob blob = repo.blob("contents");
RevTree tree = repo.tree(repo.file("foo/bar", blob));
repo.branch("master").commit().setTopLevelTree(tree).create();
String expected = "040000 tree " + repo.get(tree, "foo").name() + "\tfoo\n";
assertThat(buildBlob("/repo/+/master/", "040000")).isEqualTo(expected);
expected = "100644 blob " + blob.name() + "\tbar\n";
assertThat(buildBlob("/repo/+/master/foo", "040000")).isEqualTo(expected);
assertThat(buildBlob("/repo/+/master/foo/", "040000")).isEqualTo(expected);
}
@Test
public void treeTextEscaped() throws Exception {
RevBlob blob = repo.blob("contents");
repo.branch("master").commit().add("foo\nbar\rbaz", blob).create();
assertThat(buildBlob("/repo/+/master/", "040000"))
.isEqualTo("100644 blob " + blob.name() + "\t\"foo\\nbar\\rbaz\"\n");
}
@Test
public void nonBlobText() throws Exception {
String gitmodules =
"[submodule \"gitiles\"]\n"
+ " path = gitiles\n"
+ " url = https://gerrit.googlesource.com/gitiles\n";
final String gitilesSha = "2b2f34bba3c2be7e2506ce6b1f040949da350cf9";
repo.branch("master")
.commit()
.add("foo/bar", "contents")
.add(".gitmodules", gitmodules)
.edit(
new PathEdit("gitiles") {
@Override
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(ObjectId.fromString(gitilesSha));
}
})
.create();
assertNotFound("/repo/+/master/nonexistent", "format=text");
assertNotFound("/repo/+/master/gitiles", "format=text");
}
@Test
public void treeJsonSizes() throws Exception {
RevCommit c = repo.parseBody(repo.branch("master").commit().add("baz", "01234567").create());
Tree tree = buildJson(Tree.class, "/repo/+/master/", "long=1");
assertThat(tree.id).isEqualTo(c.getTree().name());
assertThat(tree.entries).hasSize(1);
assertThat(tree.entries.get(0).mode).isEqualTo(0100644);
assertThat(tree.entries.get(0).type).isEqualTo("blob");
assertThat(tree.entries.get(0).name).isEqualTo("baz");
assertThat(tree.entries.get(0).size).isEqualTo(8);
}
@Test
public void treeJsonLinkTarget() throws Exception {
final ObjectId targetID = repo.blob("target");
RevCommit c =
repo.parseBody(
repo.branch("master")
.commit()
.edit(
new PathEdit("link") {
@Override
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.SYMLINK);
ent.setObjectId(targetID);
}
})
.create());
Tree tree = buildJson(Tree.class, "/repo/+/master/", "long=1");
assertThat(tree.id).isEqualTo(c.getTree().name());
assertThat(tree.entries).hasSize(1);
TreeJsonData.Entry e = tree.entries.get(0);
assertThat(e.mode).isEqualTo(0120000);
assertThat(e.type).isEqualTo("blob");
assertThat(e.name).isEqualTo("link");
assertThat(e.id).isEqualTo(targetID.name());
assertThat(e.target).isEqualTo("target");
}
@Test
public void treeJsonRecursive() throws Exception {
RevCommit c =
repo.parseBody(
repo.branch("master")
.commit()
.add("foo/baz/bar/a", "bar contents")
.add("foo/baz/bar/b", "bar contents")
.add("baz", "baz contents")
.create());
Tree tree = buildJson(Tree.class, "/repo/+/master/", "recursive=1");
assertThat(tree.id).isEqualTo(c.getTree().name());
assertThat(tree.entries).hasSize(3);
assertThat(tree.entries.get(0).name).isEqualTo("baz");
assertThat(tree.entries.get(1).name).isEqualTo("foo/baz/bar/a");
assertThat(tree.entries.get(2).name).isEqualTo("foo/baz/bar/b");
tree = buildJson(Tree.class, "/repo/+/master/foo/baz", "recursive=1");
assertThat(tree.entries).hasSize(2);
assertThat(tree.entries.get(0).name).isEqualTo("bar/a");
assertThat(tree.entries.get(1).name).isEqualTo("bar/b");
}
@Test
public void treeJson() throws Exception {
RevCommit c =
repo.parseBody(
repo.branch("master")
.commit()
.add("foo/bar", "bar contents")
.add("baz", "baz contents")
.create());
Tree tree = buildJson(Tree.class, "/repo/+/master/");
assertThat(tree.id).isEqualTo(c.getTree().name());
assertThat(tree.entries).hasSize(2);
assertThat(tree.entries.get(0).mode).isEqualTo(0100644);
assertThat(tree.entries.get(0).type).isEqualTo("blob");
assertThat(tree.entries.get(0).id).isEqualTo(repo.get(c.getTree(), "baz").name());
assertThat(tree.entries.get(0).name).isEqualTo("baz");
assertThat(tree.entries.get(1).mode).isEqualTo(040000);
assertThat(tree.entries.get(1).type).isEqualTo("tree");
assertThat(tree.entries.get(1).id).isEqualTo(repo.get(c.getTree(), "foo").name());
assertThat(tree.entries.get(1).name).isEqualTo("foo");
tree = buildJson(Tree.class, "/repo/+/master/foo");
assertThat(tree.id).isEqualTo(repo.get(c.getTree(), "foo").name());
assertThat(tree.entries).hasSize(1);
assertThat(tree.entries.get(0).mode).isEqualTo(0100644);
assertThat(tree.entries.get(0).type).isEqualTo("blob");
assertThat(tree.entries.get(0).id).isEqualTo(repo.get(c.getTree(), "foo/bar").name());
assertThat(tree.entries.get(0).name).isEqualTo("bar");
tree = buildJson(Tree.class, "/repo/+/master/foo/");
assertThat(tree.id).isEqualTo(repo.get(c.getTree(), "foo").name());
assertThat(tree.entries).hasSize(1);
assertThat(tree.entries.get(0).mode).isEqualTo(0100644);
assertThat(tree.entries.get(0).type).isEqualTo("blob");
assertThat(tree.entries.get(0).id).isEqualTo(repo.get(c.getTree(), "foo/bar").name());
assertThat(tree.entries.get(0).name).isEqualTo("bar");
}
@Test
public void allowOrigin() throws Exception {
repo.branch("master").commit().add("foo", "contents").create();
FakeHttpServletResponse res = buildText("/repo/+/master/foo");
assertThat(res.getHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN))
.isEqualTo("http://localhost");
}
@Test
public void rejectOrigin() throws Exception {
repo.branch("master").commit().add("foo", "contents").create();
FakeHttpServletResponse res =
buildResponse("/repo/+/master/foo", "format=text", SC_OK, "http://notlocalhost");
assertThat(res.getHeader(HttpHeaders.CONTENT_TYPE)).isEqualTo("text/plain");
assertThat(res.getHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo(null);
}
private Map<String, ?> getBlobData(Map<String, ?> data) {
return ((Map<String, Map<String, ?>>) data).get("data");
}
private List<Map<String, ?>> getTreeEntries(Map<String, ?> data) {
return ((Map<String, List<Map<String, ?>>>) data.get("data")).get("entries");
}
private String buildBlob(String path, String expectedMode) throws Exception {
FakeHttpServletResponse res = buildText(path);
assertThat(res.getHeader(PathServlet.MODE_HEADER)).isEqualTo(expectedMode);
String base64 = res.getActualBodyString();
return new String(BaseEncoding.base64().decode(base64), UTF_8);
}
}