package server import ( "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" ) func TestHandleLogsTail_OK(t *testing.T) { srv := setupTestServer(t) logFile := filepath.Join(t.TempDir(), "test.log") lines := make([]string, 25) for i := range lines { lines[i] = "linija " + string(rune('A'+i)) } os.WriteFile(logFile, []byte(strings.Join(lines, "\n")+"\n"), 0644) srv.Config.LogFile = logFile req := httptest.NewRequest(http.MethodGet, "/api/logs/tail", nil) w := httptest.NewRecorder() srv.Router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } got := strings.Split(strings.TrimRight(w.Body.String(), "\n"), "\n") if len(got) != maxLogLines { t.Fatalf("expected %d lines, got %d", maxLogLines, len(got)) } // First returned line should be line 6 (index 5) since we have 25 lines, tail 20 if got[0] != "linija F" { t.Errorf("expected first line 'linija F', got %q", got[0]) } } func TestHandleLogsTail_LessThan20Lines(t *testing.T) { srv := setupTestServer(t) logFile := filepath.Join(t.TempDir(), "test.log") os.WriteFile(logFile, []byte("prva\ndruga\ntreca\n"), 0644) srv.Config.LogFile = logFile req := httptest.NewRequest(http.MethodGet, "/api/logs/tail", nil) w := httptest.NewRecorder() srv.Router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } got := strings.Split(strings.TrimRight(w.Body.String(), "\n"), "\n") if len(got) != 3 { t.Fatalf("expected 3 lines, got %d", len(got)) } } func TestHandleLogsTail_NoLogFile(t *testing.T) { srv := setupTestServer(t) // LogFile is empty string by default in test config req := httptest.NewRequest(http.MethodGet, "/api/logs/tail", nil) w := httptest.NewRecorder() srv.Router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } if !strings.Contains(w.Body.String(), "KAOS_LOG_FILE") { t.Error("expected message about KAOS_LOG_FILE not being set") } } func TestHandleLogsTail_FileNotFound(t *testing.T) { srv := setupTestServer(t) srv.Config.LogFile = "/tmp/nonexistent-kaos-test-log-12345.log" req := httptest.NewRequest(http.MethodGet, "/api/logs/tail", nil) w := httptest.NewRecorder() srv.Router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } if !strings.Contains(w.Body.String(), "ne postoji") { t.Error("expected message about file not existing") } } func TestHandleLogsTail_Max20Lines(t *testing.T) { srv := setupTestServer(t) logFile := filepath.Join(t.TempDir(), "test.log") lines := make([]string, 100) for i := range lines { lines[i] = "log line" } os.WriteFile(logFile, []byte(strings.Join(lines, "\n")+"\n"), 0644) srv.Config.LogFile = logFile req := httptest.NewRequest(http.MethodGet, "/api/logs/tail", nil) w := httptest.NewRecorder() srv.Router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } got := strings.Split(strings.TrimRight(w.Body.String(), "\n"), "\n") if len(got) > maxLogLines { t.Errorf("expected max %d lines, got %d", maxLogLines, len(got)) } } func TestTailLines(t *testing.T) { tests := []struct { name string text string n int expected int }{ {"empty", "", 20, 1}, {"less than n", "a\nb\nc", 20, 3}, {"exact n", "a\nb\nc", 3, 3}, {"more than n", "a\nb\nc\nd\ne", 3, 3}, {"trailing newline", "a\nb\nc\n", 2, 2}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tailLines(tt.text, tt.n) if len(got) != tt.expected { t.Errorf("tailLines(%q, %d) = %d lines, want %d", tt.text, tt.n, len(got), tt.expected) } }) } } func TestTailLines_Content(t *testing.T) { text := "first\nsecond\nthird\nfourth\nfifth\n" got := tailLines(text, 3) if len(got) != 3 { t.Fatalf("expected 3 lines, got %d", len(got)) } if got[0] != "third" { t.Errorf("expected 'third', got %q", got[0]) } if got[1] != "fourth" { t.Errorf("expected 'fourth', got %q", got[1]) } if got[2] != "fifth" { t.Errorf("expected 'fifth', got %q", got[2]) } }