Example #1
0
    def test_stream_group_info(self):
        sa = db.Stream('sa')
        ra1 = sa.add({'k': 'a1'})
        ra2 = sa.add({'k': 'a2'})
        ra3 = sa.add({'k': 'a3'})

        sb = db.Stream('sb')
        rb1 = sb.add({'k': 'b1'})

        sa_info = sa.info()
        self.assertEqual(sa_info['groups'], 0)
        self.assertEqual(sa_info['length'], 3)
        self.assertEqual(sa_info['first-entry'][0], ra1)
        self.assertEqual(sa_info['last-entry'][0], ra3)

        sb_info = sb.info()
        self.assertEqual(sb_info['groups'], 0)
        self.assertEqual(sb_info['length'], 1)
        self.assertEqual(sb_info['first-entry'][0], rb1)
        self.assertEqual(sb_info['last-entry'][0], rb1)

        self.assertEqual(sa.groups_info(), [])
        self.assertEqual(sb.groups_info(), [])

        # Create consumer groups.
        cga = db.consumer_group('cga', ['sa'])
        cga.create()
        cgab = db.consumer_group('cgab', ['sa', 'sb'])
        cgab.create()

        self.assertEqual(sa.info()['groups'], 2)
        self.assertEqual(sb.info()['groups'], 1)

        sa_groups = sa.groups_info()
        self.assertEqual(len(sa_groups), 2)
        self.assertEqual(sorted(g['name'] for g in sa_groups),
                         [b'cga', b'cgab'])

        sb_groups = sb.groups_info()
        self.assertEqual(len(sb_groups), 1)
        self.assertEqual(sb_groups[0]['name'], b'cgab')

        # Verify we can get stream info from the consumer group.
        stream_info = cgab.stream_info()
        self.assertEqual(sorted(stream_info), ['sa', 'sb'])

        # Destroy consumer group?
        cgab.destroy()
        self.assertEqual(len(sa.groups_info()), 1)
        self.assertEqual(len(sb.groups_info()), 0)
Example #2
0
 def test_set_id_stream(self):
     stream = db.Stream('my-stream')
     stream.add({'k': 'v1'}, id='3')
     self.assertTrue(stream.set_id('5'))
     self.assertRaises(Exception, stream.add, {'k': 'v2'}, id='4')
     stream.add({'k': 'v3'}, id='6')
     self.assertEqual(stream.read(), [(b'3-0', {
         b'k': b'v1'
     }), (b'6-0', {
         b'k': b'v3'
     })])
Example #3
0
    def test_basic_apis(self):
        stream = db.Stream('my-stream')

        # Item ids will be 1-0, 11-0, ...91-0.
        item_ids = [
            stream.add({'k': 'v%s' % i}, id='%s1' % i) for i in range(10)
        ]
        self.assertEqual(len(stream), 10)

        # Redis automatically adds the sequence number.
        self.assertEqual(item_ids[:3], [b'1-0', b'11-0', b'21-0'])
        self.assertEqual(item_ids[7:], [b'71-0', b'81-0', b'91-0'])

        def assertData(items, expected):
            self.assertEqual(items, [(item_ids[e], {
                b'k': encode('v%s' % e)
            }) for e in expected])

        # The sequence number is optional if it's zero.
        assertData(stream[:'1'], [0])
        assertData(stream[:'1-0'], [0])
        assertData(stream['91':], [9])
        assertData(stream['91-0':], [9])
        assertData(stream['91-1':], [])

        # We can slice up to a value. If the sequence number is omitted it will
        # be treated as zero.
        assertData(stream[:'31'], [0, 1, 2, 3])
        assertData(stream[:'31-0'], [0, 1, 2, 3])
        assertData(stream[:'31-1'], [0, 1, 2, 3])

        # We can slice up from a value as well.
        assertData(stream['71':], [7, 8, 9])
        assertData(stream['71-0':], [7, 8, 9])
        assertData(stream['71-1':], [8, 9])

        # We can also slice between values.
        assertData(stream['21':'41'], [2, 3, 4])
        assertData(stream['21-0':'41'], [2, 3, 4])
        assertData(stream['21':'41-0'], [2, 3, 4])
        assertData(stream['21-1':'41'], [3, 4])
        assertData(stream['21-1':'41-1'], [3, 4])

        # The "step" parameter, the third part of the slice, indicates count.
        assertData(stream['41'::3], [4, 5, 6])
        assertData(stream[:'41':3], [0, 1, 2])
        assertData(stream['81'::3], [8, 9])

        # Test using in-between values. The endpoints of the slice are
        # inclusive.
        assertData(stream[:'5'], [0])
        assertData(stream[:'5-1'], [0])
        assertData(stream[:'25'], [0, 1, 2])
        assertData(stream[:'25-1'], [0, 1, 2])
        assertData(stream['25':'55'], [3, 4, 5])
        assertData(stream['55':'92'], [6, 7, 8, 9])
        assertData(stream['91':'92'], [9])

        # If we go above or below, it returns an empty list.
        assertData(stream['92':], [])
        assertData(stream[:'0'], [])

        # We can also provide a count when indexing in-between.
        assertData(stream['25':'55':2], [3, 4])
        assertData(stream['55':'92':1], [6])

        # Use "del" to remove items by ID. The sequence number will be treated
        # as zero if not provided.
        del stream['21', '41-0', '61']
        del stream['51-1']  # Has no effect since we only have 51-0.
        assertData(stream['5':'65'], [1, 3, 5])
        self.assertEqual(len(stream), 7)

        del stream['21']  # Can delete non-existent items.

        # Cannot add lower than maximum ID.
        self.assertRaises(Exception, stream.add, {'k': 'v2'}, id='90-1')
        self.assertRaises(Exception, stream.add, {'k': 'v2'}, id='91-0')

        # Adding a "1" to the sequence works:
        new_id = stream.add({'k': 'v10'}, id='91-1')
        self.assertEqual(new_id, b'91-1')

        # Length reflects the latest addition.
        self.assertEqual(len(stream), 8)

        # Range starting at 91-0 yields 91-0 and 91-1.
        data = stream['91-0':]
        self.assertEqual(len(data), 2)
        self.assertEqual([obj_id for obj_id, _ in data], [b'91-0', b'91-1'])

        # Remove the two 91-x items.
        del stream['91', '91-1']

        # Sanity check that the data was really remove.
        self.assertEqual(len(stream), 6)
        assertData(stream['61':], [7, 8])

        # Can we add an item with an id lower than 91? We've deleted it so the
        # last value is 81, but this still doesn't work (?).
        for docid in ('90', '91', '91-1'):
            self.assertRaises(Exception, stream.add, {'k': 'v9'}, id='90')

        new_id = stream.add({'k': 'v9'}, id='91-2')
        self.assertEqual(new_id, b'91-2')
        self.assertEqual(stream['91':], [(b'91-2', {b'k': b'v9'})])
        del stream['91-2']

        nremoved = stream.trim(4, approximate=False)
        self.assertEqual(nremoved, 2)
        assertData(stream[:], [3, 5, 7, 8])

        # Trimming again returns 0, no items removed.
        self.assertEqual(stream.trim(4, approximate=False), 0)

        # Verify we can iterate over the stream.
        assertData(list(stream), [3, 5, 7, 8])

        # Verify we can get items by id.
        d5 = stream.get('51-0')
        self.assertEqual(d5, (b'51-0', {b'k': b'v5'}))

        # Nonexistant values return None.
        self.assertTrue(stream.get('61-0') is None)
