package logger
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
func testService(t *testing.T, prilagodi func(*Config)) *Service {
t.Helper()
cfg := DefaultConfig()
cfg.Dir = t.TempDir()
if prilagodi != nil {
prilagodi(&cfg)
}
s, err := New(cfg)
if err != nil {
t.Fatalf("New: %v", err)
}
t.Cleanup(s.store.Close)
return s
}
func TestServiceHandleUpisujeDnevnikIPamtiHeartbeat(t *testing.T) {
s := testService(t, nil)
t0 := time.Date(2026, 7, 25, 12, 0, 0, 0, time.UTC)
s.now = func() time.Time { return t0 }
s.Handle([]byte(`{"app":"TERMINIA","name":"TERM-001","mac":"1C:DB:D4:A6:A4:60","ip":"192.168.0.20","fw":"0.13.4","hb":1}`), "192.168.0.20")
s.Handle([]byte("#TERMINIA TERM-001 1C:DB:D4:A6:A4:60 0.13.4\n[stampac] javio se\n"), "192.168.0.20")
s.Handle([]byte{0x00, 0x01, 0x02, 0xff, 0xfe}, "9.9.9.9") // binarno smece
if got := s.stats.Heartbeat.Load(); got != 1 {
t.Errorf("heartbeata = %d", got)
}
if got := s.stats.LogPkts.Load(); got != 1 {
t.Errorf("paketa dnevnika = %d", got)
}
if got := s.stats.WriteErrs.Load(); got != 0 {
t.Errorf("gresaka upisa = %d", got)
}
lines, _ := s.store.Tail("1CDBD4A6A460", 10, "")
if len(lines) != 1 || !strings.Contains(lines[0], "[stampac] javio se") {
t.Errorf("dnevnik = %q", lines)
}
}
func TestServiceStranicaUredjaja(t *testing.T) {
s := testService(t, nil)
t0 := time.Date(2026, 7, 25, 12, 0, 0, 0, time.UTC)
s.now = func() time.Time { return t0 }
s.Handle([]byte("#TERMINIA TERM-001 1C:DB:D4:A6:A4:60 0.13.4\n[stampac] javio se\n[kapija] prolaz\n"), "192.168.0.20")
h := s.Handler()
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
if rec.Code != http.StatusOK {
t.Fatalf("/ = %d", rec.Code)
}
body := rec.Body.String()
if !strings.Contains(body, "TERM-001") || !strings.Contains(body, "1C:DB:D4:A6:A4:60") {
t.Errorf("spisak ne prikazuje uredjaj: %s", body)
}
rec = httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "/uredjaj?k=1CDBD4A6A460&q=stampac", nil))
if rec.Code != http.StatusOK {
t.Fatalf("/uredjaj = %d", rec.Code)
}
body = rec.Body.String()
if !strings.Contains(body, "[stampac] javio se") {
t.Error("pretraga ne vraca ocekivanu liniju")
}
if strings.Contains(body, "[kapija] prolaz") {
t.Error("pretraga vraca i linije koje ne odgovaraju upitu")
}
}
func TestServiceNepoznatUredjajJeOznacen(t *testing.T) {
s := testService(t, nil)
s.Handle([]byte("goli tekst bez zaglavlja\n"), "192.168.0.77")
rec := httptest.NewRecorder()
s.Handler().ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
body := rec.Body.String()
if !strings.Contains(body, "nepoznat uređaj") {
t.Errorf("uredjaj bez zaglavlja nije oznacen kao nepoznat:\n%s", body)
}
if !strings.Contains(body, "192.168.0.77") {
t.Error("nije prikazana izvorna adresa nepoznatog uredjaja")
}
}
func TestServiceTihUredjajJeCrven(t *testing.T) {
s := testService(t, nil)
t0 := time.Date(2026, 7, 25, 12, 0, 0, 0, time.UTC)
s.now = func() time.Time { return t0 }
s.Handle([]byte(`{"name":"TERM-001","mac":"1C:DB:D4:A6:A4:60","hb":1}`), "192.168.0.20")
s.now = func() time.Time { return t0.Add(10 * time.Minute) } // 3x60 s je davno proslo
rec := httptest.NewRecorder()
s.Handler().ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
if !strings.Contains(rec.Body.String(), `class="tih"`) {
t.Error("tih uredjaj nije oznacen crvenim redom")
}
}
func TestServiceHTMLEscapeIzPaketa(t *testing.T) {
// Sadrzaj paketa je tudji tekst - ne sme da postane HTML.
s := testService(t, nil)
s.Handle([]byte("#TERMINIA 1C:DB:D4:A6:A4:60 0.13.4\n
\n"), "1.2.3.4")
for _, url := range []string{"/", "/uredjaj?k=1CDBD4A6A460"} {
rec := httptest.NewRecorder()
s.Handler().ServeHTTP(rec, httptest.NewRequest("GET", url, nil))
if strings.Contains(rec.Body.String(), "") ||
strings.Contains(rec.Body.String(), ")