def run_consumer(name, delay): buffer = RingBuffer(name=name, size=0, create=False) shutdown = False def terminate(signum, frame): nonlocal shutdown print( "Received=", signal.Signals(signum).name, "Attempting graceful shutdown of consumer", ) shutdown = True signal.signal(signal.SIGTERM, terminate) signal.signal(signal.SIGINT, terminate) try: while not shutdown: b = buffer.get() print(f"Message: {decode_message(b)}Reader: {buffer.reader_pos()} Writer: {buffer.writer_pos()}") time.sleep(delay) buffer.close() print(f"Destroyed shared memory buffer {name}") except Exception as ex: buffer.close() print(f"Error {str(ex)}. Destroying shared memory buffer and exiting") traceback.print_exc(file=sys.stdout) sys.exit(1)
class RingBufferTests(unittest.TestCase): def setUp(self): self.capacity = 5 self.buffer = RingBuffer(self.capacity) def test_new_buffer_has_appropriate_capacity(self): self.assertEqual(self.buffer.capacity, self.capacity) def test_adding_one_element_to_buffer(self): self.buffer.append('a') self.assertEqual(self.buffer.get(), ['a']) def test_filling_buffer_to_capacity(self): self.buffer.append('a') self.buffer.append('b') self.buffer.append('c') self.buffer.append('d') self.buffer.append('e') self.assertEqual(self.buffer.get(), ['a', 'b', 'c', 'd', 'e']) def test_adding_one_element_to_full_buffer(self): self.buffer.append('a') self.buffer.append('b') self.buffer.append('c') self.buffer.append('d') self.buffer.append('e') self.buffer.append('f') self.assertEqual(self.buffer.get(), ['f', 'b', 'c', 'd', 'e']) def test_adding_many_elements_to_full_buffer(self): self.buffer.append('a') self.buffer.append('b') self.buffer.append('c') self.buffer.append('d') self.buffer.append('e') self.buffer.append('f') self.buffer.append('g') self.buffer.append('h') self.buffer.append('i') self.assertEqual(self.buffer.get(), ['f', 'g', 'h', 'i', 'e']) def test_adding_50_elements_to_buffer(self): for i in range(50): self.buffer.append(i) self.assertEqual(self.buffer.get(), [45, 46, 47, 48, 49])
def test_reader_reads_data_and_moves_offset_when_writer_wraps_around(buffer): read_buff = RingBuffer(name=buffer.name, size=0, create=False) messages = _messages(8) for m in messages[:6]: buffer.put(m) [read_buff.get() for _ in range(6)] for m in messages[6:]: buffer.put(m) got = [_decode_message(read_buff.get()) for _ in range(2)] expected = [_decode_message(m) for m in messages[6:]] assert got == expected assert read_buff.reader_pos() == 32
def test_reader_does_not_go_past_writer_when_writer_wraps_around(buffer): read_buff = RingBuffer(name=buffer.name, size=0, create=False) messages = _messages(8) for m in messages[:6]: buffer.put(m) [read_buff.get() for _ in range(6)] for m in messages[6:7]: buffer.put(m) with pytest.raises(WriterCollisionError) as excinfo: [read_buff.get() for _ in range(2)] assert str( excinfo.value ) == "Writer cursor at 16. Reader cursor attemping to read [16 :32]"
def test_reader_reads_data_and_moves_offset(buffer): read_buff = RingBuffer(name=buffer.name, size=0, create=False) messages = _messages(3) expected = [_decode_message(m) for m in messages] for m in messages: buffer.put(m) got = [_decode_message(read_buff.get()) for _ in range(3)] assert got == expected assert read_buff.reader_pos() == 48
def test_reader_does_not_go_past_writer(buffer): read_buff = RingBuffer(name=buffer.name, size=0, create=False) messages = _messages(3) for m in messages: buffer.put(m) with pytest.raises(WriterCollisionError) as excinfo: [read_buff.get() for _ in range(5)] assert str( excinfo.value ) == "Writer cursor at 48. Reader cursor attemping to read [48 :64]"