Exemplo n.º 1
0
class NetServerTest(unittest.TestCase):
    def setUp(self):
        """Test setup. Creates a new NetServer
        """
        # Get configuration
        config = Configuration()
        cfile = os.path.join(config.path, 'test', 'unit', 'default.cfg')
        if not config.parseConfig(cfile):
            exit(1)
        self.server = NetServer(config)

    def _test_device(self):
        """Create a test device object. We must load the device
        dynamically as it depends on the adbapi intialisation"""

        return Device(deveui=int('0x0F0E0E0D00010209', 16),
                      devaddr=int('0x06000001', 16),
                      appeui=int('0x0A0B0C0D0A0B0C0D', 16),
                      nwkskey=int('0xAEB48D4C6E9EA5C48C37E4F132AA8516', 16),
                      appskey=int('0x7987A96F267F0A86B739EED480FC2B3C', 16),
                      tx_chan=3,
                      tx_datr='SF7BW125',
                      gw_addr='192.168.1.125')

    def test_loadAppServerInterface(self):
        appserver = self.server._loadAppServerInterface('reflector')
        self.assertTrue(isinstance(appserver, protocol.DatagramProtocol))

    @inlineCallbacks
    def test_getOTAADevAddrs(self):
        device = self._test_device()
        mockDBObject.return_value = device
        expected = [[], [device.devaddr]]

        results = []
        # Test when no devices are found
        with patch.object(Device, 'find', classmethod(mockDBObject.findFail)):
            result = yield self.server._getOTAADevAddrs()
            results.append(result)

        # Test when one device is found
        with patch.object(Device, 'find', classmethod(mockDBObject.findOne)):
            result = yield self.server._getOTAADevAddrs()
            results.append(result)

        self.assertEqual(expected, results)

    @inlineCallbacks
    def test_getFreeOTAAddress(self):
        expected = [
            self.server.config.otaastart, self.server.config.otaastart + 1,
            self.server.config.otaaend, None
        ]
        results = []

        # Test with empty OTA device list
        # Mock the server method to return the devaddr list
        with patch.object(self.server, '_getOTAADevAddrs',
                          MagicMock(return_value=[])):
            result = yield self.server._getFreeOTAAddress()
            results.append(result)

        # Test with one OTA device
        with patch.object(
                self.server, '_getOTAADevAddrs',
                MagicMock(return_value=[self.server.config.otaastart])):
            result = yield self.server._getFreeOTAAddress()
            results.append(result)

        # Test with last address only available
        with patch.object(
                self.server, '_getOTAADevAddrs',
                MagicMock(return_value=xrange(self.server.config.otaastart,
                                              self.server.config.otaaend))):
            result = yield self.server._getFreeOTAAddress()
            results.append(result)

        # Test with no address available
        with patch.object(
                self.server, '_getOTAADevAddrs',
                MagicMock(return_value=xrange(self.server.config.otaastart,
                                              self.server.config.otaaend +
                                              1))):
            result = yield self.server._getFreeOTAAddress()
            results.append(result)

        self.assertEqual(expected, results)

    @inlineCallbacks
    def test_getActiveDevice(self):
        # Include for coverage. We are essentially testing a returnValue() call.
        device = self._test_device()
        mockDBObject.return_value = device

        expected = device.deveui

        with patch.object(Device, 'find',
                          classmethod(mockDBObject.findSuccess)):
            result = yield self.server._getActiveDevice(device.devaddr)

        self.assertEqual(expected, result.deveui)

    @inlineCallbacks
    def test_addActiveDevice(self):
        device = self._test_device()
        mockDBObject.return_value = device

        # Test for device deveui, and allocated devaddr
        expected = [self.server.config.otaastart + 1, device.deveui]
        results = []

        # Test adding a new device. i.e. Device.find() fails.
        # _addActiveDevice returns the saved device
        with patch.object(Device, 'find', classmethod(mockDBObject.findFail)), \
                patch.object(device, 'save', MagicMock(return_value=device)), \
                patch.object(self.server, '_getFreeOTAAddress',
                             MagicMock(return_value=self.server.config.otaastart + 1)):
            device.devaddr = 0
            result = yield self.server._addActiveDevice(device)
            results.append(result.devaddr)

        # Test when the device is found in the active list.
        with patch.object(Device, 'find', classmethod(mockDBObject.findSuccess)), \
                patch.object(device, 'save', MagicMock(return_value=device)):
            result = yield self.server._addActiveDevice(device)
            results.append(result.deveui)

        self.assertEqual(expected, results)

    def test_checkDuplicateMessage(self):
        m = lora_mac.MACDataMessage()
        m.mic = 1111
        self.server.config.duplicateperiod = 10

        expected = [True, False]
        result = []

        now = time.time()

        # Test a successful find of the duplicate
        for i in (1, 10):
            self.server.message_cache.append((randrange(1, 1000), now - i))
        self.server.message_cache.append(
            (m.mic, now - self.server.config.duplicateperiod + 1))
        result.append(self.server._checkDuplicateMessage(m))

        # Test an unsuccessful find of the duplicate - the message's
        # cache period has expired.
        self.server.message_cache.remove(
            (m.mic, now - self.server.config.duplicateperiod + 1))
        self.server.message_cache.append(
            (m.mic, now - self.server.config.duplicateperiod - 1))
        result.append(self.server._checkDuplicateMessage(m))

        self.assertEqual(expected, result)

    def test_cleanMessageCache(self):
        self.server.config.duplicateperiod = 10

        # Create 10 cache entries, remove 5
        now = time.time()
        for i in range(1, 21, 2):
            self.server.message_cache.append((i, now - i))

        expected = 5
        self.server._cleanMessageCache()
        result = len(self.server.message_cache)

        self.assertEqual(expected, result)

    def test_manageMACCommandQueue(self):
        self.server.config.macqueuelimit = 10

        # Create 10 cache entries, remove 5
        now = time.time()
        for i in range(1, 21, 2):
            self.server.commands.append(
                (int(now - i), i, lora_mac.LinkCheckAns()))

        expected = 5
        self.server._manageMACCommandQueue()
        result = len(self.server.commands)

        self.assertEqual(expected, result)

    @inlineCallbacks
    def test_processADRRequests(self):
        device = self._test_device()
        mockDBObject.return_value = [device]
        # Remove any delays
        self.server.config.adrmessagetime = 0

        device.snr_average = 3.5
        device.adr_datr = None

        # Test we set adr_datr device attribute properly
        expected = ['SF9BW125', False]
        results = []

        with patch.object(Device, 'all', classmethod(mockDBObject.all)), \
                patch.multiple(device, refresh=MagicMock(), save=MagicMock()), \
                patch.object(self.server, '_sendLinkADRRequest'):
            yield self.server._processADRRequests()
            results.append(device.adr_datr)

        results.append(self.server.adrprocessing)
        self.assertEqual(expected, results)

    def _createCommands(self):
        datarate = 'SF7BW125'
        chmask = int('FF', 16)
        return [
            lora_mac.LinkCheckAns(),
            lora_mac.LinkADRReq(datarate, 0, chmask, 6, 0)
        ]

    def test_queueMACCommand(self):
        device = self._test_device()
        commands = self._createCommands()

        expected = [2, lora_mac.LINKCHECKANS, lora_mac.LINKADRREQ]

        for c in commands:
            self.server._queueMACCommand(device.deveui, c)
        result = [
            len(self.server.commands), self.server.commands[0][2].cid,
            self.server.commands[1][2].cid
        ]

        self.assertEqual(expected, result)

    def test_dequeueMACCommand(self):
        device = self._test_device()
        commands = self._createCommands()
        for c in commands:
            self.server._queueMACCommand(device.deveui, c)

        self.server._dequeueMACCommand(device.deveui, commands[1])

        expected = [1, lora_mac.LINKCHECKANS]

        result = [len(self.server.commands), self.server.commands[0][2].cid]

        self.assertEqual(expected, result)

    def test_scheduleDownlinkTime(self):
        offset = 10
        tmst = randrange(0, 4294967295 - 10000000)

        expected = [tmst + 10000000, 5000000]
        result = []
        result.append(self.server._scheduleDownlinkTime(tmst, offset))
        tmst = 4294967295 - 5000000
        result.append(self.server._scheduleDownlinkTime(tmst, offset))

        self.assertEqual(expected, result)

    def test_txpkResponse(self):
        tmst = randrange(0, 4294967295)
        rxpk = loragw.Rxpk(tmst=tmst,
                           chan=3,
                           freq=915.8,
                           datr='SF7BW125',
                           data="n/uSwM0LIED8X6QV0mJMjC6oc2HOWFpCfmTry",
                           size=54)
        device = self._test_device()
        device.rx = self.server.band.rxparams((rxpk.chan, rxpk.datr),
                                              join=False)
        gateway = self.server.protocol['lora'].configuredGateway(
            device.gw_addr)
        expected = [
            (True, device.rx[1]['freq'], device.rx[1]['datr']),
            (True, device.rx[2]['freq'], device.rx[2]['datr']),
            (tmst + 1000000, device.rx[1]['freq'], device.rx[1]['datr']),
            (tmst + 2000000, device.rx[2]['freq'], device.rx[2]['datr'])
        ]

        result = []
        txpk = self.server._txpkResponse(device,
                                         rxpk.data,
                                         gateway,
                                         tmst,
                                         immediate=True)
        for i in range(1, 3):
            result.append((txpk[i].imme, txpk[i].freq, txpk[i].datr))
        txpk = self.server._txpkResponse(device,
                                         rxpk.data,
                                         gateway,
                                         tmst,
                                         immediate=False)
        for i in range(1, 3):
            result.append((txpk[i].tmst, txpk[i].freq, txpk[i].datr))

        self.assertEqual(expected, result)

    def _processJoinRequest(self, request):
        """Called by test_processJoinRequest_pass and
        test_processJoinRequest_fail"""

        msg = lora_mac.MACMessage.decode(request)
        app = self.server.config.apps[0]
        dev = self._test_device()
        # Mock _addActiveDevice
        self.server._addActiveDevice = MagicMock(return_value=True)
        return self.server._processJoinRequest(msg, app, dev)

    def test_processJoinRequest_pass(self):
        joinreq = base64.b64decode("AA0MCwoNDAsKAwIBAA0ODg9IklIgzCM=")
        result = self._processJoinRequest(joinreq)

        self.assertTrue(result)

    def test_processJoinRequest_fail(self):
        joinreq = base64.b64decode("AA0MCwoNDAsKAwIBAA0ODg9IklIgzCX=")
        result = self._processJoinRequest(joinreq)

        self.assertFalse(result)
