Ejemplo n.º 1
0
    def test_multiple_topics_and_partitions(self):
        rpk = RpkTool(self.redpanda)
        topics = self.topics
        group = "g0"

        for i in range(100):
            payload = str(random.randint(0, 1000))
            for topic_spec in topics:
                for p in range(topic_spec.partition_count):
                    rpk.produce(topic_spec.name,
                                "",
                                payload,
                                partition=p,
                                timeout=5)

        for topic_spec in topics:
            rpk.consume(topic_spec.name,
                        group=group,
                        n=100 * topic_spec.partition_count)

        metrics_offsets = self._get_offset_from_metrics(group)

        partitions_amount = sum(map(lambda x: x.partition_count, topics))
        assert len(metrics_offsets) == partitions_amount
        for topic_spec in topics:
            for i in range(topic_spec.partition_count):
                assert (topic_spec.name, str(i)) in metrics_offsets
                assert metrics_offsets[(topic_spec.name, str(i))] == 100
Ejemplo n.º 2
0
class TopicAutocreateTest(RedpandaTest):
    """
    Verify that autocreation works, and that the settings of an autocreated
    topic match those for a topic created by hand with rpk.
    """
    def __init__(self, test_context):
        super(TopicAutocreateTest, self).__init__(
            test_context=test_context,
            num_brokers=1,
            extra_rp_conf={'auto_create_topics_enabled': False})

        self.kafka_tools = KafkaCliTools(self.redpanda)
        self.rpk = RpkTool(self.redpanda)

    @cluster(num_nodes=1)
    def topic_autocreate_test(self):
        auto_topic = 'autocreated'
        manual_topic = "manuallycreated"

        # With autocreation disabled, producing to a nonexistent topic should not work.
        try:
            # Use rpk rather than kafka CLI because rpk errors out promptly
            self.rpk.produce(auto_topic, "foo", "bar")
        except Exception:
            # The write failed, and shouldn't have created a topic
            assert auto_topic not in self.kafka_tools.list_topics()
        else:
            assert False, "Producing to a nonexistent topic should fail"

        # Enable autocreation
        self.redpanda.restart_nodes(self.redpanda.nodes,
                                    {'auto_create_topics_enabled': True})

        # Auto create topic
        assert auto_topic not in self.kafka_tools.list_topics()
        self.kafka_tools.produce(auto_topic, 1, 4096)
        assert auto_topic in self.kafka_tools.list_topics()
        auto_topic_spec = self.kafka_tools.describe_topic(auto_topic)
        assert auto_topic_spec.retention_ms is None
        assert auto_topic_spec.retention_bytes is None

        # Create topic by hand, compare its properties to the autocreated one
        self.rpk.create_topic(manual_topic)
        manual_topic_spec = self.kafka_tools.describe_topic(auto_topic)
        assert manual_topic_spec.retention_ms == auto_topic_spec.retention_ms
        assert manual_topic_spec.retention_bytes == auto_topic_spec.retention_bytes

        # Clear name and compare the rest of the attributes
        manual_topic_spec.name = auto_topic_spec.name = None
        assert manual_topic_spec == auto_topic_spec
Ejemplo n.º 3
0
    def _ping_pong(self):
        kc = KafkaCat(self.redpanda)
        rpk = RpkTool(self.redpanda)

        payload = str(random.randint(0, 1000))
        start = time.time()
        offset = rpk.produce(self.topic, "tkey", payload, timeout=5)
        consumed = kc.consume_one(self.topic, 0, offset)
        latency = time.time() - start
        self.logger.info(
            f"_ping_pong produced '{payload}' consumed '{consumed}' in {(latency)*1000.0:.2f} ms"
        )
        if consumed['payload'] != payload:
            raise RuntimeError(f"expected '{payload}' got '{consumed}'")
Ejemplo n.º 4
0
    def fetch_long_poll_test(self):
        """
        Test if redpanda is able to debounce fetches when consumer requests
        to wait for data
        """
        partition_count = 20
        total_messages = 10
        topic = TopicSpec(partition_count=partition_count,
                          replication_factor=3)

        # create topic
        self.client().create_topic(specs=topic)
        rpk = RpkTool(self.redpanda)

        consumer = KafkaCliConsumer(self.test_context,
                                    self.redpanda,
                                    topic=topic.name,
                                    group='test-gr-1',
                                    from_beginning=True,
                                    consumer_properties={
                                        'fetch.min.bytes': 1024,
                                        'fetch.max.wait.ms': 1000,
                                    })
        consumer.start()
        for p in range(0, total_messages + 1):
            rpk.produce(topic.name,
                        f"k-{p}",
                        f"v-test-{p}",
                        partition=p % partition_count)
            # sleep for 2 seconds every each message
            # to prevent fetch handler from returning fast
            sleep(2)

        consumer.wait_for_messages(10)
        consumer.stop()
        consumer.wait()
