Beispiel #1
0
// Create creates the given node-session. The DevAddr must contain the same NwkID as the configured NetID. Node-sessions will expire automatically after the configured TTL.
func (a *NodeSessionAPI) Create(ctx context.Context, req *pb.CreateNodeSessionRequest) (*pb.CreateNodeSessionResponse, error) {
	var appEUI, devEUI lorawan.EUI64
	var appSKey, nwkSKey lorawan.AES128Key
	var devAddr lorawan.DevAddr

	if err := appEUI.UnmarshalText([]byte(req.AppEUI)); err != nil {
		return nil, err
	}
	if err := devEUI.UnmarshalText([]byte(req.DevEUI)); err != nil {
		return nil, err
	}
	if err := appSKey.UnmarshalText([]byte(req.AppSKey)); err != nil {
		return nil, err
	}
	if err := nwkSKey.UnmarshalText([]byte(req.NwkSKey)); err != nil {
		return nil, err
	}
	if err := devAddr.UnmarshalText([]byte(req.DevAddr)); err != nil {
		return nil, err
	}

	var cFList *lorawan.CFList
	if len(req.CFList) > len(cFList) {
		return nil, fmt.Errorf("max CFList channels is %d", len(cFList))
	}
	if len(req.CFList) > 0 {
		cFList = &lorawan.CFList{}
		for i, f := range req.CFList {
			cFList[i] = f
		}
	}

	ns := models.NodeSession{
		DevAddr:     devAddr,
		AppEUI:      appEUI,
		DevEUI:      devEUI,
		AppSKey:     appSKey,
		NwkSKey:     nwkSKey,
		FCntUp:      req.FCntUp,
		FCntDown:    req.FCntDown,
		RXDelay:     uint8(req.RxDelay),
		RX1DROffset: uint8(req.Rx1DROffset),
		CFList:      cFList,
	}

	if err := a.validateNodeSession(ns); err != nil {
		return nil, err
	}

	if err := storage.CreateNodeSession(a.ctx.RedisPool, ns); err != nil {
		return nil, err
	}

	return &pb.CreateNodeSessionResponse{}, nil
}
func TestHandleDataUpScenarios(t *testing.T) {
	conf := common.GetTestConfig()

	Convey("Given a clean state, test backends and a node-session", t, func() {
		app := &testApplicationBackend{
			rxPayloadChan:           make(chan models.RXPayload, 1),
			txPayloadChan:           make(chan models.TXPayload, 1),
			notificationPayloadChan: make(chan interface{}, 10),
		}
		gw := &testGatewayBackend{
			rxPacketChan: make(chan models.RXPacket, 1),
			txPacketChan: make(chan models.TXPacket, 1),
		}
		ctrl := &testControllerBackend{
			rxMACPayloadChan:  make(chan models.MACPayload, 2),
			txMACPayloadChan:  make(chan models.MACPayload, 1),
			rxInfoPayloadChan: make(chan models.RXInfoPayload, 1),
			errorPayloadChan:  make(chan models.ErrorPayload, 1),
		}
		p := storage.NewRedisPool(conf.RedisURL)
		common.MustFlushRedis(p)

		ctx := Context{
			RedisPool:   p,
			Gateway:     gw,
			Application: app,
			Controller:  ctrl,
		}

		ns := models.NodeSession{
			DevAddr:  [4]byte{1, 2, 3, 4},
			DevEUI:   [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
			AppSKey:  [16]byte{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
			NwkSKey:  [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
			FCntUp:   8,
			FCntDown: 5,
			AppEUI:   [8]byte{8, 7, 6, 5, 4, 3, 2, 1},
		}
		So(storage.CreateNodeSession(ctx.RedisPool, ns), ShouldBeNil)

		rxInfo := models.RXInfo{
			Frequency: common.Band.UplinkChannels[0].Frequency,
			DataRate:  common.Band.DataRates[common.Band.UplinkChannels[0].DataRates[0]],
		}

		var fPortZero uint8
		var fPortOne uint8 = 1

		Convey("Given a set of test-scenarios for basic flows (nothing in queue)", func() {
			tests := []dataUpTestCase{
				// errors
				{
					Name:                    "the application backend returns an error",
					RXInfo:                  rxInfo,
					EncryptFRMPayloadKey:    ns.AppSKey,
					SetMICKey:               ns.NwkSKey,
					ApplicationBackendError: errors.New("BOOM!"),

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedFCntUp:              8,
					ExpectedFCntDown:            5,
					ExpectedHandleRXPacketError: errors.New("send rx payload to application error: BOOM!"),
				},
				{
					Name:                 "the frame-counter is invalid",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.AppSKey,
					SetMICKey:            ns.NwkSKey,

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    7,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedFCntUp:              8,
					ExpectedFCntDown:            5,
					ExpectedHandleRXPacketError: errors.New("invalid FCnt or too many dropped frames"),
				},
				{
					Name:                 "the mic is invalid",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.AppSKey,
					SetMICKey:            ns.AppSKey,

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedFCntUp:              8,
					ExpectedFCntDown:            5,
					ExpectedHandleRXPacketError: errors.New("invalid MIC"),
				},
				// basic flows
				{
					Name:                 "unconfirmed uplink data with payload",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.AppSKey,
					SetMICKey:            ns.NwkSKey,

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort:      &fPortOne,
							FRMPayload: []lorawan.Payload{&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}}},
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1, Data: []byte{1, 2, 3, 4}},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 5,
				},
				{
					Name:                 "unconfirmed uplink data without payload (just a FPort)",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.AppSKey,
					SetMICKey:            ns.NwkSKey,

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 5,
				},
				{
					Name:                 "confirmed uplink data with payload",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.AppSKey,
					SetMICKey:            ns.NwkSKey,

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.ConfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort:      &fPortOne,
							FRMPayload: []lorawan.Payload{&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}}},
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1, Data: []byte{1, 2, 3, 4}},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
										FCtrl: lorawan.FCtrl{
											ACK: true,
										},
									},
								},
							},
						},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 6,
				},
				{
					Name:                 "confirmed uplink data without payload",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.AppSKey,
					SetMICKey:            ns.NwkSKey,

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.ConfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
										FCtrl: lorawan.FCtrl{
											ACK: true,
										},
									},
								},
							},
						},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 6,
				},
				{
					Name:                 "two uplink mac commands (FOpts)",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.NwkSKey,
					SetMICKey:            ns.NwkSKey,

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
								FOpts: []lorawan.MACCommand{
									{CID: lorawan.LinkCheckReq},
									{CID: lorawan.LinkADRAns, Payload: &lorawan.LinkADRAnsPayload{ChannelMaskACK: true}},
								},
							},
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedControllerRXMACPayloads: []models.MACPayload{
						{DevEUI: ns.DevEUI, MACCommand: []byte{2}},
						{DevEUI: ns.DevEUI, MACCommand: []byte{3, 1}},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 5,
				},
				{
					Name:                 "two uplink mac commands (FRMPayload)",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.NwkSKey,
					SetMICKey:            ns.NwkSKey,

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortZero,
							FRMPayload: []lorawan.Payload{
								&lorawan.MACCommand{CID: lorawan.LinkCheckReq},
								&lorawan.MACCommand{CID: lorawan.LinkADRAns, Payload: &lorawan.LinkADRAnsPayload{ChannelMaskACK: true}},
							},
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedControllerRXMACPayloads: []models.MACPayload{
						{DevEUI: ns.DevEUI, FRMPayload: true, MACCommand: []byte{2}},
						{DevEUI: ns.DevEUI, FRMPayload: true, MACCommand: []byte{3, 1}},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 5,
				},
			}

			runDataUpTests(ctx, ns.DevEUI, ns.DevAddr, tests)
		})

		Convey("Given a set of test-scenarios for mac-command queue", func() {
			var fPortThree uint8 = 3

			tests := []dataUpTestCase{
				{
					Name:                 "unconfirmed uplink data + two downlink mac commands in queue (FOpts)",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.AppSKey,
					SetMICKey:            ns.NwkSKey,
					TXMACPayloadQueue: []models.MACPayload{
						{DevEUI: ns.DevEUI, MACCommand: []byte{6}},
						{DevEUI: ns.DevEUI, MACCommand: []byte{8, 3}},
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort:      &fPortOne,
							FRMPayload: []lorawan.Payload{&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}}},
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1, Data: []byte{1, 2, 3, 4}},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
										FOpts: []lorawan.MACCommand{
											{CID: lorawan.CID(6)},
											{CID: lorawan.CID(8), Payload: &lorawan.RXTimingSetupReqPayload{Delay: 3}},
										},
									},
								},
							},
						},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 6,
				},
				{
					Name:                         "unconfirmed uplink data + two downlink mac commands in queue (FOpts) + unconfirmed tx-payload in queue",
					RXInfo:                       rxInfo,
					EncryptFRMPayloadKey:         ns.AppSKey,
					DecryptExpectedFRMPayloadKey: ns.AppSKey,
					SetMICKey:                    ns.NwkSKey,
					TXPayloadQueue: []models.TXPayload{
						{DevEUI: ns.DevEUI, FPort: 3, Data: []byte{4, 5, 6}},
					},
					TXMACPayloadQueue: []models.MACPayload{
						{DevEUI: ns.DevEUI, MACCommand: []byte{6}},
						{DevEUI: ns.DevEUI, MACCommand: []byte{8, 3}},
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort:      &fPortOne,
							FRMPayload: []lorawan.Payload{&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}}},
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1, Data: []byte{1, 2, 3, 4}},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
										FOpts: []lorawan.MACCommand{
											{CID: lorawan.CID(6)},
											{CID: lorawan.CID(8), Payload: &lorawan.RXTimingSetupReqPayload{Delay: 3}},
										},
									},
									FPort: &fPortThree,
									FRMPayload: []lorawan.Payload{
										&lorawan.DataPayload{Bytes: []byte{4, 5, 6}},
									},
								},
							},
						},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 6,
				},
				{
					Name:                         "unconfirmed uplink data + two downlink mac commands in queue (FRMPayload)",
					RXInfo:                       rxInfo,
					EncryptFRMPayloadKey:         ns.AppSKey,
					DecryptExpectedFRMPayloadKey: ns.NwkSKey,
					SetMICKey:                    ns.NwkSKey,
					TXMACPayloadQueue: []models.MACPayload{
						{DevEUI: ns.DevEUI, FRMPayload: true, MACCommand: []byte{6}},
						{DevEUI: ns.DevEUI, FRMPayload: true, MACCommand: []byte{8, 3}},
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort:      &fPortOne,
							FRMPayload: []lorawan.Payload{&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}}},
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1, Data: []byte{1, 2, 3, 4}},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
									},
									FPort: &fPortZero,
									FRMPayload: []lorawan.Payload{
										&lorawan.MACCommand{CID: lorawan.CID(6)},
										&lorawan.MACCommand{CID: lorawan.CID(8), Payload: &lorawan.RXTimingSetupReqPayload{Delay: 3}},
									},
								},
							},
						},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 6,
				},
				{
					Name:                         "unconfirmed uplink data + two downlink mac commands in queue (FRMPayload) + unconfirmed tx-payload in queue",
					RXInfo:                       rxInfo,
					EncryptFRMPayloadKey:         ns.AppSKey,
					DecryptExpectedFRMPayloadKey: ns.NwkSKey,
					SetMICKey:                    ns.NwkSKey,
					TXPayloadQueue: []models.TXPayload{
						{DevEUI: ns.DevEUI, FPort: 3, Data: []byte{4, 5, 6}},
					},
					TXMACPayloadQueue: []models.MACPayload{
						{DevEUI: ns.DevEUI, FRMPayload: true, MACCommand: []byte{6}},
						{DevEUI: ns.DevEUI, FRMPayload: true, MACCommand: []byte{8, 3}},
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort:      &fPortOne,
							FRMPayload: []lorawan.Payload{&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}}},
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1, Data: []byte{1, 2, 3, 4}},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
										FCtrl: lorawan.FCtrl{
											FPending: true,
										},
									},
									FPort: &fPortZero,
									FRMPayload: []lorawan.Payload{
										&lorawan.MACCommand{CID: lorawan.CID(6)},
										&lorawan.MACCommand{CID: lorawan.CID(8), Payload: &lorawan.RXTimingSetupReqPayload{Delay: 3}},
									},
								},
							},
						},
					},
					ExpectedGetTXPayloadFromQueue: &models.TXPayload{DevEUI: ns.DevEUI, FPort: 3, Data: []byte{4, 5, 6}},
					ExpectedFCntUp:                10,
					ExpectedFCntDown:              6,
				},
				{
					Name:                 "unconfirmed uplink data + 18 bytes of MAC commands (FOpts) of which one is invalid",
					RXInfo:               rxInfo,
					EncryptFRMPayloadKey: ns.AppSKey,
					SetMICKey:            ns.NwkSKey,
					TXMACPayloadQueue: []models.MACPayload{
						{Reference: "a", DevEUI: ns.DevEUI, MACCommand: []byte{2, 10, 5}},
						{Reference: "b", DevEUI: ns.DevEUI, MACCommand: []byte{6}},
						{Reference: "c", DevEUI: ns.DevEUI, MACCommand: []byte{4, 15}},
						{Reference: "d", DevEUI: ns.DevEUI, MACCommand: []byte{4, 15, 16}}, // invalid payload, should be discarded + error notification
						{Reference: "e", DevEUI: ns.DevEUI, MACCommand: []byte{2, 10, 5}},
						{Reference: "f", DevEUI: ns.DevEUI, MACCommand: []byte{2, 10, 5}},
						{Reference: "g", DevEUI: ns.DevEUI, MACCommand: []byte{2, 10, 6}}, // this payload should stay in the queue
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort:      &fPortOne,
							FRMPayload: []lorawan.Payload{&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}}},
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedControllerErrorPayloads: []models.ErrorPayload{
						{Reference: "d", DevEUI: ns.DevEUI, Message: "unmarshal mac command error: lorawan: 1 byte of data is expected"},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1, Data: []byte{1, 2, 3, 4}},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
										FCtrl: lorawan.FCtrl{
											FPending: true,
										},
										FOpts: []lorawan.MACCommand{
											{CID: lorawan.LinkCheckAns, Payload: &lorawan.LinkCheckAnsPayload{Margin: 10, GwCnt: 5}},
											{CID: lorawan.DevStatusReq},
											{CID: lorawan.DutyCycleReq, Payload: &lorawan.DutyCycleReqPayload{MaxDCCycle: 15}},
											{CID: lorawan.LinkCheckAns, Payload: &lorawan.LinkCheckAnsPayload{Margin: 10, GwCnt: 5}},
											{CID: lorawan.LinkCheckAns, Payload: &lorawan.LinkCheckAnsPayload{Margin: 10, GwCnt: 5}},
										},
									},
								},
							},
						},
					},
					ExpectedTXMACPayloadQueue: []models.MACPayload{
						{Reference: "g", DevEUI: ns.DevEUI, MACCommand: []byte{2, 10, 6}},
					},
					ExpectedFCntUp:   10,
					ExpectedFCntDown: 6,
				},
			}

			runDataUpTests(ctx, ns.DevEUI, ns.DevAddr, tests)
		})

		Convey("Given a set of test-scenarios for tx-payload queue", func() {
			var fPortTen uint8 = 10

			tests := []dataUpTestCase{
				{
					Name:                         "unconfirmed uplink data + one unconfirmed downlink payload in queue",
					RXInfo:                       rxInfo,
					EncryptFRMPayloadKey:         ns.AppSKey,
					DecryptExpectedFRMPayloadKey: ns.AppSKey,
					SetMICKey:                    ns.NwkSKey,
					TXPayloadQueue: []models.TXPayload{
						{Reference: "a", DevEUI: ns.DevEUI, FPort: 10, Data: []byte{1, 2, 3, 4}},
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
									},
									FPort: &fPortTen,
									FRMPayload: []lorawan.Payload{
										&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}},
									},
								},
							},
						},
					},

					ExpectedFCntUp:   10,
					ExpectedFCntDown: 6,
				},
				{
					Name:                         "unconfirmed uplink data + two unconfirmed downlink payloads in queue",
					RXInfo:                       rxInfo,
					EncryptFRMPayloadKey:         ns.AppSKey,
					DecryptExpectedFRMPayloadKey: ns.AppSKey,
					SetMICKey:                    ns.NwkSKey,
					TXPayloadQueue: []models.TXPayload{
						{Reference: "a", DevEUI: ns.DevEUI, FPort: 10, Data: []byte{1, 2, 3, 4}},
						{Reference: "b", DevEUI: ns.DevEUI, FPort: 10, Data: []byte{4, 3, 2, 1}},
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
										FCtrl: lorawan.FCtrl{
											FPending: true,
										},
									},
									FPort: &fPortTen,
									FRMPayload: []lorawan.Payload{
										&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}},
									},
								},
							},
						},
					},

					ExpectedFCntUp:                10,
					ExpectedFCntDown:              6,
					ExpectedGetTXPayloadFromQueue: &models.TXPayload{Reference: "b", DevEUI: ns.DevEUI, FPort: 10, Data: []byte{4, 3, 2, 1}},
				},
				{
					Name:                         "unconfirmed uplink data + one confirmed downlink payload in queue",
					RXInfo:                       rxInfo,
					EncryptFRMPayloadKey:         ns.AppSKey,
					DecryptExpectedFRMPayloadKey: ns.AppSKey,
					SetMICKey:                    ns.NwkSKey,
					TXPayloadQueue: []models.TXPayload{
						{Reference: "a", Confirmed: true, DevEUI: ns.DevEUI, FPort: 10, Data: []byte{1, 2, 3, 4}},
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.ConfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
									},
									FPort: &fPortTen,
									FRMPayload: []lorawan.Payload{
										&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}},
									},
								},
							},
						},
					},

					ExpectedFCntUp:                10,
					ExpectedFCntDown:              5, // will be incremented after the node ACKs the frame
					ExpectedGetTXPayloadFromQueue: &models.TXPayload{Reference: "a", Confirmed: true, DevEUI: ns.DevEUI, FPort: 10, Data: []byte{1, 2, 3, 4}},
				},
				{
					Name:                         "unconfirmed uplink data with ACK + one confirmed downlink payload in in-process queue",
					RXInfo:                       rxInfo,
					EncryptFRMPayloadKey:         ns.AppSKey,
					DecryptExpectedFRMPayloadKey: ns.AppSKey,
					SetMICKey:                    ns.NwkSKey,
					TXMACPayloadInProcess:        &models.TXPayload{Reference: "a", Confirmed: true, DevEUI: ns.DevEUI, FPort: 10, Data: []byte{1, 2, 3, 4}},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
								FCtrl: lorawan.FCtrl{
									ACK: true,
								},
							},
							FPort: &fPortOne,
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1},
					},
					ExpectedApplicationNotifications: []interface{}{
						models.ACKNotification{Reference: "a", DevEUI: ns.DevEUI},
					},

					ExpectedFCntUp:   10,
					ExpectedFCntDown: 6, // has been updated because of the ACK
				},
				{
					Name:                         "unconfirmed uplink data + two unconfirmed downlink payload in queue of which the first exceeds the max payload size (for dr 0)",
					RXInfo:                       rxInfo,
					EncryptFRMPayloadKey:         ns.AppSKey,
					DecryptExpectedFRMPayloadKey: ns.AppSKey,
					SetMICKey:                    ns.NwkSKey,
					TXPayloadQueue: []models.TXPayload{
						{Reference: "a", DevEUI: ns.DevEUI, FPort: 10, Data: make([]byte, 52)},
						{Reference: "b", DevEUI: ns.DevEUI, FPort: 10, Data: []byte{1, 2, 3, 4}},
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1},
					},
					ExpectedApplicationNotifications: []interface{}{
						models.ErrorPayload{Reference: "a", DevEUI: ns.DevEUI, Message: "downlink payload max size exceeded (dr: 0, allowed: 51, got: 52)"},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
									},
									FPort: &fPortTen,
									FRMPayload: []lorawan.Payload{
										&lorawan.DataPayload{Bytes: []byte{1, 2, 3, 4}},
									},
								},
							},
						},
					},

					ExpectedFCntUp:   10,
					ExpectedFCntDown: 6,
				},
				{
					Name:                         "unconfirmed uplink data + one unconfirmed downlink payload in queue (exactly max size for dr 0) + one mac command",
					RXInfo:                       rxInfo,
					EncryptFRMPayloadKey:         ns.AppSKey,
					DecryptExpectedFRMPayloadKey: ns.AppSKey,
					SetMICKey:                    ns.NwkSKey,
					TXPayloadQueue: []models.TXPayload{
						{Reference: "a", DevEUI: ns.DevEUI, FPort: 10, Data: make([]byte, 51)},
					},
					TXMACPayloadQueue: []models.MACPayload{
						{DevEUI: ns.DevEUI, MACCommand: []byte{6}},
					},

					PHYPayload: lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MACPayload: &lorawan.MACPayload{
							FHDR: lorawan.FHDR{
								DevAddr: ns.DevAddr,
								FCnt:    10,
							},
							FPort: &fPortOne,
						},
					},

					ExpectedControllerRXInfoPayloads: []models.RXInfoPayload{
						{DevEUI: ns.DevEUI, FCnt: 10, RXInfo: []models.RXInfo{rxInfo}},
					},
					ExpectedApplicationRXPayloads: []models.RXPayload{
						{DevEUI: ns.DevEUI, FPort: 1, GatewayCount: 1},
					},
					ExpectedGatewayTXPackets: []models.TXPacket{
						{
							TXInfo: models.TXInfo{
								Timestamp: rxInfo.Timestamp + 1000000,
								Frequency: rxInfo.Frequency,
								Power:     14,
								DataRate:  rxInfo.DataRate,
							},
							PHYPayload: lorawan.PHYPayload{
								MHDR: lorawan.MHDR{
									MType: lorawan.UnconfirmedDataDown,
									Major: lorawan.LoRaWANR1,
								},
								MACPayload: &lorawan.MACPayload{
									FHDR: lorawan.FHDR{
										DevAddr: ns.DevAddr,
										FCnt:    5,
										FCtrl: lorawan.FCtrl{
											FPending: true,
										},
										FOpts: []lorawan.MACCommand{
											{CID: lorawan.CID(6)},
										},
									},
								},
							},
						},
					},

					ExpectedFCntUp:                10,
					ExpectedFCntDown:              6,
					ExpectedGetTXPayloadFromQueue: &models.TXPayload{Reference: "a", DevEUI: ns.DevEUI, FPort: 10, Data: make([]byte, 51)},
				},
			}

			runDataUpTests(ctx, ns.DevEUI, ns.DevAddr, tests)
		})

	})

}