8be12602f0
PR Ready Gate / clear-labels (pull_request) Successful in 2s
CI / test (pull_request) Successful in 17s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 39s
CI / review (gpt-5, security, ., rodin/security-patterns, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m3s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m7s
- Fix extra blank lines between GetPullRequest and GetPullRequestFiles - Add TestPostReview_CommitIDFromRequest to verify CommitID passes through
583 lines
18 KiB
Go
583 lines
18 KiB
Go
package github
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"gitea.weiker.me/rodin/review-bot/vcs"
|
|
)
|
|
|
|
func TestGetPullRequest(t *testing.T) {
|
|
want := PullRequest{
|
|
Title: "My PR",
|
|
Body: "Description",
|
|
}
|
|
want.Head.Sha = "abc123"
|
|
want.Head.Ref = "feature/foo"
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/repos/owner/repo/pulls/42" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(want)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
pr, err := c.GetPullRequest(context.Background(), "owner", "repo", 42)
|
|
if err != nil {
|
|
t.Fatalf("GetPullRequest: %v", err)
|
|
}
|
|
if pr.Title != want.Title {
|
|
t.Errorf("Title = %q, want %q", pr.Title, want.Title)
|
|
}
|
|
if pr.Head.Sha != want.Head.Sha {
|
|
t.Errorf("Head.Sha = %q, want %q", pr.Head.Sha, want.Head.Sha)
|
|
}
|
|
if pr.Head.Ref != want.Head.Ref {
|
|
t.Errorf("Head.Ref = %q, want %q", pr.Head.Ref, want.Head.Ref)
|
|
}
|
|
}
|
|
|
|
func TestGetPullRequest_NotFound(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("not found"))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
_, err := c.GetPullRequest(context.Background(), "owner", "repo", 1)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
if !IsNotFound(err) {
|
|
t.Errorf("expected IsNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetPullRequestDiff(t *testing.T) {
|
|
const wantDiff = "diff --git a/foo.go b/foo.go\n+added line\n"
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Header.Get("Accept") != "application/vnd.github.diff" {
|
|
t.Errorf("Accept = %q, want application/vnd.github.diff", r.Header.Get("Accept"))
|
|
}
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
fmt.Fprint(w, wantDiff)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
diff, err := c.GetPullRequestDiff(context.Background(), "owner", "repo", 1)
|
|
if err != nil {
|
|
t.Fatalf("GetPullRequestDiff: %v", err)
|
|
}
|
|
if diff != wantDiff {
|
|
t.Errorf("diff = %q, want %q", diff, wantDiff)
|
|
}
|
|
}
|
|
|
|
func TestGetPullRequestDiff_TooLarge(t *testing.T) {
|
|
// Return a diff larger than DefaultMaxDiffSize.
|
|
hugeDiff := make([]byte, DefaultMaxDiffSize+1)
|
|
for i := range hugeDiff {
|
|
hugeDiff[i] = 'x'
|
|
}
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
w.Write(hugeDiff)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
_, err := c.GetPullRequestDiff(context.Background(), "owner", "repo", 1)
|
|
if err == nil {
|
|
t.Fatal("expected ErrDiffTooLarge, got nil")
|
|
}
|
|
if err != ErrDiffTooLarge {
|
|
t.Errorf("err = %v, want ErrDiffTooLarge", err)
|
|
}
|
|
}
|
|
|
|
func TestGetPullRequestFiles(t *testing.T) {
|
|
files := []ChangedFile{
|
|
{Filename: "foo.go", Status: "modified"},
|
|
{Filename: "bar.go", Status: "added"},
|
|
}
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/repos/owner/repo/pulls/7/files" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(files)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
got, err := c.GetPullRequestFiles(context.Background(), "owner", "repo", 7)
|
|
if err != nil {
|
|
t.Fatalf("GetPullRequestFiles: %v", err)
|
|
}
|
|
if len(got) != len(files) {
|
|
t.Fatalf("len = %d, want %d", len(got), len(files))
|
|
}
|
|
for i, f := range files {
|
|
if got[i].Filename != f.Filename || got[i].Status != f.Status {
|
|
t.Errorf("file[%d] = %+v, want %+v", i, got[i], f)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetCommitStatuses(t *testing.T) {
|
|
statuses := []CommitStatus{
|
|
{Status: "success", Context: "ci/tests", Description: "All tests passed", TargetURL: "https://ci.example.com"},
|
|
}
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/repos/owner/repo/commits/deadbeef/statuses" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(statuses)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
got, err := c.GetCommitStatuses(context.Background(), "owner", "repo", "deadbeef")
|
|
if err != nil {
|
|
t.Fatalf("GetCommitStatuses: %v", err)
|
|
}
|
|
if len(got) != 1 {
|
|
t.Fatalf("len = %d, want 1", len(got))
|
|
}
|
|
if got[0].Status != "success" || got[0].Context != "ci/tests" {
|
|
t.Errorf("status = %+v, want %+v", got[0], statuses[0])
|
|
}
|
|
}
|
|
|
|
func TestGetFileContent(t *testing.T) {
|
|
const wantContent = "package main\n\nfunc main() {}\n"
|
|
encoded := base64.StdEncoding.EncodeToString([]byte(wantContent))
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/repos/owner/repo/contents/main.go" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(contentResponse{
|
|
Type: "file",
|
|
Name: "main.go",
|
|
Path: "main.go",
|
|
Encoding: "base64",
|
|
Content: encoded,
|
|
})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
got, err := c.GetFileContent(context.Background(), "owner", "repo", "main.go")
|
|
if err != nil {
|
|
t.Fatalf("GetFileContent: %v", err)
|
|
}
|
|
if got != wantContent {
|
|
t.Errorf("content = %q, want %q", got, wantContent)
|
|
}
|
|
}
|
|
|
|
func TestGetFileContentRef(t *testing.T) {
|
|
const wantContent = "version: 2\n"
|
|
encoded := base64.StdEncoding.EncodeToString([]byte(wantContent))
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/repos/owner/repo/contents/config.yml" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
if r.URL.Query().Get("ref") != "feature/x" {
|
|
t.Errorf("ref = %q, want feature/x", r.URL.Query().Get("ref"))
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(contentResponse{
|
|
Type: "file",
|
|
Name: "config.yml",
|
|
Path: "config.yml",
|
|
Encoding: "base64",
|
|
Content: encoded,
|
|
})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
got, err := c.GetFileContentRef(context.Background(), "owner", "repo", "config.yml", "feature/x")
|
|
if err != nil {
|
|
t.Fatalf("GetFileContentRef: %v", err)
|
|
}
|
|
if got != wantContent {
|
|
t.Errorf("content = %q, want %q", got, wantContent)
|
|
}
|
|
}
|
|
|
|
func TestGetFileContent_NewlinesInBase64(t *testing.T) {
|
|
// GitHub inserts newlines every 60 chars in the base64-encoded content.
|
|
// Verify we strip them before decoding.
|
|
const wantContent = "hello world this is a long string that gets split by github with newlines in the base64 encoding"
|
|
rawEncoded := base64.StdEncoding.EncodeToString([]byte(wantContent))
|
|
// Insert newlines to simulate GitHub's format.
|
|
var chunked string
|
|
for i := 0; i < len(rawEncoded); i += 60 {
|
|
end := i + 60
|
|
if end > len(rawEncoded) {
|
|
end = len(rawEncoded)
|
|
}
|
|
chunked += rawEncoded[i:end] + "\n"
|
|
}
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(contentResponse{
|
|
Type: "file",
|
|
Encoding: "base64",
|
|
Content: chunked,
|
|
})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
got, err := c.GetFileContent(context.Background(), "owner", "repo", "file.txt")
|
|
if err != nil {
|
|
t.Fatalf("GetFileContent: %v", err)
|
|
}
|
|
if got != wantContent {
|
|
t.Errorf("content = %q, want %q", got, wantContent)
|
|
}
|
|
}
|
|
|
|
func TestListContents_Directory(t *testing.T) {
|
|
entries := []ContentEntry{
|
|
{Name: "main.go", Path: "main.go", Type: "file"},
|
|
{Name: "lib", Path: "lib", Type: "dir"},
|
|
}
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/repos/owner/repo/contents/" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(entries)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
got, err := c.ListContents(context.Background(), "owner", "repo", "")
|
|
if err != nil {
|
|
t.Fatalf("ListContents: %v", err)
|
|
}
|
|
if len(got) != len(entries) {
|
|
t.Fatalf("len = %d, want %d", len(got), len(entries))
|
|
}
|
|
for i, e := range entries {
|
|
if got[i].Name != e.Name || got[i].Type != e.Type {
|
|
t.Errorf("entry[%d] = %+v, want %+v", i, got[i], e)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestListContents_File(t *testing.T) {
|
|
// When path points to a single file, GitHub returns an object, not array.
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
// Return a single file object (not an array).
|
|
json.NewEncoder(w).Encode(contentResponse{
|
|
Type: "file",
|
|
Name: "README.md",
|
|
Path: "README.md",
|
|
Encoding: "base64",
|
|
Content: base64.StdEncoding.EncodeToString([]byte("# Hello")),
|
|
})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
got, err := c.ListContents(context.Background(), "owner", "repo", "README.md")
|
|
if err != nil {
|
|
t.Fatalf("ListContents (file): %v", err)
|
|
}
|
|
if len(got) != 1 {
|
|
t.Fatalf("len = %d, want 1", len(got))
|
|
}
|
|
if got[0].Name != "README.md" || got[0].Type != "file" {
|
|
t.Errorf("entry = %+v", got[0])
|
|
}
|
|
}
|
|
|
|
func TestGetAuthenticatedUser(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/user" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(userResponse{Login: "rodin"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
login, err := c.GetAuthenticatedUser(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("GetAuthenticatedUser: %v", err)
|
|
}
|
|
if login != "rodin" {
|
|
t.Errorf("login = %q, want %q", login, "rodin")
|
|
}
|
|
}
|
|
|
|
func TestPostReview(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
t.Errorf("method = %s, want POST", r.Method)
|
|
}
|
|
if r.URL.Path != "/repos/owner/repo/pulls/5/reviews" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
var payload postReviewRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
|
t.Errorf("decode body: %v", err)
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
if payload.Event != "REQUEST_CHANGES" {
|
|
t.Errorf("event = %q, want REQUEST_CHANGES", payload.Event)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(reviewResponse{
|
|
ID: 99,
|
|
Body: payload.Body,
|
|
State: "CHANGES_REQUESTED",
|
|
User: struct{ Login string `json:"login"` }{Login: "rodin"},
|
|
})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
review, err := c.PostReview(context.Background(), "owner", "repo", 5, vcs.ReviewRequest{
|
|
Body: "needs work",
|
|
Event: vcs.ReviewEventRequestChanges,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("PostReview: %v", err)
|
|
}
|
|
if review.ID != 99 {
|
|
t.Errorf("review.ID = %d, want 99", review.ID)
|
|
}
|
|
// Verify state translation: CHANGES_REQUESTED -> REQUEST_CHANGES
|
|
if review.State != "REQUEST_CHANGES" {
|
|
t.Errorf("review.State = %q, want REQUEST_CHANGES", review.State)
|
|
}
|
|
if review.User.Login != "rodin" {
|
|
t.Errorf("review.User.Login = %q, want rodin", review.User.Login)
|
|
}
|
|
}
|
|
|
|
func TestPostReview_ConflictingCommitIDs(t *testing.T) {
|
|
c := NewClient("tok", "https://api.github.com")
|
|
_, err := c.PostReview(context.Background(), "owner", "repo", 1, vcs.ReviewRequest{
|
|
Body: "test",
|
|
Event: vcs.ReviewEventComment,
|
|
Comments: []vcs.ReviewComment{
|
|
{Path: "a.go", Position: 1, Body: "comment 1", CommitID: "sha1"},
|
|
{Path: "b.go", Position: 2, Body: "comment 2", CommitID: "sha2"},
|
|
},
|
|
})
|
|
if err == nil {
|
|
t.Fatal("expected ErrConflictingCommitIDs, got nil")
|
|
}
|
|
if err != ErrConflictingCommitIDs {
|
|
t.Errorf("err = %v, want ErrConflictingCommitIDs", err)
|
|
}
|
|
}
|
|
|
|
func TestListReviews(t *testing.T) {
|
|
reviews := []reviewResponse{
|
|
{ID: 1, Body: "lgtm", State: "APPROVED", User: struct{ Login string `json:"login"` }{Login: "alice"}},
|
|
{ID: 2, Body: "needs work", State: "CHANGES_REQUESTED", User: struct{ Login string `json:"login"` }{Login: "bob"}},
|
|
}
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/repos/owner/repo/pulls/3/reviews" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(reviews)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
got, err := c.ListReviews(context.Background(), "owner", "repo", 3)
|
|
if err != nil {
|
|
t.Fatalf("ListReviews: %v", err)
|
|
}
|
|
if len(got) != 2 {
|
|
t.Fatalf("len = %d, want 2", len(got))
|
|
}
|
|
if got[0].State != "APPROVED" {
|
|
t.Errorf("got[0].State = %q, want APPROVED", got[0].State)
|
|
}
|
|
if got[1].State != "REQUEST_CHANGES" {
|
|
t.Errorf("got[1].State = %q, want REQUEST_CHANGES (translated from CHANGES_REQUESTED)", got[1].State)
|
|
}
|
|
}
|
|
|
|
func TestDeleteReview_Pending(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodDelete {
|
|
t.Errorf("method = %s, want DELETE", r.Method)
|
|
}
|
|
if r.URL.Path != "/repos/owner/repo/pulls/1/reviews/42" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
err := c.DeleteReview(context.Background(), "owner", "repo", 1, 42)
|
|
if err != nil {
|
|
t.Fatalf("DeleteReview: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteReview_Submitted_Returns422(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// GitHub returns 422 when trying to delete a submitted review.
|
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
w.Write([]byte(`{"message":"Cannot delete a submitted review"}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
err := c.DeleteReview(context.Background(), "owner", "repo", 1, 42)
|
|
if err == nil {
|
|
t.Fatal("expected error for submitted review deletion")
|
|
}
|
|
// Should be wrapped as ErrCannotDeleteSubmittedReview.
|
|
if !isErrCannotDeleteSubmittedReview(err) {
|
|
t.Errorf("err = %v, want ErrCannotDeleteSubmittedReview", err)
|
|
}
|
|
}
|
|
|
|
// isErrCannotDeleteSubmittedReview checks if err wraps ErrCannotDeleteSubmittedReview.
|
|
func isErrCannotDeleteSubmittedReview(err error) bool {
|
|
return err != nil && errors.Is(err, ErrCannotDeleteSubmittedReview)
|
|
}
|
|
|
|
func TestDismissReview(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPut {
|
|
t.Errorf("method = %s, want PUT", r.Method)
|
|
}
|
|
if r.URL.Path != "/repos/owner/repo/pulls/2/reviews/10/dismissals" {
|
|
t.Errorf("unexpected path: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
var payload dismissReviewRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
|
t.Errorf("decode body: %v", err)
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
if payload.Event != "DISMISS" {
|
|
t.Errorf("event = %q, want DISMISS", payload.Event)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(reviewResponse{ID: 10, State: "DISMISSED"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
err := c.DismissReview(context.Background(), "owner", "repo", 2, 10, "outdated review")
|
|
if err != nil {
|
|
t.Fatalf("DismissReview: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDoRequestWithBody_RejectsHTTP(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
t.Fatal("request should not have been sent")
|
|
}))
|
|
defer srv.Close()
|
|
|
|
// Without AllowInsecureHTTPForTest, HTTP should be rejected.
|
|
c := NewClient("tok", srv.URL)
|
|
_, err := c.doRequestWithBody(context.Background(), http.MethodPost, srv.URL+"/test", []byte(`{}`))
|
|
if err == nil {
|
|
t.Fatal("expected error for HTTP request")
|
|
}
|
|
}
|
|
|
|
func TestPostReview_CommitIDFromRequest(t *testing.T) {
|
|
const wantCommitID = "abc123def456"
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var payload postReviewRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
|
t.Errorf("decode body: %v", err)
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
if payload.CommitID != wantCommitID {
|
|
t.Errorf("commit_id = %q, want %q", payload.CommitID, wantCommitID)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(reviewResponse{
|
|
ID: 1,
|
|
Body: payload.Body,
|
|
State: "COMMENTED",
|
|
CommitID: payload.CommitID,
|
|
User: struct{ Login string `json:"login"` }{Login: "rodin"},
|
|
})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient("tok", srv.URL, AllowInsecureHTTPForTest())
|
|
review, err := c.PostReview(context.Background(), "owner", "repo", 1, vcs.ReviewRequest{
|
|
Body: "looks good",
|
|
Event: vcs.ReviewEventApprove,
|
|
CommitID: wantCommitID,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("PostReview: %v", err)
|
|
}
|
|
if review.CommitID != wantCommitID {
|
|
t.Errorf("review.CommitID = %q, want %q", review.CommitID, wantCommitID)
|
|
}
|
|
}
|