Files
2026-06-08 15:03:41 -05:00

109 lines
5.3 KiB
Go

package app
import (
"database/sql"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
)
func prRows(pr PullRequest) *sqlmock.Rows {
created := pr.CreatedAt
if created.IsZero() {
created = time.Now().UTC()
}
updated := pr.UpdatedAt
if updated.IsZero() {
updated = created
}
closed := sql.NullTime{}
if pr.ClosedAt != nil {
closed = sql.NullTime{Time: *pr.ClosedAt, Valid: true}
}
merged := sql.NullTime{}
if pr.MergedAt != nil {
merged = sql.NullTime{Time: *pr.MergedAt, Valid: true}
}
return sqlmock.NewRows([]string{"id", "number", "target_repository_id", "source_repository_id", "author_user_id", "author", "source_owner", "source_repo", "source_branch", "target_owner", "target_repo", "target_branch", "title", "description", "status", "created_at", "updated_at", "closed_at", "merged_at"}).
AddRow(pr.ID, pr.Number, pr.TargetRepositoryID, pr.SourceRepositoryID, pr.AuthorUserID, pr.Author, pr.SourceOwner, pr.SourceRepo, pr.SourceBranch, pr.TargetOwner, pr.TargetRepo, pr.TargetBranch, pr.Title, pr.Description, pr.Status, created, updated, closed, merged)
}
func TestPRListViewCloseAndComments(t *testing.T) {
s, mock, cleanup := newMockServer(t)
defer cleanup()
owner := User{ID: 1, Email: "alice@example.com", Username: "alice"}
token := "tok"
repo := Repository{ID: 10, OwnerUserID: owner.ID, Owner: "alice", Name: "demo", Visibility: "public", DefaultBranch: "main"}
pr := PullRequest{ID: 30, Number: 2, TargetRepositoryID: repo.ID, SourceRepositoryID: repo.ID, AuthorUserID: owner.ID, Author: "alice", SourceOwner: "alice", SourceRepo: "demo", SourceBranch: "feature", TargetOwner: "alice", TargetRepo: "demo", TargetBranch: "main", Title: "Fix", Description: "desc", Status: "open"}
expectLoadRepo(mock, "alice", "demo", repo)
mock.ExpectQuery("FROM pull_requests pr").WithArgs(repo.ID).WillReturnRows(prRows(pr))
rr := httptest.NewRecorder()
s.handlePRList(rr, httptest.NewRequest(http.MethodGet, "/api/repos/alice/demo/pulls", nil), "alice", "demo")
if rr.Code != http.StatusOK || !strings.Contains(rr.Body.String(), "Fix") {
t.Fatalf("list status=%d body=%s", rr.Code, rr.Body.String())
}
expectLoadRepo(mock, "alice", "demo", repo)
mock.ExpectQuery("FROM pull_requests pr").WithArgs(repo.ID, pr.Number).WillReturnRows(prRows(pr))
rr = httptest.NewRecorder()
s.handlePRView(rr, httptest.NewRequest(http.MethodGet, "/api/repos/alice/demo/pulls/2", nil), "alice", "demo", 2)
if rr.Code != http.StatusOK || !strings.Contains(rr.Body.String(), "Fix") {
t.Fatalf("view status=%d body=%s", rr.Code, rr.Body.String())
}
expectBearerUser(mock, token, owner)
expectLoadRepo(mock, "alice", "demo", repo)
mock.ExpectExec("UPDATE pull_requests SET status = 'closed'").WithArgs(repo.ID, pr.Number).WillReturnResult(sqlmock.NewResult(0, 1))
closedPR := pr
closedPR.Status = "closed"
mock.ExpectQuery("FROM pull_requests pr").WithArgs(repo.ID, pr.Number).WillReturnRows(prRows(closedPR))
rr = httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/api/repos/alice/demo/pulls/2/close", nil)
req.Header.Set("Authorization", "Bearer "+token)
s.handlePRClose(rr, req, "alice", "demo", 2)
if rr.Code != http.StatusOK || !strings.Contains(rr.Body.String(), "closed") {
t.Fatalf("close status=%d body=%s", rr.Code, rr.Body.String())
}
expectLoadRepo(mock, "alice", "demo", repo)
mock.ExpectQuery("FROM pull_requests pr").WithArgs(repo.ID, pr.Number).WillReturnRows(prRows(pr))
mock.ExpectQuery("SELECT c.id, u.username").WithArgs(pr.ID).WillReturnRows(sqlmock.NewRows([]string{"id", "username", "body", "created_at", "updated_at"}).AddRow(int64(1), "alice", "hello", time.Now().UTC(), time.Now().UTC()))
rr = httptest.NewRecorder()
s.handlePRCommentsList(rr, httptest.NewRequest(http.MethodGet, "/api/repos/alice/demo/pulls/2/comments", nil), "alice", "demo", 2)
if rr.Code != http.StatusOK || !strings.Contains(rr.Body.String(), "hello") {
t.Fatalf("comments list status=%d body=%s", rr.Code, rr.Body.String())
}
expectBearerUser(mock, token, owner)
expectLoadRepo(mock, "alice", "demo", repo)
mock.ExpectQuery("FROM pull_requests pr").WithArgs(repo.ID, pr.Number).WillReturnRows(prRows(pr))
mock.ExpectExec("INSERT INTO pull_request_comments").WithArgs(pr.ID, owner.ID, "hello").WillReturnResult(sqlmock.NewResult(5, 1))
rr = httptest.NewRecorder()
req = httptest.NewRequest(http.MethodPost, "/api/repos/alice/demo/pulls/2/comments", strings.NewReader(`{"body":" hello "}`))
req.Header.Set("Authorization", "Bearer "+token)
s.handlePRCommentCreate(rr, req, "alice", "demo", 2)
if rr.Code != http.StatusCreated || !strings.Contains(rr.Body.String(), "hello") {
t.Fatalf("comment create status=%d body=%s", rr.Code, rr.Body.String())
}
expectBearerUser(mock, token, owner)
expectLoadRepo(mock, "alice", "demo", repo)
mock.ExpectQuery("FROM pull_requests pr").WithArgs(repo.ID, pr.Number).WillReturnRows(prRows(pr))
rr = httptest.NewRecorder()
req = httptest.NewRequest(http.MethodPost, "/api/repos/alice/demo/pulls/2/comments", strings.NewReader(`{"body":" "}`))
req.Header.Set("Authorization", "Bearer "+token)
s.handlePRCommentCreate(rr, req, "alice", "demo", 2)
if rr.Code != http.StatusBadRequest {
t.Fatalf("empty comment status=%d body=%s", rr.Code, rr.Body.String())
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatal(err)
}
}