Ejemplo n.º 5
0
    def test_check_value(self):
        rpk = RpkTool(self.redpanda)
        topic = next(filter(lambda x: x.partition_count == 1,
                            self.topics)).name

        for i in range(100):
            payload = str(random.randint(0, 1000))
            offset = rpk.produce(topic, "", payload, timeout=5)

        group_1 = "g1"
        metric_key = (topic, "0")
        for i in range(10):
            rpk.consume(topic, group=group_1, n=10)
            metrics_offsets = self._get_offset_from_metrics(group_1)
            assert metric_key in metrics_offsets
            assert metrics_offsets[metric_key] == (i + 1) * 10

        group_2 = "g2"
        rpk.consume(topic, group=group_2, n=50)
        gr_2_metrics_offsets = self._get_offset_from_metrics(group_2)
        assert metric_key in gr_2_metrics_offsets
        assert gr_2_metrics_offsets[metric_key] == 50

        rpk.group_seek_to_group(group_1, group_2)
        gr_1_metrics_offsets = self._get_offset_from_metrics(group_1)
        assert metric_key in gr_1_metrics_offsets
        assert gr_1_metrics_offsets[metric_key] == 50

        rpk.group_seek_to(group_2, "start")
        gr_2_metrics_offsets = self._get_offset_from_metrics(group_2)
        assert metric_key in gr_2_metrics_offsets
        assert gr_2_metrics_offsets[metric_key] == 0

        self.client().delete_topic(topic)

        def metrics_gone():
            metrics_offsets = self._get_offset_from_metrics(group_1)
            return metrics_offsets is None

        wait_until(metrics_gone, timeout_sec=30, backoff_sec=5)
Ejemplo n.º 6
0
class RpkToolTest(RedpandaTest):
    def __init__(self, ctx):
        super(RpkToolTest, self).__init__(test_context=ctx)
        self._ctx = ctx
        self._rpk = RpkTool(self.redpanda)

    @cluster(num_nodes=3)
    def test_create_topic(self):
        self._rpk.create_topic("topic")

        wait_until(lambda: "topic" in self._rpk.list_topics(),
                   timeout_sec=10,
                   backoff_sec=1,
                   err_msg="Topic never appeared.")

    @cluster(num_nodes=4)
    def test_produce(self):
        topic = 'topic'
        message = 'message'
        key = 'key'
        h_key = 'h_key'
        h_value = 'h_value'
        headers = [h_key + ':' + h_value]

        self._rpk.create_topic(topic)
        self._rpk.produce(topic, key, message, headers)

        c = RpkConsumer(self._ctx, self.redpanda, topic)
        c.start()

        def cond():
            return c.messages is not None \
                and len(c.messages) == 1 \
                and c.messages[0]['value'] == message \
                and c.messages[0]['key'] == key \
                and c.messages[0]['headers'] == [
                    {'key': h_key, 'value': h_value},
                ]

        wait_until(cond,
                   timeout_sec=120,
                   backoff_sec=30,
                   err_msg="Message didn't appear.")

    @cluster(num_nodes=4)
    def test_consume_as_group(self):
        topic = 'topic_group'
        message = 'message'
        key = 'key'
        h_key = 'h_key'
        h_value = 'h_value'
        headers = [h_key + ':' + h_value]

        self._rpk.create_topic(topic)

        c = RpkConsumer(self._ctx, self.redpanda, topic, group='group')
        c.start()

        def cond():
            if c.error:
                raise c.error
            self._rpk.produce(topic, key, message, headers)
            return c.messages \
                and c.messages[0]['value'] == message \
                and c.messages[0]['key'] == key \
                and c.messages[0]['headers'] == [
                    {'key': h_key, 'value': h_value},
                ]

        wait_until(cond,
                   timeout_sec=120,
                   backoff_sec=15,
                   err_msg="Message didn't appear.")

    @cluster(num_nodes=4)
    def test_consume_newest(self):
        topic = 'topic_newest'
        message = 'newest message'
        key = 'key'
        h_key = 'h_key'
        h_value = 'h_value'
        headers = [h_key + ':' + h_value]

        self._rpk.create_topic(topic)

        c = RpkConsumer(self._ctx, self.redpanda, topic, offset='newest')
        c.start()

        def cond():
            if c.error:
                raise c.error
            self._rpk.produce(topic, key, message, headers)
            return c.messages \
                and c.messages[0]['value'] == message \
                and c.messages[0]['key'] == key \
                and c.messages[0]['headers'] == [
                    {'key': h_key, 'value': h_value},
                ]

        wait_until(cond,
                   timeout_sec=150,
                   backoff_sec=30,
                   err_msg="Message didn't appear.")

    @cluster(num_nodes=4)
    def test_consume_oldest(self):
        topic = 'topic'

        n = random.randint(10, 100)
        msgs = {}
        for i in range(n):
            msgs['key-' + str(i)] = 'message-' + str(i)

        self._rpk.create_topic(topic)

        # Produce messages
        for k in msgs:
            self._rpk.produce(topic, k, msgs[k])

        c = RpkConsumer(self._ctx, self.redpanda, topic)
        c.start()

        def cond():
            # Consume from the beginning
            if len(c.messages) != len(msgs):
                return False

            for m in c.messages:
                key = m['key']
                if key is None:
                    return False

                if m['value'] != msgs[key]:
                    return False

            return True

        wait_until(cond,
                   timeout_sec=60,
                   backoff_sec=20,
                   err_msg="Message didn't appear.")

    @cluster(num_nodes=4)
    def test_consume_from_partition(self):
        topic = 'topic_partition'

        n_parts = random.randint(3, 100)
        self._rpk.create_topic(topic, partitions=n_parts)

        n = random.randint(10, 30)
        msgs = {}
        for i in range(n):
            msgs['key-' + str(i)] = 'message-' + str(i)

        part = random.randint(0, n_parts - 1)
        # Produce messages to a random partition
        for k in msgs:
            self._rpk.produce(topic, k, msgs[k], partition=part)

        # Consume from the beginning
        c = RpkConsumer(self._ctx,
                        self.redpanda,
                        topic,
                        offset='oldest',
                        partitions=[part])
        c.start()

        def cond():
            if len(c.messages) != len(msgs):
                return False

            for m in c.messages:
                key = m['key']
                if key is None:
                    return False

                if m['value'] != msgs[key]:
                    return False

            return True

        # timeout loop, but reset the timeout if we appear to be making progress
        retries = 10
        prev_msg_count = len(c.messages)
        while retries > 0:
            self.redpanda.logger.debug(
                f"Message count {len(c.messages)} retries {retries}")
            if cond():
                return
            if len(c.messages) > prev_msg_count:
                prev_msg_count = len(c.messages)
                retries = 10
            time.sleep(1)
            retries -= 1

        raise ducktape.errors.TimeoutError("Message didn't appear")