Example #4
0
    def test_read_api(self):
        sa = db.Stream('a')
        sb = db.Stream('b')
        sc = db.Stream('c')
        streams = [sa, sb, sc]
        docids = []
        for i in range(20):
            stream = streams[i % 3]
            docids.append(stream.add({'k': 'v%s' % i}, id=i + 1))

        def assertData(ret, idxs):
            accum = {}
            for idx in idxs:
                sname = 'abc'[idx % 3]
                accum.setdefault(sname, [])
                accum[sname].append((docids[idx], {b'k': encode('v%s' % idx)}))
            self.assertEqual(ret, accum)

        assertData(sa.read(), [0, 3, 6, 9, 12, 15, 18])
        assertData(sc.read(), [2, 5, 8, 11, 14, 17])

        # We can specify a maximum number of records via "count".
        assertData(sa.read(3), [0, 3, 6])
        assertData(sb.read(2), [1, 4])
        assertData(sc.read(4), [2, 5, 8, 11])

        # We get the same values we read earlier.
        assertData(sa.read(2), [0, 3])

        # We can pass a minimum ID and will get newer data -- even if the ID
        # does not exist in the stream. We can also pass an exact ID and unlike
        # the range function, it is not inclusive.
        assertData(sa.read(2, last_id=docids[3]), [6, 9])
        assertData(sa.read(2, last_id=docids[4]), [6, 9])

        # If the last ID exceeds the highest ID (indicating no data), None is
        # returned. This is the same whether or not "count" is specified.
        self.assertTrue(sa.read(last_id=docids[18]) is None)
        self.assertTrue(sa.read(2, last_id=docids[18]) is None)

        # The count is a maximum, so up-to 2 items are return -- but since only
        # one item in the stream exceeds the given ID, we only get one result.
        assertData(sa.read(2, last_id=docids[17]), [18])

        # If a timeout is set and any stream can return a value, then that
        # value is returned immediately.
        assertData(sa.read(2, timeout=1, last_id=docids[17]), [18])
        assertData(sb.read(2, timeout=1, last_id=docids[18]), [19])

        # If no items are available and we timed-out, None is returned.
        self.assertTrue(sc.read(timeout=1, last_id=docids[19]) is None)
        self.assertTrue(sc.read(2, timeout=1, last_id=docids[19]) is None)

        # When multiple keys are given, up-to "count" items per stream
        # are returned.
        res = db.xread(keys=['a', 'b', 'c'], count=2)
        assertData(res, [0, 1, 2, 3, 4, 5])

        # Specify max-ids for each stream. The max value in "c" is 17, so
        # nothing will be returned for "c".
        uids = [decode(docid) for docid in docids]
        res = db.xread(key_to_id={
            'a': uids[15],
            'b': uids[16],
            'c': uids[17]
        },
                       count=3)
        assertData(res, [18, 19])

        # Now we limit ourselves to being able to pull only a single item from
        # stream "c".
        res = db.xread(key_to_id={'a': uids[18], 'b': uids[19], 'c': uids[16]})
        assertData(res, [17])

        # None is returned when no results are present and timeout is None or
        # if we reach the timeout.
        res = db.xread(key_to_id={'a': uids[18], 'b': uids[19], 'c': uids[17]})
        self.assertTrue(res is None)

        res = db.xread(key_to_id={
            'a': uids[18],
            'b': uids[19],
            'c': uids[17]
        },
                       count=1,
                       timeout=1)
        self.assertTrue(res is None)