@ohos-ports/confluentinc-kafka-javascript 1.10.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +457 -0
- package/LICENSE.kafkajs +31 -0
- package/LICENSE.node-rdkafka +25 -0
- package/LICENSE.txt +20 -0
- package/README.md +133 -0
- package/binding.gyp +184 -0
- package/build/Release/confluent-kafka-javascript.node +0 -0
- package/build/deps/librdkafka++.so.1 +0 -0
- package/build/deps/librdkafka.Makefile +6 -0
- package/build/deps/librdkafka.so.1 +0 -0
- package/build/deps/librdkafka.target.mk +55 -0
- package/deps/librdkafka/.clang-format +136 -0
- package/deps/librdkafka/.clang-format-cpp +103 -0
- package/deps/librdkafka/.dir-locals.el +10 -0
- package/deps/librdkafka/.formatignore +35 -0
- package/deps/librdkafka/.gdbmacros +19 -0
- package/deps/librdkafka/CHANGELOG.md +2477 -0
- package/deps/librdkafka/CMakeLists.txt +291 -0
- package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
- package/deps/librdkafka/CONFIGURATION.md +212 -0
- package/deps/librdkafka/CONTRIBUTING.md +431 -0
- package/deps/librdkafka/Doxyfile +2375 -0
- package/deps/librdkafka/INTRODUCTION.md +2752 -0
- package/deps/librdkafka/LICENSE +26 -0
- package/deps/librdkafka/LICENSE.cjson +22 -0
- package/deps/librdkafka/LICENSE.crc32c +28 -0
- package/deps/librdkafka/LICENSE.fnv1a +18 -0
- package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
- package/deps/librdkafka/LICENSE.lz4 +26 -0
- package/deps/librdkafka/LICENSE.murmur2 +25 -0
- package/deps/librdkafka/LICENSE.nanopb +22 -0
- package/deps/librdkafka/LICENSE.opentelemetry +203 -0
- package/deps/librdkafka/LICENSE.pycrc +23 -0
- package/deps/librdkafka/LICENSE.queue +31 -0
- package/deps/librdkafka/LICENSE.regexp +5 -0
- package/deps/librdkafka/LICENSE.snappy +36 -0
- package/deps/librdkafka/LICENSE.tinycthread +26 -0
- package/deps/librdkafka/LICENSE.wingetopt +49 -0
- package/deps/librdkafka/LICENSES.txt +625 -0
- package/deps/librdkafka/Makefile +125 -0
- package/deps/librdkafka/README.md +201 -0
- package/deps/librdkafka/README.win32 +26 -0
- package/deps/librdkafka/STATISTICS.md +624 -0
- package/deps/librdkafka/configure +214 -0
- package/deps/librdkafka/configure.self +341 -0
- package/deps/librdkafka/dev-conf.sh +123 -0
- package/deps/librdkafka/lds-gen.py +73 -0
- package/deps/librdkafka/mainpage.doxy +40 -0
- package/deps/librdkafka/mklove/Makefile.base +329 -0
- package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
- package/deps/librdkafka/mklove/modules/configure.base +2484 -0
- package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
- package/deps/librdkafka/mklove/modules/configure.cc +186 -0
- package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
- package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
- package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
- package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
- package/deps/librdkafka/mklove/modules/configure.host +132 -0
- package/deps/librdkafka/mklove/modules/configure.lib +49 -0
- package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
- package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
- package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
- package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
- package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
- package/deps/librdkafka/mklove/modules/configure.pic +16 -0
- package/deps/librdkafka/mklove/modules/configure.socket +20 -0
- package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
- package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
- package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
- package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
- package/deps/librdkafka/service.yml +182 -0
- package/deps/librdkafka/src/CMakeLists.txt +379 -0
- package/deps/librdkafka/src/Makefile +105 -0
- package/deps/librdkafka/src/README.lz4.md +30 -0
- package/deps/librdkafka/src/cJSON.c +3191 -0
- package/deps/librdkafka/src/cJSON.h +306 -0
- package/deps/librdkafka/src/crc32c.c +430 -0
- package/deps/librdkafka/src/crc32c.h +38 -0
- package/deps/librdkafka/src/generate_proto.sh +66 -0
- package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
- package/deps/librdkafka/src/lz4.c +2727 -0
- package/deps/librdkafka/src/lz4.h +842 -0
- package/deps/librdkafka/src/lz4frame.c +2078 -0
- package/deps/librdkafka/src/lz4frame.h +692 -0
- package/deps/librdkafka/src/lz4frame_static.h +47 -0
- package/deps/librdkafka/src/lz4hc.c +1631 -0
- package/deps/librdkafka/src/lz4hc.h +413 -0
- package/deps/librdkafka/src/nanopb/pb.h +917 -0
- package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
- package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
- package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
- package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
- package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
- package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
- package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
- package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
- package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
- package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
- package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
- package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
- package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
- package/deps/librdkafka/src/queue.h +850 -0
- package/deps/librdkafka/src/rd.h +592 -0
- package/deps/librdkafka/src/rdaddr.c +255 -0
- package/deps/librdkafka/src/rdaddr.h +202 -0
- package/deps/librdkafka/src/rdatomic.h +262 -0
- package/deps/librdkafka/src/rdavg.h +260 -0
- package/deps/librdkafka/src/rdavl.c +210 -0
- package/deps/librdkafka/src/rdavl.h +250 -0
- package/deps/librdkafka/src/rdbase64.c +200 -0
- package/deps/librdkafka/src/rdbase64.h +43 -0
- package/deps/librdkafka/src/rdbuf.c +1884 -0
- package/deps/librdkafka/src/rdbuf.h +375 -0
- package/deps/librdkafka/src/rdcrc32.c +114 -0
- package/deps/librdkafka/src/rdcrc32.h +170 -0
- package/deps/librdkafka/src/rddl.c +179 -0
- package/deps/librdkafka/src/rddl.h +43 -0
- package/deps/librdkafka/src/rdendian.h +175 -0
- package/deps/librdkafka/src/rdfloat.h +67 -0
- package/deps/librdkafka/src/rdfnv1a.c +113 -0
- package/deps/librdkafka/src/rdfnv1a.h +35 -0
- package/deps/librdkafka/src/rdgz.c +120 -0
- package/deps/librdkafka/src/rdgz.h +46 -0
- package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
- package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
- package/deps/librdkafka/src/rdhttp.c +831 -0
- package/deps/librdkafka/src/rdhttp.h +101 -0
- package/deps/librdkafka/src/rdinterval.h +177 -0
- package/deps/librdkafka/src/rdkafka.c +7287 -0
- package/deps/librdkafka/src/rdkafka.h +11795 -0
- package/deps/librdkafka/src/rdkafka_admin.c +10165 -0
- package/deps/librdkafka/src/rdkafka_admin.h +658 -0
- package/deps/librdkafka/src/rdkafka_assignment.c +1282 -0
- package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
- package/deps/librdkafka/src/rdkafka_assignor.c +1800 -0
- package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
- package/deps/librdkafka/src/rdkafka_aux.c +409 -0
- package/deps/librdkafka/src/rdkafka_aux.h +174 -0
- package/deps/librdkafka/src/rdkafka_background.c +222 -0
- package/deps/librdkafka/src/rdkafka_broker.c +6736 -0
- package/deps/librdkafka/src/rdkafka_broker.h +851 -0
- package/deps/librdkafka/src/rdkafka_buf.c +543 -0
- package/deps/librdkafka/src/rdkafka_buf.h +1525 -0
- package/deps/librdkafka/src/rdkafka_cert.c +576 -0
- package/deps/librdkafka/src/rdkafka_cert.h +62 -0
- package/deps/librdkafka/src/rdkafka_cgrp.c +8310 -0
- package/deps/librdkafka/src/rdkafka_cgrp.h +589 -0
- package/deps/librdkafka/src/rdkafka_conf.c +5177 -0
- package/deps/librdkafka/src/rdkafka_conf.h +746 -0
- package/deps/librdkafka/src/rdkafka_confval.h +97 -0
- package/deps/librdkafka/src/rdkafka_coord.c +623 -0
- package/deps/librdkafka/src/rdkafka_coord.h +132 -0
- package/deps/librdkafka/src/rdkafka_error.c +228 -0
- package/deps/librdkafka/src/rdkafka_error.h +80 -0
- package/deps/librdkafka/src/rdkafka_event.c +502 -0
- package/deps/librdkafka/src/rdkafka_event.h +126 -0
- package/deps/librdkafka/src/rdkafka_feature.c +898 -0
- package/deps/librdkafka/src/rdkafka_feature.h +104 -0
- package/deps/librdkafka/src/rdkafka_fetcher.c +3820 -0
- package/deps/librdkafka/src/rdkafka_fetcher.h +62 -0
- package/deps/librdkafka/src/rdkafka_header.c +220 -0
- package/deps/librdkafka/src/rdkafka_header.h +76 -0
- package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
- package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
- package/deps/librdkafka/src/rdkafka_int.h +1505 -0
- package/deps/librdkafka/src/rdkafka_interceptor.c +842 -0
- package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
- package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
- package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
- package/deps/librdkafka/src/rdkafka_metadata.c +2347 -0
- package/deps/librdkafka/src/rdkafka_metadata.h +350 -0
- package/deps/librdkafka/src/rdkafka_metadata_cache.c +1183 -0
- package/deps/librdkafka/src/rdkafka_mock.c +4514 -0
- package/deps/librdkafka/src/rdkafka_mock.h +867 -0
- package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1877 -0
- package/deps/librdkafka/src/rdkafka_mock_handlers.c +5255 -0
- package/deps/librdkafka/src/rdkafka_mock_int.h +1005 -0
- package/deps/librdkafka/src/rdkafka_mock_sharegrp.c +1207 -0
- package/deps/librdkafka/src/rdkafka_msg.c +2619 -0
- package/deps/librdkafka/src/rdkafka_msg.h +629 -0
- package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
- package/deps/librdkafka/src/rdkafka_msgset.h +105 -0
- package/deps/librdkafka/src/rdkafka_msgset_reader.c +2099 -0
- package/deps/librdkafka/src/rdkafka_msgset_writer.c +1474 -0
- package/deps/librdkafka/src/rdkafka_offset.c +1565 -0
- package/deps/librdkafka/src/rdkafka_offset.h +150 -0
- package/deps/librdkafka/src/rdkafka_op.c +1219 -0
- package/deps/librdkafka/src/rdkafka_op.h +1065 -0
- package/deps/librdkafka/src/rdkafka_partition.c +5109 -0
- package/deps/librdkafka/src/rdkafka_partition.h +1215 -0
- package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
- package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
- package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
- package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
- package/deps/librdkafka/src/rdkafka_proto.h +739 -0
- package/deps/librdkafka/src/rdkafka_protocol.h +131 -0
- package/deps/librdkafka/src/rdkafka_queue.c +1351 -0
- package/deps/librdkafka/src/rdkafka_queue.h +1235 -0
- package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
- package/deps/librdkafka/src/rdkafka_request.c +7298 -0
- package/deps/librdkafka/src/rdkafka_request.h +761 -0
- package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
- package/deps/librdkafka/src/rdkafka_sasl.c +589 -0
- package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
- package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
- package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1833 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1827 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +52 -0
- package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
- package/deps/librdkafka/src/rdkafka_sasl_scram.c +858 -0
- package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
- package/deps/librdkafka/src/rdkafka_share_acknowledgement.c +1445 -0
- package/deps/librdkafka/src/rdkafka_share_acknowledgement.h +373 -0
- package/deps/librdkafka/src/rdkafka_ssl.c +2235 -0
- package/deps/librdkafka/src/rdkafka_ssl.h +86 -0
- package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4785 -0
- package/deps/librdkafka/src/rdkafka_subscription.c +411 -0
- package/deps/librdkafka/src/rdkafka_telemetry.c +761 -0
- package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
- package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1307 -0
- package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
- package/deps/librdkafka/src/rdkafka_telemetry_encode.c +1309 -0
- package/deps/librdkafka/src/rdkafka_telemetry_encode.h +459 -0
- package/deps/librdkafka/src/rdkafka_timer.c +407 -0
- package/deps/librdkafka/src/rdkafka_timer.h +117 -0
- package/deps/librdkafka/src/rdkafka_topic.c +2382 -0
- package/deps/librdkafka/src/rdkafka_topic.h +369 -0
- package/deps/librdkafka/src/rdkafka_transport.c +1309 -0
- package/deps/librdkafka/src/rdkafka_transport.h +99 -0
- package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
- package/deps/librdkafka/src/rdkafka_txnmgr.c +3256 -0
- package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
- package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
- package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
- package/deps/librdkafka/src/rdlist.c +593 -0
- package/deps/librdkafka/src/rdlist.h +444 -0
- package/deps/librdkafka/src/rdlog.c +89 -0
- package/deps/librdkafka/src/rdlog.h +41 -0
- package/deps/librdkafka/src/rdmap.c +508 -0
- package/deps/librdkafka/src/rdmap.h +492 -0
- package/deps/librdkafka/src/rdmurmur2.c +167 -0
- package/deps/librdkafka/src/rdmurmur2.h +35 -0
- package/deps/librdkafka/src/rdports.c +61 -0
- package/deps/librdkafka/src/rdports.h +38 -0
- package/deps/librdkafka/src/rdposix.h +250 -0
- package/deps/librdkafka/src/rdrand.c +151 -0
- package/deps/librdkafka/src/rdrand.h +72 -0
- package/deps/librdkafka/src/rdregex.c +156 -0
- package/deps/librdkafka/src/rdregex.h +43 -0
- package/deps/librdkafka/src/rdsignal.h +57 -0
- package/deps/librdkafka/src/rdstring.c +645 -0
- package/deps/librdkafka/src/rdstring.h +98 -0
- package/deps/librdkafka/src/rdsysqueue.h +404 -0
- package/deps/librdkafka/src/rdtime.h +356 -0
- package/deps/librdkafka/src/rdtypes.h +86 -0
- package/deps/librdkafka/src/rdunittest.c +564 -0
- package/deps/librdkafka/src/rdunittest.h +232 -0
- package/deps/librdkafka/src/rdunittest_acknowledge.c +1177 -0
- package/deps/librdkafka/src/rdunittest_fetcher.c +1211 -0
- package/deps/librdkafka/src/rdunittest_msgset_errors.c +1521 -0
- package/deps/librdkafka/src/rdvarint.c +134 -0
- package/deps/librdkafka/src/rdvarint.h +165 -0
- package/deps/librdkafka/src/rdwin32.h +382 -0
- package/deps/librdkafka/src/rdxxhash.c +1030 -0
- package/deps/librdkafka/src/rdxxhash.h +328 -0
- package/deps/librdkafka/src/regexp.c +1352 -0
- package/deps/librdkafka/src/regexp.h +41 -0
- package/deps/librdkafka/src/snappy.c +1866 -0
- package/deps/librdkafka/src/snappy.h +62 -0
- package/deps/librdkafka/src/snappy_compat.h +138 -0
- package/deps/librdkafka/src/statistics_schema.json +444 -0
- package/deps/librdkafka/src/tinycthread.c +932 -0
- package/deps/librdkafka/src/tinycthread.h +503 -0
- package/deps/librdkafka/src/tinycthread_extra.c +210 -0
- package/deps/librdkafka/src/tinycthread_extra.h +218 -0
- package/deps/librdkafka/src/win32_config.h +58 -0
- package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
- package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
- package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
- package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
- package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
- package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
- package/deps/librdkafka/src-cpp/Makefile +55 -0
- package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
- package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
- package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
- package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
- package/deps/librdkafka/src-cpp/README.md +16 -0
- package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
- package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
- package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
- package/deps/librdkafka/src-cpp/rdkafkacpp.h +3797 -0
- package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
- package/deps/librdkafka/tests/0000-unittests.c +72 -0
- package/deps/librdkafka/tests/0001-multiobj.c +102 -0
- package/deps/librdkafka/tests/0002-unkpart.c +244 -0
- package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
- package/deps/librdkafka/tests/0004-conf.c +934 -0
- package/deps/librdkafka/tests/0005-order.c +133 -0
- package/deps/librdkafka/tests/0006-symbols.c +163 -0
- package/deps/librdkafka/tests/0007-autotopic.c +136 -0
- package/deps/librdkafka/tests/0008-reqacks.c +179 -0
- package/deps/librdkafka/tests/0009-mock_cluster.c +272 -0
- package/deps/librdkafka/tests/0011-produce_batch.c +753 -0
- package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
- package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
- package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
- package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
- package/deps/librdkafka/tests/0016-client_swname.c +181 -0
- package/deps/librdkafka/tests/0017-compression.c +140 -0
- package/deps/librdkafka/tests/0018-cgrp_term.c +444 -0
- package/deps/librdkafka/tests/0019-list_groups.c +289 -0
- package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
- package/deps/librdkafka/tests/0021-rkt_destroy.c +72 -0
- package/deps/librdkafka/tests/0022-consume_batch.c +331 -0
- package/deps/librdkafka/tests/0025-timers.c +147 -0
- package/deps/librdkafka/tests/0026-consume_pause.c +547 -0
- package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
- package/deps/librdkafka/tests/0029-assign_offset.c +202 -0
- package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
- package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
- package/deps/librdkafka/tests/0033-regex_subscribe.c +536 -0
- package/deps/librdkafka/tests/0034-offset_reset.c +398 -0
- package/deps/librdkafka/tests/0035-api_version.c +73 -0
- package/deps/librdkafka/tests/0036-partial_fetch.c +87 -0
- package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
- package/deps/librdkafka/tests/0038-performance.c +121 -0
- package/deps/librdkafka/tests/0039-event.c +284 -0
- package/deps/librdkafka/tests/0040-io_event.c +257 -0
- package/deps/librdkafka/tests/0041-fetch_max_bytes.c +97 -0
- package/deps/librdkafka/tests/0042-many_topics.c +252 -0
- package/deps/librdkafka/tests/0043-no_connection.c +77 -0
- package/deps/librdkafka/tests/0044-partition_cnt.c +94 -0
- package/deps/librdkafka/tests/0045-subscribe_update.c +1010 -0
- package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
- package/deps/librdkafka/tests/0047-partial_buf_tmout.c +98 -0
- package/deps/librdkafka/tests/0048-partitioner.c +283 -0
- package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
- package/deps/librdkafka/tests/0050-subscribe_adds.c +145 -0
- package/deps/librdkafka/tests/0051-assign_adds.c +126 -0
- package/deps/librdkafka/tests/0052-msg_timestamps.c +238 -0
- package/deps/librdkafka/tests/0053-stats_cb.cpp +527 -0
- package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
- package/deps/librdkafka/tests/0055-producer_latency.c +539 -0
- package/deps/librdkafka/tests/0056-balanced_group_mt.c +315 -0
- package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
- package/deps/librdkafka/tests/0058-log.cpp +123 -0
- package/deps/librdkafka/tests/0059-bsearch.cpp +241 -0
- package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
- package/deps/librdkafka/tests/0061-consumer_lag.cpp +295 -0
- package/deps/librdkafka/tests/0062-stats_event.c +126 -0
- package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
- package/deps/librdkafka/tests/0064-interceptors.c +529 -0
- package/deps/librdkafka/tests/0065-yield.cpp +140 -0
- package/deps/librdkafka/tests/0066-plugins.cpp +143 -0
- package/deps/librdkafka/tests/0067-empty_topic.cpp +151 -0
- package/deps/librdkafka/tests/0068-produce_timeout.c +136 -0
- package/deps/librdkafka/tests/0069-consumer_add_parts.c +119 -0
- package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
- package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
- package/deps/librdkafka/tests/0073-headers.c +381 -0
- package/deps/librdkafka/tests/0074-producev.c +87 -0
- package/deps/librdkafka/tests/0075-retry.c +290 -0
- package/deps/librdkafka/tests/0076-produce_retry.c +452 -0
- package/deps/librdkafka/tests/0077-compaction.c +366 -0
- package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
- package/deps/librdkafka/tests/0079-fork.c +93 -0
- package/deps/librdkafka/tests/0080-admin_ut.c +3095 -0
- package/deps/librdkafka/tests/0081-admin.c +5633 -0
- package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +137 -0
- package/deps/librdkafka/tests/0083-cb_event.c +233 -0
- package/deps/librdkafka/tests/0084-destroy_flags.c +208 -0
- package/deps/librdkafka/tests/0085-headers.cpp +392 -0
- package/deps/librdkafka/tests/0086-purge.c +368 -0
- package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
- package/deps/librdkafka/tests/0089-max_poll_interval.c +511 -0
- package/deps/librdkafka/tests/0090-idempotence.c +171 -0
- package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +295 -0
- package/deps/librdkafka/tests/0092-mixed_msgver.c +103 -0
- package/deps/librdkafka/tests/0093-holb.c +200 -0
- package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +231 -0
- package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
- package/deps/librdkafka/tests/0097-ssl_verify.cpp +674 -0
- package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
- package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
- package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
- package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
- package/deps/librdkafka/tests/0102-static_group_rebalance.c +836 -0
- package/deps/librdkafka/tests/0103-transactions.c +1383 -0
- package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +625 -0
- package/deps/librdkafka/tests/0105-transactions_mock.c +3930 -0
- package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +318 -0
- package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
- package/deps/librdkafka/tests/0109-auto_create_topics.cpp +278 -0
- package/deps/librdkafka/tests/0110-batch_size.cpp +182 -0
- package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
- package/deps/librdkafka/tests/0112-assign_unknown_part.c +87 -0
- package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3473 -0
- package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
- package/deps/librdkafka/tests/0115-producer_auth.cpp +182 -0
- package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +216 -0
- package/deps/librdkafka/tests/0117-mock_errors.c +331 -0
- package/deps/librdkafka/tests/0118-commit_rebalance.c +154 -0
- package/deps/librdkafka/tests/0119-consumer_auth.cpp +167 -0
- package/deps/librdkafka/tests/0120-asymmetric_subscription.c +185 -0
- package/deps/librdkafka/tests/0121-clusterid.c +115 -0
- package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
- package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
- package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
- package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
- package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +1164 -0
- package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
- package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +217 -0
- package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +79 -0
- package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
- package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
- package/deps/librdkafka/tests/0132-strategy_ordering.c +179 -0
- package/deps/librdkafka/tests/0133-ssl_keys.c +150 -0
- package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
- package/deps/librdkafka/tests/0135-sasl_credentials.cpp +279 -0
- package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
- package/deps/librdkafka/tests/0137-barrier_batch_consume.c +752 -0
- package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
- package/deps/librdkafka/tests/0139-offset_validation_mock.c +950 -0
- package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
- package/deps/librdkafka/tests/0142-reauthentication.c +931 -0
- package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +552 -0
- package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
- package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
- package/deps/librdkafka/tests/0146-metadata_mock.c +505 -0
- package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +1210 -0
- package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +569 -0
- package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
- package/deps/librdkafka/tests/0150-telemetry_mock.c +651 -0
- package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
- package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
- package/deps/librdkafka/tests/0153-memberid.c +128 -0
- package/deps/librdkafka/tests/0155-share_group_heartbeat_mock.c +2695 -0
- package/deps/librdkafka/tests/0156-share_consumer_fetch_mock.c +1551 -0
- package/deps/librdkafka/tests/0157-share_consumer_ack_mock.c +1788 -0
- package/deps/librdkafka/tests/0158-share_consumer_transactions_mock.c +467 -0
- package/deps/librdkafka/tests/0170-share_consumer_subscription.c +2192 -0
- package/deps/librdkafka/tests/0171-share_consumer_consume.c +2150 -0
- package/deps/librdkafka/tests/0172-share_consumer_acknowledge.c +1919 -0
- package/deps/librdkafka/tests/0173-share_consumer_commit_async.c +2735 -0
- package/deps/librdkafka/tests/0174-share_consumer_concurrency.c +1434 -0
- package/deps/librdkafka/tests/0175-share_consumer_groups.c +574 -0
- package/deps/librdkafka/tests/0176-share_consumer_commit_sync.c +2986 -0
- package/deps/librdkafka/tests/0177-share_consumer_transactions.c +1815 -0
- package/deps/librdkafka/tests/0178-share_consumer_close.c +2102 -0
- package/deps/librdkafka/tests/0179-share_consumer_destroy.c +2482 -0
- package/deps/librdkafka/tests/0180-share_consumer_config.c +1677 -0
- package/deps/librdkafka/tests/0181-share_consumer_topic_delete.c +354 -0
- package/deps/librdkafka/tests/0182-share_consumer_error_handling_mock.c +3358 -0
- package/deps/librdkafka/tests/0183-share_consumer_leader_change_mock.c +1234 -0
- package/deps/librdkafka/tests/0184-share_consumer_topic_recreate.c +1356 -0
- package/deps/librdkafka/tests/0185-share_consumer_max_poll_interval.c +557 -0
- package/deps/librdkafka/tests/0186-share_consumer_fatal_error.c +360 -0
- package/deps/librdkafka/tests/0190-share_consumer_telemetry.c +387 -0
- package/deps/librdkafka/tests/1000-unktopic.c +164 -0
- package/deps/librdkafka/tests/8000-idle.cpp +60 -0
- package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
- package/deps/librdkafka/tests/CMakeLists.txt +193 -0
- package/deps/librdkafka/tests/LibrdkafkaTestApp.py +291 -0
- package/deps/librdkafka/tests/Makefile +182 -0
- package/deps/librdkafka/tests/README.md +514 -0
- package/deps/librdkafka/tests/autotest.sh +33 -0
- package/deps/librdkafka/tests/backtrace.gdb +30 -0
- package/deps/librdkafka/tests/broker_version_tests.py +315 -0
- package/deps/librdkafka/tests/buildbox.sh +17 -0
- package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
- package/deps/librdkafka/tests/cluster_testing.py +203 -0
- package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
- package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
- package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
- package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
- package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
- package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +50 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.key +46 -0
- package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +168 -0
- package/deps/librdkafka/tests/fuzzers/Makefile +12 -0
- package/deps/librdkafka/tests/fuzzers/README.md +31 -0
- package/deps/librdkafka/tests/fuzzers/fuzz_regex.c +74 -0
- package/deps/librdkafka/tests/fuzzers/helpers.h +90 -0
- package/deps/librdkafka/tests/gen-ssl-certs.sh +165 -0
- package/deps/librdkafka/tests/interactive_broker_version.py +170 -0
- package/deps/librdkafka/tests/interceptor_test/CMakeLists.txt +16 -0
- package/deps/librdkafka/tests/interceptor_test/Makefile +22 -0
- package/deps/librdkafka/tests/interceptor_test/interceptor_test.c +314 -0
- package/deps/librdkafka/tests/interceptor_test/interceptor_test.h +54 -0
- package/deps/librdkafka/tests/java/IncrementalRebalanceCli.java +97 -0
- package/deps/librdkafka/tests/java/Makefile +13 -0
- package/deps/librdkafka/tests/java/Murmur2Cli.java +46 -0
- package/deps/librdkafka/tests/java/README.md +14 -0
- package/deps/librdkafka/tests/java/TransactionProducerCli.java +162 -0
- package/deps/librdkafka/tests/java/run-class.sh +11 -0
- package/deps/librdkafka/tests/librdkafka.suppressions +483 -0
- package/deps/librdkafka/tests/lz4_manual_test.sh +59 -0
- package/deps/librdkafka/tests/multi-broker-version-test.sh +50 -0
- package/deps/librdkafka/tests/parse-refcnt.sh +43 -0
- package/deps/librdkafka/tests/performance_plot.py +115 -0
- package/deps/librdkafka/tests/plugin_test/Makefile +19 -0
- package/deps/librdkafka/tests/plugin_test/plugin_test.c +58 -0
- package/deps/librdkafka/tests/requirements.txt +2 -0
- package/deps/librdkafka/tests/run-all-tests.sh +81 -0
- package/deps/librdkafka/tests/run-consumer-tests.sh +16 -0
- package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
- package/deps/librdkafka/tests/run-test-batches.py +157 -0
- package/deps/librdkafka/tests/run-test.sh +141 -0
- package/deps/librdkafka/tests/rusage.c +249 -0
- package/deps/librdkafka/tests/sasl_test.py +289 -0
- package/deps/librdkafka/tests/scenarios/README.md +6 -0
- package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
- package/deps/librdkafka/tests/scenarios/default.json +5 -0
- package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
- package/deps/librdkafka/tests/share_telemetry_verify/share-otel-collector-config.yaml +28 -0
- package/deps/librdkafka/tests/sockem.c +801 -0
- package/deps/librdkafka/tests/sockem.h +85 -0
- package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
- package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
- package/deps/librdkafka/tests/test.c +8376 -0
- package/deps/librdkafka/tests/test.conf.example +27 -0
- package/deps/librdkafka/tests/test.h +1150 -0
- package/deps/librdkafka/tests/testcpp.cpp +131 -0
- package/deps/librdkafka/tests/testcpp.h +388 -0
- package/deps/librdkafka/tests/testshared.h +416 -0
- package/deps/librdkafka/tests/tools/README.md +4 -0
- package/deps/librdkafka/tests/tools/stats/README.md +21 -0
- package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
- package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
- package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
- package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
- package/deps/librdkafka/tests/trivup/trivup-0.15.0.tar.gz +0 -0
- package/deps/librdkafka/tests/until-fail.sh +87 -0
- package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
- package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
- package/deps/librdkafka/vcpkg.json +23 -0
- package/deps/librdkafka/win32/README.md +5 -0
- package/deps/librdkafka/win32/build-package.bat +3 -0
- package/deps/librdkafka/win32/build.bat +19 -0
- package/deps/librdkafka/win32/common.vcxproj +84 -0
- package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
- package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
- package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
- package/deps/librdkafka/win32/librdkafka.sln +226 -0
- package/deps/librdkafka/win32/librdkafka.vcxproj +282 -0
- package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
- package/deps/librdkafka/win32/msbuild.ps1 +58 -0
- package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
- package/deps/librdkafka/win32/package-zip.ps1 +46 -0
- package/deps/librdkafka/win32/packages/repositories.config +4 -0
- package/deps/librdkafka/win32/push-package.bat +4 -0
- package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
- package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
- package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
- package/deps/librdkafka/win32/setup-msys2.ps1 +47 -0
- package/deps/librdkafka/win32/setup-vcpkg.ps1 +34 -0
- package/deps/librdkafka/win32/tests/test.conf.example +25 -0
- package/deps/librdkafka/win32/tests/tests.vcxproj +278 -0
- package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
- package/deps/librdkafka/win32/wingetopt.c +564 -0
- package/deps/librdkafka/win32/wingetopt.h +101 -0
- package/deps/librdkafka/win32/wintime.h +33 -0
- package/deps/librdkafka.gyp +83 -0
- package/deps/windows-install.py +80 -0
- package/index.d.ts +3 -0
- package/lib/admin.js +732 -0
- package/lib/client.js +679 -0
- package/lib/error.js +501 -0
- package/lib/index.js +8 -0
- package/lib/kafka-consumer-stream.js +399 -0
- package/lib/kafka-consumer.js +798 -0
- package/lib/kafkajs/_admin.js +1052 -0
- package/lib/kafkajs/_common.js +887 -0
- package/lib/kafkajs/_consumer.js +2156 -0
- package/lib/kafkajs/_consumer_cache.js +310 -0
- package/lib/kafkajs/_error.js +298 -0
- package/lib/kafkajs/_kafka.js +125 -0
- package/lib/kafkajs/_linked-list.js +220 -0
- package/lib/kafkajs/_producer.js +863 -0
- package/lib/kafkajs/index.js +5 -0
- package/lib/producer/high-level-producer.js +400 -0
- package/lib/producer-stream.js +337 -0
- package/lib/producer.js +405 -0
- package/lib/rdkafka.js +44 -0
- package/lib/tools/ref-counter.js +53 -0
- package/lib/topic-partition.js +91 -0
- package/lib/topic.js +43 -0
- package/lib/util.js +55 -0
- package/librdkafka.js +12 -0
- package/package.json +85 -0
- package/shim/source_location +54 -0
- package/src/admin.cc +1597 -0
- package/src/admin.h +112 -0
- package/src/binding.cc +76 -0
- package/src/binding.h +25 -0
- package/src/callbacks.cc +676 -0
- package/src/callbacks.h +302 -0
- package/src/common.cc +1628 -0
- package/src/common.h +192 -0
- package/src/config.cc +219 -0
- package/src/config.h +61 -0
- package/src/connection.cc +703 -0
- package/src/connection.h +117 -0
- package/src/errors.cc +119 -0
- package/src/errors.h +60 -0
- package/src/kafka-consumer.cc +1539 -0
- package/src/kafka-consumer.h +147 -0
- package/src/producer.cc +917 -0
- package/src/producer.h +124 -0
- package/src/topic.cc +173 -0
- package/src/topic.h +54 -0
- package/src/workers.cc +1714 -0
- package/src/workers.h +690 -0
- package/types/config.d.ts +1269 -0
- package/types/errors.d.ts +373 -0
- package/types/kafkajs.d.ts +568 -0
- package/types/rdkafka.d.ts +571 -0
- package/util/configure.js +32 -0
- package/util/generate-docs.sh +18 -0
- package/util/get-env.js +6 -0
- package/util/test-compile.js +11 -0
- package/util/test-producer-delivery.js +100 -0
|
@@ -0,0 +1,1919 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* librdkafka - Apache Kafka C library
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025, Confluent Inc.
|
|
5
|
+
* All rights reserved.
|
|
6
|
+
*
|
|
7
|
+
* Redistribution and use in source and binary forms, with or without
|
|
8
|
+
* modification, are permitted provided that the following conditions are met:
|
|
9
|
+
*
|
|
10
|
+
* 1. Redistributions of source code must retain the above copyright notice,
|
|
11
|
+
* this list of conditions and the following disclaimer.
|
|
12
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
* this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
* and/or other materials provided with the distribution.
|
|
15
|
+
*
|
|
16
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
17
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
18
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
19
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
20
|
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
21
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
22
|
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
23
|
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
24
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
25
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
26
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
#include "test.h"
|
|
30
|
+
|
|
31
|
+
/** Common producer reused across all tests. */
|
|
32
|
+
static rd_kafka_t *common_producer;
|
|
33
|
+
|
|
34
|
+
/** Common admin client reused across all tests. */
|
|
35
|
+
static rd_kafka_t *common_admin;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @brief Share consumer acknowledge API integration tests.
|
|
39
|
+
*
|
|
40
|
+
* Tests the acknowledge APIs (ACCEPT, REJECT, RELEASE) with real/mock broker.
|
|
41
|
+
*
|
|
42
|
+
* Expected Behavior:
|
|
43
|
+
* - RELEASE: Records redelivered to the same or another consumer in the same
|
|
44
|
+
* group.
|
|
45
|
+
* - REJECT: NOT redelivered
|
|
46
|
+
* - ACCEPT: Records committed, NOT redelivered
|
|
47
|
+
*
|
|
48
|
+
* All tests use share.acknowledgement.mode = "explicit"
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
#define MAX_TOPICS 16
|
|
52
|
+
#define MAX_PARTITIONS 8
|
|
53
|
+
#define MAX_CONSUMERS 4
|
|
54
|
+
#define MAX_MSGS_PER_PART 100
|
|
55
|
+
#define BATCH_SIZE 10000
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @brief Test configuration structure
|
|
59
|
+
*/
|
|
60
|
+
typedef struct {
|
|
61
|
+
const char *test_name;
|
|
62
|
+
int topic_cnt;
|
|
63
|
+
int partitions[MAX_TOPICS];
|
|
64
|
+
int msgs_per_partition;
|
|
65
|
+
int consumer_cnt;
|
|
66
|
+
int poll_timeout_ms;
|
|
67
|
+
int max_attempts;
|
|
68
|
+
int total_msgs;
|
|
69
|
+
rd_bool_t use_random_acks; /**< Generate random acks at runtime */
|
|
70
|
+
rd_kafka_share_AcknowledgeType_t
|
|
71
|
+
single_ack_type; /**< Ack type when not using random */
|
|
72
|
+
} ack_test_config_t;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @brief Test state structure
|
|
76
|
+
*/
|
|
77
|
+
typedef struct {
|
|
78
|
+
rd_kafka_share_t *consumers[MAX_CONSUMERS];
|
|
79
|
+
char *topic_names[MAX_TOPICS];
|
|
80
|
+
int64_t original_offsets[1000];
|
|
81
|
+
int original_cnt;
|
|
82
|
+
rd_kafka_topic_partition_list_t *released_msgs; /**< RELEASE'd msgs */
|
|
83
|
+
rd_kafka_topic_partition_list_t
|
|
84
|
+
*redelivered_msgs; /**< Redelivered msgs */
|
|
85
|
+
int msgs_produced;
|
|
86
|
+
int msgs_consumed;
|
|
87
|
+
int msgs_redelivered;
|
|
88
|
+
char group_name[300];
|
|
89
|
+
/* Random mode counters */
|
|
90
|
+
int msgs_accepted;
|
|
91
|
+
int msgs_rejected;
|
|
92
|
+
int msgs_released;
|
|
93
|
+
} ack_test_state_t;
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @brief Generate random ack type with roughly equal distribution
|
|
98
|
+
*/
|
|
99
|
+
static rd_kafka_share_AcknowledgeType_t get_random_ack_type(void) {
|
|
100
|
+
return (rd_kafka_share_AcknowledgeType_t)jitter(1, 3);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @brief Create topics and produce messages
|
|
105
|
+
*/
|
|
106
|
+
static void setup_topics_and_produce(ack_test_config_t *config,
|
|
107
|
+
ack_test_state_t *state) {
|
|
108
|
+
int t, p;
|
|
109
|
+
int msgs_per_partition;
|
|
110
|
+
int total_partitions = 0;
|
|
111
|
+
|
|
112
|
+
state->msgs_produced = 0;
|
|
113
|
+
|
|
114
|
+
/* Calculate msgs_per_partition based on mode */
|
|
115
|
+
if (config->use_random_acks && config->total_msgs > 0) {
|
|
116
|
+
for (t = 0; t < config->topic_cnt; t++)
|
|
117
|
+
total_partitions += config->partitions[t];
|
|
118
|
+
msgs_per_partition = config->total_msgs / total_partitions;
|
|
119
|
+
} else {
|
|
120
|
+
msgs_per_partition = config->msgs_per_partition;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for (t = 0; t < config->topic_cnt; t++) {
|
|
124
|
+
state->topic_names[t] =
|
|
125
|
+
rd_strdup(test_mk_topic_name("0172-ack-test", 1));
|
|
126
|
+
|
|
127
|
+
test_create_topic_wait_exists(NULL, state->topic_names[t],
|
|
128
|
+
config->partitions[t], -1,
|
|
129
|
+
60 * 1000);
|
|
130
|
+
|
|
131
|
+
for (p = 0; p < config->partitions[t]; p++) {
|
|
132
|
+
test_produce_msgs_simple(common_producer,
|
|
133
|
+
state->topic_names[t], p,
|
|
134
|
+
msgs_per_partition);
|
|
135
|
+
state->msgs_produced += msgs_per_partition;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
TEST_SAY("Topic '%s': %d partition(s), %d msgs/partition\n",
|
|
139
|
+
state->topic_names[t], config->partitions[t],
|
|
140
|
+
msgs_per_partition);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
TEST_SAY("Produced %d messages total\n", state->msgs_produced);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @brief Subscribe consumers to topics
|
|
148
|
+
*/
|
|
149
|
+
static void subscribe_consumers(ack_test_config_t *config,
|
|
150
|
+
ack_test_state_t *state) {
|
|
151
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
152
|
+
int t, i;
|
|
153
|
+
|
|
154
|
+
test_share_set_auto_offset_reset(state->group_name, "earliest");
|
|
155
|
+
|
|
156
|
+
subs = rd_kafka_topic_partition_list_new(config->topic_cnt);
|
|
157
|
+
for (t = 0; t < config->topic_cnt; t++) {
|
|
158
|
+
rd_kafka_topic_partition_list_add(subs, state->topic_names[t],
|
|
159
|
+
RD_KAFKA_PARTITION_UA);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
for (i = 0; i < config->consumer_cnt; i++) {
|
|
163
|
+
rd_kafka_share_subscribe(state->consumers[i], subs);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
167
|
+
|
|
168
|
+
TEST_SAY("Subscribed %d consumer(s) to %d topic(s)\n",
|
|
169
|
+
config->consumer_cnt, config->topic_cnt);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @brief Find message index in list by topic+partition+offset
|
|
174
|
+
* @returns Index if found, -1 otherwise
|
|
175
|
+
*/
|
|
176
|
+
static int find_message_in_list(rd_kafka_topic_partition_list_t *list,
|
|
177
|
+
const char *topic,
|
|
178
|
+
int32_t partition,
|
|
179
|
+
int64_t offset) {
|
|
180
|
+
int i;
|
|
181
|
+
for (i = 0; i < list->cnt; i++) {
|
|
182
|
+
rd_kafka_topic_partition_t *elem = &list->elems[i];
|
|
183
|
+
if (strcmp(elem->topic, topic) == 0 &&
|
|
184
|
+
elem->partition == partition && elem->offset == offset)
|
|
185
|
+
return i;
|
|
186
|
+
}
|
|
187
|
+
return -1;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @brief Remove message from list by index (swap with last element)
|
|
192
|
+
*/
|
|
193
|
+
static void remove_message_from_list_at(rd_kafka_topic_partition_list_t *list,
|
|
194
|
+
int idx) {
|
|
195
|
+
if (idx < 0 || idx >= list->cnt)
|
|
196
|
+
return;
|
|
197
|
+
|
|
198
|
+
/* Free the topic string being removed */
|
|
199
|
+
rd_free(list->elems[idx].topic);
|
|
200
|
+
|
|
201
|
+
/* Swap with last element and decrement count */
|
|
202
|
+
if (idx < list->cnt - 1) {
|
|
203
|
+
list->elems[idx] = list->elems[list->cnt - 1];
|
|
204
|
+
/* Null out the moved element to prevent double-free */
|
|
205
|
+
list->elems[list->cnt - 1].topic = NULL;
|
|
206
|
+
}
|
|
207
|
+
list->cnt--;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @brief Handle a redelivered message (delivery_count == 2).
|
|
212
|
+
*
|
|
213
|
+
* Verifies the message was previously RELEASE'd (in released_msgs),
|
|
214
|
+
* removes it from released_msgs, and acknowledges as ACCEPT.
|
|
215
|
+
*/
|
|
216
|
+
static void handle_redelivered_message(ack_test_state_t *state,
|
|
217
|
+
rd_kafka_message_t *msg) {
|
|
218
|
+
int released_idx;
|
|
219
|
+
|
|
220
|
+
released_idx = find_message_in_list(state->released_msgs,
|
|
221
|
+
rd_kafka_topic_name(msg->rkt),
|
|
222
|
+
msg->partition, msg->offset);
|
|
223
|
+
|
|
224
|
+
TEST_ASSERT(released_idx >= 0,
|
|
225
|
+
"Redelivered message (delivery_count=2) not found in "
|
|
226
|
+
"released_msgs: topic=%s, partition=%d, offset=%" PRId64,
|
|
227
|
+
rd_kafka_topic_name(msg->rkt), msg->partition, msg->offset);
|
|
228
|
+
|
|
229
|
+
remove_message_from_list_at(state->released_msgs, released_idx);
|
|
230
|
+
state->msgs_redelivered++;
|
|
231
|
+
|
|
232
|
+
rd_kafka_share_acknowledge_type(state->consumers[0], msg,
|
|
233
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @brief Determine ack type based on config.
|
|
238
|
+
*/
|
|
239
|
+
static rd_kafka_share_AcknowledgeType_t
|
|
240
|
+
determine_ack_type(ack_test_config_t *config) {
|
|
241
|
+
if (config->use_random_acks)
|
|
242
|
+
return get_random_ack_type();
|
|
243
|
+
return config->single_ack_type;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @brief Track ack type in state and add to released list if RELEASE.
|
|
248
|
+
*/
|
|
249
|
+
static void track_ack_type(ack_test_state_t *state,
|
|
250
|
+
rd_kafka_message_t *msg,
|
|
251
|
+
rd_kafka_share_AcknowledgeType_t ack_type) {
|
|
252
|
+
if (ack_type == RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_RELEASE) {
|
|
253
|
+
rd_kafka_topic_partition_t *rktpar;
|
|
254
|
+
rktpar = rd_kafka_topic_partition_list_add(
|
|
255
|
+
state->released_msgs, rd_kafka_topic_name(msg->rkt),
|
|
256
|
+
msg->partition);
|
|
257
|
+
rktpar->offset = msg->offset;
|
|
258
|
+
state->msgs_released++;
|
|
259
|
+
} else if (ack_type == RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT) {
|
|
260
|
+
state->msgs_accepted++;
|
|
261
|
+
} else {
|
|
262
|
+
state->msgs_rejected++;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @brief Consume messages and apply acknowledgements based on config
|
|
268
|
+
*/
|
|
269
|
+
static void consume_and_acknowledge(ack_test_config_t *config,
|
|
270
|
+
ack_test_state_t *state) {
|
|
271
|
+
rd_kafka_messages_t *batch = NULL;
|
|
272
|
+
int poll_timeout =
|
|
273
|
+
config->poll_timeout_ms > 0 ? config->poll_timeout_ms : 3000;
|
|
274
|
+
int attempts = config->max_attempts > 0 ? config->max_attempts : 50;
|
|
275
|
+
size_t total_consumed = 0;
|
|
276
|
+
|
|
277
|
+
if (config->use_random_acks) {
|
|
278
|
+
poll_timeout = 5000;
|
|
279
|
+
attempts = 200 + (config->total_msgs / 1000) * 50;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
state->original_cnt = 0;
|
|
283
|
+
state->msgs_consumed = 0;
|
|
284
|
+
state->msgs_accepted = 0;
|
|
285
|
+
state->msgs_rejected = 0;
|
|
286
|
+
state->msgs_released = 0;
|
|
287
|
+
state->msgs_redelivered = 0;
|
|
288
|
+
|
|
289
|
+
TEST_SAY("Consuming %d messages%s...\n", state->msgs_produced,
|
|
290
|
+
config->use_random_acks ? " with random acks" : "");
|
|
291
|
+
|
|
292
|
+
while ((int)total_consumed < state->msgs_produced && attempts-- > 0) {
|
|
293
|
+
size_t rcvd = 0;
|
|
294
|
+
size_t m;
|
|
295
|
+
rd_kafka_error_t *err;
|
|
296
|
+
|
|
297
|
+
err = rd_kafka_share_poll(state->consumers[0], poll_timeout,
|
|
298
|
+
&batch);
|
|
299
|
+
if (err) {
|
|
300
|
+
rd_kafka_error_destroy(err);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
304
|
+
|
|
305
|
+
for (m = 0; m < rcvd; m++) {
|
|
306
|
+
rd_kafka_message_t *msg =
|
|
307
|
+
rd_kafka_messages_get(batch, m);
|
|
308
|
+
rd_kafka_share_AcknowledgeType_t ack_type;
|
|
309
|
+
rd_kafka_resp_err_t ack_err;
|
|
310
|
+
int16_t delivery_count =
|
|
311
|
+
rd_kafka_message_delivery_count(msg);
|
|
312
|
+
|
|
313
|
+
/* Error messages must use acknowledge_offset API */
|
|
314
|
+
if (msg->err) {
|
|
315
|
+
ack_type = determine_ack_type(config);
|
|
316
|
+
ack_err = rd_kafka_share_acknowledge_offset(
|
|
317
|
+
state->consumers[0],
|
|
318
|
+
rd_kafka_topic_name(msg->rkt),
|
|
319
|
+
msg->partition, msg->offset, ack_type);
|
|
320
|
+
TEST_ASSERT(
|
|
321
|
+
ack_err == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
322
|
+
"acknowledge_offset failed for error msg: "
|
|
323
|
+
"%s",
|
|
324
|
+
rd_kafka_err2str(ack_err));
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/* Redelivered message (delivery_count == 2) */
|
|
329
|
+
if (delivery_count == 2) {
|
|
330
|
+
handle_redelivered_message(state, msg);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/* First delivery */
|
|
335
|
+
TEST_ASSERT(delivery_count == 1,
|
|
336
|
+
"Expected delivery_count=1, got %d",
|
|
337
|
+
delivery_count);
|
|
338
|
+
|
|
339
|
+
ack_type = determine_ack_type(config);
|
|
340
|
+
track_ack_type(state, msg, ack_type);
|
|
341
|
+
|
|
342
|
+
ack_err = rd_kafka_share_acknowledge_type(
|
|
343
|
+
state->consumers[0], msg, ack_type);
|
|
344
|
+
TEST_ASSERT(
|
|
345
|
+
ack_err == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
346
|
+
"Acknowledge failed: %s (topic=%s, partition=%d, "
|
|
347
|
+
"offset=%" PRId64 ", type=%d)",
|
|
348
|
+
rd_kafka_err2str(ack_err),
|
|
349
|
+
rd_kafka_topic_name(msg->rkt), msg->partition,
|
|
350
|
+
msg->offset, ack_type);
|
|
351
|
+
|
|
352
|
+
if (state->original_cnt < 1000)
|
|
353
|
+
state->original_offsets[state->original_cnt++] =
|
|
354
|
+
msg->offset;
|
|
355
|
+
|
|
356
|
+
total_consumed++;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
rd_kafka_messages_destroy(batch);
|
|
360
|
+
batch = NULL;
|
|
361
|
+
|
|
362
|
+
if (config->use_random_acks) {
|
|
363
|
+
if (total_consumed % 500 == 0 || rcvd > 0)
|
|
364
|
+
TEST_SAY(
|
|
365
|
+
"Progress: %zu/%d (A:%d R:%d L:%d "
|
|
366
|
+
"redeliv:%d)\n",
|
|
367
|
+
total_consumed, state->msgs_produced,
|
|
368
|
+
state->msgs_accepted, state->msgs_rejected,
|
|
369
|
+
state->msgs_released,
|
|
370
|
+
state->msgs_redelivered);
|
|
371
|
+
} else {
|
|
372
|
+
TEST_SAY("Progress: %zu/%d\n", total_consumed,
|
|
373
|
+
state->msgs_produced);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
state->msgs_consumed = (int)total_consumed;
|
|
378
|
+
TEST_ASSERT(state->msgs_consumed == state->msgs_produced,
|
|
379
|
+
"Expected to consume %d messages, got %d",
|
|
380
|
+
state->msgs_produced, state->msgs_consumed);
|
|
381
|
+
|
|
382
|
+
if (config->use_random_acks)
|
|
383
|
+
TEST_SAY(
|
|
384
|
+
"Consumed %d: ACCEPT=%d, REJECT=%d, RELEASE=%d, "
|
|
385
|
+
"redelivered=%d\n",
|
|
386
|
+
state->msgs_consumed, state->msgs_accepted,
|
|
387
|
+
state->msgs_rejected, state->msgs_released,
|
|
388
|
+
state->msgs_redelivered);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* @brief Poll for redelivered messages after acknowledgements
|
|
393
|
+
*/
|
|
394
|
+
static void poll_for_redelivery(ack_test_config_t *config,
|
|
395
|
+
ack_test_state_t *state) {
|
|
396
|
+
rd_kafka_messages_t *batch = NULL;
|
|
397
|
+
int poll_timeout =
|
|
398
|
+
config->poll_timeout_ms > 0 ? config->poll_timeout_ms : 3000;
|
|
399
|
+
int attempts = 10;
|
|
400
|
+
int expected_count = state->msgs_released;
|
|
401
|
+
|
|
402
|
+
/* Use higher timeout/attempts for random mode */
|
|
403
|
+
if (config->use_random_acks) {
|
|
404
|
+
poll_timeout = 5000;
|
|
405
|
+
/* Scale attempts based on expected redeliveries */
|
|
406
|
+
attempts = 100 + (expected_count / 500) * 50;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/*
|
|
410
|
+
* In random mode, some redeliveries may have already been handled
|
|
411
|
+
* during consume_and_acknowledge. Don't reset the counter.
|
|
412
|
+
* For non-random mode, reset as before.
|
|
413
|
+
*/
|
|
414
|
+
if (!config->use_random_acks)
|
|
415
|
+
state->msgs_redelivered = 0;
|
|
416
|
+
|
|
417
|
+
TEST_SAY(
|
|
418
|
+
"Polling for redelivered messages (expecting %d, have %d)...\n",
|
|
419
|
+
expected_count, state->msgs_redelivered);
|
|
420
|
+
|
|
421
|
+
while (attempts-- > 0) {
|
|
422
|
+
size_t rcvd = 0;
|
|
423
|
+
size_t m;
|
|
424
|
+
rd_kafka_error_t *err;
|
|
425
|
+
|
|
426
|
+
err = rd_kafka_share_poll(state->consumers[0], poll_timeout,
|
|
427
|
+
&batch);
|
|
428
|
+
if (err) {
|
|
429
|
+
rd_kafka_error_destroy(err);
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
433
|
+
|
|
434
|
+
for (m = 0; m < rcvd; m++) {
|
|
435
|
+
rd_kafka_message_t *msg =
|
|
436
|
+
rd_kafka_messages_get(batch, m);
|
|
437
|
+
if (!msg->err) {
|
|
438
|
+
rd_kafka_topic_partition_t *rktpar;
|
|
439
|
+
int16_t delivery_count =
|
|
440
|
+
rd_kafka_message_delivery_count(msg);
|
|
441
|
+
const char *msg_topic =
|
|
442
|
+
rd_kafka_topic_name(msg->rkt);
|
|
443
|
+
int32_t msg_partition = msg->partition;
|
|
444
|
+
int64_t msg_offset = msg->offset;
|
|
445
|
+
int released_idx;
|
|
446
|
+
|
|
447
|
+
/* Verify delivery_count >= 2 on redelivery */
|
|
448
|
+
TEST_ASSERT(
|
|
449
|
+
delivery_count >= 2,
|
|
450
|
+
"Expected delivery_count>=2 on redelivery, "
|
|
451
|
+
"got %d",
|
|
452
|
+
delivery_count);
|
|
453
|
+
|
|
454
|
+
/* Verify message was in released list */
|
|
455
|
+
released_idx = find_message_in_list(
|
|
456
|
+
state->released_msgs, msg_topic,
|
|
457
|
+
msg_partition, msg_offset);
|
|
458
|
+
|
|
459
|
+
TEST_ASSERT(released_idx >= 0,
|
|
460
|
+
"Redelivered message (topic=%s, "
|
|
461
|
+
"partition=%d, offset=%" PRId64
|
|
462
|
+
") was NOT in RELEASE'd list",
|
|
463
|
+
msg_topic, msg_partition,
|
|
464
|
+
msg_offset);
|
|
465
|
+
|
|
466
|
+
/* Remove from released list */
|
|
467
|
+
remove_message_from_list_at(
|
|
468
|
+
state->released_msgs, released_idx);
|
|
469
|
+
|
|
470
|
+
/* Track redelivered message */
|
|
471
|
+
rktpar = rd_kafka_topic_partition_list_add(
|
|
472
|
+
state->redelivered_msgs, msg_topic,
|
|
473
|
+
msg_partition);
|
|
474
|
+
rktpar->offset = msg_offset;
|
|
475
|
+
|
|
476
|
+
state->msgs_redelivered++;
|
|
477
|
+
|
|
478
|
+
rd_kafka_share_acknowledge_type(
|
|
479
|
+
state->consumers[0], msg,
|
|
480
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
rd_kafka_messages_destroy(batch);
|
|
485
|
+
batch = NULL;
|
|
486
|
+
|
|
487
|
+
if (rcvd > 0) {
|
|
488
|
+
TEST_SAY("Redelivered so far: %d/%d\n",
|
|
489
|
+
state->msgs_redelivered, expected_count);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (state->msgs_redelivered >= expected_count &&
|
|
493
|
+
expected_count > 0) {
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* @brief Verify redelivery results
|
|
501
|
+
*
|
|
502
|
+
* Verification approach:
|
|
503
|
+
* - released_msgs is emptied as messages are redelivered
|
|
504
|
+
* - Verify redelivered count matches expected count
|
|
505
|
+
* - Verify released_msgs is empty (all RELEASE'd messages were redelivered)
|
|
506
|
+
*/
|
|
507
|
+
static void verify_results(ack_test_config_t *config, ack_test_state_t *state) {
|
|
508
|
+
int expected_count = state->msgs_released;
|
|
509
|
+
|
|
510
|
+
TEST_SAY("Verifying: consumed=%d, redelivered=%d (expected=%d)\n",
|
|
511
|
+
state->msgs_consumed, state->msgs_redelivered, expected_count);
|
|
512
|
+
|
|
513
|
+
TEST_ASSERT(state->msgs_redelivered == expected_count,
|
|
514
|
+
"Expected %d redelivered messages, got %d", expected_count,
|
|
515
|
+
state->msgs_redelivered);
|
|
516
|
+
|
|
517
|
+
/*
|
|
518
|
+
* All RELEASE'd messages should have been redelivered and removed
|
|
519
|
+
* from released_msgs. Verify the list is empty.
|
|
520
|
+
*/
|
|
521
|
+
TEST_ASSERT(state->released_msgs->cnt == 0,
|
|
522
|
+
"Expected all RELEASE'd messages to be redelivered, "
|
|
523
|
+
"but %d remain in released list",
|
|
524
|
+
state->released_msgs->cnt);
|
|
525
|
+
|
|
526
|
+
TEST_SAY("All %d redelivered messages verified correctly\n",
|
|
527
|
+
state->msgs_redelivered);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* @brief Cleanup test state
|
|
532
|
+
*/
|
|
533
|
+
static void cleanup_test(ack_test_config_t *config, ack_test_state_t *state) {
|
|
534
|
+
int t, i;
|
|
535
|
+
|
|
536
|
+
for (t = 0; t < config->topic_cnt; t++) {
|
|
537
|
+
if (state->topic_names[t]) {
|
|
538
|
+
rd_free(state->topic_names[t]);
|
|
539
|
+
state->topic_names[t] = NULL;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
for (i = 0; i < config->consumer_cnt; i++) {
|
|
544
|
+
if (state->consumers[i]) {
|
|
545
|
+
test_share_consumer_close(state->consumers[i]);
|
|
546
|
+
test_share_destroy(state->consumers[i]);
|
|
547
|
+
state->consumers[i] = NULL;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/* Destroy tracking lists */
|
|
552
|
+
if (state->released_msgs)
|
|
553
|
+
rd_kafka_topic_partition_list_destroy(state->released_msgs);
|
|
554
|
+
if (state->redelivered_msgs)
|
|
555
|
+
rd_kafka_topic_partition_list_destroy(state->redelivered_msgs);
|
|
556
|
+
|
|
557
|
+
TEST_SAY("Cleanup complete\n");
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* @brief Run a test scenario based on configuration
|
|
562
|
+
*/
|
|
563
|
+
static int run_ack_test(ack_test_config_t *config) {
|
|
564
|
+
ack_test_state_t state = {0};
|
|
565
|
+
int i;
|
|
566
|
+
int list_capacity;
|
|
567
|
+
char unique_suffix[64];
|
|
568
|
+
char unique_test_name[256];
|
|
569
|
+
|
|
570
|
+
/* Append a per-invocation unique suffix to the test name; the
|
|
571
|
+
* group name is derived from it below, so this guarantees a
|
|
572
|
+
* fresh share-group on the broker for each run. */
|
|
573
|
+
rd_snprintf(unique_suffix, sizeof(unique_suffix), "rnd%" PRIx64,
|
|
574
|
+
test_id_generate());
|
|
575
|
+
rd_snprintf(unique_test_name, sizeof(unique_test_name), "%s-%s",
|
|
576
|
+
config->test_name, unique_suffix);
|
|
577
|
+
config->test_name = unique_test_name;
|
|
578
|
+
|
|
579
|
+
TEST_SAY("\n");
|
|
580
|
+
TEST_SAY(
|
|
581
|
+
"============================================================"
|
|
582
|
+
"\n");
|
|
583
|
+
TEST_SAY("=== %s ===\n", config->test_name);
|
|
584
|
+
TEST_SAY(
|
|
585
|
+
"============================================================"
|
|
586
|
+
"\n");
|
|
587
|
+
|
|
588
|
+
rd_snprintf(state.group_name, sizeof(state.group_name), "share-%s",
|
|
589
|
+
config->test_name);
|
|
590
|
+
|
|
591
|
+
/* Initialize tracking lists with larger capacity for random mode */
|
|
592
|
+
list_capacity = config->use_random_acks ? 6000 : 100;
|
|
593
|
+
state.released_msgs = rd_kafka_topic_partition_list_new(list_capacity);
|
|
594
|
+
state.redelivered_msgs =
|
|
595
|
+
rd_kafka_topic_partition_list_new(list_capacity);
|
|
596
|
+
|
|
597
|
+
for (i = 0; i < config->consumer_cnt; i++) {
|
|
598
|
+
state.consumers[i] =
|
|
599
|
+
test_create_share_consumer(state.group_name, "explicit");
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
setup_topics_and_produce(config, &state);
|
|
603
|
+
subscribe_consumers(config, &state);
|
|
604
|
+
consume_and_acknowledge(config, &state);
|
|
605
|
+
poll_for_redelivery(config, &state);
|
|
606
|
+
verify_results(config, &state);
|
|
607
|
+
cleanup_test(config, &state);
|
|
608
|
+
|
|
609
|
+
TEST_SAY("=== %s: PASSED ===\n", config->test_name);
|
|
610
|
+
return 0;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
/***************************************************************************
|
|
615
|
+
* Core Tests
|
|
616
|
+
***************************************************************************/
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* @brief RELEASE causes redelivery
|
|
620
|
+
*/
|
|
621
|
+
static void do_test_release_redelivery(void) {
|
|
622
|
+
ack_test_config_t config = {
|
|
623
|
+
.test_name = "release-redelivery",
|
|
624
|
+
.topic_cnt = 1,
|
|
625
|
+
.partitions = {1},
|
|
626
|
+
.msgs_per_partition = 5,
|
|
627
|
+
.consumer_cnt = 1,
|
|
628
|
+
.single_ack_type = RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_RELEASE};
|
|
629
|
+
SUB_TEST();
|
|
630
|
+
run_ack_test(&config);
|
|
631
|
+
SUB_TEST_PASS();
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* @brief REJECT prevents redelivery
|
|
636
|
+
*/
|
|
637
|
+
static void do_test_reject_no_redelivery(void) {
|
|
638
|
+
ack_test_config_t config = {.test_name = "reject-no-redelivery",
|
|
639
|
+
.topic_cnt = 1,
|
|
640
|
+
.partitions = {1},
|
|
641
|
+
.msgs_per_partition = 5,
|
|
642
|
+
.consumer_cnt = 1,
|
|
643
|
+
.single_ack_type =
|
|
644
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_REJECT};
|
|
645
|
+
SUB_TEST();
|
|
646
|
+
run_ack_test(&config);
|
|
647
|
+
SUB_TEST_PASS();
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* @brief ACCEPT prevents redelivery
|
|
652
|
+
*/
|
|
653
|
+
static void do_test_accept_no_redelivery(void) {
|
|
654
|
+
ack_test_config_t config = {.test_name = "accept-no-redelivery",
|
|
655
|
+
.topic_cnt = 1,
|
|
656
|
+
.partitions = {1},
|
|
657
|
+
.msgs_per_partition = 5,
|
|
658
|
+
.consumer_cnt = 1,
|
|
659
|
+
.single_ack_type =
|
|
660
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT};
|
|
661
|
+
SUB_TEST();
|
|
662
|
+
run_ack_test(&config);
|
|
663
|
+
SUB_TEST_PASS();
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
/***************************************************************************
|
|
668
|
+
* Error Handling Tests (Standalone)
|
|
669
|
+
***************************************************************************/
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* @brief Acknowledge with NULL message
|
|
673
|
+
*/
|
|
674
|
+
static void do_test_ack_null_message(void) {
|
|
675
|
+
rd_kafka_share_t *rkshare;
|
|
676
|
+
rd_kafka_resp_err_t err;
|
|
677
|
+
const char *group = "share-null-msg-test";
|
|
678
|
+
|
|
679
|
+
SUB_TEST();
|
|
680
|
+
|
|
681
|
+
TEST_SAY("\n");
|
|
682
|
+
TEST_SAY("=== test_ack_null_message ===\n");
|
|
683
|
+
|
|
684
|
+
rkshare = test_create_share_consumer(group, "explicit");
|
|
685
|
+
|
|
686
|
+
err = rd_kafka_share_acknowledge(rkshare, NULL);
|
|
687
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__INVALID_ARG,
|
|
688
|
+
"Expected INVALID_ARG, got %s", rd_kafka_err2str(err));
|
|
689
|
+
|
|
690
|
+
err = rd_kafka_share_acknowledge_type(
|
|
691
|
+
rkshare, NULL, RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
692
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__INVALID_ARG,
|
|
693
|
+
"Expected INVALID_ARG, got %s", rd_kafka_err2str(err));
|
|
694
|
+
|
|
695
|
+
test_share_consumer_close(rkshare);
|
|
696
|
+
test_share_destroy(rkshare);
|
|
697
|
+
|
|
698
|
+
TEST_SAY("=== test_ack_null_message: PASSED ===\n");
|
|
699
|
+
|
|
700
|
+
SUB_TEST_PASS();
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* @brief Acknowledge with NULL rkshare
|
|
705
|
+
*/
|
|
706
|
+
static void do_test_ack_null_rkshare(void) {
|
|
707
|
+
rd_kafka_resp_err_t err;
|
|
708
|
+
rd_kafka_message_t fake_msg = {0};
|
|
709
|
+
|
|
710
|
+
SUB_TEST();
|
|
711
|
+
|
|
712
|
+
TEST_SAY("\n");
|
|
713
|
+
TEST_SAY("=== test_ack_null_rkshare ===\n");
|
|
714
|
+
|
|
715
|
+
/* NULL rkshare is rejected up-front with STATE */
|
|
716
|
+
err = rd_kafka_share_acknowledge(NULL, &fake_msg);
|
|
717
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE, "Expected STATE, got %s",
|
|
718
|
+
rd_kafka_err2str(err));
|
|
719
|
+
|
|
720
|
+
err = rd_kafka_share_acknowledge_type(
|
|
721
|
+
NULL, &fake_msg, RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
722
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE, "Expected STATE, got %s",
|
|
723
|
+
rd_kafka_err2str(err));
|
|
724
|
+
|
|
725
|
+
/* Test NULL rkshare directly via acknowledge_offset */
|
|
726
|
+
err = rd_kafka_share_acknowledge_offset(
|
|
727
|
+
NULL, "topic", 0, 0, RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
728
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE, "Expected STATE, got %s",
|
|
729
|
+
rd_kafka_err2str(err));
|
|
730
|
+
|
|
731
|
+
TEST_SAY("=== test_ack_null_rkshare: PASSED ===\n");
|
|
732
|
+
|
|
733
|
+
SUB_TEST_PASS();
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* @brief Acknowledge with invalid type
|
|
738
|
+
*/
|
|
739
|
+
static void do_test_ack_invalid_type(void) {
|
|
740
|
+
rd_kafka_share_t *rkshare;
|
|
741
|
+
rd_kafka_messages_t *batch = NULL;
|
|
742
|
+
rd_kafka_error_t *err;
|
|
743
|
+
rd_kafka_resp_err_t ack_err;
|
|
744
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
745
|
+
const char *group = "share-invalid-type-test";
|
|
746
|
+
const char *topic;
|
|
747
|
+
size_t rcvd = 0;
|
|
748
|
+
int attempts;
|
|
749
|
+
rd_kafka_message_t *msg0;
|
|
750
|
+
|
|
751
|
+
SUB_TEST();
|
|
752
|
+
|
|
753
|
+
TEST_SAY("\n");
|
|
754
|
+
TEST_SAY("=== test_ack_invalid_type ===\n");
|
|
755
|
+
|
|
756
|
+
rkshare = test_create_share_consumer(group, "explicit");
|
|
757
|
+
topic = test_mk_topic_name("0172-invalid-type", 1);
|
|
758
|
+
test_create_topic_wait_exists(NULL, topic, 1, -1, 60 * 1000);
|
|
759
|
+
test_produce_msgs_simple(common_producer, topic, 0, 1);
|
|
760
|
+
|
|
761
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
762
|
+
|
|
763
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
764
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
765
|
+
rd_kafka_share_subscribe(rkshare, subs);
|
|
766
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
767
|
+
|
|
768
|
+
attempts = 20;
|
|
769
|
+
while (rcvd == 0 && attempts-- > 0) {
|
|
770
|
+
if (batch) {
|
|
771
|
+
rd_kafka_messages_destroy(batch);
|
|
772
|
+
batch = NULL;
|
|
773
|
+
}
|
|
774
|
+
err = rd_kafka_share_poll(rkshare, 2000, &batch);
|
|
775
|
+
if (err)
|
|
776
|
+
rd_kafka_error_destroy(err);
|
|
777
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
TEST_ASSERT(rcvd == 1, "Expected exactly 1 message, got %zu", rcvd);
|
|
781
|
+
|
|
782
|
+
msg0 = rd_kafka_messages_get(batch, 0);
|
|
783
|
+
|
|
784
|
+
/* Try invalid type (99) */
|
|
785
|
+
ack_err = rd_kafka_share_acknowledge_type(
|
|
786
|
+
rkshare, msg0, (rd_kafka_share_AcknowledgeType_t)99);
|
|
787
|
+
TEST_ASSERT(ack_err == RD_KAFKA_RESP_ERR__INVALID_ARG,
|
|
788
|
+
"Expected INVALID_ARG for type 99, got %s",
|
|
789
|
+
rd_kafka_err2str(ack_err));
|
|
790
|
+
|
|
791
|
+
/* Try GAP type (0) - internal only */
|
|
792
|
+
ack_err = rd_kafka_share_acknowledge_type(
|
|
793
|
+
rkshare, msg0, (rd_kafka_share_AcknowledgeType_t)0);
|
|
794
|
+
TEST_ASSERT(ack_err == RD_KAFKA_RESP_ERR__INVALID_ARG,
|
|
795
|
+
"Expected INVALID_ARG for type 0 (GAP), got %s",
|
|
796
|
+
rd_kafka_err2str(ack_err));
|
|
797
|
+
|
|
798
|
+
/* Clean up with valid acknowledge */
|
|
799
|
+
rd_kafka_share_acknowledge_type(rkshare, msg0,
|
|
800
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
801
|
+
rd_kafka_messages_destroy(batch);
|
|
802
|
+
batch = NULL;
|
|
803
|
+
|
|
804
|
+
test_share_consumer_close(rkshare);
|
|
805
|
+
test_share_destroy(rkshare);
|
|
806
|
+
|
|
807
|
+
TEST_SAY("=== test_ack_invalid_type: PASSED ===\n");
|
|
808
|
+
|
|
809
|
+
SUB_TEST_PASS();
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* @brief RELEASE then REJECT - final type is REJECT (no redelivery)
|
|
814
|
+
*/
|
|
815
|
+
static void do_test_release_then_reject_no_redelivery(void) {
|
|
816
|
+
rd_kafka_share_t *rkshare;
|
|
817
|
+
rd_kafka_messages_t *batches[30] = {NULL};
|
|
818
|
+
int batch_cnt = 0;
|
|
819
|
+
rd_kafka_messages_t *batch = NULL;
|
|
820
|
+
rd_kafka_error_t *err;
|
|
821
|
+
rd_kafka_resp_err_t ack_err;
|
|
822
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
823
|
+
const char *group = "share-release-then-reject";
|
|
824
|
+
const char *topic;
|
|
825
|
+
size_t rcvd = 0;
|
|
826
|
+
size_t m;
|
|
827
|
+
int attempts;
|
|
828
|
+
int redelivered = 0;
|
|
829
|
+
int i;
|
|
830
|
+
rd_kafka_message_t *first_msg = NULL;
|
|
831
|
+
|
|
832
|
+
SUB_TEST();
|
|
833
|
+
|
|
834
|
+
TEST_SAY("\n");
|
|
835
|
+
TEST_SAY("=== test_release_then_reject_no_redelivery ===\n");
|
|
836
|
+
|
|
837
|
+
rkshare = test_create_share_consumer(group, "explicit");
|
|
838
|
+
topic = test_mk_topic_name("0172-release-reject", 1);
|
|
839
|
+
test_create_topic_wait_exists(NULL, topic, 1, -1, 60 * 1000);
|
|
840
|
+
test_produce_msgs_simple(common_producer, topic, 0, 5);
|
|
841
|
+
|
|
842
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
843
|
+
|
|
844
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
845
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
846
|
+
rd_kafka_share_subscribe(rkshare, subs);
|
|
847
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
848
|
+
|
|
849
|
+
/* Consume all messages */
|
|
850
|
+
attempts = 30;
|
|
851
|
+
while (rcvd < 5 && attempts-- > 0 && batch_cnt < 30) {
|
|
852
|
+
rd_kafka_messages_t *b = NULL;
|
|
853
|
+
size_t batch_rcvd;
|
|
854
|
+
err = rd_kafka_share_poll(rkshare, 2000, &b);
|
|
855
|
+
if (err)
|
|
856
|
+
rd_kafka_error_destroy(err);
|
|
857
|
+
batch_rcvd = rd_kafka_messages_count(b);
|
|
858
|
+
if (batch_rcvd > 0) {
|
|
859
|
+
batches[batch_cnt++] = b;
|
|
860
|
+
rcvd += batch_rcvd;
|
|
861
|
+
} else {
|
|
862
|
+
rd_kafka_messages_destroy(b);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
TEST_ASSERT(rcvd == 5, "Expected 5 messages, got %zu", rcvd);
|
|
867
|
+
|
|
868
|
+
/* Locate the first message across batches */
|
|
869
|
+
first_msg = rd_kafka_messages_get(batches[0], 0);
|
|
870
|
+
|
|
871
|
+
/* First RELEASE offset 0, then override with REJECT */
|
|
872
|
+
ack_err = rd_kafka_share_acknowledge_type(
|
|
873
|
+
rkshare, first_msg, RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_RELEASE);
|
|
874
|
+
TEST_ASSERT(ack_err == RD_KAFKA_RESP_ERR_NO_ERROR, "RELEASE failed: %s",
|
|
875
|
+
rd_kafka_err2str(ack_err));
|
|
876
|
+
|
|
877
|
+
ack_err = rd_kafka_share_acknowledge_type(
|
|
878
|
+
rkshare, first_msg, RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_REJECT);
|
|
879
|
+
TEST_ASSERT(ack_err == RD_KAFKA_RESP_ERR_NO_ERROR, "REJECT failed: %s",
|
|
880
|
+
rd_kafka_err2str(ack_err));
|
|
881
|
+
|
|
882
|
+
/* ACCEPT remaining messages - skip the very first one (index 0 of
|
|
883
|
+
* batches[0]) which is already REJECT'd above */
|
|
884
|
+
{
|
|
885
|
+
rd_bool_t skipped_first = rd_false;
|
|
886
|
+
for (i = 0; i < batch_cnt; i++) {
|
|
887
|
+
size_t bcnt = rd_kafka_messages_count(batches[i]);
|
|
888
|
+
for (m = 0; m < bcnt; m++) {
|
|
889
|
+
rd_kafka_message_t *msg =
|
|
890
|
+
rd_kafka_messages_get(batches[i], m);
|
|
891
|
+
if (!skipped_first) {
|
|
892
|
+
skipped_first = rd_true;
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
rd_kafka_share_acknowledge_type(
|
|
896
|
+
rkshare, msg,
|
|
897
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/* Destroy batches */
|
|
903
|
+
for (i = 0; i < batch_cnt; i++) {
|
|
904
|
+
rd_kafka_messages_destroy(batches[i]);
|
|
905
|
+
batches[i] = NULL;
|
|
906
|
+
}
|
|
907
|
+
batch_cnt = 0;
|
|
908
|
+
|
|
909
|
+
/* Poll for redelivery - should get 0 */
|
|
910
|
+
TEST_SAY("Polling for redelivery (expecting 0)...\n");
|
|
911
|
+
attempts = 5;
|
|
912
|
+
while (attempts-- > 0) {
|
|
913
|
+
size_t redeliv_rcvd;
|
|
914
|
+
err = rd_kafka_share_poll(rkshare, 2000, &batch);
|
|
915
|
+
if (err) {
|
|
916
|
+
rd_kafka_error_destroy(err);
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
919
|
+
redeliv_rcvd = rd_kafka_messages_count(batch);
|
|
920
|
+
|
|
921
|
+
for (m = 0; m < redeliv_rcvd; m++) {
|
|
922
|
+
rd_kafka_message_t *msg =
|
|
923
|
+
rd_kafka_messages_get(batch, m);
|
|
924
|
+
if (!msg->err)
|
|
925
|
+
redelivered++;
|
|
926
|
+
rd_kafka_share_acknowledge_type(
|
|
927
|
+
rkshare, msg,
|
|
928
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
929
|
+
}
|
|
930
|
+
rd_kafka_messages_destroy(batch);
|
|
931
|
+
batch = NULL;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
TEST_ASSERT(redelivered == 0,
|
|
935
|
+
"Expected 0 redelivered (REJECT overrides RELEASE), got %d",
|
|
936
|
+
redelivered);
|
|
937
|
+
|
|
938
|
+
test_share_consumer_close(rkshare);
|
|
939
|
+
test_share_destroy(rkshare);
|
|
940
|
+
|
|
941
|
+
TEST_SAY("=== test_release_then_reject_no_redelivery: PASSED ===\n");
|
|
942
|
+
|
|
943
|
+
SUB_TEST_PASS();
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* @brief Test changing acknowledgement type before commit
|
|
950
|
+
*
|
|
951
|
+
* Verifies that acknowledgement type can be changed before commit completes.
|
|
952
|
+
*/
|
|
953
|
+
static void do_test_change_ack_type_before_commit(void) {
|
|
954
|
+
rd_kafka_share_t *rkshare;
|
|
955
|
+
rd_kafka_messages_t *batch = NULL;
|
|
956
|
+
rd_kafka_error_t *err;
|
|
957
|
+
rd_kafka_resp_err_t ack_err;
|
|
958
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
959
|
+
const char *group = "share-change-ack-type";
|
|
960
|
+
const char *topic;
|
|
961
|
+
size_t rcvd = 0;
|
|
962
|
+
int attempts;
|
|
963
|
+
test_ack_cb_state_t state = {0};
|
|
964
|
+
|
|
965
|
+
SUB_TEST();
|
|
966
|
+
|
|
967
|
+
TEST_SAY("\n");
|
|
968
|
+
TEST_SAY("=== test_change_ack_type_before_commit ===\n");
|
|
969
|
+
|
|
970
|
+
/* Explicit mode with explicit commit and callback */
|
|
971
|
+
rkshare =
|
|
972
|
+
test_create_share_consumer_with_cb(group, "explicit", &state, NULL);
|
|
973
|
+
topic = test_mk_topic_name("0172-change-ack-explicit", 1);
|
|
974
|
+
test_create_topic_wait_exists(NULL, topic, 1, -1, 60 * 1000);
|
|
975
|
+
test_produce_msgs_simple(common_producer, topic, 0, 1);
|
|
976
|
+
|
|
977
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
978
|
+
|
|
979
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
980
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
981
|
+
rd_kafka_share_subscribe(rkshare, subs);
|
|
982
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
983
|
+
|
|
984
|
+
/* Consume one message */
|
|
985
|
+
attempts = 30;
|
|
986
|
+
while (rcvd == 0 && attempts-- > 0) {
|
|
987
|
+
if (batch) {
|
|
988
|
+
rd_kafka_messages_destroy(batch);
|
|
989
|
+
batch = NULL;
|
|
990
|
+
}
|
|
991
|
+
err = rd_kafka_share_poll(rkshare, 2000, &batch);
|
|
992
|
+
if (err)
|
|
993
|
+
rd_kafka_error_destroy(err);
|
|
994
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
995
|
+
if (rcvd > 0) {
|
|
996
|
+
rd_kafka_share_acknowledge_type(
|
|
997
|
+
rkshare, rd_kafka_messages_get(batch, 0),
|
|
998
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
TEST_SAY("Consumed %zu messages after first commit\n", rcvd);
|
|
1003
|
+
|
|
1004
|
+
/* Second: Change to RELEASE for first message before commit */
|
|
1005
|
+
ack_err = rd_kafka_share_acknowledge_type(
|
|
1006
|
+
rkshare, rd_kafka_messages_get(batch, 0),
|
|
1007
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_RELEASE);
|
|
1008
|
+
TEST_ASSERT(ack_err == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1009
|
+
"RELEASE (changing from ACCEPT) failed: %s",
|
|
1010
|
+
rd_kafka_err2str(ack_err));
|
|
1011
|
+
|
|
1012
|
+
rd_kafka_messages_destroy(batch);
|
|
1013
|
+
batch = NULL;
|
|
1014
|
+
|
|
1015
|
+
/* Commit async - should succeed with RELEASE as final ack type */
|
|
1016
|
+
err = rd_kafka_share_commit_async(rkshare);
|
|
1017
|
+
TEST_ASSERT(!err, "commit_async failed: %s",
|
|
1018
|
+
err ? rd_kafka_error_string(err) : "");
|
|
1019
|
+
|
|
1020
|
+
/* Poll to receive the RELEASED message that should be redelivered
|
|
1021
|
+
* This loop also processes the first callback */
|
|
1022
|
+
rcvd = 0;
|
|
1023
|
+
attempts = 30;
|
|
1024
|
+
while (rcvd == 0 && attempts-- > 0) {
|
|
1025
|
+
if (batch) {
|
|
1026
|
+
rd_kafka_messages_destroy(batch);
|
|
1027
|
+
batch = NULL;
|
|
1028
|
+
}
|
|
1029
|
+
err = rd_kafka_share_poll(rkshare, 2000, &batch);
|
|
1030
|
+
if (err)
|
|
1031
|
+
rd_kafka_error_destroy(err);
|
|
1032
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1033
|
+
if (rcvd > 0) {
|
|
1034
|
+
rd_kafka_share_acknowledge_type(
|
|
1035
|
+
rkshare, rd_kafka_messages_get(batch, 0),
|
|
1036
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
1037
|
+
rd_kafka_messages_destroy(batch);
|
|
1038
|
+
batch = NULL;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
TEST_ASSERT(state.callback_cnt == 1, "Expected 1 callback, got %d",
|
|
1043
|
+
state.callback_cnt);
|
|
1044
|
+
TEST_ASSERT(test_ack_cb_state_first_err(&state) ==
|
|
1045
|
+
RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1046
|
+
"First callback failed: %s",
|
|
1047
|
+
rd_kafka_err2name(test_ack_cb_state_first_err(&state)));
|
|
1048
|
+
TEST_SAY("First commit callback received: offsets=%zu, err=%s\n",
|
|
1049
|
+
state.total_offsets,
|
|
1050
|
+
rd_kafka_err2name(test_ack_cb_state_first_err(&state)));
|
|
1051
|
+
TEST_SAY("Consumed %zu redelivered messages\n", rcvd);
|
|
1052
|
+
TEST_ASSERT(rcvd == 1, "Expected 1 redelivered message, got %zu", rcvd);
|
|
1053
|
+
|
|
1054
|
+
/* Commit async again for the remaining messages */
|
|
1055
|
+
err = rd_kafka_share_commit_async(rkshare);
|
|
1056
|
+
TEST_ASSERT(!err, "Second commit_async failed: %s",
|
|
1057
|
+
err ? rd_kafka_error_string(err) : "");
|
|
1058
|
+
|
|
1059
|
+
/* Wait for second callback and verify (expecting 2 total callbacks) */
|
|
1060
|
+
test_wait_for_cb_with_poll(&state, rkshare, 2, 10000);
|
|
1061
|
+
TEST_ASSERT(state.callback_cnt == 2,
|
|
1062
|
+
"Expected 2 callbacks total, got %d", state.callback_cnt);
|
|
1063
|
+
TEST_ASSERT(state.errs[1] == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1064
|
+
"Second callback failed: %s",
|
|
1065
|
+
rd_kafka_err2name(state.errs[1]));
|
|
1066
|
+
TEST_SAY("Second commit callback received: total_offsets=%zu, err=%s\n",
|
|
1067
|
+
state.total_offsets, rd_kafka_err2name(state.errs[1]));
|
|
1068
|
+
|
|
1069
|
+
test_share_consumer_close(rkshare);
|
|
1070
|
+
test_share_destroy(rkshare);
|
|
1071
|
+
test_ack_cb_state_destroy(&state);
|
|
1072
|
+
|
|
1073
|
+
TEST_SAY("=== test_change_ack_type_before_commit: PASSED ===\n");
|
|
1074
|
+
|
|
1075
|
+
SUB_TEST_PASS();
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* @brief Test that acknowledging after commit fails
|
|
1080
|
+
*
|
|
1081
|
+
* After commit completes, acknowledged messages are removed from
|
|
1082
|
+
* inflight_acks map. Attempting to acknowledge again should fail with _STATE.
|
|
1083
|
+
*/
|
|
1084
|
+
static void do_test_ack_after_commit(void) {
|
|
1085
|
+
rd_kafka_share_t *rkshare;
|
|
1086
|
+
rd_kafka_messages_t *batch = NULL;
|
|
1087
|
+
rd_kafka_error_t *err;
|
|
1088
|
+
rd_kafka_resp_err_t ack_err;
|
|
1089
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
1090
|
+
const char *group = "share-ack-after-commit";
|
|
1091
|
+
const char *topic;
|
|
1092
|
+
size_t rcvd = 0;
|
|
1093
|
+
int attempts;
|
|
1094
|
+
const char *saved_topic = NULL;
|
|
1095
|
+
int32_t saved_partition = -1;
|
|
1096
|
+
int64_t saved_offset = -1;
|
|
1097
|
+
test_ack_cb_state_t state = {0};
|
|
1098
|
+
rd_kafka_message_t *msg0;
|
|
1099
|
+
|
|
1100
|
+
SUB_TEST();
|
|
1101
|
+
|
|
1102
|
+
TEST_SAY("\n");
|
|
1103
|
+
TEST_SAY("=== test_ack_after_commit ===\n");
|
|
1104
|
+
|
|
1105
|
+
/* Test 1: Explicit mode with explicit commit and callback */
|
|
1106
|
+
rkshare =
|
|
1107
|
+
test_create_share_consumer_with_cb(group, "explicit", &state, NULL);
|
|
1108
|
+
topic = test_mk_topic_name("0172-ack-after-commit-explicit", 1);
|
|
1109
|
+
test_create_topic_wait_exists(NULL, topic, 1, -1, 60 * 1000);
|
|
1110
|
+
test_produce_msgs_simple(common_producer, topic, 0, 1);
|
|
1111
|
+
|
|
1112
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
1113
|
+
|
|
1114
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
1115
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1116
|
+
rd_kafka_share_subscribe(rkshare, subs);
|
|
1117
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1118
|
+
|
|
1119
|
+
/* Consume and acknowledge messages, save first message info */
|
|
1120
|
+
attempts = 30;
|
|
1121
|
+
while (rcvd == 0 && attempts-- > 0) {
|
|
1122
|
+
if (batch) {
|
|
1123
|
+
rd_kafka_messages_destroy(batch);
|
|
1124
|
+
batch = NULL;
|
|
1125
|
+
}
|
|
1126
|
+
err = rd_kafka_share_poll(rkshare, 2000, &batch);
|
|
1127
|
+
if (err)
|
|
1128
|
+
rd_kafka_error_destroy(err);
|
|
1129
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1130
|
+
if (rcvd > 0) {
|
|
1131
|
+
rd_kafka_share_acknowledge_type(
|
|
1132
|
+
rkshare, rd_kafka_messages_get(batch, 0),
|
|
1133
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
TEST_ASSERT(rcvd == 1, "Expected 1 message, got %zu", rcvd);
|
|
1138
|
+
|
|
1139
|
+
/* Save first message info and acknowledge all */
|
|
1140
|
+
msg0 = rd_kafka_messages_get(batch, 0);
|
|
1141
|
+
saved_topic = topic;
|
|
1142
|
+
saved_partition = msg0->partition;
|
|
1143
|
+
saved_offset = msg0->offset;
|
|
1144
|
+
|
|
1145
|
+
rd_kafka_messages_destroy(batch);
|
|
1146
|
+
batch = NULL;
|
|
1147
|
+
|
|
1148
|
+
/* Explicit commit */
|
|
1149
|
+
err = rd_kafka_share_commit_async(rkshare);
|
|
1150
|
+
TEST_ASSERT(!err, "commit_async failed");
|
|
1151
|
+
|
|
1152
|
+
/* Wait for callback and verify */
|
|
1153
|
+
test_wait_for_cb_with_poll(&state, rkshare, 1, 10000);
|
|
1154
|
+
TEST_ASSERT(state.callback_cnt >= 1,
|
|
1155
|
+
"Expected at least 1 callback, got %d", state.callback_cnt);
|
|
1156
|
+
TEST_ASSERT(test_ack_cb_state_first_err(&state) ==
|
|
1157
|
+
RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1158
|
+
"Callback failed: %s",
|
|
1159
|
+
rd_kafka_err2name(test_ack_cb_state_first_err(&state)));
|
|
1160
|
+
TEST_SAY("Commit callback received: offsets=%zu, err=%s\n",
|
|
1161
|
+
state.total_offsets,
|
|
1162
|
+
rd_kafka_err2name(test_ack_cb_state_first_err(&state)));
|
|
1163
|
+
|
|
1164
|
+
/* Now try to acknowledge the same message again - should fail */
|
|
1165
|
+
ack_err = rd_kafka_share_acknowledge_offset(
|
|
1166
|
+
rkshare, saved_topic, saved_partition, saved_offset,
|
|
1167
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
1168
|
+
TEST_ASSERT(ack_err == RD_KAFKA_RESP_ERR__STATE,
|
|
1169
|
+
"Expected _STATE after commit, got %s",
|
|
1170
|
+
rd_kafka_err2str(ack_err));
|
|
1171
|
+
TEST_SAY(
|
|
1172
|
+
"Explicit mode: Re-ack after commit correctly failed with "
|
|
1173
|
+
"_STATE\n");
|
|
1174
|
+
|
|
1175
|
+
test_share_consumer_close(rkshare);
|
|
1176
|
+
test_share_destroy(rkshare);
|
|
1177
|
+
test_ack_cb_state_destroy(&state);
|
|
1178
|
+
|
|
1179
|
+
TEST_SAY("=== test_ack_after_commit: PASSED ===\n");
|
|
1180
|
+
|
|
1181
|
+
SUB_TEST_PASS();
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
/***************************************************************************
|
|
1185
|
+
* Max Delivery Attempts Tests
|
|
1186
|
+
***************************************************************************/
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* @brief Release a record 5 times (max attempts), verify no 6th delivery
|
|
1190
|
+
*
|
|
1191
|
+
* Default share.record.lock.partition.limit is 5. After 5 RELEASE attempts,
|
|
1192
|
+
* the broker should not attempt any redelivery.
|
|
1193
|
+
*/
|
|
1194
|
+
static void do_test_max_delivery_attempts(void) {
|
|
1195
|
+
rd_kafka_share_t *rkshare;
|
|
1196
|
+
rd_kafka_messages_t *batch = NULL;
|
|
1197
|
+
rd_kafka_error_t *err;
|
|
1198
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
1199
|
+
const char *group = "share-max-delivery-attempts";
|
|
1200
|
+
const char *topic;
|
|
1201
|
+
size_t rcvd;
|
|
1202
|
+
int delivery_attempt;
|
|
1203
|
+
int attempts;
|
|
1204
|
+
const int max_deliveries = 5;
|
|
1205
|
+
rd_kafka_message_t *msg0;
|
|
1206
|
+
|
|
1207
|
+
SUB_TEST();
|
|
1208
|
+
|
|
1209
|
+
TEST_SAY("\n");
|
|
1210
|
+
TEST_SAY("=== test_max_delivery_attempts ===\n");
|
|
1211
|
+
TEST_SAY(
|
|
1212
|
+
"Testing that record is not redelivered after %d RELEASE "
|
|
1213
|
+
"attempts\n",
|
|
1214
|
+
max_deliveries);
|
|
1215
|
+
|
|
1216
|
+
rkshare = test_create_share_consumer(group, "explicit");
|
|
1217
|
+
topic = test_mk_topic_name("0172-max-delivery", 1);
|
|
1218
|
+
test_create_topic_wait_exists(NULL, topic, 1, -1, 60 * 1000);
|
|
1219
|
+
test_produce_msgs_simple(common_producer, topic, 0,
|
|
1220
|
+
1); /* Just 1 message */
|
|
1221
|
+
|
|
1222
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
1223
|
+
|
|
1224
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
1225
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1226
|
+
rd_kafka_share_subscribe(rkshare, subs);
|
|
1227
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1228
|
+
|
|
1229
|
+
/* RELEASE the same message max_deliveries times */
|
|
1230
|
+
for (delivery_attempt = 1; delivery_attempt <= max_deliveries;
|
|
1231
|
+
delivery_attempt++) {
|
|
1232
|
+
rcvd = 0;
|
|
1233
|
+
attempts = 30;
|
|
1234
|
+
|
|
1235
|
+
while (rcvd == 0 && attempts-- > 0) {
|
|
1236
|
+
if (batch) {
|
|
1237
|
+
rd_kafka_messages_destroy(batch);
|
|
1238
|
+
batch = NULL;
|
|
1239
|
+
}
|
|
1240
|
+
err = rd_kafka_share_poll(rkshare, 2000, &batch);
|
|
1241
|
+
if (err)
|
|
1242
|
+
rd_kafka_error_destroy(err);
|
|
1243
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
TEST_ASSERT(rcvd == 1,
|
|
1247
|
+
"Delivery attempt %d: expected 1 message, got %zu",
|
|
1248
|
+
delivery_attempt, rcvd);
|
|
1249
|
+
|
|
1250
|
+
msg0 = rd_kafka_messages_get(batch, 0);
|
|
1251
|
+
|
|
1252
|
+
/* Verify delivery_count matches attempt number */
|
|
1253
|
+
TEST_ASSERT(
|
|
1254
|
+
rd_kafka_message_delivery_count(msg0) == delivery_attempt,
|
|
1255
|
+
"Delivery attempt %d: expected delivery_count=%d, got %d",
|
|
1256
|
+
delivery_attempt, delivery_attempt,
|
|
1257
|
+
rd_kafka_message_delivery_count(msg0));
|
|
1258
|
+
|
|
1259
|
+
TEST_SAY(
|
|
1260
|
+
"Delivery attempt %d: received message "
|
|
1261
|
+
"(delivery_count=%d), sending RELEASE\n",
|
|
1262
|
+
delivery_attempt, rd_kafka_message_delivery_count(msg0));
|
|
1263
|
+
|
|
1264
|
+
/* RELEASE to trigger redelivery */
|
|
1265
|
+
rd_kafka_share_acknowledge_type(
|
|
1266
|
+
rkshare, msg0, RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_RELEASE);
|
|
1267
|
+
rd_kafka_messages_destroy(batch);
|
|
1268
|
+
batch = NULL;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/* Now poll again - message should NOT be redelivered (max attempts
|
|
1272
|
+
* reached) */
|
|
1273
|
+
TEST_SAY("Polling for 6th delivery (should NOT receive message)...\n");
|
|
1274
|
+
rcvd = 0;
|
|
1275
|
+
attempts = 5;
|
|
1276
|
+
while (attempts-- > 0) {
|
|
1277
|
+
size_t batch_rcvd;
|
|
1278
|
+
err = rd_kafka_share_poll(rkshare, 2000, &batch);
|
|
1279
|
+
if (err)
|
|
1280
|
+
rd_kafka_error_destroy(err);
|
|
1281
|
+
batch_rcvd = rd_kafka_messages_count(batch);
|
|
1282
|
+
|
|
1283
|
+
if (batch_rcvd > 0) {
|
|
1284
|
+
size_t m;
|
|
1285
|
+
for (m = 0; m < batch_rcvd; m++) {
|
|
1286
|
+
rd_kafka_message_t *msg =
|
|
1287
|
+
rd_kafka_messages_get(batch, m);
|
|
1288
|
+
if (!msg->err)
|
|
1289
|
+
rcvd++;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
rd_kafka_messages_destroy(batch);
|
|
1293
|
+
batch = NULL;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
TEST_ASSERT(rcvd == 0,
|
|
1297
|
+
"Expected 0 messages after %d RELEASE attempts, got %zu",
|
|
1298
|
+
max_deliveries, rcvd);
|
|
1299
|
+
|
|
1300
|
+
TEST_SAY("SUCCESS: Message not redelivered after %d RELEASE attempts\n",
|
|
1301
|
+
max_deliveries);
|
|
1302
|
+
|
|
1303
|
+
test_share_consumer_close(rkshare);
|
|
1304
|
+
test_share_destroy(rkshare);
|
|
1305
|
+
|
|
1306
|
+
TEST_SAY("=== test_max_delivery_attempts: PASSED ===\n");
|
|
1307
|
+
|
|
1308
|
+
SUB_TEST_PASS();
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
|
|
1312
|
+
/***************************************************************************
|
|
1313
|
+
* High-Intensity Random Acknowledgement Tests
|
|
1314
|
+
*
|
|
1315
|
+
* These tests produce large numbers of messages and apply random
|
|
1316
|
+
* acknowledgement types (ACCEPT/REJECT/RELEASE) to stress test the
|
|
1317
|
+
* acknowledgement infrastructure across different topologies.
|
|
1318
|
+
***************************************************************************/
|
|
1319
|
+
|
|
1320
|
+
/**
|
|
1321
|
+
* @brief High-intensity random acks: Single topic, single partition
|
|
1322
|
+
*
|
|
1323
|
+
* 5000 messages on 1 topic with 1 partition.
|
|
1324
|
+
* Random ACCEPT/REJECT/RELEASE for each message.
|
|
1325
|
+
*/
|
|
1326
|
+
static void do_test_random_ack_single_topic_single_partition(void) {
|
|
1327
|
+
ack_test_config_t config = {.test_name = "random-ack-1t-1p-5000msgs",
|
|
1328
|
+
.topic_cnt = 1,
|
|
1329
|
+
.partitions = {1},
|
|
1330
|
+
.consumer_cnt = 1,
|
|
1331
|
+
.use_random_acks = rd_true,
|
|
1332
|
+
.total_msgs = 5000};
|
|
1333
|
+
SUB_TEST();
|
|
1334
|
+
run_ack_test(&config);
|
|
1335
|
+
SUB_TEST_PASS();
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
/**
|
|
1339
|
+
* @brief High-intensity random acks: Multiple topics, single partition each
|
|
1340
|
+
*
|
|
1341
|
+
* 5000 messages across 4 topics, 1 partition each (~1250 msgs per topic).
|
|
1342
|
+
* Random ACCEPT/REJECT/RELEASE for each message.
|
|
1343
|
+
*/
|
|
1344
|
+
static void do_test_random_ack_multiple_topics_single_partition(void) {
|
|
1345
|
+
ack_test_config_t config = {.test_name = "random-ack-4t-1p-5000msgs",
|
|
1346
|
+
.topic_cnt = 4,
|
|
1347
|
+
.partitions = {1, 1, 1, 1},
|
|
1348
|
+
.consumer_cnt = 1,
|
|
1349
|
+
.use_random_acks = rd_true,
|
|
1350
|
+
.total_msgs = 5000};
|
|
1351
|
+
SUB_TEST();
|
|
1352
|
+
run_ack_test(&config);
|
|
1353
|
+
SUB_TEST_PASS();
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
/**
|
|
1357
|
+
* @brief High-intensity random acks: Single topic, multiple partitions
|
|
1358
|
+
*
|
|
1359
|
+
* 5000 messages on 1 topic with 4 partitions (~1250 msgs per partition).
|
|
1360
|
+
* Random ACCEPT/REJECT/RELEASE for each message.
|
|
1361
|
+
*/
|
|
1362
|
+
static void do_test_random_ack_single_topic_multiple_partitions(void) {
|
|
1363
|
+
ack_test_config_t config = {.test_name = "random-ack-1t-4p-5000msgs",
|
|
1364
|
+
.topic_cnt = 1,
|
|
1365
|
+
.partitions = {4},
|
|
1366
|
+
.consumer_cnt = 1,
|
|
1367
|
+
.use_random_acks = rd_true,
|
|
1368
|
+
.total_msgs = 5000};
|
|
1369
|
+
SUB_TEST();
|
|
1370
|
+
run_ack_test(&config);
|
|
1371
|
+
SUB_TEST_PASS();
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
/**
|
|
1375
|
+
* @brief High-intensity random acks: Multiple topics, multiple partitions
|
|
1376
|
+
*
|
|
1377
|
+
* 5000 messages across 2 topics, 2 partitions each (~1250 msgs per partition).
|
|
1378
|
+
* Random ACCEPT/REJECT/RELEASE for each message.
|
|
1379
|
+
*/
|
|
1380
|
+
static void do_test_random_ack_multiple_topics_multiple_partitions(void) {
|
|
1381
|
+
ack_test_config_t config = {.test_name = "random-ack-2t-2p-5000msgs",
|
|
1382
|
+
.topic_cnt = 2,
|
|
1383
|
+
.partitions = {2, 2},
|
|
1384
|
+
.consumer_cnt = 1,
|
|
1385
|
+
.use_random_acks = rd_true,
|
|
1386
|
+
.total_msgs = 5000};
|
|
1387
|
+
SUB_TEST();
|
|
1388
|
+
run_ack_test(&config);
|
|
1389
|
+
SUB_TEST_PASS();
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* @brief Scale test: 15 topics, 1 partition each, 10000 messages
|
|
1394
|
+
*
|
|
1395
|
+
* ~666 messages per topic. Tests handling many topics with random acks.
|
|
1396
|
+
*/
|
|
1397
|
+
static void do_test_scale_15_topics_single_partition(void) {
|
|
1398
|
+
ack_test_config_t config = {
|
|
1399
|
+
.test_name = "scale-15t-1p-10000msgs",
|
|
1400
|
+
.topic_cnt = 15,
|
|
1401
|
+
.partitions = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
1402
|
+
.consumer_cnt = 1,
|
|
1403
|
+
.use_random_acks = rd_true,
|
|
1404
|
+
.total_msgs = 10000};
|
|
1405
|
+
SUB_TEST();
|
|
1406
|
+
run_ack_test(&config);
|
|
1407
|
+
SUB_TEST_PASS();
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* @brief Scale test: 15 topics, 2 partitions each, 10000 messages
|
|
1412
|
+
*
|
|
1413
|
+
* ~333 messages per partition (30 partitions total).
|
|
1414
|
+
* Tests handling many topics with multiple partitions.
|
|
1415
|
+
*/
|
|
1416
|
+
static void do_test_scale_15_topics_multiple_partitions(void) {
|
|
1417
|
+
ack_test_config_t config = {
|
|
1418
|
+
.test_name = "scale-15t-2p-10000msgs",
|
|
1419
|
+
.topic_cnt = 15,
|
|
1420
|
+
.partitions = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
|
|
1421
|
+
.consumer_cnt = 1,
|
|
1422
|
+
.use_random_acks = rd_true,
|
|
1423
|
+
.total_msgs = 10000};
|
|
1424
|
+
SUB_TEST();
|
|
1425
|
+
run_ack_test(&config);
|
|
1426
|
+
SUB_TEST_PASS();
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
/**
|
|
1430
|
+
* @brief Scale test: 8 topics, 4 partitions each, 8000 messages
|
|
1431
|
+
*
|
|
1432
|
+
* ~250 messages per partition (32 partitions total).
|
|
1433
|
+
* Tests high partition count scenario.
|
|
1434
|
+
*/
|
|
1435
|
+
static void do_test_scale_8_topics_4_partitions(void) {
|
|
1436
|
+
ack_test_config_t config = {.test_name = "scale-8t-4p-8000msgs",
|
|
1437
|
+
.topic_cnt = 8,
|
|
1438
|
+
.partitions = {4, 4, 4, 4, 4, 4, 4, 4},
|
|
1439
|
+
.consumer_cnt = 1,
|
|
1440
|
+
.use_random_acks = rd_true,
|
|
1441
|
+
.total_msgs = 8000};
|
|
1442
|
+
SUB_TEST();
|
|
1443
|
+
run_ack_test(&config);
|
|
1444
|
+
SUB_TEST_PASS();
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
/**
|
|
1448
|
+
* @brief Scale test: Single topic, 8 partitions, 10000 messages
|
|
1449
|
+
*
|
|
1450
|
+
* 1250 messages per partition. Tests single topic with many partitions.
|
|
1451
|
+
*/
|
|
1452
|
+
static void do_test_scale_single_topic_8_partitions(void) {
|
|
1453
|
+
ack_test_config_t config = {.test_name = "scale-1t-8p-10000msgs",
|
|
1454
|
+
.topic_cnt = 1,
|
|
1455
|
+
.partitions = {8},
|
|
1456
|
+
.consumer_cnt = 1,
|
|
1457
|
+
.use_random_acks = rd_true,
|
|
1458
|
+
.total_msgs = 10000};
|
|
1459
|
+
SUB_TEST();
|
|
1460
|
+
run_ack_test(&config);
|
|
1461
|
+
SUB_TEST_PASS();
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
/**
|
|
1465
|
+
* @brief Scale test: 10 topics, 3 partitions each, 15000 messages
|
|
1466
|
+
*
|
|
1467
|
+
* 500 messages per partition (30 partitions total).
|
|
1468
|
+
* Large scale test for acknowledgement infrastructure.
|
|
1469
|
+
*/
|
|
1470
|
+
static void do_test_scale_10_topics_3_partitions(void) {
|
|
1471
|
+
ack_test_config_t config = {
|
|
1472
|
+
.test_name = "scale-10t-3p-15000msgs",
|
|
1473
|
+
.topic_cnt = 10,
|
|
1474
|
+
.partitions = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
|
|
1475
|
+
.consumer_cnt = 1,
|
|
1476
|
+
.use_random_acks = rd_true,
|
|
1477
|
+
.total_msgs = 15000};
|
|
1478
|
+
SUB_TEST();
|
|
1479
|
+
run_ack_test(&config);
|
|
1480
|
+
SUB_TEST_PASS();
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
|
|
1484
|
+
/**
|
|
1485
|
+
* @brief Re-acknowledging a record after the batch has been polled past
|
|
1486
|
+
* returns _STATE.
|
|
1487
|
+
*
|
|
1488
|
+
* In explicit mode, poll batch1 (1 record), acknowledge it, poll batch2
|
|
1489
|
+
* (empty), then try to acknowledge batch1's record again. The second
|
|
1490
|
+
* acknowledge must return _STATE because the record is no longer in the
|
|
1491
|
+
* current batch / inflight map.
|
|
1492
|
+
*/
|
|
1493
|
+
static void do_test_ack_message_from_earlier_batch(void) {
|
|
1494
|
+
rd_kafka_share_t *rkshare;
|
|
1495
|
+
rd_kafka_messages_t *batch1 = NULL;
|
|
1496
|
+
rd_kafka_messages_t *batch2 = NULL;
|
|
1497
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
1498
|
+
rd_kafka_resp_err_t ack_err;
|
|
1499
|
+
const char *group = "share-cross-batch-ack";
|
|
1500
|
+
const char *topic;
|
|
1501
|
+
size_t b1_rcvd = 0;
|
|
1502
|
+
size_t r = 0;
|
|
1503
|
+
rd_kafka_error_t *e;
|
|
1504
|
+
int attempts;
|
|
1505
|
+
rd_kafka_message_t *b1_msg0;
|
|
1506
|
+
|
|
1507
|
+
SUB_TEST();
|
|
1508
|
+
|
|
1509
|
+
TEST_SAY("\n");
|
|
1510
|
+
TEST_SAY("=== test_ack_message_from_earlier_batch ===\n");
|
|
1511
|
+
|
|
1512
|
+
rkshare = test_create_share_consumer(group, "explicit");
|
|
1513
|
+
topic = test_mk_topic_name("0172-cross-batch", 1);
|
|
1514
|
+
test_create_topic_wait_exists(NULL, topic, 1, -1, 60 * 1000);
|
|
1515
|
+
test_produce_msgs_simple(common_producer, topic, 0, 1);
|
|
1516
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
1517
|
+
|
|
1518
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
1519
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1520
|
+
rd_kafka_share_subscribe(rkshare, subs);
|
|
1521
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1522
|
+
|
|
1523
|
+
/* Poll batch 1 */
|
|
1524
|
+
attempts = 30;
|
|
1525
|
+
while (b1_rcvd < 1 && attempts-- > 0) {
|
|
1526
|
+
if (batch1) {
|
|
1527
|
+
rd_kafka_messages_destroy(batch1);
|
|
1528
|
+
batch1 = NULL;
|
|
1529
|
+
}
|
|
1530
|
+
e = rd_kafka_share_poll(rkshare, 2000, &batch1);
|
|
1531
|
+
if (e)
|
|
1532
|
+
rd_kafka_error_destroy(e);
|
|
1533
|
+
b1_rcvd = rd_kafka_messages_count(batch1);
|
|
1534
|
+
}
|
|
1535
|
+
TEST_ASSERT(b1_rcvd == 1, "Expected 1 record in batch1, got %zu",
|
|
1536
|
+
b1_rcvd);
|
|
1537
|
+
|
|
1538
|
+
b1_msg0 = rd_kafka_messages_get(batch1, 0);
|
|
1539
|
+
|
|
1540
|
+
ack_err = rd_kafka_share_acknowledge(rkshare, b1_msg0);
|
|
1541
|
+
TEST_ASSERT(ack_err == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1542
|
+
"First ack failed: %s", rd_kafka_err2name(ack_err));
|
|
1543
|
+
|
|
1544
|
+
/* Poll batch 2 - must be empty (we already consumed and acked
|
|
1545
|
+
* the only record). */
|
|
1546
|
+
e = rd_kafka_share_poll(rkshare, 2000, &batch2);
|
|
1547
|
+
if (e)
|
|
1548
|
+
rd_kafka_error_destroy(e);
|
|
1549
|
+
r = rd_kafka_messages_count(batch2);
|
|
1550
|
+
TEST_ASSERT(r == 0,
|
|
1551
|
+
"Expected batch 2 to be empty after acking the only "
|
|
1552
|
+
"record, got %zu records",
|
|
1553
|
+
r);
|
|
1554
|
+
rd_kafka_messages_destroy(batch2);
|
|
1555
|
+
batch2 = NULL;
|
|
1556
|
+
|
|
1557
|
+
/* Re-acknowledge from batch1 - should fail with _STATE */
|
|
1558
|
+
ack_err = rd_kafka_share_acknowledge(rkshare, b1_msg0);
|
|
1559
|
+
TEST_ASSERT(ack_err == RD_KAFKA_RESP_ERR__STATE,
|
|
1560
|
+
"Expected _STATE for re-ack across batches, got %s",
|
|
1561
|
+
rd_kafka_err2name(ack_err));
|
|
1562
|
+
|
|
1563
|
+
rd_kafka_messages_destroy(batch1);
|
|
1564
|
+
batch1 = NULL;
|
|
1565
|
+
|
|
1566
|
+
test_share_consumer_close(rkshare);
|
|
1567
|
+
test_share_destroy(rkshare);
|
|
1568
|
+
|
|
1569
|
+
TEST_SAY("=== test_ack_message_from_earlier_batch: PASSED ===\n");
|
|
1570
|
+
|
|
1571
|
+
SUB_TEST_PASS();
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
|
|
1575
|
+
/**
|
|
1576
|
+
* @brief acknowledge_offset() before any record has been consumed
|
|
1577
|
+
* returns _STATE.
|
|
1578
|
+
*
|
|
1579
|
+
* Subscribe but do not poll; call acknowledge_offset() with arbitrary
|
|
1580
|
+
* topic/partition/offset values and expect _STATE (nothing in inflight).
|
|
1581
|
+
*/
|
|
1582
|
+
static void do_test_ack_offset_before_consume(void) {
|
|
1583
|
+
rd_kafka_share_t *rkshare;
|
|
1584
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
1585
|
+
rd_kafka_resp_err_t err;
|
|
1586
|
+
const char *group = "share-ack-before-consume";
|
|
1587
|
+
const char *topic;
|
|
1588
|
+
|
|
1589
|
+
SUB_TEST();
|
|
1590
|
+
|
|
1591
|
+
TEST_SAY("\n");
|
|
1592
|
+
TEST_SAY("=== test_ack_offset_before_consume ===\n");
|
|
1593
|
+
|
|
1594
|
+
rkshare = test_create_share_consumer(group, "explicit");
|
|
1595
|
+
topic = test_mk_topic_name("0172-ack-precons", 1);
|
|
1596
|
+
test_create_topic_wait_exists(NULL, topic, 1, -1, 60 * 1000);
|
|
1597
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
1598
|
+
|
|
1599
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
1600
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1601
|
+
rd_kafka_share_subscribe(rkshare, subs);
|
|
1602
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1603
|
+
|
|
1604
|
+
err = rd_kafka_share_acknowledge_offset(
|
|
1605
|
+
rkshare, topic, 0, 0, RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
1606
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE,
|
|
1607
|
+
"Expected _STATE for ack_offset before any consume, "
|
|
1608
|
+
"got %s",
|
|
1609
|
+
rd_kafka_err2name(err));
|
|
1610
|
+
|
|
1611
|
+
test_share_consumer_close(rkshare);
|
|
1612
|
+
test_share_destroy(rkshare);
|
|
1613
|
+
|
|
1614
|
+
TEST_SAY("=== test_ack_offset_before_consume: PASSED ===\n");
|
|
1615
|
+
|
|
1616
|
+
SUB_TEST_PASS();
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
|
|
1620
|
+
/**
|
|
1621
|
+
* @brief acknowledge_offset() with wrong topic / partition / offset
|
|
1622
|
+
* returns _STATE; correct values succeed.
|
|
1623
|
+
*
|
|
1624
|
+
* Consume one record so we have a valid (topic, partition, offset) tuple
|
|
1625
|
+
* in the inflight map. Calling acknowledge_offset() with wrong values for
|
|
1626
|
+
* any of the three components must return _STATE. The correct values then
|
|
1627
|
+
* succeed.
|
|
1628
|
+
*/
|
|
1629
|
+
static void do_test_ack_offset_wrong_params(void) {
|
|
1630
|
+
rd_kafka_share_t *rkshare;
|
|
1631
|
+
rd_kafka_messages_t *batch = NULL;
|
|
1632
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
1633
|
+
rd_kafka_resp_err_t err;
|
|
1634
|
+
const char *group = "share-ack-wrong-params";
|
|
1635
|
+
const char *topic;
|
|
1636
|
+
size_t rcvd = 0;
|
|
1637
|
+
int attempts;
|
|
1638
|
+
int32_t partition;
|
|
1639
|
+
int64_t offset;
|
|
1640
|
+
rd_kafka_message_t *msg0;
|
|
1641
|
+
|
|
1642
|
+
SUB_TEST();
|
|
1643
|
+
|
|
1644
|
+
TEST_SAY("\n");
|
|
1645
|
+
TEST_SAY("=== test_ack_offset_wrong_params ===\n");
|
|
1646
|
+
|
|
1647
|
+
rkshare = test_create_share_consumer(group, "explicit");
|
|
1648
|
+
topic = test_mk_topic_name("0172-wrong-params", 1);
|
|
1649
|
+
test_create_topic_wait_exists(NULL, topic, 1, -1, 60 * 1000);
|
|
1650
|
+
test_produce_msgs_simple(common_producer, topic, 0, 1);
|
|
1651
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
1652
|
+
|
|
1653
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
1654
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1655
|
+
rd_kafka_share_subscribe(rkshare, subs);
|
|
1656
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1657
|
+
|
|
1658
|
+
attempts = 30;
|
|
1659
|
+
while (rcvd < 1 && attempts-- > 0) {
|
|
1660
|
+
rd_kafka_error_t *e;
|
|
1661
|
+
if (batch) {
|
|
1662
|
+
rd_kafka_messages_destroy(batch);
|
|
1663
|
+
batch = NULL;
|
|
1664
|
+
}
|
|
1665
|
+
e = rd_kafka_share_poll(rkshare, 2000, &batch);
|
|
1666
|
+
if (e)
|
|
1667
|
+
rd_kafka_error_destroy(e);
|
|
1668
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1669
|
+
}
|
|
1670
|
+
TEST_ASSERT(rcvd == 1, "Expected 1 record, got %zu", rcvd);
|
|
1671
|
+
|
|
1672
|
+
msg0 = rd_kafka_messages_get(batch, 0);
|
|
1673
|
+
partition = msg0->partition;
|
|
1674
|
+
offset = msg0->offset;
|
|
1675
|
+
|
|
1676
|
+
/* Wrong offset */
|
|
1677
|
+
err = rd_kafka_share_acknowledge_offset(
|
|
1678
|
+
rkshare, topic, partition, offset + 100,
|
|
1679
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
1680
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE,
|
|
1681
|
+
"Expected _STATE for wrong offset, got %s",
|
|
1682
|
+
rd_kafka_err2name(err));
|
|
1683
|
+
|
|
1684
|
+
/* Wrong topic */
|
|
1685
|
+
err = rd_kafka_share_acknowledge_offset(
|
|
1686
|
+
rkshare, "0172-nonexistent-topic", partition, offset,
|
|
1687
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
1688
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE,
|
|
1689
|
+
"Expected _STATE for wrong topic, got %s",
|
|
1690
|
+
rd_kafka_err2name(err));
|
|
1691
|
+
|
|
1692
|
+
/* Wrong partition */
|
|
1693
|
+
err = rd_kafka_share_acknowledge_offset(
|
|
1694
|
+
rkshare, topic, partition + 100, offset,
|
|
1695
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
1696
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE,
|
|
1697
|
+
"Expected _STATE for wrong partition, got %s",
|
|
1698
|
+
rd_kafka_err2name(err));
|
|
1699
|
+
|
|
1700
|
+
/* Correct values - should succeed */
|
|
1701
|
+
err = rd_kafka_share_acknowledge_offset(
|
|
1702
|
+
rkshare, topic, partition, offset,
|
|
1703
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
1704
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1705
|
+
"Expected success for correct params, got %s",
|
|
1706
|
+
rd_kafka_err2name(err));
|
|
1707
|
+
|
|
1708
|
+
rd_kafka_messages_destroy(batch);
|
|
1709
|
+
batch = NULL;
|
|
1710
|
+
|
|
1711
|
+
test_share_consumer_close(rkshare);
|
|
1712
|
+
test_share_destroy(rkshare);
|
|
1713
|
+
|
|
1714
|
+
TEST_SAY("=== test_ack_offset_wrong_params: PASSED ===\n");
|
|
1715
|
+
|
|
1716
|
+
SUB_TEST_PASS();
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
|
|
1720
|
+
/**
|
|
1721
|
+
* @brief Mix of implicit and explicit ack-mode consumers in the same group.
|
|
1722
|
+
*
|
|
1723
|
+
* `share.acknowledgement.mode` is a CLIENT-side config, so two consumers
|
|
1724
|
+
* in the same share group can use different modes. Verifies that:
|
|
1725
|
+
* - The implicit consumer auto-acks on each consume_batch.
|
|
1726
|
+
* - The explicit consumer's accepted records are not redelivered after
|
|
1727
|
+
* commit_sync.
|
|
1728
|
+
* - All produced records are delivered (no losses), and the total
|
|
1729
|
+
* count matches the produced count once the explicit consumer
|
|
1730
|
+
* commits (no duplicates).
|
|
1731
|
+
*/
|
|
1732
|
+
static void do_test_mixed_ack_mode_same_group(void) {
|
|
1733
|
+
const char *group = "share-mixed-ack-mode";
|
|
1734
|
+
const char *topic;
|
|
1735
|
+
rd_kafka_share_t *implicit_c;
|
|
1736
|
+
rd_kafka_share_t *explicit_c;
|
|
1737
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
1738
|
+
rd_kafka_messages_t *batch = NULL;
|
|
1739
|
+
const int total_msgs = 400;
|
|
1740
|
+
int implicit_cnt = 0;
|
|
1741
|
+
int explicit_cnt = 0;
|
|
1742
|
+
int attempts;
|
|
1743
|
+
rd_kafka_error_t *cerr;
|
|
1744
|
+
test_ack_cb_state_t exp_state = {0};
|
|
1745
|
+
|
|
1746
|
+
SUB_TEST();
|
|
1747
|
+
|
|
1748
|
+
TEST_SAY("\n");
|
|
1749
|
+
TEST_SAY(
|
|
1750
|
+
"=== Mixed ack-mode (implicit + explicit) in same group ===\n");
|
|
1751
|
+
|
|
1752
|
+
topic = test_mk_topic_name("0172-mixed-ack-mode", 1);
|
|
1753
|
+
test_create_topic_wait_exists(NULL, topic, 4, -1, 60 * 1000);
|
|
1754
|
+
test_produce_msgs_simple(common_producer, topic, RD_KAFKA_PARTITION_UA,
|
|
1755
|
+
total_msgs);
|
|
1756
|
+
|
|
1757
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
1758
|
+
|
|
1759
|
+
implicit_c = test_create_share_consumer(group, "implicit");
|
|
1760
|
+
explicit_c = test_create_share_consumer_with_cb(group, "explicit",
|
|
1761
|
+
&exp_state, NULL);
|
|
1762
|
+
|
|
1763
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
1764
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1765
|
+
rd_kafka_share_subscribe(implicit_c, subs);
|
|
1766
|
+
rd_kafka_share_subscribe(explicit_c, subs);
|
|
1767
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1768
|
+
|
|
1769
|
+
/* Round-robin poll across both consumers. The implicit consumer's
|
|
1770
|
+
* messages are auto-acked by the next consume_batch call; the
|
|
1771
|
+
* explicit consumer must call rd_kafka_share_acknowledge per
|
|
1772
|
+
* message. */
|
|
1773
|
+
attempts = 200;
|
|
1774
|
+
while (implicit_cnt + explicit_cnt < total_msgs && attempts-- > 0) {
|
|
1775
|
+
size_t rcvd = 0;
|
|
1776
|
+
size_t m;
|
|
1777
|
+
rd_kafka_error_t *err;
|
|
1778
|
+
|
|
1779
|
+
/* Implicit consumer */
|
|
1780
|
+
err = rd_kafka_share_poll(implicit_c, 1000, &batch);
|
|
1781
|
+
if (err) {
|
|
1782
|
+
rd_kafka_error_destroy(err);
|
|
1783
|
+
} else {
|
|
1784
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1785
|
+
for (m = 0; m < rcvd; m++) {
|
|
1786
|
+
rd_kafka_message_t *msg =
|
|
1787
|
+
rd_kafka_messages_get(batch, m);
|
|
1788
|
+
if (!msg->err)
|
|
1789
|
+
implicit_cnt++;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
rd_kafka_messages_destroy(batch);
|
|
1793
|
+
batch = NULL;
|
|
1794
|
+
|
|
1795
|
+
/* Explicit consumer */
|
|
1796
|
+
rcvd = 0;
|
|
1797
|
+
err = rd_kafka_share_poll(explicit_c, 1000, &batch);
|
|
1798
|
+
if (err) {
|
|
1799
|
+
rd_kafka_error_destroy(err);
|
|
1800
|
+
continue;
|
|
1801
|
+
}
|
|
1802
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1803
|
+
for (m = 0; m < rcvd; m++) {
|
|
1804
|
+
rd_kafka_message_t *msg =
|
|
1805
|
+
rd_kafka_messages_get(batch, m);
|
|
1806
|
+
if (!msg->err) {
|
|
1807
|
+
rd_kafka_resp_err_t ack_err =
|
|
1808
|
+
rd_kafka_share_acknowledge_type(
|
|
1809
|
+
explicit_c, msg,
|
|
1810
|
+
RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
1811
|
+
TEST_ASSERT(!ack_err,
|
|
1812
|
+
"explicit ACCEPT failed: %s",
|
|
1813
|
+
rd_kafka_err2str(ack_err));
|
|
1814
|
+
explicit_cnt++;
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
rd_kafka_messages_destroy(batch);
|
|
1818
|
+
batch = NULL;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
TEST_SAY("Consumed: implicit=%d explicit=%d total=%d/%d\n",
|
|
1822
|
+
implicit_cnt, explicit_cnt, implicit_cnt + explicit_cnt,
|
|
1823
|
+
total_msgs);
|
|
1824
|
+
|
|
1825
|
+
/* Flush explicit consumer's accepted acks to the broker so they
|
|
1826
|
+
* are durable before we tear the consumer down. */
|
|
1827
|
+
rd_kafka_topic_partition_list_t *commit_parts = NULL;
|
|
1828
|
+
cerr = rd_kafka_share_commit_sync(explicit_c, 30000, &commit_parts);
|
|
1829
|
+
TEST_ASSERT(!cerr, "explicit commit_sync failed: %s",
|
|
1830
|
+
cerr ? rd_kafka_error_string(cerr) : "");
|
|
1831
|
+
if (commit_parts)
|
|
1832
|
+
rd_kafka_topic_partition_list_destroy(commit_parts);
|
|
1833
|
+
TEST_ASSERT(test_ack_cb_state_first_err(&exp_state) ==
|
|
1834
|
+
RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1835
|
+
"explicit ack callback reported err: %s",
|
|
1836
|
+
rd_kafka_err2name(test_ack_cb_state_first_err(&exp_state)));
|
|
1837
|
+
|
|
1838
|
+
/* Final flush poll on the implicit consumer so the last batch's
|
|
1839
|
+
* piggybacked acks reach the broker. */
|
|
1840
|
+
rd_kafka_error_t *err = rd_kafka_share_poll(implicit_c, 1000, &batch);
|
|
1841
|
+
if (err)
|
|
1842
|
+
rd_kafka_error_destroy(err);
|
|
1843
|
+
rd_kafka_messages_destroy(batch);
|
|
1844
|
+
batch = NULL;
|
|
1845
|
+
|
|
1846
|
+
TEST_ASSERT(implicit_cnt + explicit_cnt == total_msgs,
|
|
1847
|
+
"Expected exactly %d total records across both consumers, "
|
|
1848
|
+
"got %d (implicit=%d explicit=%d)",
|
|
1849
|
+
total_msgs, implicit_cnt + explicit_cnt, implicit_cnt,
|
|
1850
|
+
explicit_cnt);
|
|
1851
|
+
TEST_ASSERT(implicit_cnt > 0, "Implicit consumer received no records");
|
|
1852
|
+
TEST_ASSERT(explicit_cnt > 0, "Explicit consumer received no records");
|
|
1853
|
+
|
|
1854
|
+
test_share_consumer_close(implicit_c);
|
|
1855
|
+
test_share_destroy(implicit_c);
|
|
1856
|
+
test_share_consumer_close(explicit_c);
|
|
1857
|
+
test_share_destroy(explicit_c);
|
|
1858
|
+
test_ack_cb_state_destroy(&exp_state);
|
|
1859
|
+
|
|
1860
|
+
TEST_SAY(
|
|
1861
|
+
"SUCCESS: mixed ack-mode group - implicit=%d explicit=%d "
|
|
1862
|
+
"(total=%d)\n",
|
|
1863
|
+
implicit_cnt, explicit_cnt, implicit_cnt + explicit_cnt);
|
|
1864
|
+
|
|
1865
|
+
SUB_TEST_PASS();
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
|
|
1869
|
+
int main_0172_share_consumer_acknowledge(int argc, char **argv) {
|
|
1870
|
+
|
|
1871
|
+
test_timeout_set(600); /* 10 minutes for all tests */
|
|
1872
|
+
|
|
1873
|
+
/* Create common handles for all tests */
|
|
1874
|
+
common_producer = test_create_producer();
|
|
1875
|
+
common_admin = test_create_producer();
|
|
1876
|
+
|
|
1877
|
+
/* Core tests */
|
|
1878
|
+
do_test_release_redelivery();
|
|
1879
|
+
do_test_reject_no_redelivery();
|
|
1880
|
+
do_test_accept_no_redelivery();
|
|
1881
|
+
|
|
1882
|
+
/* Error handling tests */
|
|
1883
|
+
do_test_ack_null_message();
|
|
1884
|
+
do_test_ack_null_rkshare();
|
|
1885
|
+
do_test_ack_invalid_type();
|
|
1886
|
+
do_test_release_then_reject_no_redelivery();
|
|
1887
|
+
|
|
1888
|
+
/* Acknowledgement state tests */
|
|
1889
|
+
do_test_change_ack_type_before_commit();
|
|
1890
|
+
do_test_ack_after_commit();
|
|
1891
|
+
do_test_ack_message_from_earlier_batch();
|
|
1892
|
+
do_test_ack_offset_before_consume();
|
|
1893
|
+
do_test_ack_offset_wrong_params();
|
|
1894
|
+
|
|
1895
|
+
/* Max delivery attempts test */
|
|
1896
|
+
do_test_max_delivery_attempts();
|
|
1897
|
+
|
|
1898
|
+
/* High-intensity random acknowledgement tests */
|
|
1899
|
+
do_test_random_ack_single_topic_single_partition();
|
|
1900
|
+
do_test_random_ack_multiple_topics_single_partition();
|
|
1901
|
+
do_test_random_ack_single_topic_multiple_partitions();
|
|
1902
|
+
do_test_random_ack_multiple_topics_multiple_partitions();
|
|
1903
|
+
|
|
1904
|
+
/* Scale tests - high topic/partition counts with many messages */
|
|
1905
|
+
do_test_scale_15_topics_single_partition();
|
|
1906
|
+
do_test_scale_15_topics_multiple_partitions();
|
|
1907
|
+
do_test_scale_8_topics_4_partitions();
|
|
1908
|
+
do_test_scale_single_topic_8_partitions();
|
|
1909
|
+
do_test_scale_10_topics_3_partitions();
|
|
1910
|
+
|
|
1911
|
+
/* Mixed ack-mode within the same share group */
|
|
1912
|
+
do_test_mixed_ack_mode_same_group();
|
|
1913
|
+
|
|
1914
|
+
/* Cleanup common handles */
|
|
1915
|
+
rd_kafka_destroy(common_admin);
|
|
1916
|
+
rd_kafka_destroy(common_producer);
|
|
1917
|
+
|
|
1918
|
+
return 0;
|
|
1919
|
+
}
|