package logger import ( "fmt" "testing" "time" ) func hbPaket(mac string) Packet { return ParsePacket([]byte(fmt.Sprintf( `{"app":"TERMINIA","name":"TERM","mac":"%s","ip":"192.168.0.20","fw":"0.13.4","hb":1}`, mac)), "192.168.0.20") } func TestRegistryMeriIntervalHeartbeata(t *testing.T) { r := NewRegistry(10, 60) t0 := time.Date(2026, 7, 25, 12, 0, 0, 0, time.UTC) r.Update(hbPaket("1C:DB:D4:A6:A4:60"), t0) key, _ := r.Update(hbPaket("1C:DB:D4:A6:A4:60"), t0.Add(30*time.Second)) d, ok := r.Get(key) if !ok { t.Fatal("uredjaj nije u registru") } if d.IntervalSec != 30 { t.Errorf("interval = %d, ocekivano 30", d.IntervalSec) } if d.Heartbeats != 2 { t.Errorf("heartbeata = %d", d.Heartbeats) } // 3x30 s = 90 s praga (poslednji paket je stigao u t0+30 s) if r.Stale(&d, t0.Add(150*time.Second)) == false { t.Error("posle 90 s tisine uredjaj mora biti oznacen kao tih") } if r.Stale(&d, t0.Add(40*time.Second)) { t.Error("uredjaj koji se javio pre 10 s ne sme biti tih") } } func TestRegistryBezHeartbeataKoristiPodrazumevaniInterval(t *testing.T) { r := NewRegistry(10, 60) t0 := time.Now() key, _ := r.Update(ParsePacket([]byte("#TERMINIA T 1C:DB:D4:A6:A4:60 0.13.4\nred\n"), "1.2.3.4"), t0) d, _ := r.Get(key) if got := r.Interval(&d); got != 60 { t.Errorf("interval = %d, ocekivano 60 (podrazumevani)", got) } if !r.Stale(&d, t0.Add(200*time.Second)) { t.Error("posle 180 s mora biti tih") } } func TestRegistryOgranicavaBrojUredjaja(t *testing.T) { r := NewRegistry(3, 60) t0 := time.Now() for i := 0; i < 50; i++ { p := ParsePacket([]byte("neka linija\n"), fmt.Sprintf("10.0.0.%d", i)) r.Update(p, t0.Add(time.Duration(i)*time.Second)) } if n := r.Count(); n != 3 { t.Errorf("uredjaja u registru = %d, ocekivano 3 (granica)", n) } // Najstariji mora ispasti, najnoviji ostati. if _, ok := r.Get("nepoznat-10_0_0_49"); !ok { t.Error("poslednji uredjaj mora ostati u registru") } if _, ok := r.Get("nepoznat-10_0_0_0"); ok { t.Error("najstariji uredjaj je morao biti izbacen") } } func TestRegistryZadrzavaIdentitetIzZaglavlja(t *testing.T) { r := NewRegistry(10, 60) t0 := time.Now() key, _ := r.Update(ParsePacket([]byte("#TERMINIA TERM-001 1C:DB:D4:A6:A4:60 0.13.4\nprvi red\n"), "1.2.3.4"), t0) // Kasniji paket bez zaglavlja sa istim MAC-om ne postoji, ali heartbeat // dopunjuje IP i serijski. r.Update(hbPaket("1C:DB:D4:A6:A4:60"), t0.Add(time.Second)) d, _ := r.Get(key) if !d.Identified || d.MAC != "1C:DB:D4:A6:A4:60" || d.IP != "192.168.0.20" { t.Errorf("uredjaj = %+v", d) } if d.LogLines != 1 || d.LastLine != "prvi red" { t.Errorf("linije = %d / %q", d.LogLines, d.LastLine) } } func TestRegistrySnapshotStavljaTiheNaVrh(t *testing.T) { r := NewRegistry(10, 60) t0 := time.Date(2026, 7, 25, 12, 0, 0, 0, time.UTC) r.Update(hbPaket("AA:AA:AA:AA:AA:AA"), t0.Add(-time.Hour)) r.Update(hbPaket("BB:BB:BB:BB:BB:BB"), t0) snap := r.Snapshot(t0) if len(snap) != 2 { t.Fatalf("snapshot = %d", len(snap)) } if snap[0].MAC != "AA:AA:AA:AA:AA:AA" { t.Errorf("tih uredjaj mora biti prvi, dobijeno %s", snap[0].MAC) } } func TestRegistryIgnorisSmece(t *testing.T) { r := NewRegistry(10, 60) if _, ok := r.Update(ParsePacket([]byte("{"), "1.2.3.4"), time.Now()); ok { t.Error("smece ne sme uci u registar") } if r.Count() != 0 { t.Errorf("registar nije prazan: %d", r.Count()) } }