blob: db88eefb04657becdb882891ea894eb6d346e7c2 [file] [log] [blame]
// Copyright 2017 The LUCI Authors.
//
// 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 gitiles
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"sort"
"testing"
"go.chromium.org/luci/common/proto/git"
"go.chromium.org/luci/common/proto/gitiles"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
func TestNewRESTClient(t *testing.T) {
t.Parallel()
Convey("accept valid gitiles host", t, func() {
c, err := NewRESTClient(&http.Client{}, "chromium.googlesource.com", false)
So(c, ShouldNotBeNil)
So(err, ShouldBeNil)
})
Convey("accept valid gitiles host with dash", t, func() {
c, err := NewRESTClient(&http.Client{}, "chromium-foo.googlesource.com", false)
So(c, ShouldNotBeNil)
So(err, ShouldBeNil)
})
Convey("Reject invalid gitiles host", t, func() {
c, err := NewRESTClient(&http.Client{}, "chromium.hijacked.com", false)
So(c, ShouldBeNil)
So(err, ShouldErrLike, "is not a valid Gitiles host")
})
Convey("Reject invalid gitiles host with matching suffix", t, func() {
c, err := NewRESTClient(&http.Client{}, "chromium.hijacked.com/chromium.googlesource.com", false)
So(c, ShouldBeNil)
So(err, ShouldErrLike, "is not a valid Gitiles host")
})
}
func TestLog(t *testing.T) {
t.Parallel()
ctx := context.Background()
Convey("Log with bad project", t, func() {
srv, c := newMockClient(func(w http.ResponseWriter, r *http.Request) {})
defer srv.Close()
_, err := c.Log(ctx, &gitiles.LogRequest{})
So(err, ShouldErrLike, "project is required")
})
Convey("Log w/o pages", t, func() {
srv, c := newMockClient(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, ")]}'\n{\"log\": [%s, %s]}\n", fakeCommit1Str, fakeCommit2Str)
})
defer srv.Close()
Convey("Return All", func() {
res, err := c.Log(ctx, &gitiles.LogRequest{
Project: "repo",
Committish: "8de6836858c99e48f3c58164ab717bda728e95dd",
ExcludeAncestorsOf: "master",
PageSize: 10,
})
So(err, ShouldBeNil)
So(len(res.Log), ShouldEqual, 2)
So(res.Log[0].Author.Name, ShouldEqual, "Author 1")
So(res.Log[1].Id, ShouldEqual, "dc1dbf1aa56e4dd4cbfaab61c4d30a35adce5f40")
})
})
}
func TestRefs(t *testing.T) {
t.Parallel()
ctx := context.Background()
Convey("bad project", t, func() {
c := &client{BaseURL: "https://a.googlesource.com/a"}
_, err := c.Refs(ctx, &gitiles.RefsRequest{
RefsPath: gitiles.AllRefs,
})
So(err, ShouldErrLike, `project is required`)
})
Convey("bad RefsPath", t, func() {
c := &client{BaseURL: "https://a.googlesource.com/a"}
_, err := c.Refs(ctx, &gitiles.RefsRequest{
Project: "repo",
RefsPath: "bad",
})
So(err, ShouldErrLike, `refsPath must be "refs" or start with "refs/"`)
})
Convey("Refs All", t, func() {
srv, c := newMockClient(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, `)]}'
{
"refs/heads/master": { "value": "deadbeef" },
"refs/heads/infra/config": { "value": "0000beef" },
"refs/changes/01/123001/1": { "value": "123dead001beef1" },
"refs/other/ref": { "value": "ba6" },
"123deadbeef123": { "target": "f00" },
"HEAD": {
"value": "deadbeef",
"target": "refs/heads/master"
}
}
`)
})
defer srv.Close()
res, err := c.Refs(ctx, &gitiles.RefsRequest{
Project: "repo",
RefsPath: gitiles.AllRefs,
})
So(err, ShouldBeNil)
So(res.Revisions, ShouldResemble, map[string]string{
"HEAD": "refs/heads/master",
"refs/heads/master": "deadbeef",
"refs/heads/infra/config": "0000beef",
"refs/other/ref": "ba6",
"refs/changes/01/123001/1": "123dead001beef1",
// Skipping "123dead001beef1" which has no value.
})
})
Convey("Refs heads", t, func() {
srv, c := newMockClient(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, `)]}'
{
"master": { "value": "deadbeef" },
"infra/config": { "value": "0000beef" }
}
`)
})
defer srv.Close()
res, err := c.Refs(ctx, &gitiles.RefsRequest{
Project: "repo",
RefsPath: gitiles.Branches,
})
So(err, ShouldBeNil)
So(res.Revisions, ShouldResemble, map[string]string{
"refs/heads/master": "deadbeef",
"refs/heads/infra/config": "0000beef",
})
})
}
func TestProjects(t *testing.T) {
t.Parallel()
ctx := context.Background()
Convey("List Projects", t, func() {
srv, c := newMockClient(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, `)]}'
{
"All-Projects": {
"name": "All-Projects",
"clone_url": "https://foo.googlesource.com/All-Projects",
"description": "foo"
},
"bar": {
"name": "bar",
"clone_url": "https://foo.googlesource.com/bar",
"description": "bar description"
}
}
`)
})
defer srv.Close()
res, err := c.Projects(ctx, &gitiles.ProjectsRequest{})
So(err, ShouldBeNil)
// Sort project to make it deterministic
sort.Strings(res.Projects)
So(res.Projects, ShouldResemble, []string{
"All-Projects",
"bar",
})
})
}
func TestList(t *testing.T) {
t.Parallel()
ctx := context.Background()
Convey("ListFiles", t, func() {
srv, c := newMockClient(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, `)]}'
{
"id": "860c9c8901a8de14bf9f6210257f2400ac19d11e",
"entries": [
{
"mode": 33188,
"type": "blob",
"id": "7e5b457d492b50762386611fc7f1302f23b313cf",
"name": "foo.txt"
},
{
"mode": 33188,
"type": "blob",
"id": "a07e845539145d1fb697c20b75689b25e266d6d6",
"name": "bar.txt"
},
{
"mode": 33188,
"type": "tree",
"id": "b90e845539145d1fb697c20b75689b25e266d6c3",
"name": "directory"
},
{
"mode": 33188,
"type": "random type",
"id": "k93b845539145d1fb697c20b75689b25e266d6q1",
"name": "new"
}
]
}
`)
})
defer srv.Close()
res, err := c.ListFiles(ctx, &gitiles.ListFilesRequest{
Project: "project",
Committish: "main",
Path: "path/to/dir",
})
So(err, ShouldBeNil)
So(res.Files, ShouldResemble, []*git.File{
{
Mode: 33188,
Id: "7e5b457d492b50762386611fc7f1302f23b313cf",
Path: "foo.txt",
Type: git.File_BLOB,
},
{
Mode: 33188,
Id: "a07e845539145d1fb697c20b75689b25e266d6d6",
Path: "bar.txt",
Type: git.File_BLOB,
},
{
Mode: 33188,
Id: "b90e845539145d1fb697c20b75689b25e266d6c3",
Path: "directory",
Type: git.File_TREE,
},
{
Mode: 33188,
Id: "k93b845539145d1fb697c20b75689b25e266d6q1",
Path: "new",
Type: git.File_UNKNOWN,
},
})
})
}
func newMockClient(handler func(w http.ResponseWriter, r *http.Request)) (*httptest.Server, gitiles.GitilesClient) {
srv := httptest.NewServer(http.HandlerFunc(handler))
return srv, &client{BaseURL: srv.URL}
}
var (
fakeCommit1Str = `{
"commit": "0b2c5409e58a71c691b05454b55cc5580cc822d1",
"tree": "3c6f95bc757698cd6aca3c49f88f640fd145ea69",
"parents": [ "dc1dbf1aa56e4dd4cbfaab61c4d30a35adce5f40" ],
"author": {
"name": "Author 1",
"email": "author1@example.com",
"time": "Mon Jul 17 15:02:43 2017 -0800"
},
"committer": {
"name": "Commit Bot",
"email": "commit-bot@chromium.org",
"time": "Mon Jul 17 15:02:43 2017 +0000"
},
"message": "Import wpt@d96d68ed964f9bfc2bb248c2d2fab7a8870dc685\\n\\nCr-Commit-Position: refs/heads/master@{#487078}"
}`
fakeCommit2Str = `{
"commit": "dc1dbf1aa56e4dd4cbfaab61c4d30a35adce5f40",
"tree": "1ba2335c07915c31597b97a8d824aecc85a996f6",
"parents": ["8de6836858c99e48f3c58164ab717bda728e95dd"],
"author": {
"name": "Author 2",
"email": "author-2@example.com",
"time": "Mon Jul 17 15:01:13 2017"
},
"committer": {
"name": "Commit Bot",
"email": "commit-bot@chromium.org",
"time": "Mon Jul 17 15:01:13 2017"
},
"message": "[Web Payments] User weak ptr in Payment Request\u0027s error callback\\n\\nBug: 742329\\nReviewed-on: https://chromium-review.googlesource.com/570982\\nCr-Commit-Position: refs/heads/master@{#487077}"
}`
)