func handleTXPayloads(ctx Context) { var wg sync.WaitGroup for txPayload := range ctx.Application.TXPayloadChan() { go func(txPayload models.TXPayload) { wg.Add(1) defer wg.Done() if err := storage.AddTXPayloadToQueue(ctx.RedisPool, txPayload); err != nil { log.WithFields(log.Fields{ "dev_eui": txPayload.DevEUI, "reference": txPayload.Reference, "data_base64": base64.StdEncoding.EncodeToString(txPayload.Data), }).Errorf("add tx-payload to queue error: %s", err) } }(txPayload) } wg.Wait() }
func runDataUpTests(ctx Context, devEUI lorawan.EUI64, devAddr lorawan.DevAddr, tests []dataUpTestCase) { for i, test := range tests { Convey(fmt.Sprintf("When testing: %s [%d]", test.Name, i), func() { ctx.Application.(*testApplicationBackend).err = test.ApplicationBackendError for _, pl := range test.TXPayloadQueue { So(storage.AddTXPayloadToQueue(ctx.RedisPool, pl), ShouldBeNil) } for _, mac := range test.TXMACPayloadQueue { So(storage.AddMACPayloadToTXQueue(ctx.RedisPool, mac), ShouldBeNil) } if test.TXMACPayloadInProcess != nil { So(storage.AddTXPayloadToQueue(ctx.RedisPool, *test.TXMACPayloadInProcess), ShouldBeNil) _, err := storage.GetTXPayloadFromQueue(ctx.RedisPool, devEUI) // getting an item from the queue will put it into in-process So(err, ShouldBeNil) } So(test.PHYPayload.EncryptFRMPayload(test.EncryptFRMPayloadKey), ShouldBeNil) So(test.PHYPayload.SetMIC(test.SetMICKey), ShouldBeNil) rxPacket := models.RXPacket{ PHYPayload: test.PHYPayload, RXInfo: test.RXInfo, } So(handleRXPacket(ctx, rxPacket), ShouldResemble, test.ExpectedHandleRXPacketError) Convey("Then the expected rx-info payloads are sent to the network-controller", func() { So(ctx.Controller.(*testControllerBackend).rxInfoPayloadChan, ShouldHaveLength, len(test.ExpectedControllerRXInfoPayloads)) for _, expPL := range test.ExpectedControllerRXInfoPayloads { pl := <-ctx.Controller.(*testControllerBackend).rxInfoPayloadChan So(pl, ShouldResemble, expPL) } }) Convey("Then the expected error payloads are sent to the network-controller", func() { So(ctx.Controller.(*testControllerBackend).errorPayloadChan, ShouldHaveLength, len(test.ExpectedControllerErrorPayloads)) for _, expPL := range test.ExpectedControllerErrorPayloads { pl := <-ctx.Controller.(*testControllerBackend).errorPayloadChan So(pl, ShouldResemble, expPL) } }) Convey("Then the expected mac-commands are received by the network-controller", func() { So(ctx.Controller.(*testControllerBackend).rxMACPayloadChan, ShouldHaveLength, len(test.ExpectedControllerRXMACPayloads)) for _, expPl := range test.ExpectedControllerRXMACPayloads { pl := <-ctx.Controller.(*testControllerBackend).rxMACPayloadChan So(pl, ShouldResemble, expPl) } }) Convey("Then the expected rx-payloads are received by the application-backend", func() { So(ctx.Application.(*testApplicationBackend).rxPayloadChan, ShouldHaveLength, len(test.ExpectedApplicationRXPayloads)) for _, expPL := range test.ExpectedApplicationRXPayloads { pl := <-ctx.Application.(*testApplicationBackend).rxPayloadChan So(pl, ShouldResemble, expPL) } }) Convey("Then the expected notifications are received by the application-backend", func() { So(ctx.Application.(*testApplicationBackend).notificationPayloadChan, ShouldHaveLength, len(test.ExpectedApplicationNotifications)) for _, expPL := range test.ExpectedApplicationNotifications { pl := <-ctx.Application.(*testApplicationBackend).notificationPayloadChan So(pl, ShouldResemble, expPL) } }) Convey("Then the expected tx-packets are received by the gateway (FRMPayload decrypted and MIC ignored)", func() { So(ctx.Gateway.(*testGatewayBackend).txPacketChan, ShouldHaveLength, len(test.ExpectedGatewayTXPackets)) for _, expPL := range test.ExpectedGatewayTXPackets { pl := <-ctx.Gateway.(*testGatewayBackend).txPacketChan So(pl.PHYPayload.DecryptFRMPayload(test.DecryptExpectedFRMPayloadKey), ShouldBeNil) expPL.PHYPayload.MIC = pl.PHYPayload.MIC So(pl, ShouldResemble, expPL) } }) Convey("Then the frame-counters are as expected", func() { ns, err := storage.GetNodeSessionByDevEUI(ctx.RedisPool, devEUI) So(err, ShouldBeNil) So(ns.FCntDown, ShouldEqual, test.ExpectedFCntDown) So(ns.FCntUp, ShouldEqual, test.ExpectedFCntUp) }) Convey("Then the MACPayload tx-queue is as expected", func() { macQueue, err := storage.ReadMACPayloadTXQueue(ctx.RedisPool, devAddr) So(err, ShouldBeNil) So(macQueue, ShouldResemble, test.ExpectedTXMACPayloadQueue) }) Convey("Then the next TXPayload is as expected", func() { txPL, err := storage.GetTXPayloadFromQueue(ctx.RedisPool, devEUI) if test.ExpectedGetTXPayloadFromQueue == nil { So(err, ShouldResemble, common.ErrEmptyQueue) } else { So(err, ShouldBeNil) So(txPL, ShouldResemble, *test.ExpectedGetTXPayloadFromQueue) } }) }) } }
func TestNodeAPI(t *testing.T) { conf := common.GetTestConfig() Convey("Given a clean database with an application and api instance", t, func() { db, err := storage.OpenDatabase(conf.PostgresDSN) So(err, ShouldBeNil) common.MustResetDB(db) p := storage.NewRedisPool(conf.RedisURL) common.MustFlushRedis(p) ctx := context.Background() lsCtx := loraserver.Context{DB: db, RedisPool: p} api := NewNodeAPI(lsCtx) app := models.Application{ AppEUI: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, Name: "test app", } So(storage.CreateApplication(db, app), ShouldBeNil) Convey("When creating a node", func() { _, err := api.Create(ctx, &pb.CreateNodeRequest{ DevEUI: "0807060504030201", AppEUI: "0102030405060708", AppKey: "01020304050607080102030405060708", RxDelay: 1, Rx1DROffset: 3, }) So(err, ShouldBeNil) Convey("The node has been created", func() { node, err := api.Get(ctx, &pb.GetNodeRequest{DevEUI: "0807060504030201"}) So(err, ShouldBeNil) So(node, ShouldResemble, &pb.GetNodeResponse{ DevEUI: "0807060504030201", AppEUI: "0102030405060708", AppKey: "01020304050607080102030405060708", RxDelay: 1, Rx1DROffset: 3, }) }) Convey("Then listing the nodes returns a single items", func() { nodes, err := api.List(ctx, &pb.ListNodeRequest{ Limit: 10, }) So(err, ShouldBeNil) So(nodes.Result, ShouldHaveLength, 1) So(nodes.TotalCount, ShouldEqual, 1) So(nodes.Result[0], ShouldResemble, &pb.GetNodeResponse{ DevEUI: "0807060504030201", AppEUI: "0102030405060708", AppKey: "01020304050607080102030405060708", RxDelay: 1, Rx1DROffset: 3, }) }) Convey("Then listing the nodes for a given AppEUI returns a single item", func() { nodes, err := api.ListByAppEUI(ctx, &pb.ListNodeByAppEUIRequest{ Limit: 10, AppEUI: "0102030405060708", }) So(err, ShouldBeNil) So(nodes.Result, ShouldHaveLength, 1) So(nodes.TotalCount, ShouldEqual, 1) So(nodes.Result[0], ShouldResemble, &pb.GetNodeResponse{ DevEUI: "0807060504030201", AppEUI: "0102030405060708", AppKey: "01020304050607080102030405060708", RxDelay: 1, Rx1DROffset: 3, }) }) Convey("When updating the node", func() { _, err := api.Update(ctx, &pb.UpdateNodeRequest{ DevEUI: "0807060504030201", AppEUI: "0102030405060708", AppKey: "08070605040302010807060504030201", RxDelay: 3, Rx1DROffset: 1, }) So(err, ShouldBeNil) Convey("Then the node has been updated", func() { node, err := api.Get(ctx, &pb.GetNodeRequest{DevEUI: "0807060504030201"}) So(err, ShouldBeNil) So(node, ShouldResemble, &pb.GetNodeResponse{ DevEUI: "0807060504030201", AppEUI: "0102030405060708", AppKey: "08070605040302010807060504030201", RxDelay: 3, Rx1DROffset: 1, }) }) }) Convey("After deleting the node", func() { _, err := api.Delete(ctx, &pb.DeleteNodeRequest{DevEUI: "0807060504030201"}) So(err, ShouldBeNil) Convey("Then listing the nodes returns zero nodes", func() { nodes, err := api.List(ctx, &pb.ListNodeRequest{Limit: 10}) So(err, ShouldBeNil) So(nodes.TotalCount, ShouldEqual, 0) So(nodes.Result, ShouldHaveLength, 0) }) }) Convey("Given a tx payload in the the queue", func() { So(storage.AddTXPayloadToQueue(p, models.TXPayload{ DevEUI: [8]byte{8, 7, 6, 5, 4, 3, 2, 1}, Data: []byte("hello!"), }), ShouldBeNil) count, err := storage.GetTXPayloadQueueSize(p, [8]byte{8, 7, 6, 5, 4, 3, 2, 1}) So(err, ShouldBeNil) So(count, ShouldEqual, 1) Convey("When flushing the tx-payload queue", func() { _, err := api.FlushTXPayloadQueue(ctx, &pb.FlushTXPayloadQueueRequest{DevEUI: "0807060504030201"}) So(err, ShouldBeNil) Convey("Then the queue is empty", func() { count, err := storage.GetTXPayloadQueueSize(p, [8]byte{8, 7, 6, 5, 4, 3, 2, 1}) So(err, ShouldBeNil) So(count, ShouldEqual, 0) }) }) }) }) }) }