- Razbijen monolitni server_test.go na fokusirane test fajlove: api_test.go, dashboard_test.go, docs_test.go, search_test.go, submit_test.go, task_detail_test.go, console_test.go, sse_test.go, timestamp_test.go, ui_test.go, test_helpers_test.go - Dodat logs.go handler (handleLogsTail) koji je nedostajao - Dodat LogFile u config - Fix konzola: prompt se šalje preko fajla umesto direktno u PTY - 192 testova prolazi Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
313 lines
7.9 KiB
Go
313 lines
7.9 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestConsolePage(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", w.Code)
|
|
}
|
|
|
|
body := w.Body.String()
|
|
if !containsStr(body, "KAOS") {
|
|
t.Error("expected 'KAOS' in console page")
|
|
}
|
|
if !containsStr(body, "Konzola") {
|
|
t.Error("expected 'Konzola' in console page")
|
|
}
|
|
}
|
|
|
|
func TestConsoleSessions_Empty(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console/sessions", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", w.Code)
|
|
}
|
|
|
|
var sessions []taskSessionResponse
|
|
if err := json.Unmarshal(w.Body.Bytes(), &sessions); err != nil {
|
|
t.Fatalf("invalid JSON: %v", err)
|
|
}
|
|
|
|
if len(sessions) != 0 {
|
|
t.Fatalf("expected 0 sessions, got %d", len(sessions))
|
|
}
|
|
}
|
|
|
|
func TestConsoleKill_NotFound(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/console/kill/T99", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestSessionKey(t *testing.T) {
|
|
if got := sessionKey("T01", "work"); got != "T01" {
|
|
t.Errorf("expected T01, got %s", got)
|
|
}
|
|
if got := sessionKey("T01", "review"); got != "T01-review" {
|
|
t.Errorf("expected T01-review, got %s", got)
|
|
}
|
|
}
|
|
|
|
func TestTaskSessionManager_ListEmpty(t *testing.T) {
|
|
sm := newTaskSessionManager()
|
|
sessions := sm.listSessions()
|
|
if len(sessions) != 0 {
|
|
t.Errorf("expected 0 sessions, got %d", len(sessions))
|
|
}
|
|
}
|
|
|
|
func TestTaskSessionManager_KillNotFound(t *testing.T) {
|
|
sm := newTaskSessionManager()
|
|
if sm.killSession("T99", "work") {
|
|
t.Error("expected false for non-existent session")
|
|
}
|
|
}
|
|
|
|
func TestTaskSessionManager_GetNotFound(t *testing.T) {
|
|
sm := newTaskSessionManager()
|
|
if sm.getSessionByKey("T99") != nil {
|
|
t.Error("expected nil for non-existent session")
|
|
}
|
|
}
|
|
|
|
func TestBuildWorkPrompt(t *testing.T) {
|
|
prompt := buildWorkPrompt("T08", []byte("# T08: Test task\n\nOpis."))
|
|
|
|
if !containsStr(prompt, "T08") {
|
|
t.Error("expected task ID in prompt")
|
|
}
|
|
if !containsStr(prompt, "Test task") {
|
|
t.Error("expected task content in prompt")
|
|
}
|
|
if !containsStr(prompt, "agents/coder/CLAUDE.md") {
|
|
t.Error("expected coder CLAUDE.md reference")
|
|
}
|
|
if !containsStr(prompt, "go test") {
|
|
t.Error("expected test instruction")
|
|
}
|
|
if !containsStr(prompt, "report") {
|
|
t.Error("expected report instruction")
|
|
}
|
|
}
|
|
|
|
func TestBuildReviewPrompt(t *testing.T) {
|
|
prompt := buildReviewPrompt("T08", []byte("# T08: Test\n"), []byte("# Report\nSve ok."))
|
|
|
|
if !containsStr(prompt, "T08") {
|
|
t.Error("expected task ID in review prompt")
|
|
}
|
|
if !containsStr(prompt, "Sve ok") {
|
|
t.Error("expected report content in review prompt")
|
|
}
|
|
if !containsStr(prompt, "agents/checker/CLAUDE.md") {
|
|
t.Error("expected checker CLAUDE.md reference")
|
|
}
|
|
}
|
|
|
|
func TestBuildReviewPrompt_NoReport(t *testing.T) {
|
|
prompt := buildReviewPrompt("T08", []byte("# T08: Test\n"), nil)
|
|
|
|
if !containsStr(prompt, "T08") {
|
|
t.Error("expected task ID")
|
|
}
|
|
if containsStr(prompt, "Izveštaj agenta") {
|
|
t.Error("should not include report section when no report")
|
|
}
|
|
}
|
|
|
|
func TestReviewTask_NotFound(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/task/T99/review", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestConsolePage_HasKillButton(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
body := w.Body.String()
|
|
if !containsStr(body, "killSession") {
|
|
t.Error("expected killSession function in console page")
|
|
}
|
|
}
|
|
|
|
func TestTaskDetail_HasProveriButton(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
// Put T08 in review
|
|
os.Rename(
|
|
filepath.Join(srv.Config.TasksDir, "backlog", "T08.md"),
|
|
filepath.Join(srv.Config.TasksDir, "review", "T08.md"),
|
|
)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/task/T08", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
body := w.Body.String()
|
|
if !containsStr(body, "Proveri") {
|
|
t.Error("expected 'Proveri' button for review task")
|
|
}
|
|
if !containsStr(body, "/review") {
|
|
t.Error("expected /review endpoint in Proveri button")
|
|
}
|
|
}
|
|
|
|
func TestConsolePage_ToolbarAbovePanels(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
body := w.Body.String()
|
|
// Toolbar should appear before console-panels in the HTML
|
|
toolbarIdx := strings.Index(body, "console-toolbar")
|
|
panelsIdx := strings.Index(body, "console-panels")
|
|
|
|
if toolbarIdx == -1 {
|
|
t.Fatal("expected console-toolbar in console page")
|
|
}
|
|
if panelsIdx == -1 {
|
|
t.Fatal("expected console-panels in console page")
|
|
}
|
|
if toolbarIdx > panelsIdx {
|
|
t.Error("expected toolbar before panels in console HTML")
|
|
}
|
|
}
|
|
|
|
func TestConsolePage_HasDynamicSessions(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
body := w.Body.String()
|
|
if !containsStr(body, "refreshSessions") {
|
|
t.Error("expected refreshSessions function in console page")
|
|
}
|
|
if !containsStr(body, "/console/sessions") {
|
|
t.Error("expected /console/sessions API call")
|
|
}
|
|
}
|
|
|
|
func TestConsolePage_HasXtermJS(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
body := w.Body.String()
|
|
if !containsStr(body, "xterm.min.js") {
|
|
t.Error("expected xterm.min.js CDN link in console page")
|
|
}
|
|
if !containsStr(body, "addon-fit") {
|
|
t.Error("expected addon-fit CDN link in console page")
|
|
}
|
|
if !containsStr(body, "xterm.css") {
|
|
t.Error("expected xterm.css CDN link in console page")
|
|
}
|
|
}
|
|
|
|
func TestConsolePage_HasWebSocket(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
body := w.Body.String()
|
|
if !containsStr(body, "console/ws/") {
|
|
t.Error("expected WebSocket URL console/ws/ in console page")
|
|
}
|
|
if !containsStr(body, "new WebSocket") {
|
|
t.Error("expected WebSocket constructor in console page")
|
|
}
|
|
}
|
|
|
|
func TestConsolePage_HasEmptyState(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
body := w.Body.String()
|
|
if !containsStr(body, "empty-state") {
|
|
t.Error("expected empty-state element")
|
|
}
|
|
if !containsStr(body, "Pusti") {
|
|
t.Error("expected 'Pusti' instruction in empty state")
|
|
}
|
|
if !containsStr(body, "console-terminal") {
|
|
t.Error("expected console-terminal class in JS code")
|
|
}
|
|
}
|
|
|
|
func TestConsolePage_HasBinaryMessageSupport(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
body := w.Body.String()
|
|
if !containsStr(body, "arraybuffer") {
|
|
t.Error("expected arraybuffer binary type for WebSocket")
|
|
}
|
|
if !containsStr(body, "Uint8Array") {
|
|
t.Error("expected Uint8Array handling for binary messages")
|
|
}
|
|
}
|
|
|
|
func TestConsolePage_HasResizeHandler(t *testing.T) {
|
|
srv := setupTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/console", nil)
|
|
w := httptest.NewRecorder()
|
|
srv.Router.ServeHTTP(w, req)
|
|
|
|
body := w.Body.String()
|
|
if !containsStr(body, "fitAddon.fit()") {
|
|
t.Error("expected fitAddon.fit() for resize handling")
|
|
}
|
|
if !containsStr(body, `'resize'`) {
|
|
t.Error("expected resize message type in WebSocket handler")
|
|
}
|
|
}
|