package main import ( "encoding/gob" "net" "testing" "time" "github.com/amenzhinsky/go-gpsd" "macker/datapoint" ) func TestBackoffFor(t *testing.T) { want := []time.Duration{5 * time.Second, 10 * time.Second, 20 * time.Second, 40 * time.Second, 60 * time.Second, 60 * time.Second} for i, w := range want { if got := backoffFor(i); got != w { t.Errorf("backoffFor(%d) = %v, want %v", i, got, w) } } // 100-retry cycle wraps back to the starter delay. if got := backoffFor(99); got != 60*time.Second { t.Errorf("backoffFor(99) = %v, want 60s", got) } if got := backoffFor(100); got != 5*time.Second { t.Errorf("backoffFor(100) = %v, want 5s", got) } } func TestSolidifyData(t *testing.T) { tpv := &gpsd.TPV{Mode: 3, Speed: 12.5, Lat: 45.5, Lon: -122.6, Alt: 100, Epy: 1.5, Epx: 2.5, Epv: 3.5} dp, err := solidifyData(tpv) if err != nil { t.Fatalf("solidifyData: %v", err) } if dp.Lat != 45.5 || dp.LatErr != 1.5 || dp.Long != -122.6 || dp.LongErr != 2.5 || dp.Alt != 100 || dp.AltErr != 3.5 { t.Errorf("bad mapping: %+v", dp) } if dp.Speed == nil || *dp.Speed != 12.5 { t.Errorf("speed was not preserved: %v", dp.Speed) } if _, err := solidifyData(&gpsd.TPV{Mode: 1}); err == nil { t.Error("expected report without position fix to be rejected") } if dp.Timestamp != 0 { t.Errorf("zero time should leave Timestamp 0, got %d", dp.Timestamp) } if _, err := solidifyData(&gpsd.SKY{}); err == nil { t.Error("expected error for non-TPV report") } } // Fake server: gob-decode []byte then unzip JSON, as the real receiver does. func TestSendLoopEndToEnd(t *testing.T) { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } defer ln.Close() type batch struct { points []datapoint.DataPoint err error } got := make(chan batch, 4) go func() { for { con, err := ln.Accept() if err != nil { return } var raw []byte if err := gob.NewDecoder(con).Decode(&raw); err != nil { got <- batch{err: err} con.Close() continue } pts, err := datapoint.UnzipBatch(raw) if err != nil { got <- batch{err: err} con.Close() continue } got <- batch{points: pts} con.Close() } }() errorChan := make(chan error, 16) go manageErrors(errorChan) batches := make(chan []datapoint.DataPoint, 4) _, port, err := net.SplitHostPort(ln.Addr().String()) if err != nil { t.Fatal(err) } go sendLoop("127.0.0.1", port, batches, time.Hour, 2, errorChan) batches <- []datapoint.DataPoint{{Timestamp: 1, Lat: 1}, {Timestamp: 2, Lat: 2}} batches <- []datapoint.DataPoint{{Timestamp: 3, Lat: 3}} // First batch trips the size-2 threshold. select { case b := <-got: if b.err != nil { t.Fatalf("decode: %v", b.err) } if len(b.points) != 2 || b.points[0].Lat != 1 || b.points[1].Lat != 2 { t.Fatalf("bad first batch: %+v", b.points) } case <-time.After(3 * time.Second): t.Fatal("timeout waiting for first batch") } // Second batch waits for the ticker (1h), so just prove it accumulates. select { case b := <-got: t.Fatalf("unexpected flush before interval: %+v", b) case <-time.After(300 * time.Millisecond): } }