Ejemplo n.º 7
0
 def _produce(self, topic, msg_cnt):
     rpk = RpkTool(self.redpanda)
     for i in range(0, msg_cnt):
         rpk.produce(topic, f"k-{i}", f"v-{i}")
Ejemplo n.º 8
0
class RpkToolTest(RedpandaTest):
    def __init__(self, ctx):
        super(RpkToolTest, self).__init__(test_context=ctx)
        self._ctx = ctx
        self._rpk = RpkTool(self.redpanda)

    def test_create_topic(self):
        self._rpk.create_topic("topic")

        wait_until(lambda: "topic" in self._rpk.list_topics(),
                   timeout_sec=10,
                   backoff_sec=1,
                   err_msg="Topic never appeared.")

    def test_produce(self):
        topic = 'topic'
        message = 'message'
        key = 'key'
        h_key = 'h_key'
        h_value = 'h_value'
        headers = [h_key + ':' + h_value]

        self._rpk.create_topic(topic)
        self._rpk.produce(topic, key, message, headers)

        c = RpkConsumer(self._ctx, self.redpanda, topic)
        c.start()

        def cond():
            return len(c.messages) == 1 \
                and c.messages[0]['message'] == message \
                and c.messages[0]['key'] == key \
                and c.messages[0]['headers'] == [
                    {'key': h_key, 'value': h_value},
                ]

        wait_until(cond,
                   timeout_sec=30,
                   backoff_sec=2,
                   err_msg="Message didn't appear.")

    def test_consume_as_group(self):
        topic = 'topic_group'
        message = 'message'
        key = 'key'
        h_key = 'h_key'
        h_value = 'h_value'
        headers = [h_key + ':' + h_value]

        self._rpk.create_topic(topic)

        c = RpkConsumer(self._ctx, self.redpanda, topic, group='group')
        c.start()

        def cond():
            if c.error:
                raise c.error
            self._rpk.produce(topic, key, message, headers)
            return c.messages \
                and c.messages[0]['message'] == message \
                and c.messages[0]['key'] == key \
                and c.messages[0]['headers'] == [
                    {'key': h_key, 'value': h_value},
                ]

        wait_until(cond,
                   timeout_sec=30,
                   backoff_sec=8,
                   err_msg="Message didn't appear.")

    def test_consume_newest(self):
        topic = 'topic_newest'
        message = 'message'
        key = 'key'
        h_key = 'h_key'
        h_value = 'h_value'
        headers = [h_key + ':' + h_value]

        self._rpk.create_topic(topic)
        # Gotta sleep to make sure the topic is replicated and the
        # consumer doesn't fail.
        time.sleep(5)

        c = RpkConsumer(self._ctx, self.redpanda, topic, offset='newest')
        c.start()

        def cond():
            if c.error:
                raise c.error
            self._rpk.produce(topic, key, message, headers)
            return c.messages \
                and c.messages[0]['message'] == message \
                and c.messages[0]['key'] == key \
                and c.messages[0]['headers'] == [
                    {'key': h_key, 'value': h_value},
                ]

        wait_until(cond,
                   timeout_sec=30,
                   backoff_sec=8,
                   err_msg="Message didn't appear.")

    def test_consume_oldest(self):
        topic = 'topic'

        n = random.randint(10, 100)
        msgs = {}
        for i in range(n):
            msgs['key-' + str(i)] = 'message-' + str(i)

        # Produce messages
        for k in msgs:
            self._rpk.produce(topic, k, msgs[k])

        c = RpkConsumer(self._ctx, self.redpanda, topic)
        c.start()

        def cond():
            # Consume from the beginning
            if len(c.messages) != len(msgs):
                return False

            for m in c.messages:
                key = m['key']
                if key is None:
                    return False

                if m['message'] != msgs[key]:
                    return False

            return True

        wait_until(cond,
                   timeout_sec=30,
                   backoff_sec=8,
                   err_msg="Message didn't appear.")

    def test_consume_from_partition(self):
        topic = 'topic_partition'

        n_parts = random.randint(3, 100)
        self._rpk.create_topic(topic, partitions=n_parts)

        n = random.randint(10, 30)
        msgs = {}
        for i in range(n):
            msgs['key-' + str(i)] = 'message-' + str(i)

        part = random.randint(0, n_parts)
        # Produce messages to a random partition
        for k in msgs:
            self._rpk.produce(topic, k, msgs[k], partition=part)

        # Consume from the beginning
        c = RpkConsumer(self._ctx,
                        self.redpanda,
                        topic,
                        offset='oldest',
                        partitions=[part])
        c.start()

        def cond():
            if len(c.messages) != len(msgs):
                return False

            for m in c.messages:
                key = m['key']
                if key is None:
                    return False

                if m['message'] != msgs[key]:
                    return False

            return True

        wait_until(cond,
                   timeout_sec=10,
                   backoff_sec=1,
                   err_msg="Message didn't appear.")
