mirror of
https://github.com/alibaba/open-code-review.git
synced 2026-07-09 17:28:58 +00:00
238 lines
6 KiB
Go
238 lines
6 KiB
Go
package viewer
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseTemplate_ReposHTML(t *testing.T) {
|
|
tmpl, err := parseTemplate("repos.html")
|
|
if err != nil {
|
|
t.Fatalf("parseTemplate(repos.html) error: %v", err)
|
|
}
|
|
if tmpl == nil {
|
|
t.Fatal("parseTemplate returned nil template")
|
|
}
|
|
}
|
|
|
|
func TestParseTemplate_SessionsHTML(t *testing.T) {
|
|
tmpl, err := parseTemplate("sessions.html")
|
|
if err != nil {
|
|
t.Fatalf("parseTemplate(sessions.html) error: %v", err)
|
|
}
|
|
if tmpl == nil {
|
|
t.Fatal("parseTemplate returned nil template")
|
|
}
|
|
}
|
|
|
|
func TestParseTemplate_SessionHTML(t *testing.T) {
|
|
tmpl, err := parseTemplate("session.html")
|
|
if err != nil {
|
|
t.Fatalf("parseTemplate(session.html) error: %v", err)
|
|
}
|
|
if tmpl == nil {
|
|
t.Fatal("parseTemplate returned nil template")
|
|
}
|
|
}
|
|
|
|
func TestParseTemplate_NonExistent(t *testing.T) {
|
|
_, err := parseTemplate("nonexistent.html")
|
|
if err == nil {
|
|
t.Error("expected error for non-existent template")
|
|
}
|
|
}
|
|
|
|
func TestRenderTemplate_Success(t *testing.T) {
|
|
rr := httptest.NewRecorder()
|
|
renderTemplate(rr, "repos.html", map[string]any{
|
|
"Repos": []RepoInfo{},
|
|
})
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Errorf("status = %d, want 200", rr.Code)
|
|
}
|
|
ct := rr.Header().Get("Content-Type")
|
|
if ct != "text/html; charset=utf-8" {
|
|
t.Errorf("Content-Type = %q", ct)
|
|
}
|
|
if !strings.Contains(rr.Body.String(), "No session data found") {
|
|
t.Errorf("expected empty repos message in rendered output")
|
|
}
|
|
}
|
|
|
|
func TestRenderTemplate_WithRepos(t *testing.T) {
|
|
rr := httptest.NewRecorder()
|
|
renderTemplate(rr, "repos.html", map[string]any{
|
|
"Repos": []RepoInfo{
|
|
{EncodedPath: "my-project", SessionCount: 3},
|
|
},
|
|
})
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Errorf("status = %d, want 200", rr.Code)
|
|
}
|
|
if !strings.Contains(rr.Body.String(), "my-project") {
|
|
t.Errorf("expected repo name in rendered output")
|
|
}
|
|
}
|
|
|
|
func TestRenderTemplate_BadTemplate(t *testing.T) {
|
|
rr := httptest.NewRecorder()
|
|
renderTemplate(rr, "nonexistent.html", nil)
|
|
|
|
if rr.Code != http.StatusInternalServerError {
|
|
t.Errorf("status = %d, want 500", rr.Code)
|
|
}
|
|
if !strings.Contains(rr.Body.String(), "template error") {
|
|
t.Errorf("expected template error message")
|
|
}
|
|
}
|
|
|
|
func TestRenderTemplate_Sessions(t *testing.T) {
|
|
rr := httptest.NewRecorder()
|
|
renderTemplate(rr, "sessions.html", sessionsData{
|
|
EncodedRepo: "test-repo",
|
|
RepoName: "MyProject",
|
|
Sessions: []SessionSummary{},
|
|
})
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Errorf("status = %d, want 200", rr.Code)
|
|
}
|
|
if !strings.Contains(rr.Body.String(), "MyProject") {
|
|
t.Errorf("expected repo name in sessions template")
|
|
}
|
|
}
|
|
|
|
func TestRenderTemplate_SessionPage(t *testing.T) {
|
|
rr := httptest.NewRecorder()
|
|
vs := &ViewSession{
|
|
Summary: SessionSummary{
|
|
SessionID: "abc",
|
|
Model: "gpt-4",
|
|
CWD: "/test",
|
|
},
|
|
Files: []*FileGroup{
|
|
{
|
|
FilePath: "main.go",
|
|
Tasks: map[TaskType][]*TaskCard{
|
|
MainTask: {
|
|
{
|
|
RequestNo: 1,
|
|
ResponseContent: "looks good",
|
|
Model: "gpt-4",
|
|
PromptTokens: 100,
|
|
CompletionTokens: 50,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
renderTemplate(rr, "session.html", sessionPageData{
|
|
EncodedRepo: "repo",
|
|
RepoName: "MyRepo",
|
|
Session: vs,
|
|
})
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Errorf("status = %d, want 200", rr.Code)
|
|
}
|
|
}
|
|
|
|
func TestRenderTemplate_ExecutionError(t *testing.T) {
|
|
rr := httptest.NewRecorder()
|
|
// Pass wrong data type to trigger template execution error
|
|
// repos.html expects .Repos to be rangeable; passing a string causes execution error
|
|
renderTemplate(rr, "repos.html", map[string]any{
|
|
"Repos": "not-a-slice",
|
|
})
|
|
// Template execution may partially write before failing, so we just check it didn't panic
|
|
// and that something was written (the header was set before Execute)
|
|
ct := rr.Header().Get("Content-Type")
|
|
if ct != "text/html; charset=utf-8" {
|
|
t.Errorf("Content-Type = %q", ct)
|
|
}
|
|
}
|
|
|
|
func TestStaticFS(t *testing.T) {
|
|
sfs := staticFS()
|
|
if sfs == nil {
|
|
t.Fatal("staticFS() returned nil")
|
|
}
|
|
// Should be able to open style.css
|
|
f, err := sfs.Open("style.css")
|
|
if err != nil {
|
|
t.Fatalf("failed to open style.css from staticFS: %v", err)
|
|
}
|
|
_ = f.Close()
|
|
}
|
|
|
|
func TestResolveAllowedHostsFromEnv(t *testing.T) {
|
|
t.Setenv(EnvAllowedHosts, "custom.host,other.host")
|
|
allowed := resolveAllowedHostsFromEnv("192.168.1.5:5483")
|
|
|
|
if _, ok := allowed["localhost"]; !ok {
|
|
t.Error("missing localhost")
|
|
}
|
|
if _, ok := allowed["192.168.1.5"]; !ok {
|
|
t.Error("missing bind host")
|
|
}
|
|
if _, ok := allowed["custom.host"]; !ok {
|
|
t.Error("missing custom.host from env")
|
|
}
|
|
if _, ok := allowed["other.host"]; !ok {
|
|
t.Error("missing other.host from env")
|
|
}
|
|
}
|
|
|
|
func TestBuildAllowedHosts_BracketedIPv6(t *testing.T) {
|
|
a := buildAllowedHosts("[fe80::1]", "")
|
|
if _, ok := a["fe80::1"]; !ok {
|
|
t.Errorf("bracketed IPv6 bind host not stripped: %v", a)
|
|
}
|
|
}
|
|
|
|
func TestResolveAllowedHostsFromEnv_NoEnv(t *testing.T) {
|
|
t.Setenv(EnvAllowedHosts, "")
|
|
allowed := resolveAllowedHostsFromEnv(":5483")
|
|
|
|
if len(allowed) != 3 {
|
|
t.Errorf("expected 3 default hosts, got %d: %v", len(allowed), allowed)
|
|
}
|
|
}
|
|
|
|
func TestTemplateFuncTaskTypeClass(t *testing.T) {
|
|
tmpl, err := parseTemplate("session.html")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Verify we can execute with task data that exercises taskTypeClass
|
|
rr := httptest.NewRecorder()
|
|
vs := &ViewSession{
|
|
Summary: SessionSummary{SessionID: "x", CWD: "/p"},
|
|
Files: []*FileGroup{
|
|
{
|
|
FilePath: "f.go",
|
|
Tasks: map[TaskType][]*TaskCard{
|
|
PlanTask: {{RequestNo: 1, ResponseContent: "plan"}},
|
|
MainTask: {{RequestNo: 2, ResponseContent: "main"}},
|
|
MemoryCompressionTask: {{RequestNo: 3, ResponseContent: "mem"}},
|
|
ReLocationTask: {{RequestNo: 4, ResponseContent: "reloc"}},
|
|
TaskType("custom"): {{RequestNo: 5, ResponseContent: "custom"}},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
err = tmpl.Execute(rr, sessionPageData{
|
|
EncodedRepo: "r",
|
|
RepoName: "R",
|
|
Session: vs,
|
|
})
|
|
if err != nil {
|
|
t.Errorf("template execution with all task types: %v", err)
|
|
}
|
|
}
|