def test_valid_wildcard(self):
        channel = channels.ResourceValues(device_id='AB')
        self.assertEqual({
            'channel': 'notifications',
            'ep': ['AB']
        }, channel._route_seeds)

        channel = channels.ResourceValues(device_id=['A', 'B'])
        self.assertEqual({
            'channel': 'notifications',
            'ep': ['A', 'B']
        }, channel._route_seeds)

        channel = channels.ResourceValues(device_id='AB*')
        self.assertEqual({'channel': 'notifications'}, channel._route_seeds)

        channel = channels.ResourceValues(device_id='A',
                                          resource_path='/3/0/1/*')
        self.assertEqual({
            'channel': 'notifications',
            'ep': ['A']
        }, channel._route_seeds)
        self.assertEqual({'path': ['/3/0/1/*']}, channel._local_filters)

        channel = channels.ResourceValues(device_id=['a*', 'b'],
                                          resource_path=['/3/0/1/*', '4/*'])
        self.assertEqual({'channel': 'notifications'}, channel._route_seeds)
        self.assertEqual({
            'ep': ['a*', 'b'],
            'path': ['/3/0/1/*', '4/*']
        }, channel._local_filters)
    def test_parameters_as_lists(self):
        subs = SubscriptionsManager(mock.MagicMock())
        observer_a = subs.subscribe(
            channels.ResourceValues(device_id='a', resource_path=['a', 'b']))
        observer_b = subs.subscribe(
            channels.ResourceValues(device_id=['x', 'y'],
                                    resource_path=['a', 'b']))
        subs.notify({
            channels.ChannelIdentifiers.notifications: [
                # should trigger A
                {
                    'ep': 'a',
                    'path': 'a'
                },
                # should trigger A
                {
                    'ep': 'a',
                    'path': 'b'
                },
                # should trigger B
                {
                    'ep': 'x',
                    'path': 'b'
                },
            ]
        })

        self.assertEqual(2, observer_a.notify_count)
        self.assertEqual(1, observer_b.notify_count)
    def test_invalid_wildcard(self):
        # can't have a wildcard in anything other than last character
        with self.assertRaises(ValueError):
            channels.ResourceValues(device_id='A*B*', resource_path=5)

        with self.assertRaises(ValueError):
            channels.ResourceValues(resource_path=['1', '**/'])