Exemplo n.º 2
0
class NetServerTest(unittest.TestCase):
    @inlineCallbacks
    def setUp(self):
        """Test setup. Creates a new NetServer
        
        Use factory default configuration.
        """

        Registry.getConfig = MagicMock(return_value=None)

        # Get factory default configuration
        with patch.object(Model, 'save', MagicMock()):
            config = yield Config.loadFactoryDefaults()
        self.server = NetServer(config)

    def _test_device(self):
        """Create a test device object """

        return Device(deveui=int('0x0F0E0E0D00010209', 16),
                      devaddr=int('0x06000001', 16),
                      appeui=int('0x0A0B0C0D0A0B0C0D', 16),
                      nwkskey=int('0xAEB48D4C6E9EA5C48C37E4F132AA8516', 16),
                      appskey=int('0x7987A96F267F0A86B739EED480FC2B3C', 16),
                      adr=True,
                      tx_chan=3,
                      tx_datr='SF7BW125',
                      gw_addr='192.168.1.125',
                      enabled=True)

    def test_checkDevaddr(self):
        """Test checkDevaddr method"""
        # Check valid address
        device = self._test_device()
        result = self.server.checkDevaddr(device.devaddr)
        self.assertTrue(result)

        # Check invalid address
        devaddr = int('0x11223344', 16)
        result = self.server.checkDevaddr(devaddr)
        self.assertFalse(result)

    @inlineCallbacks
    def test_getOTAADevAddrs(self):
        """Test getOTAADevAddrs method"""
        device = self._test_device()
        mockDBObject.return_value = device
        expected = [[], [device.devaddr]]

        results = []
        # Test when no devices are found
        with patch.object(Device, 'find', classmethod(mockDBObject.findFail)):
            result = yield self.server._getOTAADevAddrs()
            results.append(result)

        # Test when one device is found
        with patch.object(Device, 'find', classmethod(mockDBObject.findOne)):
            result = yield self.server._getOTAADevAddrs()
            results.append(result)

        self.assertEqual(expected, results)

    @inlineCallbacks
    def test_getFreeOTAAddress(self):
        expected = [
            self.server.config.otaastart, self.server.config.otaastart + 1,
            self.server.config.otaaend, None
        ]
        results = []

        # Test with empty OTA device list
        # Mock the server method to return the devaddr list
        with patch.object(self.server, '_getOTAADevAddrs',
                          MagicMock(return_value=[])):
            result = yield self.server._getFreeOTAAddress()
            results.append(result)

        # Test with one OTA device
        with patch.object(
                self.server, '_getOTAADevAddrs',
                MagicMock(return_value=[self.server.config.otaastart])):
            result = yield self.server._getFreeOTAAddress()
            results.append(result)

        # Test with last address only available
        with patch.object(
                self.server, '_getOTAADevAddrs',
                MagicMock(return_value=xrange(self.server.config.otaastart,
                                              self.server.config.otaaend))):
            result = yield self.server._getFreeOTAAddress()
            results.append(result)

        # Test with no address available
        with patch.object(
                self.server, '_getOTAADevAddrs',
                MagicMock(return_value=xrange(self.server.config.otaastart,
                                              self.server.config.otaaend +
                                              1))):
            result = yield self.server._getFreeOTAAddress()
            results.append(result)

        self.assertEqual(expected, results)

    @inlineCallbacks
    def test_getActiveDevice(self):
        # Include for coverage. We are essentially testing a returnValue() call.
        device = self._test_device()
        mockDBObject.return_value = device

        expected = device.deveui

        with patch.object(Device, 'find',
                          classmethod(mockDBObject.findSuccess)):
            result = yield self.server._getActiveDevice(device.devaddr)

        self.assertEqual(expected, result.deveui)

    def test_checkDuplicateMessage(self):
        m = lora_mac.MACDataMessage()
        m.mic = 1111
        self.server.config.duplicateperiod = 10

        expected = [True, False]
        result = []

        now = time.time()

        # Test a successful find of the duplicate
        for i in (1, 10):
            self.server.message_cache.append((randrange(1, 1000), now - i))
        self.server.message_cache.append(
            (m.mic, now - self.server.config.duplicateperiod + 1))
        result.append(self.server._checkDuplicateMessage(m))

        # Test an unsuccessful find of the duplicate - the message's
        # cache period has expired.
        self.server.message_cache.remove(
            (m.mic, now - self.server.config.duplicateperiod + 1))
        self.server.message_cache.append(
            (m.mic, now - self.server.config.duplicateperiod - 1))
        result.append(self.server._checkDuplicateMessage(m))

        self.assertEqual(expected, result)

    def test_cleanMessageCache(self):
        self.server.config.duplicateperiod = 10

        # Create 10 cache entries, remove 5
        now = time.time()
        for i in range(1, 21, 2):
            self.server.message_cache.append((i, now - i))

        expected = 5
        self.server._cleanMessageCache()
        result = len(self.server.message_cache)

        self.assertEqual(expected, result)

    def test_manageMACCommandQueue(self):
        self.server.config.macqueuelimit = 10

        # Create 10 cache entries, remove 5
        now = time.time()
        for i in range(1, 21, 2):
            self.server.commands.append(
                (int(now - i), i, lora_mac.LinkCheckAns()))

        expected = 5
        self.server._manageMACCommandQueue()
        result = len(self.server.commands)

        self.assertEqual(expected, result)

    @inlineCallbacks
    def test_processADRRequests(self):
        device = self._test_device()
        device.snr_average = 3.5
        device.adr_datr = None

        # Test we set adr_datr device attribute properly
        expected = ['SF9BW125', False]
        results = []

        mockDBObject.return_value = [device]
        mockModel.mock_object = device
        with patch.object(Device, 'all', classmethod(mockDBObject.all)), \
                patch.object(device, 'update', mockModel.update), \
                patch.object(self.server, '_sendLinkADRRequest', MagicMock()):
            # Remove any delays
            self.server.config.adrmessagetime = 0
            yield self.server._processADRRequests()

        results.append(device.adr_datr)
        results.append(self.server.adrprocessing)
        self.assertEqual(expected, results)

    def _createCommands(self):
        datarate = 'SF7BW125'
        chmask = int('FF', 16)
        return [
            lora_mac.LinkCheckAns(),
            lora_mac.LinkADRReq(datarate, 0, chmask, 6, 0)
        ]

    def test_queueMACCommand(self):
        device = self._test_device()
        commands = self._createCommands()

        expected = [2, lora_mac.LINKCHECKANS, lora_mac.LINKADRREQ]

        for c in commands:
            self.server._queueMACCommand(device.deveui, c)
        result = [
            len(self.server.commands), self.server.commands[0][2].cid,
            self.server.commands[1][2].cid
        ]

        self.assertEqual(expected, result)

    def test_dequeueMACCommand(self):
        device = self._test_device()
        commands = self._createCommands()
        for c in commands:
            self.server._queueMACCommand(device.deveui, c)

        self.server._dequeueMACCommand(device.deveui, commands[1])

        expected = [1, lora_mac.LINKCHECKANS]

        result = [len(self.server.commands), self.server.commands[0][2].cid]

        self.assertEqual(expected, result)

    def test_scheduleDownlinkTime(self):
        offset = 10
        tmst = randrange(0, 4294967295 - 10000000)

        expected = [tmst + 10000000, 5000000]
        result = []
        result.append(self.server._scheduleDownlinkTime(tmst, offset))
        tmst = 4294967295 - 5000000
        result.append(self.server._scheduleDownlinkTime(tmst, offset))

        self.assertEqual(expected, result)

    def test_txpkResponse(self):
        self.server.lora = LoraWAN(self)
        self.server.lora.addGateway(
            Gateway(host='192.168.1.125', name='Test', enabled=True, power=26))
        tmst = randrange(0, 4294967295)
        rxpk = Rxpk(tmst=tmst,
                    chan=3,
                    freq=915.8,
                    datr='SF7BW125',
                    data="n/uSwM0LIED8X6QV0mJMjC6oc2HOWFpCfmTry",
                    size=54)
        device = self._test_device()
        device.rx = self.server.band.rxparams((rxpk.chan, rxpk.datr),
                                              join=False)
        gateway = self.server.lora.gateway(device.gw_addr)
        expected = [
            (True, device.rx[1]['freq'], device.rx[1]['datr']),
            (True, device.rx[2]['freq'], device.rx[2]['datr']),
            (tmst + 1000000, device.rx[1]['freq'], device.rx[1]['datr']),
            (tmst + 2000000, device.rx[2]['freq'], device.rx[2]['datr'])
        ]

        result = []
        txpk = self.server._txpkResponse(device,
                                         rxpk.data,
                                         gateway,
                                         tmst,
                                         immediate=True)
        for i in range(1, 3):
            result.append((txpk[i].imme, txpk[i].freq, txpk[i].datr))
        txpk = self.server._txpkResponse(device,
                                         rxpk.data,
                                         gateway,
                                         tmst,
                                         immediate=False)
        for i in range(1, 3):
            result.append((txpk[i].tmst, txpk[i].freq, txpk[i].datr))

        self.assertEqual(expected, result)

    def _processJoinRequest(self, request):
        """Called by test_processJoinRequest_pass and
        test_processJoinRequest_fail"""
        device = self._test_device()
        app = self.server.config.apps[0]

        # Passing join request
        request = base64.b64decode("AA0MCwoNDAsKAwIBAA0ODg9IklIgzCM=")
        msg = lora_mac.MACMessage.decode(request)
        result = yield self.server._processJoinRequest(msg, app, device)

        self.assertTrue(result)

        # Failing join request
        request = base64.b64decode("AA0MCwoNDAsKAwIBAA0ODg9IklIgzCX=")
        msg = lora_mac.MACMessage.decode(request)
        result = yield self.server._processJoinRequest(msg, app, device)

        self.assertFalse(result)