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(), "