package influxdb import ( "context" "encoding/json" "fmt" "sync" "testing" "time" client "github.com/influxdata/influxdb1-client/v2" "github.com/stretchr/testify/require" "src.dualinventive.com/go/dinet/ditime" "src.dualinventive.com/go/dinet/rpc" "src.dualinventive.com/go/dinet/rts" "src.dualinventive.com/go/lib/kv" ) //nolint: gochecknoglobals var ( processDeviceUID = "01234567890123456789012345678901" sensorDataMsg = &rpc.Msg{ Dinetrpc: 1, DeviceUID: processDeviceUID, ID: 1, Time: ditime.Now(), Type: rpc.MsgTypePublish, ClassMethod: rpc.ClassMethodSensorData, Result: rpc.NewResult([]map[string]interface{}{ { "uid": float64(1), "value": float64(1), "time": ditime.Now(), }, { "uid": float64(1), "value": float64(2), "time": ditime.Now(), }, { "uid": float64(1), "value": float64(3), "time": ditime.Now(), }, { // This value will be dropped because there is no sensor:info present // for uid 2 "uid": float64(2), "value": float64(3), "time": ditime.Now(), }, }), } sensorDataValuesMsg = &rpc.Msg{ Dinetrpc: 1, DeviceUID: processDeviceUID, ID: 1, Time: ditime.Now(), Type: rpc.MsgTypePublish, ClassMethod: rpc.ClassMethodSensorData, Result: rpc.NewResult([]rpc.ResultValueItem{ { UID: 100, Time: ditime.Now(), Values: &rpc.ResultValuesItem{ Interval: 312*time.Microsecond + 500*time.Nanosecond, Samples: []float64{ 10.23, 20.1, 30.25, 40.50, 50.22, }, }, }, }), } notifyDataMsg = &rpc.Msg{ Dinetrpc: 1, DeviceUID: processDeviceUID, ID: 1, Time: ditime.Now(), Type: rpc.MsgTypePublish, ClassMethod: rpc.ClassMethodNotifyData, Result: rpc.NewResult([]map[string]interface{}{ { "uid": float64(1), "value": true, "time": ditime.Now(), }, { "uid": float64(1), "value": false, "time": ditime.Now(), }, }), } deviceMsg = &rpc.Msg{ Dinetrpc: 1, DeviceUID: processDeviceUID, ID: 1, Time: ditime.Now(), Type: rpc.MsgTypeReply, ClassMethod: rpc.ClassMethodDeviceData, Result: rpc.NewResult([]map[string]interface{}{ { "state": "idle", "error": true, "errors": []interface{}{1.0, 2.0, 3.0}, }, }), } ) func fillCache(t *testing.T, kv kv.KV) { require.Nil(t, kv.HSet(rts.KeyPrefixDevice+processDeviceUID, "sensor:1:info", `{"label":"bat1-voltage","last_update":1517914855147,"time":1517914854889,"type":"number","uid":1}`)) require.Nil(t, kv.HSet(rts.KeyPrefixDevice+processDeviceUID, "sensor:100:info", `{"label":"rvm-vibration-1","last_update":1517914855147,"time":1517914854889,"type":"numbers","uid":100}`)) require.Nil(t, kv.HSet(rts.KeyPrefixDevice+processDeviceUID, "notify:1:info", `{"label":"du-detection","last_update":1517914855553,"time":1517914855337,"type":"bool","uid":1}`)) require.Nil(t, kv.HSet(rts.KeyPrefixDevice+processDeviceUID, string(rpc.ClassMethodDeviceInfo), `{"last_update":1519137369375,"revision":3,"time":1519137368544,"type":"tws-3000-duu","version":"0.8.0"}`)) } func TestSend(t *testing.T) { testcases := []struct { name string msg *rpc.Msg class rpc.Class nrOfPoints int }{ {name: "device:data", msg: deviceMsg, class: rpc.ClassDevice, nrOfPoints: 5}, {name: "sensor:data", msg: sensorDataMsg, class: rpc.ClassSensor, nrOfPoints: 4}, {name: "sensor:data", msg: sensorDataValuesMsg, class: rpc.ClassSensor, nrOfPoints: 6}, {name: "notify:data", msg: notifyDataMsg, class: rpc.ClassNotify, nrOfPoints: 3}, } for _, tc := range testcases { tc := tc t.Run(tc.name, func(t *testing.T) { ramKV, err := kv.New(kv.TypeRAM, "") require.Nil(t, err) fillCache(t, ramKV) i, err := New("http://127.0.0.1", "root", "root", "db", 5, ramKV, 1, time.Second) require.Nil(t, err) require.NotNil(t, i) // Convert the writer is mock writer tw := &testWriter{c: make(chan *client.Point)} i.writer = tw ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup wg.Add(2) go func(cancel func()) { defer wg.Done() switch tc.class { case rpc.ClassSensor: tc.msg.ClassMethod = rpc.ClassMethodSensorData case rpc.ClassNotify: tc.msg.ClassMethod = rpc.ClassMethodNotifyData } // XXX this is the most ugly hack to satisfy the non-idiomatic rpc defereddecoder // it is copy pasted from the rpc test transport. because rpc.Msg is unusable // to get result when no decoder is attached b, err := json.Marshal(tc.msg) require.Nil(t, err) msg := &rpc.Msg{} err = json.Unmarshal(b, msg) require.Nil(t, err) fmt.Println(msg) err = i.Send(msg) require.Nil(t, err) cancel() }(cancel) go func() { defer wg.Done() for i := 0; i < tc.nrOfPoints; i++ { pt := <-tw.c fmt.Printf("%+v\n", pt) } select { case pt := <-tw.c: require.Fail(t, "expected no other point", pt.String()) default: } }() i.Process(ctx, time.Second) wg.Wait() }) } }