107 lines
2.6 KiB
Go
107 lines
2.6 KiB
Go
|
|
package store
|
||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestAddHeartbeat_FirstSetsFirstLastAndCount(t *testing.T) {
|
||
|
|
s := New(nil)
|
||
|
|
id := DeviceID("device-1")
|
||
|
|
t0 := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC)
|
||
|
|
|
||
|
|
if err := s.AddHeartbeat(id, t0); err != nil {
|
||
|
|
t.Fatalf("AddHeartbeat: %v", err)
|
||
|
|
}
|
||
|
|
if got := s.Uptime(id); got != 100 {
|
||
|
|
t.Fatalf("uptime = %v, want 100 (1 beat / 1 minute)", got)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestAddHeartbeat_LaterUpdatesLast(t *testing.T) {
|
||
|
|
s := New(nil)
|
||
|
|
id := DeviceID("device-1")
|
||
|
|
t0 := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC)
|
||
|
|
t1 := t0.Add(time.Minute)
|
||
|
|
|
||
|
|
_ = s.AddHeartbeat(id, t0)
|
||
|
|
if err := s.AddHeartbeat(id, t1); err != nil {
|
||
|
|
t.Fatalf("AddHeartbeat: %v", err)
|
||
|
|
}
|
||
|
|
// (2 beats / 1 minute) * 100
|
||
|
|
if got := s.Uptime(id); got != 200 {
|
||
|
|
t.Fatalf("uptime = %v, want 200", got)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestAddHeartbeat_SameTimestampAccepted(t *testing.T) {
|
||
|
|
s := New(nil)
|
||
|
|
id := DeviceID("device-1")
|
||
|
|
t0 := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC)
|
||
|
|
|
||
|
|
_ = s.AddHeartbeat(id, t0)
|
||
|
|
if err := s.AddHeartbeat(id, t0); err != nil {
|
||
|
|
t.Fatalf("same timestamp should be accepted: %v", err)
|
||
|
|
}
|
||
|
|
// span still zero → 1 minute floor; 2 beats → 200
|
||
|
|
if got := s.Uptime(id); got != 200 {
|
||
|
|
t.Fatalf("uptime = %v, want 200", got)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestAddHeartbeat_OutOfSequence(t *testing.T) {
|
||
|
|
s := New(nil)
|
||
|
|
id := DeviceID("device-1")
|
||
|
|
t0 := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC)
|
||
|
|
t1 := t0.Add(time.Minute)
|
||
|
|
|
||
|
|
_ = s.AddHeartbeat(id, t1)
|
||
|
|
err := s.AddHeartbeat(id, t0)
|
||
|
|
if !errors.Is(err, ErrOutOfSequence) {
|
||
|
|
t.Fatalf("err = %v, want ErrOutOfSequence", err)
|
||
|
|
}
|
||
|
|
// rejected beat must not affect uptime: still 1 beat → 100
|
||
|
|
if got := s.Uptime(id); got != 100 {
|
||
|
|
t.Fatalf("uptime = %v, want 100", got)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestUptime_TwoHeartbeatsOverTwoMinutes(t *testing.T) {
|
||
|
|
s := New(nil)
|
||
|
|
id := DeviceID("device-1")
|
||
|
|
t0 := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC)
|
||
|
|
|
||
|
|
_ = s.AddHeartbeat(id, t0)
|
||
|
|
_ = s.AddHeartbeat(id, t0.Add(2*time.Minute))
|
||
|
|
|
||
|
|
if got := s.Uptime(id); got != 100 {
|
||
|
|
t.Fatalf("uptime = %v, want 100", got)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestUptime_UnknownDevice(t *testing.T) {
|
||
|
|
s := New(nil)
|
||
|
|
if got := s.Uptime(DeviceID("missing")); got != 0 {
|
||
|
|
t.Fatalf("uptime = %v, want 0", got)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestUptime_IsPerDevice(t *testing.T) {
|
||
|
|
s := New(nil)
|
||
|
|
a := DeviceID("device-1")
|
||
|
|
b := DeviceID("device-2")
|
||
|
|
t0 := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC)
|
||
|
|
|
||
|
|
_ = s.AddHeartbeat(a, t0)
|
||
|
|
_ = s.AddHeartbeat(a, t0.Add(time.Minute))
|
||
|
|
_ = s.AddHeartbeat(b, t0)
|
||
|
|
|
||
|
|
if got := s.Uptime(a); got != 200 {
|
||
|
|
t.Fatalf("device-1 uptime = %v, want 200", got)
|
||
|
|
}
|
||
|
|
if got := s.Uptime(b); got != 100 {
|
||
|
|
t.Fatalf("device-2 uptime = %v, want 100 (single beat = 1 minute)", got)
|
||
|
|
}
|
||
|
|
}
|