Exemple #4
0
    def test_routing_performance(self):
        subs = SubscriptionsManager(mock.MagicMock())
        sample_id = 42
        sample = None
        # register a bunch of subscribers
        for i in range(1000):
            subs.subscribe(channels.ResourceValues(device_id=i))
            obs = subs.subscribe(channels.ResourceValues(device_id=i, resource_path=['/3/0/*', '/4/0/1']))
            if i == sample_id:
                sample = obs
            subs.subscribe(channels.ResourceValues(**{'device_id': i, str(i): 'abc'}))

        notification_count = 33
        start = timeit.default_timer()
        for i in range(notification_count):
            subs.notify({'notifications': [{'endpoint-name': str(42), 'resource-path': '/3/0/1'}]})
            subs.notify({'notifications': [{'endpoint-name': str(42), 'resource-path': '/3/1'}]})
            subs.notify({'notifications': [{'endpoint-name': str(5), 'resource-path': '/3/1'}]})
        stop = timeit.default_timer()
        duration = stop - start
        self.assertEqual(notification_count, sample.notify_count)

        # mildly contrived, but for cross-machine consistency we need
        # to use a benchmark to compare the lookup performance with
        self.assertLess(duration, 100 * self.bench)
    def test_observable_single(self):
        channel = channels.ResourceValues(device_id="Device1",
                                          resource_path="/10252/0/3")
        # Mock the Connect API to return connected devices and available resources
        channel._api = mock.Mock().method.return_value = FakeConnectAPI()

        self.assertEqual([], channel._matching_device_resources(),
                         "The specified resource was not observable")
    def test_device_no_match(self):
        channel = channels.ResourceValues(device_id="Device",
                                          resource_path="*")
        # Mock the Connect API to return connected devices and available resources
        channel._api = mock.Mock().method.return_value = FakeConnectAPI()

        self.assertEqual([], channel._matching_device_resources(),
                         "'Device' should not match any devices")
    def test_list_device(self):
        channel = channels.ResourceValues(device_id=["Device1", "Device2"],
                                          resource_path="/10252/0/5")
        # Mock the Connect API to return connected devices and available resources
        channel._api = mock.Mock().method.return_value = FakeConnectAPI()

        self.assertEqual(
            [('Device1', '/10252/0/5'), ('Device2', '/10252/0/5')],
            channel._matching_device_resources(),
            "Defining devices as a list should explicitly match device IDs")
    def test_wildcard_resource(self):
        channel = channels.ResourceValues(device_id="Device1",
                                          resource_path="/35011/0*")
        # Mock the Connect API to return connected devices and available resources
        channel._api = mock.Mock().method.return_value = FakeConnectAPI()

        self.assertEqual(
            [('Device1', '/35011/0'), ('Device1', '/35011/0/27002')],
            channel._matching_device_resources(),
            "'/35011/0*' should match all resource beginning '/35011/0'")
    def test_observable_pattern(self):
        channel = channels.ResourceValues(device_id="Device1",
                                          resource_path="/10252/0/*")
        # Mock the Connect API to return connected devices and available resources
        channel._api = mock.Mock().method.return_value = FakeConnectAPI()

        self.assertEqual([
            ('Device1', '/10252/0/5'), ('Device1', '/10252/0/2')
        ], channel._matching_device_resources(
        ), "Only the observable resources beginning '/10252/0/' on Device1 should be returned"
                         )
    def test_observable_list(self):
        channel = channels.ResourceValues(
            device_id="Device1", resource_path=["/10252/0/1", "/10252/0/5"])
        # Mock the Connect API to return connected devices and available resources
        channel._api = mock.Mock().method.return_value = FakeConnectAPI()

        self.assertEqual([
            ('Device1', '/10252/0/5')
        ], channel._matching_device_resources(
        ), "Only the observable resources in the specified list, on Device1 should be returned"
                         )
    def test_wildcard_device(self):
        channel = channels.ResourceValues(
            # device_id=["Device1", "Device2"],
            device_id="Device*",
            resource_path="/10252/0/5")
        # Mock the Connect API to return connected devices and available resources
        channel._api = mock.Mock().method.return_value = FakeConnectAPI()

        self.assertEqual(
            [('Device1', '/10252/0/5'), ('Device2', '/10252/0/5'),
             ('Device3', '/10252/0/5')], channel._matching_device_resources(),
            "'Device*' should not match all devices starting with 'Device'")
    def test_multiple_matches(self):
        channel = channels.ResourceValues(
            device_id=["Device1", "Device*"],
            resource_path=["/35011/0", "/35011*"])
        # Mock the Connect API to return connected devices and available resources
        channel._api = mock.Mock().method.return_value = FakeConnectAPI()

        self.assertEqual(
            [('Device1', '/35011/0'), ('Device1', '/35011/0/27002'),
             ('Device2', '/35011/0'), ('Device2', '/35011/0/27002'),
             ('Device3', '/35011/0'), ('Device3', '/35011/0/27002')],
            channel._matching_device_resources(),
            "Each Device and resource path should be listed once")
    def test_live_device_state_change(self):
        api = ConnectAPI()
        api.delete_presubscriptions()
        d = api.list_connected_devices().first()
        api.delete_device_subscriptions(d.id)
        channel = channels.ResourceValues(device_id=d.id,
                                          resource_path=['/3/0/*'])
        observer = api.subscribe(channel)
        # don't actually care about notifications, we want to see subscriptions
        current_subs = api.list_device_subscriptions(d.id)
        self.assertGreaterEqual(len(current_subs), 3)
        for path in current_subs:
            self.assertIn('/3/0', path)

        channel.stop()
        current_subs = api.list_device_subscriptions(d.id)
        self.assertIsNone(None, current_subs)
    def test_payload(self):
        # subscription to wildcard value should be triggered when receiving specific value
        device_id1 = 'ABCD_E'
        subs = SubscriptionsManager(mock.MagicMock())
        observer_a = subs.subscribe(
            channels.ResourceValues(device_id=device_id1,
                                    resource_path='/10255/0/4'))

        subs.notify({
            channels.ChannelIdentifiers.notifications: [
                {
                    "ct": "application/vnd.oma.lwm2m+tlv",
                    "ep": device_id1,
                    "max-age": 0,
                    "path": "/10255/0/4",
                    "payload": "iAsLSAAIAAAAAAAAAAA=",
                    'unexpected': 'extra',
                },
            ],
        })

        self.assertEqual(1, observer_a.notify_count)
        received_payload = observer_a.next().block(1)

        self.assertEqual(
            received_payload, {
                'ct': 'application/vnd.oma.lwm2m+tlv',
                'device_id': device_id1,
                'max-age': 0,
                'resource_path': '/10255/0/4',
                'payload': {
                    '11': {
                        '0': 0
                    }
                },
                'channel': 'notifications',
                'unexpected': 'extra',
            })