118 lines
3.9 KiB
Python
118 lines
3.9 KiB
Python
"""
|
|
OffsetCommitContext tests.
|
|
"""
|
|
from . import unittest
|
|
|
|
from mock import MagicMock, patch
|
|
|
|
from kafka.common import OffsetOutOfRangeError
|
|
from kafka.context import OffsetCommitContext
|
|
|
|
|
|
class TestOffsetCommitContext(unittest.TestCase):
|
|
"""
|
|
OffsetCommitContext tests.
|
|
"""
|
|
|
|
def setUp(self):
|
|
self.client = MagicMock()
|
|
self.consumer = MagicMock()
|
|
self.topic = "topic"
|
|
self.group = "group"
|
|
self.partition = 0
|
|
self.consumer.topic = self.topic
|
|
self.consumer.group = self.group
|
|
self.consumer.client = self.client
|
|
self.consumer.offsets = {self.partition: 0}
|
|
self.context = OffsetCommitContext(self.consumer)
|
|
|
|
def test_noop(self):
|
|
"""
|
|
Should revert consumer after context exit with no mark() call.
|
|
"""
|
|
with self.context:
|
|
# advance offset
|
|
self.consumer.offsets = {self.partition: 1}
|
|
|
|
# offset restored
|
|
self.assertEqual(self.consumer.offsets, {self.partition: 0})
|
|
# and seek called with relative zero delta
|
|
self.assertEqual(self.consumer.seek.call_count, 1)
|
|
self.assertEqual(self.consumer.seek.call_args[0], (0, 1))
|
|
|
|
def test_mark(self):
|
|
"""
|
|
Should remain at marked location ater context exit.
|
|
"""
|
|
with self.context as context:
|
|
context.mark(self.partition, 0)
|
|
# advance offset
|
|
self.consumer.offsets = {self.partition: 1}
|
|
|
|
# offset sent to client
|
|
self.assertEqual(self.client.send_offset_commit_request.call_count, 1)
|
|
|
|
# offset remains advanced
|
|
self.assertEqual(self.consumer.offsets, {self.partition: 1})
|
|
|
|
# and seek called with relative zero delta
|
|
self.assertEqual(self.consumer.seek.call_count, 1)
|
|
self.assertEqual(self.consumer.seek.call_args[0], (0, 1))
|
|
|
|
def test_mark_multiple(self):
|
|
"""
|
|
Should remain at highest marked location after context exit.
|
|
"""
|
|
with self.context as context:
|
|
context.mark(self.partition, 0)
|
|
context.mark(self.partition, 1)
|
|
context.mark(self.partition, 2)
|
|
# advance offset
|
|
self.consumer.offsets = {self.partition: 3}
|
|
|
|
# offset sent to client
|
|
self.assertEqual(self.client.send_offset_commit_request.call_count, 1)
|
|
|
|
# offset remains advanced
|
|
self.assertEqual(self.consumer.offsets, {self.partition: 3})
|
|
|
|
# and seek called with relative zero delta
|
|
self.assertEqual(self.consumer.seek.call_count, 1)
|
|
self.assertEqual(self.consumer.seek.call_args[0], (0, 1))
|
|
|
|
def test_rollback(self):
|
|
"""
|
|
Should rollback to initial offsets on context exit with exception.
|
|
"""
|
|
with self.assertRaises(Exception):
|
|
with self.context as context:
|
|
context.mark(self.partition, 0)
|
|
# advance offset
|
|
self.consumer.offsets = {self.partition: 1}
|
|
|
|
raise Exception("Intentional failure")
|
|
|
|
# offset rolled back (ignoring mark)
|
|
self.assertEqual(self.consumer.offsets, {self.partition: 0})
|
|
|
|
# and seek called with relative zero delta
|
|
self.assertEqual(self.consumer.seek.call_count, 1)
|
|
self.assertEqual(self.consumer.seek.call_args[0], (0, 1))
|
|
|
|
def test_out_of_range(self):
|
|
"""
|
|
Should reset to beginning of valid offsets on `OffsetOutOfRangeError`
|
|
"""
|
|
def _seek(offset, whence):
|
|
# seek must be called with 0, 0 to find the beginning of the range
|
|
self.assertEqual(offset, 0)
|
|
self.assertEqual(whence, 0)
|
|
# set offsets to something different
|
|
self.consumer.offsets = {self.partition: 100}
|
|
|
|
with patch.object(self.consumer, "seek", _seek):
|
|
with self.context:
|
|
raise OffsetOutOfRangeError()
|
|
|
|
self.assertEqual(self.consumer.offsets, {self.partition: 100})
|