Ejemplo n.º 9
0
    def simple_fetch_handler_fairness_test(self, type):
        """
        Testing if when fetching from single node all partitions are 
        returned in round robin fashion
        """
        def multiple_topics(count):
            return [
                TopicSpec(partition_count=1, replication_factor=1)
                for _ in range(count)
            ]

        def multiple_partitions(count):
            return [TopicSpec(partition_count=count, replication_factor=1)]

        number_of_partitions = 32
        records_per_partition = 100
        topics = []

        if type == 'multiple-topics':
            topics = multiple_topics(number_of_partitions)
        else:
            topics = multiple_partitions(number_of_partitions)

        # create topics
        self.client().create_topic(specs=topics)
        self.redpanda.logger.info(f"topics: {topics}")
        rpk = RpkTool(self.redpanda)

        # publish 10 messages to each topic/partition

        for s in topics:
            t = s.name
            for p in range(0, s.partition_count):
                for i in range(0, records_per_partition):
                    self.redpanda.logger.info(f"producing to : {t}/{p}")
                    rpk.produce(t,
                                f"k.{t}.{p}.{i}",
                                f"p.{t}.{p}.{i}",
                                partition=p)

        # configure kcl to fetch at most 1 byte in single fetch request,
        # this way we should receive exactly one record per each partition

        consumed_frequency = defaultdict(lambda: 0)
        kcl = KCL(self.redpanda)

        expected_frequency = records_per_partition / 2
        # issue single kcl command that will generate multiple fetch requests
        # in single fetch session, it should include single partition in each
        # fetch response.
        to_consume = int(number_of_partitions * expected_frequency)
        consumed = kcl.consume(topic="topic-.*",
                               n=to_consume,
                               regex=True,
                               fetch_max_bytes=1,
                               group="test-gr-1")

        for c in consumed.split():
            parts = c.split('.')
            consumed_frequency[(parts[1], parts[2])] += 1

        for p, freq in consumed_frequency.items():
            self.redpanda.logger.info(f"consumed {freq} messages from: {p}")
            # assert that frequency is in expected range
            assert freq <= expected_frequency + 0.1 * expected_frequency
            assert freq >= expected_frequency - 0.1 * expected_frequency