Example #1
0
func TestHandleActivation(t *testing.T) {
	a := New(t)

	gtwID := "eui-0102030405060708"
	devEUI := types.DevEUI([8]byte{0, 1, 2, 3, 4, 5, 6, 7})
	appEUI := types.AppEUI([8]byte{0, 1, 2, 3, 4, 5, 6, 7})

	b := getTestBroker(t)
	b.ns.EXPECT().PrepareActivation(gomock.Any(), gomock.Any()).Return(&pb_broker.DeduplicatedDeviceActivationRequest{
		Payload: []byte{},
		DevEui:  &devEUI,
		AppEui:  &appEUI,
		AppId:   "appid",
		DevId:   "devid",
		GatewayMetadata: []*gateway.RxMetadata{
			&gateway.RxMetadata{Snr: 1.2, GatewayId: gtwID},
		},
		ProtocolMetadata: &protocol.RxMetadata{},
	}, nil)
	b.discovery.EXPECT().GetAllHandlersForAppID("appid").Return([]*pb_discovery.Announcement{}, nil)

	res, err := b.HandleActivation(&pb_broker.DeviceActivationRequest{
		Payload:          []byte{},
		DevEui:           &devEUI,
		AppEui:           &appEUI,
		GatewayMetadata:  &gateway.RxMetadata{Snr: 1.2, GatewayId: gtwID},
		ProtocolMetadata: &protocol.RxMetadata{},
	})
	a.So(err, ShouldNotBeNil)
	a.So(res, ShouldBeNil)

	b.ctrl.Finish()

	// TODO: Integration test with Handler
}
// JoinRequestPayloadFromPayload creates a new JoinRequestPayload from a lorawan.Payload
func JoinRequestPayloadFromPayload(payload lorawan.Payload) (request JoinRequestPayload) {
	if payload, ok := payload.(*lorawan.JoinRequestPayload); ok {
		request.AppEui = types.AppEUI(payload.AppEUI)
		request.DevEui = types.DevEUI(payload.DevEUI)
		request.DevNonce = types.DevNonce(payload.DevNonce)
	}
	return
}
Example #3
0
func TestHandleActivate(t *testing.T) {
	a := New(t)
	ns := &networkServer{
		devices: device.NewRedisDeviceStore(GetRedisClient(), "test-handle-activate"),
	}
	ns.InitStatus()

	dev := &device.Device{
		AppEUI: types.AppEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1)),
		DevEUI: types.DevEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1)),
	}
	a.So(ns.devices.Set(dev), ShouldBeNil)
	defer func() {
		ns.devices.Delete(types.AppEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1)), types.DevEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1)))
	}()

	_, err := ns.HandleActivate(&pb_handler.DeviceActivationResponse{})
	a.So(err, ShouldNotBeNil)

	_, err = ns.HandleActivate(&pb_handler.DeviceActivationResponse{
		ActivationMetadata: &pb_protocol.ActivationMetadata{},
	})
	a.So(err, ShouldNotBeNil)

	devAddr := getDevAddr(0, 0, 3, 1)
	var nwkSKey types.NwkSKey
	copy(nwkSKey[:], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1})
	appEUI := types.AppEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1))
	devEUI := types.DevEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1))
	_, err = ns.HandleActivate(&pb_handler.DeviceActivationResponse{
		ActivationMetadata: &pb_protocol.ActivationMetadata{Protocol: &pb_protocol.ActivationMetadata_Lorawan{
			Lorawan: &pb_lorawan.ActivationMetadata{
				AppEui:  &appEUI,
				DevEui:  &devEUI,
				DevAddr: &devAddr,
				NwkSKey: &nwkSKey,
			},
		}},
	})
	a.So(err, ShouldBeNil)
}
func buildConversionDownlink() (*pb_broker.DownlinkMessage, *types.DownlinkMessage) {
	appEUI := types.AppEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8})
	devEUI := types.DevEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8})
	ttnDown := &pb_broker.DownlinkMessage{
		AppEui: &appEUI,
		DevEui: &devEUI,
	}
	appDown := &types.DownlinkMessage{
		FPort:         1,
		AppID:         "AppID-1",
		DevID:         "DevID-1",
		PayloadFields: map[string]interface{}{"temperature": 30},
		// We want to "build" the payload with the content of the fields
	}
	return ttnDown, appDown
}
func TestMetadataTextMarshaling(t *testing.T) {
	a := New(t)
	subjects := map[string]Metadata{
		"AppEUI 0102030405060708": AppEUIMetadata{types.AppEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8})},
		"AppID AppID":             AppIDMetadata{"AppID"},
		"Prefix 00000000/0":       PrefixMetadata{types.DevAddrPrefix{}},
	}

	for str, obj := range subjects {
		marshaled, err := obj.MarshalText()
		a.So(err, ShouldBeNil)
		a.So(string(marshaled), ShouldEqual, str)
		unmarshaled := MetadataFromString(str)
		a.So(unmarshaled, ShouldResemble, obj)
	}
}
func TestAnnouncementToProto(t *testing.T) {
	a := New(t)
	announcement := &Announcement{
		ID: "ID",
		Metadata: []Metadata{
			AppEUIMetadata{types.AppEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8})},
			AppIDMetadata{"AppID"},
			PrefixMetadata{types.DevAddrPrefix{}},
		},
	}
	proto := announcement.ToProto()
	a.So(proto.Id, ShouldEqual, announcement.ID)
	a.So(proto.Metadata, ShouldHaveLength, 3)
	a.So(proto.Metadata[0].GetAppEui(), ShouldResemble, []byte{1, 2, 3, 4, 5, 6, 7, 8})
	a.So(proto.Metadata[1].GetAppId(), ShouldEqual, "AppID")
	a.So(proto.Metadata[2].GetDevAddrPrefix(), ShouldResemble, []byte{0, 0, 0, 0, 0})
}
Example #7
0
func TestHandleDownlink(t *testing.T) {
	a := New(t)
	ns := &networkServer{
		devices: device.NewRedisDeviceStore(GetRedisClient(), "test-handle-downlink"),
	}
	ns.InitStatus()

	appEUI := types.AppEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8))
	devEUI := types.DevEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8))
	devAddr := getDevAddr(1, 2, 3, 4)

	// Device Not Found
	message := &pb_broker.DownlinkMessage{
		AppEui:  &appEUI,
		DevEui:  &devEUI,
		Payload: []byte{},
	}
	_, err := ns.HandleDownlink(message)
	a.So(err, ShouldNotBeNil)

	ns.devices.Set(&device.Device{
		DevAddr: devAddr,
		AppEUI:  appEUI,
		DevEUI:  devEUI,
	})
	defer func() {
		ns.devices.Delete(appEUI, devEUI)
	}()

	// Invalid Payload
	message = &pb_broker.DownlinkMessage{
		AppEui:  &appEUI,
		DevEui:  &devEUI,
		Payload: []byte{},
	}
	_, err = ns.HandleDownlink(message)
	a.So(err, ShouldNotBeNil)

	fPort := uint8(3)
	phy := lorawan.PHYPayload{
		MHDR: lorawan.MHDR{
			MType: lorawan.UnconfirmedDataDown,
			Major: lorawan.LoRaWANR1,
		},
		MACPayload: &lorawan.MACPayload{
			FPort: &fPort,
			FHDR: lorawan.FHDR{
				FCtrl: lorawan.FCtrl{
					ACK: true,
				},
			},
		},
	}
	bytes, _ := phy.MarshalBinary()

	message = &pb_broker.DownlinkMessage{
		AppEui:  &appEUI,
		DevEui:  &devEUI,
		Payload: bytes,
	}
	res, err := ns.HandleDownlink(message)
	a.So(err, ShouldBeNil)

	var phyPayload lorawan.PHYPayload
	phyPayload.UnmarshalBinary(res.Payload)
	macPayload, _ := phyPayload.MACPayload.(*lorawan.MACPayload)
	a.So(*macPayload.FPort, ShouldEqual, 3)
	a.So(macPayload.FHDR.DevAddr, ShouldEqual, lorawan.DevAddr{1, 2, 3, 4})
	a.So(macPayload.FHDR.FCnt, ShouldEqual, 0)                // The first Frame counter is zero
	a.So(phyPayload.MIC, ShouldNotEqual, [4]byte{0, 0, 0, 0}) // MIC should be set, we'll check it with actual examples in the integration test

	dev, _ := ns.devices.Get(appEUI, devEUI)
	a.So(dev.FCntDown, ShouldEqual, 1)

}
Example #8
0
func TestHandlePrepareActivation(t *testing.T) {
	a := New(t)
	ns := &networkServer{
		netID: [3]byte{0x00, 0x00, 0x13},
		prefixes: map[types.DevAddrPrefix][]string{
			types.DevAddrPrefix{DevAddr: [4]byte{0x26, 0x00, 0x00, 0x00}, Length: 7}: []string{
				"otaa",
				"local",
			},
		},
		devices: device.NewRedisDeviceStore(GetRedisClient(), "test-handle-prepare-activation"),
	}

	appEUI := types.AppEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8))
	devEUI := types.DevEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8))

	// Device not registered
	resp, err := ns.HandlePrepareActivation(&pb_broker.DeduplicatedDeviceActivationRequest{
		ActivationMetadata: &pb_protocol.ActivationMetadata{Protocol: &pb_protocol.ActivationMetadata_Lorawan{
			Lorawan: &pb_lorawan.ActivationMetadata{
				CfList: &pb_lorawan.CFList{Freq: []uint32{867100000, 867300000, 867500000, 867700000, 867900000}},
			},
		}},
		ResponseTemplate: &pb_broker.DeviceActivationResponse{},
	})
	a.So(err, ShouldNotBeNil)

	dev := &device.Device{AppEUI: appEUI, DevEUI: devEUI, Options: device.Options{
		ActivationConstraints: "private",
	}}
	a.So(ns.devices.Set(dev), ShouldBeNil)

	defer func() {
		ns.devices.Delete(appEUI, devEUI)
	}()

	// Constrained Device
	resp, err = ns.HandlePrepareActivation(&pb_broker.DeduplicatedDeviceActivationRequest{
		DevEui: &devEUI,
		AppEui: &appEUI,
		ActivationMetadata: &pb_protocol.ActivationMetadata{Protocol: &pb_protocol.ActivationMetadata_Lorawan{
			Lorawan: &pb_lorawan.ActivationMetadata{
				CfList: &pb_lorawan.CFList{Freq: []uint32{867100000, 867300000, 867500000, 867700000, 867900000}},
			},
		}},
		ResponseTemplate: &pb_broker.DeviceActivationResponse{},
	})
	a.So(err, ShouldNotBeNil)

	dev.StartUpdate()
	dev.Options = device.Options{}
	a.So(ns.devices.Set(dev), ShouldBeNil)

	// Device registered
	resp, err = ns.HandlePrepareActivation(&pb_broker.DeduplicatedDeviceActivationRequest{
		DevEui: &devEUI,
		AppEui: &appEUI,
		ActivationMetadata: &pb_protocol.ActivationMetadata{Protocol: &pb_protocol.ActivationMetadata_Lorawan{
			Lorawan: &pb_lorawan.ActivationMetadata{
				CfList: &pb_lorawan.CFList{Freq: []uint32{867100000, 867300000, 867500000, 867700000, 867900000}},
			},
		}},
		ResponseTemplate: &pb_broker.DeviceActivationResponse{},
	})
	a.So(err, ShouldBeNil)
	devAddr := resp.ActivationMetadata.GetLorawan().DevAddr
	a.So(devAddr.IsEmpty(), ShouldBeFalse)
	a.So(devAddr[0]&254, ShouldEqual, 19<<1) // 7 MSB should be NetID

	var resPHY lorawan.PHYPayload
	resPHY.UnmarshalBinary(resp.ResponseTemplate.Payload)
	resMAC, _ := resPHY.MACPayload.(*lorawan.DataPayload)
	joinAccept := &lorawan.JoinAcceptPayload{}
	joinAccept.UnmarshalBinary(false, resMAC.Bytes)

	a.So(joinAccept.DevAddr[0]&254, ShouldEqual, 19<<1)
	a.So(*joinAccept.CFList, ShouldEqual, lorawan.CFList{867100000, 867300000, 867500000, 867700000, 867900000})
}
Example #9
0
func TestCachedAnnouncementStore(t *testing.T) {
	a := New(t)

	s := NewRedisAnnouncementStore(GetRedisClient(), "discovery-test-announcement-store")

	s = NewCachedAnnouncementStore(s, DefaultCacheOptions)

	// Get non-existing
	dev, err := s.Get("router", "router1")
	a.So(err, ShouldNotBeNil)
	a.So(dev, ShouldBeNil)

	// Create
	err = s.Set(&Announcement{
		ServiceName: "router",
		ID:          "router1",
	})
	a.So(err, ShouldBeNil)

	defer func() {
		s.Delete("router", "router1")
	}()

	// Get existing
	dev, err = s.Get("router", "router1")
	a.So(err, ShouldBeNil)
	a.So(dev, ShouldNotBeNil)

	// Create extra
	err = s.Set(&Announcement{
		ServiceName: "handler",
		ID:          "handler1",
	})
	a.So(err, ShouldBeNil)

	defer func() {
		s.Delete("handler", "handler1")
	}()

	err = s.Set(&Announcement{
		ServiceName: "handler",
		ID:          "handler2",
	})
	a.So(err, ShouldBeNil)

	defer func() {
		s.Delete("handler", "handler2")
	}()

	appEUI := types.AppEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8})

	err = s.AddMetadata("handler", "handler1",
		AppEUIMetadata{AppEUI: appEUI},
		AppIDMetadata{AppID: "AppID"},
	)
	a.So(err, ShouldBeNil)

	handler, err := s.GetForAppEUI(appEUI)
	a.So(err, ShouldBeNil)
	a.So(handler, ShouldNotBeNil)
	a.So(handler.ID, ShouldEqual, "handler1")

	handler, err = s.GetForAppID("AppID")
	a.So(err, ShouldBeNil)
	a.So(handler, ShouldNotBeNil)
	a.So(handler.ID, ShouldEqual, "handler1")

	err = s.AddMetadata("handler", "handler2",
		AppEUIMetadata{AppEUI: appEUI},
		AppIDMetadata{AppID: "AppID"},
		AppIDMetadata{AppID: "OtherAppID"},
	)
	a.So(err, ShouldBeNil)

	metadata, err := s.GetMetadata("handler", "handler2")
	a.So(err, ShouldBeNil)
	a.So(metadata, ShouldHaveLength, 3)

	err = s.AddMetadata("handler", "handler2",
		AppEUIMetadata{AppEUI: appEUI},
		AppIDMetadata{AppID: "AppID"},
	)
	a.So(err, ShouldBeNil)

	metadata, err = s.GetMetadata("handler", "handler2")
	a.So(err, ShouldBeNil)
	a.So(metadata, ShouldHaveLength, 3)

	handler, err = s.GetForAppEUI(appEUI)
	a.So(err, ShouldBeNil)
	a.So(handler, ShouldNotBeNil)
	a.So(handler.ID, ShouldEqual, "handler2")

	handler, err = s.GetForAppID("AppID")
	a.So(err, ShouldBeNil)
	a.So(handler, ShouldNotBeNil)
	a.So(handler.ID, ShouldEqual, "handler2")

	err = s.RemoveMetadata("handler", "handler1",
		AppEUIMetadata{AppEUI: appEUI},
		AppIDMetadata{AppID: "AppID"},
	)
	a.So(err, ShouldBeNil)

	err = s.RemoveMetadata("handler", "handler2",
		AppEUIMetadata{AppEUI: appEUI},
		AppIDMetadata{AppID: "AppID"},
	)
	a.So(err, ShouldBeNil)

	// List
	announcements, err := s.List()
	a.So(err, ShouldBeNil)
	a.So(announcements, ShouldHaveLength, 3)

	// List
	announcements, err = s.ListService("router")
	a.So(err, ShouldBeNil)
	a.So(announcements, ShouldHaveLength, 1)

	// Delete
	err = s.Delete("router", "router1")
	a.So(err, ShouldBeNil)

	// Get deleted
	dev, err = s.Get("router", "router1")
	a.So(err, ShouldNotBeNil)
	a.So(dev, ShouldBeNil)

	// Delete with Metadata
	err = s.Delete("handler", "handler2")
	a.So(err, ShouldBeNil)
}
Example #10
0
func TestHandleUplink(t *testing.T) {
	a := New(t)
	ns := &networkServer{
		devices: device.NewRedisDeviceStore(GetRedisClient(), "ns-test-handle-uplink"),
	}
	ns.InitStatus()

	appEUI := types.AppEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8))
	devEUI := types.DevEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8))
	devAddr := getDevAddr(1, 2, 3, 4)

	// Device Not Found
	message := &pb_broker.DeduplicatedUplinkMessage{
		AppEui:  &appEUI,
		DevEui:  &devEUI,
		Payload: []byte{},
	}
	_, err := ns.HandleUplink(message)
	a.So(err, ShouldNotBeNil)

	ns.devices.Set(&device.Device{
		DevAddr: devAddr,
		AppEUI:  appEUI,
		DevEUI:  devEUI,
	})
	defer func() {
		ns.devices.Delete(appEUI, devEUI)
	}()

	// Invalid Payload
	message = &pb_broker.DeduplicatedUplinkMessage{
		AppEui:  &appEUI,
		DevEui:  &devEUI,
		Payload: []byte{},
	}
	_, err = ns.HandleUplink(message)
	a.So(err, ShouldNotBeNil)

	phy := lorawan.PHYPayload{
		MHDR: lorawan.MHDR{
			MType: lorawan.UnconfirmedDataUp,
			Major: lorawan.LoRaWANR1,
		},
		MACPayload: &lorawan.MACPayload{
			FHDR: lorawan.FHDR{
				DevAddr: lorawan.DevAddr([4]byte{1, 2, 3, 4}),
				FCnt:    1,
				FCtrl: lorawan.FCtrl{
					ADR:       true,
					ADRACKReq: true,
				},
				FOpts: []lorawan.MACCommand{
					lorawan.MACCommand{CID: lorawan.LinkCheckReq},
				},
			},
		},
	}
	bytes, _ := phy.MarshalBinary()

	// Valid Uplink
	message = &pb_broker.DeduplicatedUplinkMessage{
		AppEui:           &appEUI,
		DevEui:           &devEUI,
		Payload:          bytes,
		ResponseTemplate: &pb_broker.DownlinkMessage{},
		GatewayMetadata: []*pb_gateway.RxMetadata{
			&pb_gateway.RxMetadata{},
		},
		ProtocolMetadata: &pb_protocol.RxMetadata{Protocol: &pb_protocol.RxMetadata_Lorawan{
			Lorawan: &pb_lorawan.Metadata{
				DataRate: "SF7BW125",
			},
		}},
	}
	res, err := ns.HandleUplink(message)
	a.So(err, ShouldBeNil)
	a.So(res.ResponseTemplate, ShouldNotBeNil)

	// LoRaWAN: Unmarshal
	var phyPayload lorawan.PHYPayload
	phyPayload.UnmarshalBinary(res.ResponseTemplate.Payload)
	macPayload, _ := phyPayload.MACPayload.(*lorawan.MACPayload)

	// ResponseTemplate DevAddr should match
	a.So([4]byte(macPayload.FHDR.DevAddr), ShouldEqual, [4]byte(devAddr))

	// ResponseTemplate should ACK the ADRACKReq
	a.So(macPayload.FHDR.FCtrl.ACK, ShouldBeTrue)
	a.So(macPayload.FHDR.FOpts, ShouldHaveLength, 1)
	a.So(macPayload.FHDR.FOpts[0].Payload, ShouldResemble, &lorawan.LinkCheckAnsPayload{GwCnt: 1, Margin: 7})

	// Frame Counter should have been updated
	dev, _ := ns.devices.Get(appEUI, devEUI)
	a.So(dev.FCntUp, ShouldEqual, 1)
	a.So(time.Now().Sub(dev.LastSeen), ShouldBeLessThan, 1*time.Second)
}
Example #11
0
func TestHandleUplink(t *testing.T) {
	a := New(t)
	var err error
	var wg WaitGroup
	appEUI := types.AppEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8})
	appID := "appid"
	devEUI := types.DevEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8})
	devID := "devid"
	h := &handler{
		Component:    &component.Component{Ctx: GetLogger(t, "TestHandleUplink")},
		devices:      device.NewRedisDeviceStore(GetRedisClient(), "handler-test-handle-uplink"),
		applications: application.NewRedisApplicationStore(GetRedisClient(), "handler-test-handle-uplink"),
	}
	h.InitStatus()
	dev := &device.Device{
		AppID:  appID,
		DevID:  devID,
		AppEUI: appEUI,
		DevEUI: devEUI,
	}
	h.devices.Set(dev)
	defer func() {
		h.devices.Delete(appID, devID)
	}()
	h.applications.Set(&application.Application{
		AppID: appID,
	})
	defer func() {
		h.applications.Delete(appID)
	}()
	h.mqttUp = make(chan *types.UplinkMessage)
	h.mqttEvent = make(chan *types.DeviceEvent, 10)
	h.downlink = make(chan *pb_broker.DownlinkMessage)

	uplink, _ := buildLorawanUplink([]byte{0x40, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x0A, 0x4D, 0xDA, 0x23, 0x99, 0x61, 0xD4})

	downlinkEmpty := []byte{0x60, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x21, 0xEA, 0x8B, 0x0E}
	downlinkACK := []byte{0x60, 0x04, 0x03, 0x02, 0x01, 0x20, 0x00, 0x00, 0x0A, 0x3B, 0x3F, 0x77, 0x0B}
	downlinkMAC := []byte{0x60, 0x04, 0x03, 0x02, 0x01, 0x05, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x0A, 0x4D, 0x11, 0x55, 0x01}
	expected := []byte{0x60, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x66, 0xE6, 0x1D, 0x49, 0x82, 0x84}

	downlink := &pb_broker.DownlinkMessage{
		DownlinkOption: &pb_broker.DownlinkOption{
			ProtocolConfig: &pb_protocol.TxConfiguration{Protocol: &pb_protocol.TxConfiguration_Lorawan{Lorawan: &pb_lorawan.TxConfiguration{
				FCnt: 0,
			}}},
		},
	}

	// Test Uplink, no downlink option available
	wg.Add(1)
	go func() {
		<-h.mqttUp
		wg.Done()
	}()
	err = h.HandleUplink(uplink)
	a.So(err, ShouldBeNil)
	wg.WaitFor(50 * time.Millisecond)

	uplink.ResponseTemplate = downlink

	// Test Uplink, no downlink needed
	wg.Add(1)
	go func() {
		<-h.mqttUp
		wg.Done()
	}()
	downlink.Payload = downlinkEmpty
	err = h.HandleUplink(uplink)
	a.So(err, ShouldBeNil)
	wg.WaitFor(50 * time.Millisecond)

	// Test Uplink, ACK downlink needed
	wg.Add(2)
	go func() {
		<-h.mqttUp
		wg.Done()
	}()
	go func() {
		<-h.downlink
		wg.Done()
	}()
	downlink.Payload = downlinkACK
	err = h.HandleUplink(uplink)
	a.So(err, ShouldBeNil)
	wg.WaitFor(50 * time.Millisecond)

	// Test Uplink, MAC downlink needed
	wg.Add(2)
	go func() {
		<-h.mqttUp
		wg.Done()
	}()
	go func() {
		<-h.downlink
		wg.Done()
	}()
	downlink.Payload = downlinkMAC
	err = h.HandleUplink(uplink)
	a.So(err, ShouldBeNil)
	wg.WaitFor(50 * time.Millisecond)

	dev.StartUpdate()
	dev.NextDownlink = &types.DownlinkMessage{
		PayloadRaw: []byte{0xaa, 0xbc},
	}

	// Test Uplink, Data downlink needed
	h.devices.Set(dev)
	wg.Add(2)
	go func() {
		<-h.mqttUp
		wg.Done()
	}()
	go func() {
		dl := <-h.downlink
		a.So(dl.Payload, ShouldResemble, expected)
		wg.Done()
	}()
	downlink.Payload = downlinkEmpty
	err = h.HandleUplink(uplink)
	a.So(err, ShouldBeNil)
	wg.WaitFor(50 * time.Millisecond)

	dev, _ = h.devices.Get(appID, devID)
	a.So(dev.NextDownlink, ShouldBeNil)
}
Example #12
0
func TestDeviceStore(t *testing.T) {
	a := New(t)

	NewRedisDeviceStore(GetRedisClient(), "")

	s := NewRedisDeviceStore(GetRedisClient(), "handler-test-device-store")

	// Get non-existing
	dev, err := s.Get("AppID-1", "DevID-1")
	a.So(err, ShouldNotBeNil)
	a.So(dev, ShouldBeNil)

	devs, err := s.ListForApp("AppID-1")
	a.So(err, ShouldBeNil)
	a.So(devs, ShouldHaveLength, 0)

	// Create
	err = s.Set(&Device{
		DevAddr: types.DevAddr([4]byte{0, 0, 0, 1}),
		DevEUI:  types.DevEUI([8]byte{0, 0, 0, 0, 0, 0, 0, 1}),
		AppEUI:  types.AppEUI([8]byte{0, 0, 0, 0, 0, 0, 0, 1}),
		AppID:   "AppID-1",
		DevID:   "DevID-1",
	})
	a.So(err, ShouldBeNil)

	defer func() {
		s.Delete("AppID-1", "DevID-1")
	}()

	// Get existing
	dev, err = s.Get("AppID-1", "DevID-1")
	a.So(err, ShouldBeNil)
	a.So(dev, ShouldNotBeNil)

	devs, err = s.ListForApp("AppID-1")
	a.So(err, ShouldBeNil)
	a.So(devs, ShouldHaveLength, 1)

	// Create extra and update
	dev = &Device{
		DevAddr: types.DevAddr([4]byte{0, 0, 0, 2}),
		DevEUI:  types.DevEUI([8]byte{0, 0, 0, 0, 0, 0, 0, 2}),
		AppEUI:  types.AppEUI([8]byte{0, 0, 0, 0, 0, 0, 0, 1}),
		AppID:   "AppID-1",
		DevID:   "DevID-2",
	}
	err = s.Set(dev)
	a.So(err, ShouldBeNil)

	err = s.Set(&Device{
		old:     dev,
		DevAddr: types.DevAddr([4]byte{0, 0, 0, 3}),
		DevEUI:  types.DevEUI([8]byte{0, 0, 0, 0, 0, 0, 0, 3}),
		AppEUI:  types.AppEUI([8]byte{0, 0, 0, 0, 0, 0, 0, 2}),
		AppID:   "AppID-1",
		DevID:   "DevID-2",
	})
	a.So(err, ShouldBeNil)

	dev, err = s.Get("AppID-1", "DevID-2")
	a.So(err, ShouldBeNil)
	a.So(dev, ShouldNotBeNil)
	a.So(dev.DevEUI, ShouldEqual, types.DevEUI([8]byte{0, 0, 0, 0, 0, 0, 0, 3}))

	defer func() {
		s.Delete("AppID-1", "DevID-2")
	}()

	// List
	devices, err := s.List()
	a.So(err, ShouldBeNil)
	a.So(devices, ShouldHaveLength, 2)

	// Delete
	err = s.Delete("AppID-1", "DevID-1")
	a.So(err, ShouldBeNil)

	// Get deleted
	dev, err = s.Get("AppID-1", "DevID-1")
	a.So(err, ShouldNotBeNil)
	a.So(dev, ShouldBeNil)

	devs, err = s.ListForApp("AppID-1")
	a.So(err, ShouldBeNil)
	a.So(devs, ShouldHaveLength, 1)

}
func TestMarshalUnmarshalPayload(t *testing.T) {
	a := New(t)

	var subjects []payloadMarshalerUnmarshaler

	// Do nothing when message and payload are nil
	subjects = []payloadMarshalerUnmarshaler{
		&UplinkMessage{},
		&DownlinkMessage{},
		&DeviceActivationRequest{},
	}

	for _, sub := range subjects {
		a.So(sub.MarshalPayload(), ShouldEqual, nil)
		a.So(sub.UnmarshalPayload(), ShouldEqual, nil)
	}

	rxMeta := &pb_protocol.RxMetadata{Protocol: &pb_protocol.RxMetadata_Lorawan{Lorawan: &pb_lorawan.Metadata{}}}
	txConf := &pb_protocol.TxConfiguration{Protocol: &pb_protocol.TxConfiguration_Lorawan{Lorawan: &pb_lorawan.TxConfiguration{}}}

	macMsg := &pb_protocol.Message{Protocol: &pb_protocol.Message_Lorawan{Lorawan: &pb_lorawan.Message{
		MHDR: pb_lorawan.MHDR{
			Major: 1,
			MType: pb_lorawan.MType_UNCONFIRMED_UP,
		},
		Payload: &pb_lorawan.Message_MacPayload{MacPayload: &pb_lorawan.MACPayload{
			FHDR: pb_lorawan.FHDR{
				DevAddr: types.DevAddr([4]byte{1, 2, 3, 4}),
				FCnt:    1,
			},
		}},
		Mic: []byte{1, 2, 3, 4},
	}}}
	macBin := []byte{65, 4, 3, 2, 1, 0, 1, 0, 0, 1, 2, 3, 4}
	joinReqMsg := &pb_protocol.Message{Protocol: &pb_protocol.Message_Lorawan{Lorawan: &pb_lorawan.Message{
		MHDR: pb_lorawan.MHDR{
			Major: 1,
			MType: pb_lorawan.MType_JOIN_REQUEST,
		},
		Payload: &pb_lorawan.Message_JoinRequestPayload{JoinRequestPayload: &pb_lorawan.JoinRequestPayload{
			AppEui:   types.AppEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8}),
			DevEui:   types.DevEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8}),
			DevNonce: types.DevNonce([2]byte{1, 2}),
		}},
		Mic: []byte{1, 2, 3, 4},
	}}}
	joinReqBin := []byte{1, 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1, 2, 1, 1, 2, 3, 4}

	// Only Marshal
	subjects = []payloadMarshalerUnmarshaler{
		&UplinkMessage{
			ProtocolMetadata: rxMeta,
			Message:          macMsg,
		},
		&DownlinkMessage{
			ProtocolConfiguration: txConf,
			Message:               macMsg,
		},
		&DeviceActivationRequest{
			ProtocolMetadata: rxMeta,
			Message:          joinReqMsg,
		},
	}

	for _, sub := range subjects {
		a.So(sub.UnmarshalPayload(), ShouldEqual, nil)
		a.So(sub.MarshalPayload(), ShouldEqual, nil)
	}

	// Only Unmarshal
	subjects = []payloadMarshalerUnmarshaler{
		&UplinkMessage{
			ProtocolMetadata: rxMeta,
			Payload:          macBin,
		},
		&DownlinkMessage{
			ProtocolConfiguration: txConf,
			Payload:               macBin,
		},
		&DeviceActivationRequest{
			ProtocolMetadata: rxMeta,
			Payload:          joinReqBin,
		},
	}

	for _, sub := range subjects {
		a.So(sub.MarshalPayload(), ShouldEqual, nil)
		a.So(sub.UnmarshalPayload(), ShouldEqual, nil)
	}

}
Example #14
0
func TestHandleGetDevices(t *testing.T) {
	a := New(t)

	ns := &networkServer{
		devices: device.NewRedisDeviceStore(GetRedisClient(), "ns-test-handle-get-devices"),
	}

	nwkSKey := types.NwkSKey{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}

	// No Devices
	devAddr1 := getDevAddr(1, 2, 3, 4)
	res, err := ns.HandleGetDevices(&pb.DevicesRequest{
		DevAddr: &devAddr1,
		FCnt:    5,
	})
	a.So(err, ShouldBeNil)
	a.So(res.Results, ShouldBeEmpty)

	// Matching Device
	ns.devices.Set(&device.Device{
		DevAddr: getDevAddr(1, 2, 3, 4),
		AppEUI:  types.AppEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8)),
		DevEUI:  types.DevEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8)),
		NwkSKey: nwkSKey,
		FCntUp:  5,
	})
	defer func() {
		ns.devices.Delete(types.AppEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8)), types.DevEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8)))
	}()

	res, err = ns.HandleGetDevices(&pb.DevicesRequest{
		DevAddr: &devAddr1,
		FCnt:    5,
	})
	a.So(err, ShouldBeNil)
	a.So(res.Results, ShouldHaveLength, 1)

	// Non-Matching DevAddr
	devAddr2 := getDevAddr(5, 6, 7, 8)
	res, err = ns.HandleGetDevices(&pb.DevicesRequest{
		DevAddr: &devAddr2,
		FCnt:    5,
	})
	a.So(err, ShouldBeNil)
	a.So(res.Results, ShouldHaveLength, 0)

	// Non-Matching FCnt
	res, err = ns.HandleGetDevices(&pb.DevicesRequest{
		DevAddr: &devAddr1,
		FCnt:    4,
	})
	a.So(err, ShouldBeNil)
	a.So(res.Results, ShouldHaveLength, 0)

	// Non-Matching FCnt, but FCnt Check Disabled
	ns.devices.Set(&device.Device{
		DevAddr: getDevAddr(5, 6, 7, 8),
		AppEUI:  types.AppEUI(getEUI(5, 6, 7, 8, 1, 2, 3, 4)),
		DevEUI:  types.DevEUI(getEUI(5, 6, 7, 8, 1, 2, 3, 4)),
		NwkSKey: nwkSKey,
		FCntUp:  5,
		Options: device.Options{
			DisableFCntCheck: true,
		},
	})
	defer func() {
		ns.devices.Delete(types.AppEUI(getEUI(5, 6, 7, 8, 1, 2, 3, 4)), types.DevEUI(getEUI(5, 6, 7, 8, 1, 2, 3, 4)))
	}()
	res, err = ns.HandleGetDevices(&pb.DevicesRequest{
		DevAddr: &devAddr2,
		FCnt:    4,
	})
	a.So(err, ShouldBeNil)
	a.So(res.Results, ShouldHaveLength, 1)

	// 32 Bit Frame Counter (A)
	ns.devices.Set(&device.Device{
		DevAddr: getDevAddr(2, 2, 3, 4),
		AppEUI:  types.AppEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8)),
		DevEUI:  types.DevEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8)),
		NwkSKey: nwkSKey,
		FCntUp:  5 + (2 << 16),
		Options: device.Options{
			Uses32BitFCnt: true,
		},
	})
	defer func() {
		ns.devices.Delete(types.AppEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8)), types.DevEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8)))
	}()
	devAddr3 := getDevAddr(2, 2, 3, 4)
	res, err = ns.HandleGetDevices(&pb.DevicesRequest{
		DevAddr: &devAddr3,
		FCnt:    5,
	})
	a.So(err, ShouldBeNil)
	a.So(res.Results, ShouldHaveLength, 1)

	// 32 Bit Frame Counter (B)
	ns.devices.Set(&device.Device{
		DevAddr: getDevAddr(2, 2, 3, 5),
		AppEUI:  types.AppEUI(getEUI(2, 2, 3, 4, 5, 3, 7, 8)),
		DevEUI:  types.DevEUI(getEUI(2, 2, 3, 4, 5, 3, 7, 8)),
		NwkSKey: nwkSKey,
		FCntUp:  (2 << 16) - 1,
		Options: device.Options{
			Uses32BitFCnt: true,
		},
	})
	defer func() {
		ns.devices.Delete(types.AppEUI(getEUI(2, 2, 3, 4, 5, 3, 7, 8)), types.DevEUI(getEUI(2, 2, 3, 4, 5, 3, 7, 8)))
	}()
	devAddr4 := getDevAddr(2, 2, 3, 5)
	res, err = ns.HandleGetDevices(&pb.DevicesRequest{
		DevAddr: &devAddr4,
		FCnt:    5,
	})
	a.So(err, ShouldBeNil)
	a.So(res.Results, ShouldHaveLength, 1)

}
Example #15
0
func TestHandleDownlink(t *testing.T) {
	a := New(t)
	var err error
	var wg WaitGroup
	appID := "app2"
	devID := "dev2"
	appEUI := types.AppEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8})
	devEUI := types.DevEUI([8]byte{1, 2, 3, 4, 5, 6, 7, 8})
	h := &handler{
		Component:    &component.Component{Ctx: GetLogger(t, "TestHandleDownlink")},
		devices:      device.NewRedisDeviceStore(GetRedisClient(), "handler-test-handle-downlink"),
		applications: application.NewRedisApplicationStore(GetRedisClient(), "handler-test-enqueue-downlink"),
		downlink:     make(chan *pb_broker.DownlinkMessage),
		mqttEvent:    make(chan *types.DeviceEvent, 10),
	}
	h.InitStatus()
	// Neither payload nor Fields provided : ERROR
	err = h.HandleDownlink(&types.DownlinkMessage{
		AppID: appID,
		DevID: devID,
	}, &pb_broker.DownlinkMessage{
		AppEui: &appEUI,
		DevEui: &devEUI,
	})
	a.So(err, ShouldNotBeNil)

	h.devices.Set(&device.Device{
		AppID: appID,
		DevID: devID,
	})
	defer func() {
		h.devices.Delete(appID, devID)
	}()
	err = h.HandleDownlink(&types.DownlinkMessage{
		AppID: appID,
		DevID: devID,
	}, &pb_broker.DownlinkMessage{
		AppEui:  &appEUI,
		DevEui:  &devEUI,
		Payload: []byte{96, 4, 3, 2, 1, 0, 1, 0, 1, 0, 0, 0, 0},
	})
	a.So(err, ShouldBeNil)

	// Payload provided
	wg.Add(1)
	go func() {
		dl := <-h.downlink
		a.So(dl.Payload, ShouldNotBeEmpty)
		wg.Done()
	}()
	err = h.HandleDownlink(&types.DownlinkMessage{
		AppID:      appID,
		DevID:      devID,
		PayloadRaw: []byte{0xAA, 0xBC},
	}, &pb_broker.DownlinkMessage{
		AppEui:         &appEUI,
		DevEui:         &devEUI,
		Payload:        []byte{96, 4, 3, 2, 1, 0, 1, 0, 1, 0, 0, 0, 0},
		DownlinkOption: &pb_broker.DownlinkOption{},
	})
	a.So(err, ShouldBeNil)
	wg.WaitFor(100 * time.Millisecond)

	// Both Payload and Fields provided
	h.applications.Set(&application.Application{
		AppID: appID,
		Encoder: `function Encoder (payload){
	  		return [96, 4, 3, 2, 1, 0, 1, 0, 1, 0, 0, 0, 0]
			}`,
	})
	defer func() {
		h.applications.Delete(appID)
	}()
	jsonFields := map[string]interface{}{"temperature": 11}
	err = h.HandleDownlink(&types.DownlinkMessage{
		FPort:         1,
		AppID:         appID,
		DevID:         devID,
		PayloadFields: jsonFields,
		PayloadRaw:    []byte{0xAA, 0xBC},
	}, &pb_broker.DownlinkMessage{
		AppEui:  &appEUI,
		DevEui:  &devEUI,
		Payload: []byte{96, 4, 3, 2, 1, 0, 1, 0, 1, 0, 0, 0, 0},
	})
	a.So(err, ShouldNotBeNil)

	// JSON Fields provided
	wg.Add(1)
	go func() {
		dl := <-h.downlink
		a.So(dl.Payload, ShouldNotBeEmpty)
		wg.Done()
	}()
	err = h.HandleDownlink(&types.DownlinkMessage{
		FPort:         1,
		AppID:         appID,
		DevID:         devID,
		PayloadFields: jsonFields,
	}, &pb_broker.DownlinkMessage{
		AppEui:         &appEUI,
		DevEui:         &devEUI,
		Payload:        []byte{96, 4, 3, 2, 1, 0, 1, 0, 1, 0, 0, 0, 0},
		DownlinkOption: &pb_broker.DownlinkOption{},
	})
	a.So(err, ShouldBeNil)
	wg.WaitFor(100 * time.Millisecond)
}
Example #16
0
func (r *router) HandleUplink(gatewayID string, uplink *pb.UplinkMessage) (err error) {
	ctx := r.Ctx.WithField("GatewayID", gatewayID)
	start := time.Now()
	defer func() {
		if err != nil {
			ctx.WithError(err).Warn("Could not handle uplink")
		}
	}()
	r.status.uplink.Mark(1)

	// LoRaWAN: Unmarshal
	var phyPayload lorawan.PHYPayload
	err = phyPayload.UnmarshalBinary(uplink.Payload)
	if err != nil {
		return err
	}

	if phyPayload.MHDR.MType == lorawan.JoinRequest {
		joinRequestPayload, ok := phyPayload.MACPayload.(*lorawan.JoinRequestPayload)
		if !ok {
			return errors.NewErrInvalidArgument("Join Request", "does not contain a JoinRequest payload")
		}
		devEUI := types.DevEUI(joinRequestPayload.DevEUI)
		appEUI := types.AppEUI(joinRequestPayload.AppEUI)
		ctx.WithFields(log.Fields{
			"DevEUI": devEUI,
			"AppEUI": appEUI,
		}).Debug("Handle Uplink as Activation")
		r.HandleActivation(gatewayID, &pb.DeviceActivationRequest{
			Payload:          uplink.Payload,
			DevEui:           &devEUI,
			AppEui:           &appEUI,
			ProtocolMetadata: uplink.ProtocolMetadata,
			GatewayMetadata:  uplink.GatewayMetadata,
		})
		return nil
	}

	if lorawan := uplink.ProtocolMetadata.GetLorawan(); lorawan != nil {
		ctx = ctx.WithField("Modulation", lorawan.Modulation.String())
		if lorawan.Modulation == pb_lorawan.Modulation_LORA {
			ctx = ctx.WithField("DataRate", lorawan.DataRate)
		} else {
			ctx = ctx.WithField("BitRate", lorawan.BitRate)
		}
	}

	if gateway := uplink.GatewayMetadata; gateway != nil {
		ctx = ctx.WithFields(log.Fields{
			"Frequency": gateway.Frequency,
			"RSSI":      gateway.Rssi,
			"SNR":       gateway.Snr,
		})
	}

	macPayload, ok := phyPayload.MACPayload.(*lorawan.MACPayload)
	if !ok {
		return errors.NewErrInvalidArgument("Uplink", "does not contain a MAC payload")
	}
	devAddr := types.DevAddr(macPayload.FHDR.DevAddr)

	ctx = ctx.WithFields(log.Fields{
		"DevAddr": devAddr,
		"FCnt":    macPayload.FHDR.FCnt,
	})

	gateway := r.getGateway(gatewayID)

	if err = gateway.HandleUplink(uplink); err != nil {
		return err
	}

	var downlinkOptions []*pb_broker.DownlinkOption
	if gateway.Schedule.IsActive() {
		downlinkOptions = r.buildDownlinkOptions(uplink, false, gateway)
	}

	ctx = ctx.WithField("DownlinkOptions", len(downlinkOptions))

	// Find Broker
	brokers, err := r.Discovery.GetAllBrokersForDevAddr(devAddr)
	if err != nil {
		return err
	}

	if len(brokers) == 0 {
		ctx.Debug("No brokers to forward message to")
		return nil
	}

	ctx = ctx.WithField("NumBrokers", len(brokers))

	// Forward to all brokers
	for _, broker := range brokers {
		broker, err := r.getBroker(broker)
		if err != nil {
			continue
		}
		broker.uplink <- &pb_broker.UplinkMessage{
			Payload:          uplink.Payload,
			ProtocolMetadata: uplink.ProtocolMetadata,
			GatewayMetadata:  uplink.GatewayMetadata,
			DownlinkOptions:  downlinkOptions,
		}
	}

	ctx.WithField("Duration", time.Now().Sub(start)).Info("Handled uplink")

	return nil
}