@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,2102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* librdkafka - Apache Kafka C library
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2026, 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
|
+
#include "rdkafka.h"
|
|
31
|
+
#include "rdkafka_protocol.h"
|
|
32
|
+
|
|
33
|
+
#define MAX_TOPICS 16
|
|
34
|
+
#define MAX_PARTITIONS 32
|
|
35
|
+
#define BATCH_SIZE 10000
|
|
36
|
+
#define MAX_CONSUME_ATTEMPTS 30
|
|
37
|
+
|
|
38
|
+
/** Common producer reused across all real-broker tests. */
|
|
39
|
+
static rd_kafka_t *common_producer;
|
|
40
|
+
|
|
41
|
+
/** Common admin client reused across all real-broker tests. */
|
|
42
|
+
static rd_kafka_t *common_admin;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @brief Commit mode for test scenarios
|
|
46
|
+
*/
|
|
47
|
+
typedef enum {
|
|
48
|
+
COMMIT_MODE_NONE, /**< No commit before close */
|
|
49
|
+
COMMIT_MODE_ASYNC, /**< Call commitAsync before close */
|
|
50
|
+
COMMIT_MODE_SYNC /**< Call commitSync before close */
|
|
51
|
+
} commit_mode_t;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @brief Generic test context for topic and message tracking
|
|
55
|
+
*/
|
|
56
|
+
typedef struct {
|
|
57
|
+
char *topic_names[MAX_TOPICS];
|
|
58
|
+
int topic_cnt;
|
|
59
|
+
char *group_id;
|
|
60
|
+
int total_msgs_produced;
|
|
61
|
+
} test_context_t;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @brief Tracked message info for verification
|
|
65
|
+
*/
|
|
66
|
+
typedef struct {
|
|
67
|
+
char *topic;
|
|
68
|
+
int32_t partition;
|
|
69
|
+
int64_t offset;
|
|
70
|
+
} tracked_msg_t;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @brief Sink that collects ack receipts from both the share-ack callback
|
|
74
|
+
* and synchronous commit_sync results.
|
|
75
|
+
*
|
|
76
|
+
* Each (topic, partition, offset) is recorded at most once (idempotent add),
|
|
77
|
+
* so callback + commit_sync overlaps are harmless.
|
|
78
|
+
*/
|
|
79
|
+
typedef struct {
|
|
80
|
+
tracked_msg_t *receipts;
|
|
81
|
+
int receipt_cnt;
|
|
82
|
+
int receipt_capacity;
|
|
83
|
+
int callback_invocations; /* diagnostic */
|
|
84
|
+
rd_kafka_resp_err_t last_cb_err;
|
|
85
|
+
mtx_t lock;
|
|
86
|
+
} ack_receipts_t;
|
|
87
|
+
|
|
88
|
+
static void ack_receipts_init(ack_receipts_t *r) {
|
|
89
|
+
memset(r, 0, sizeof(*r));
|
|
90
|
+
mtx_init(&r->lock, mtx_plain);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static void ack_receipts_destroy(ack_receipts_t *r) {
|
|
94
|
+
int i;
|
|
95
|
+
for (i = 0; i < r->receipt_cnt; i++)
|
|
96
|
+
rd_free(r->receipts[i].topic);
|
|
97
|
+
if (r->receipts)
|
|
98
|
+
rd_free(r->receipts);
|
|
99
|
+
mtx_destroy(&r->lock);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Idempotent: dedupes on (topic, partition, offset). */
|
|
103
|
+
static void ack_receipts_add(ack_receipts_t *r,
|
|
104
|
+
const char *topic,
|
|
105
|
+
int32_t partition,
|
|
106
|
+
int64_t offset) {
|
|
107
|
+
int i;
|
|
108
|
+
mtx_lock(&r->lock);
|
|
109
|
+
for (i = 0; i < r->receipt_cnt; i++) {
|
|
110
|
+
if (r->receipts[i].partition == partition &&
|
|
111
|
+
r->receipts[i].offset == offset &&
|
|
112
|
+
strcmp(r->receipts[i].topic, topic) == 0) {
|
|
113
|
+
mtx_unlock(&r->lock);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (r->receipt_cnt == r->receipt_capacity) {
|
|
118
|
+
int new_cap =
|
|
119
|
+
r->receipt_capacity ? r->receipt_capacity * 2 : 16;
|
|
120
|
+
r->receipts =
|
|
121
|
+
rd_realloc(r->receipts, new_cap * sizeof(*r->receipts));
|
|
122
|
+
r->receipt_capacity = new_cap;
|
|
123
|
+
}
|
|
124
|
+
r->receipts[r->receipt_cnt].topic = rd_strdup(topic);
|
|
125
|
+
r->receipts[r->receipt_cnt].partition = partition;
|
|
126
|
+
r->receipts[r->receipt_cnt].offset = offset;
|
|
127
|
+
r->receipt_cnt++;
|
|
128
|
+
mtx_unlock(&r->lock);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @brief Share-ack callback that funnels every reported offset into
|
|
133
|
+
* the provided ack_receipts_t (passed as opaque).
|
|
134
|
+
*/
|
|
135
|
+
static void test_0178_ack_cb(rd_kafka_share_t *rkshare,
|
|
136
|
+
rd_kafka_share_partition_offsets_list_t *parts,
|
|
137
|
+
rd_kafka_resp_err_t err,
|
|
138
|
+
void *opaque) {
|
|
139
|
+
ack_receipts_t *r = opaque;
|
|
140
|
+
size_t pcnt, p;
|
|
141
|
+
|
|
142
|
+
(void)rkshare;
|
|
143
|
+
|
|
144
|
+
mtx_lock(&r->lock);
|
|
145
|
+
r->callback_invocations++;
|
|
146
|
+
r->last_cb_err = err;
|
|
147
|
+
mtx_unlock(&r->lock);
|
|
148
|
+
|
|
149
|
+
pcnt = rd_kafka_share_partition_offsets_list_count(parts);
|
|
150
|
+
TEST_SAY("ack_cb: invocation=%d err=%s partitions=%zu\n",
|
|
151
|
+
r->callback_invocations, rd_kafka_err2name(err), pcnt);
|
|
152
|
+
|
|
153
|
+
if (err != RD_KAFKA_RESP_ERR_NO_ERROR)
|
|
154
|
+
return;
|
|
155
|
+
|
|
156
|
+
for (p = 0; p < pcnt; p++) {
|
|
157
|
+
const rd_kafka_share_partition_offsets_t *entry =
|
|
158
|
+
rd_kafka_share_partition_offsets_list_get(parts, p);
|
|
159
|
+
const rd_kafka_topic_partition_t *tp;
|
|
160
|
+
const int64_t *offsets;
|
|
161
|
+
int ocnt, o;
|
|
162
|
+
|
|
163
|
+
if (!entry)
|
|
164
|
+
continue;
|
|
165
|
+
|
|
166
|
+
tp = rd_kafka_share_partition_offsets_partition(entry);
|
|
167
|
+
offsets = rd_kafka_share_partition_offsets_offsets(entry);
|
|
168
|
+
ocnt = rd_kafka_share_partition_offsets_offsets_cnt(entry);
|
|
169
|
+
|
|
170
|
+
for (o = 0; o < ocnt; o++)
|
|
171
|
+
ack_receipts_add(r, tp->topic, tp->partition,
|
|
172
|
+
offsets[o]);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @brief Build a share consumer with our ack callback wired in.
|
|
178
|
+
*
|
|
179
|
+
* Mirrors what test_create_share_consumer_with_cb does, but uses
|
|
180
|
+
* @p receipts as the opaque so test_0178_ack_cb can record into it.
|
|
181
|
+
*/
|
|
182
|
+
static rd_kafka_share_t *
|
|
183
|
+
create_share_consumer_with_receipts(const char *group_id,
|
|
184
|
+
const char *ack_mode,
|
|
185
|
+
ack_receipts_t *receipts) {
|
|
186
|
+
rd_kafka_share_t *rkshare;
|
|
187
|
+
rd_kafka_conf_t *conf;
|
|
188
|
+
char errstr[512];
|
|
189
|
+
|
|
190
|
+
test_conf_init(&conf, NULL, 60);
|
|
191
|
+
rd_kafka_conf_set(conf, "group.id", group_id, errstr, sizeof(errstr));
|
|
192
|
+
rd_kafka_conf_set(conf, "share.acknowledgement.mode", ack_mode, errstr,
|
|
193
|
+
sizeof(errstr));
|
|
194
|
+
|
|
195
|
+
rkshare = rd_kafka_share_consumer_new(conf, errstr, sizeof(errstr));
|
|
196
|
+
TEST_ASSERT(rkshare, "Failed to create share consumer: %s", errstr);
|
|
197
|
+
|
|
198
|
+
rd_kafka_error_t *error = rd_kafka_share_set_acknowledgement_commit_cb(
|
|
199
|
+
rkshare, test_0178_ack_cb, receipts);
|
|
200
|
+
TEST_ASSERT(error == NULL,
|
|
201
|
+
"Failed to set acknowledgement commit callback: %s",
|
|
202
|
+
rd_kafka_error_string(error));
|
|
203
|
+
return rkshare;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @brief Assert that @p r contains a receipt for every entry in
|
|
208
|
+
* @p expected[0..expected_cnt). Extra receipts trigger a warning.
|
|
209
|
+
*/
|
|
210
|
+
static void verify_receipts_match(ack_receipts_t *r,
|
|
211
|
+
const tracked_msg_t *expected,
|
|
212
|
+
int expected_cnt,
|
|
213
|
+
const char *context_label) {
|
|
214
|
+
rd_bool_t *seen =
|
|
215
|
+
expected_cnt > 0 ? rd_calloc(expected_cnt, sizeof(*seen)) : NULL;
|
|
216
|
+
int matched = 0;
|
|
217
|
+
int i, j;
|
|
218
|
+
|
|
219
|
+
mtx_lock(&r->lock);
|
|
220
|
+
|
|
221
|
+
for (i = 0; i < r->receipt_cnt; i++) {
|
|
222
|
+
rd_bool_t expected_hit = rd_false;
|
|
223
|
+
for (j = 0; j < expected_cnt; j++) {
|
|
224
|
+
if (seen[j])
|
|
225
|
+
continue;
|
|
226
|
+
if (r->receipts[i].partition == expected[j].partition &&
|
|
227
|
+
r->receipts[i].offset == expected[j].offset &&
|
|
228
|
+
strcmp(r->receipts[i].topic, expected[j].topic) ==
|
|
229
|
+
0) {
|
|
230
|
+
seen[j] = rd_true;
|
|
231
|
+
expected_hit = rd_true;
|
|
232
|
+
matched++;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (!expected_hit) {
|
|
237
|
+
TEST_WARN(
|
|
238
|
+
"ack receipts: unexpected receipt for %s [%d] "
|
|
239
|
+
"@ offset %" PRId64 " (context: %s)\n",
|
|
240
|
+
r->receipts[i].topic, r->receipts[i].partition,
|
|
241
|
+
r->receipts[i].offset, context_label);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
for (j = 0; j < expected_cnt; j++) {
|
|
246
|
+
if (!seen[j]) {
|
|
247
|
+
mtx_unlock(&r->lock);
|
|
248
|
+
TEST_FAIL(
|
|
249
|
+
"ack receipts: missing receipt for %s [%d] "
|
|
250
|
+
"@ offset %" PRId64
|
|
251
|
+
" (context: %s, "
|
|
252
|
+
"matched=%d/%d, total receipts=%d, cb invocations="
|
|
253
|
+
"%d)",
|
|
254
|
+
expected[j].topic, expected[j].partition,
|
|
255
|
+
expected[j].offset, context_label, matched,
|
|
256
|
+
expected_cnt, r->receipt_cnt,
|
|
257
|
+
r->callback_invocations);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
TEST_SAY(
|
|
262
|
+
"ack receipts: matched %d/%d expected (context: %s, total "
|
|
263
|
+
"receipts=%d, cb invocations=%d)\n",
|
|
264
|
+
matched, expected_cnt, context_label, r->receipt_cnt,
|
|
265
|
+
r->callback_invocations);
|
|
266
|
+
|
|
267
|
+
mtx_unlock(&r->lock);
|
|
268
|
+
if (seen)
|
|
269
|
+
rd_free(seen);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* @brief Get string representation of commit mode
|
|
274
|
+
*/
|
|
275
|
+
static const char *commit_mode_str(commit_mode_t mode) {
|
|
276
|
+
switch (mode) {
|
|
277
|
+
case COMMIT_MODE_NONE:
|
|
278
|
+
return "no-commit";
|
|
279
|
+
case COMMIT_MODE_ASYNC:
|
|
280
|
+
return "commit-async";
|
|
281
|
+
case COMMIT_MODE_SYNC:
|
|
282
|
+
return "commit-sync";
|
|
283
|
+
default:
|
|
284
|
+
return "unknown";
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* @brief Setup topics and produce messages (modular helper)
|
|
290
|
+
*
|
|
291
|
+
* @param ctx Test context to populate
|
|
292
|
+
* @param topic_cnt Number of topics to create
|
|
293
|
+
* @param partitions Array of partition counts per topic
|
|
294
|
+
* @param msgs_per_partition Messages to produce per partition
|
|
295
|
+
*
|
|
296
|
+
* @returns Total number of messages produced
|
|
297
|
+
*/
|
|
298
|
+
static int setup_topics_and_produce(test_context_t *ctx,
|
|
299
|
+
int topic_cnt,
|
|
300
|
+
const int *partitions,
|
|
301
|
+
int msgs_per_partition) {
|
|
302
|
+
int t, p;
|
|
303
|
+
int total_msgs = 0;
|
|
304
|
+
|
|
305
|
+
ctx->topic_cnt = topic_cnt;
|
|
306
|
+
|
|
307
|
+
for (t = 0; t < topic_cnt; t++) {
|
|
308
|
+
ctx->topic_names[t] =
|
|
309
|
+
rd_strdup(test_mk_topic_name("0178-close-test", 1));
|
|
310
|
+
|
|
311
|
+
TEST_SAY("Creating topic %s with %d partition(s)\n",
|
|
312
|
+
ctx->topic_names[t], partitions[t]);
|
|
313
|
+
|
|
314
|
+
test_create_topic_wait_exists(common_admin, ctx->topic_names[t],
|
|
315
|
+
partitions[t], -1, 60 * 1000);
|
|
316
|
+
|
|
317
|
+
for (p = 0; p < partitions[t]; p++) {
|
|
318
|
+
test_produce_msgs_simple(common_producer,
|
|
319
|
+
ctx->topic_names[t], p,
|
|
320
|
+
msgs_per_partition);
|
|
321
|
+
total_msgs += msgs_per_partition;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
TEST_SAY(
|
|
325
|
+
"Topic %s: produced %d messages (%d partitions * %d"
|
|
326
|
+
"msgs)\n",
|
|
327
|
+
ctx->topic_names[t], partitions[t] * msgs_per_partition,
|
|
328
|
+
partitions[t], msgs_per_partition);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
ctx->total_msgs_produced = total_msgs;
|
|
332
|
+
TEST_SAY("Total messages produced: %d\n", total_msgs);
|
|
333
|
+
return total_msgs;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @brief Subscribe consumer to topics
|
|
338
|
+
*
|
|
339
|
+
* @param rkshare Consumer handle
|
|
340
|
+
* @param topic_names Array of topic names to subscribe to
|
|
341
|
+
* @param topic_cnt Number of topics
|
|
342
|
+
*/
|
|
343
|
+
static void subscribe_consumer(rd_kafka_share_t *rkshare,
|
|
344
|
+
char **topic_names,
|
|
345
|
+
int topic_cnt) {
|
|
346
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
347
|
+
rd_kafka_resp_err_t err;
|
|
348
|
+
int t;
|
|
349
|
+
|
|
350
|
+
/* Build subscription list */
|
|
351
|
+
subs = rd_kafka_topic_partition_list_new(topic_cnt);
|
|
352
|
+
for (t = 0; t < topic_cnt; t++) {
|
|
353
|
+
rd_kafka_topic_partition_list_add(subs, topic_names[t],
|
|
354
|
+
RD_KAFKA_PARTITION_UA);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* Subscribe */
|
|
358
|
+
err = rd_kafka_share_subscribe(rkshare, subs);
|
|
359
|
+
if (err) {
|
|
360
|
+
TEST_FAIL("Subscribe failed: %s", rd_kafka_err2str(err));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* @brief Consume messages, track them, and optionally ACCEPT-acknowledge.
|
|
368
|
+
*
|
|
369
|
+
* In ack mode (do_acknowledge=true), messages are acknowledged with ACCEPT;
|
|
370
|
+
* any remaining messages in a batch beyond target_count are RELEASE'd so they
|
|
371
|
+
* can be redelivered. In no-ack mode (do_acknowledge=false), messages are
|
|
372
|
+
* tracked and destroyed without acknowledging — close() should release them.
|
|
373
|
+
*
|
|
374
|
+
* @param rkshare Consumer handle
|
|
375
|
+
* @param consumer_name Name for logging (e.g., "C1", "C2")
|
|
376
|
+
* @param target_count Number of messages to track (and ACCEPT in ack mode)
|
|
377
|
+
* @param do_acknowledge If true, ACCEPT each tracked message and RELEASE the
|
|
378
|
+
* rest of the batch; if false, track-and-destroy only.
|
|
379
|
+
* @param tracked_msgs If non-NULL, track messages here
|
|
380
|
+
* @param tracked_cnt If non-NULL, store count of tracked messages here
|
|
381
|
+
*
|
|
382
|
+
* @returns Number of messages tracked
|
|
383
|
+
*/
|
|
384
|
+
static int consume_and_track(rd_kafka_share_t *rkshare,
|
|
385
|
+
const char *consumer_name,
|
|
386
|
+
int target_count,
|
|
387
|
+
rd_bool_t do_acknowledge,
|
|
388
|
+
tracked_msg_t *tracked_msgs,
|
|
389
|
+
int *tracked_cnt) {
|
|
390
|
+
rd_kafka_messages_t *batch = NULL;
|
|
391
|
+
int attempt;
|
|
392
|
+
rd_kafka_error_t *error;
|
|
393
|
+
int tracked = 0;
|
|
394
|
+
|
|
395
|
+
TEST_SAY("%s: Consuming and %s %d messages (max %d attempts)...\n",
|
|
396
|
+
consumer_name,
|
|
397
|
+
do_acknowledge ? "acknowledging" : "tracking (no ack)",
|
|
398
|
+
target_count, MAX_CONSUME_ATTEMPTS);
|
|
399
|
+
|
|
400
|
+
for (attempt = 0;
|
|
401
|
+
attempt < MAX_CONSUME_ATTEMPTS && tracked < target_count;
|
|
402
|
+
attempt++) {
|
|
403
|
+
size_t rcvd_msgs = 0;
|
|
404
|
+
int i;
|
|
405
|
+
|
|
406
|
+
error = rd_kafka_share_poll(rkshare, 3000, &batch);
|
|
407
|
+
|
|
408
|
+
if (error) {
|
|
409
|
+
TEST_SAY("%s: Attempt %d/%d: error: %s\n",
|
|
410
|
+
consumer_name, attempt + 1,
|
|
411
|
+
MAX_CONSUME_ATTEMPTS,
|
|
412
|
+
rd_kafka_error_string(error));
|
|
413
|
+
rd_kafka_error_destroy(error);
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
rcvd_msgs = rd_kafka_messages_count(batch);
|
|
418
|
+
|
|
419
|
+
if (rcvd_msgs == 0) {
|
|
420
|
+
rd_kafka_messages_destroy(batch);
|
|
421
|
+
batch = NULL;
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
TEST_SAY("%s: Attempt %d/%d: Received %d messages\n",
|
|
426
|
+
consumer_name, attempt + 1, MAX_CONSUME_ATTEMPTS,
|
|
427
|
+
(int)rcvd_msgs);
|
|
428
|
+
|
|
429
|
+
for (i = 0; i < (int)rcvd_msgs && tracked < target_count; i++) {
|
|
430
|
+
rd_kafka_message_t *rkm =
|
|
431
|
+
rd_kafka_messages_get(batch, i);
|
|
432
|
+
|
|
433
|
+
if (rkm->err) {
|
|
434
|
+
TEST_SAY(
|
|
435
|
+
"%s: Skipping message %d with error: %s\n",
|
|
436
|
+
consumer_name, i,
|
|
437
|
+
rd_kafka_message_errstr(rkm));
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (tracked_msgs && tracked < BATCH_SIZE) {
|
|
442
|
+
tracked_msgs[tracked].topic =
|
|
443
|
+
rd_strdup(rd_kafka_topic_name(rkm->rkt));
|
|
444
|
+
tracked_msgs[tracked].partition =
|
|
445
|
+
rkm->partition;
|
|
446
|
+
tracked_msgs[tracked].offset = rkm->offset;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
TEST_SAY("%s: %s message %d: %s [%d] @ offset %" PRId64
|
|
450
|
+
"\n",
|
|
451
|
+
consumer_name,
|
|
452
|
+
do_acknowledge ? "Acking" : "Tracking",
|
|
453
|
+
tracked, rd_kafka_topic_name(rkm->rkt),
|
|
454
|
+
rkm->partition, rkm->offset);
|
|
455
|
+
|
|
456
|
+
if (do_acknowledge)
|
|
457
|
+
rd_kafka_share_acknowledge(rkshare, rkm);
|
|
458
|
+
tracked++;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
rd_kafka_messages_destroy(batch);
|
|
462
|
+
batch = NULL;
|
|
463
|
+
|
|
464
|
+
if (tracked >= target_count) {
|
|
465
|
+
TEST_SAY("%s: Reached target of %d tracked messages\n",
|
|
466
|
+
consumer_name, target_count);
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
TEST_SAY("%s: Finished - tracked %d messages\n", consumer_name,
|
|
472
|
+
tracked);
|
|
473
|
+
|
|
474
|
+
if (tracked < target_count) {
|
|
475
|
+
TEST_FAIL("%s: Expected to track %d messages, got %d",
|
|
476
|
+
consumer_name, target_count, tracked);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (tracked_cnt)
|
|
480
|
+
*tracked_cnt = tracked;
|
|
481
|
+
|
|
482
|
+
return tracked;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* @brief Execute commit based on mode (modular helper)
|
|
487
|
+
*
|
|
488
|
+
* @param rkshare Consumer handle
|
|
489
|
+
* @param consumer_name Name for logging
|
|
490
|
+
* @param mode Commit mode to execute
|
|
491
|
+
*/
|
|
492
|
+
static void perform_commit(rd_kafka_share_t *rkshare,
|
|
493
|
+
const char *consumer_name,
|
|
494
|
+
commit_mode_t mode,
|
|
495
|
+
ack_receipts_t *receipts) {
|
|
496
|
+
rd_kafka_error_t *error;
|
|
497
|
+
|
|
498
|
+
switch (mode) {
|
|
499
|
+
case COMMIT_MODE_NONE:
|
|
500
|
+
TEST_SAY("%s: Skipping commit (mode: %s)\n", consumer_name,
|
|
501
|
+
commit_mode_str(mode));
|
|
502
|
+
break;
|
|
503
|
+
|
|
504
|
+
case COMMIT_MODE_ASYNC:
|
|
505
|
+
TEST_SAY("%s: Calling commitAsync\n", consumer_name);
|
|
506
|
+
error = rd_kafka_share_commit_async(rkshare);
|
|
507
|
+
if (error) {
|
|
508
|
+
TEST_FAIL("%s: commitAsync failed: %s", consumer_name,
|
|
509
|
+
rd_kafka_error_string(error));
|
|
510
|
+
rd_kafka_error_destroy(error);
|
|
511
|
+
}
|
|
512
|
+
/* Give async commit some time to process */
|
|
513
|
+
rd_sleep(1);
|
|
514
|
+
break;
|
|
515
|
+
|
|
516
|
+
case COMMIT_MODE_SYNC: {
|
|
517
|
+
rd_kafka_topic_partition_list_t *partitions = NULL;
|
|
518
|
+
int p;
|
|
519
|
+
TEST_SAY("%s: Calling commitSync\n", consumer_name);
|
|
520
|
+
error = rd_kafka_share_commit_sync(rkshare, 30000, &partitions);
|
|
521
|
+
if (error) {
|
|
522
|
+
TEST_FAIL("%s: commitSync failed: %s", consumer_name,
|
|
523
|
+
rd_kafka_error_string(error));
|
|
524
|
+
rd_kafka_error_destroy(error);
|
|
525
|
+
}
|
|
526
|
+
/* Honour synchronous per-partition results. IN_PROGRESS means
|
|
527
|
+
* the result will arrive via the ack callback later, so skip
|
|
528
|
+
* — the callback path will fill the receipt. */
|
|
529
|
+
if (receipts && partitions) {
|
|
530
|
+
for (p = 0; p < partitions->cnt; p++) {
|
|
531
|
+
rd_kafka_topic_partition_t *tp =
|
|
532
|
+
&partitions->elems[p];
|
|
533
|
+
if (tp->err == RD_KAFKA_RESP_ERR__IN_PROGRESS)
|
|
534
|
+
continue;
|
|
535
|
+
if (tp->err != RD_KAFKA_RESP_ERR_NO_ERROR)
|
|
536
|
+
TEST_FAIL(
|
|
537
|
+
"%s: commitSync per-partition "
|
|
538
|
+
"error for %s [%d]: %s",
|
|
539
|
+
consumer_name, tp->topic,
|
|
540
|
+
tp->partition,
|
|
541
|
+
rd_kafka_err2str(tp->err));
|
|
542
|
+
ack_receipts_add(receipts, tp->topic,
|
|
543
|
+
tp->partition, tp->offset);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (partitions)
|
|
547
|
+
rd_kafka_topic_partition_list_destroy(partitions);
|
|
548
|
+
TEST_SAY("%s: commitSync completed successfully\n",
|
|
549
|
+
consumer_name);
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
default:
|
|
554
|
+
TEST_FAIL("Unknown commit mode: %d", mode);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* @brief Verify whether tracked messages are (or are not) redelivered.
|
|
560
|
+
*
|
|
561
|
+
* Consumes up to @p max_total_msgs messages and compares each against the
|
|
562
|
+
* @p tracked_msgs list. Behavior depends on @p expect_redelivery:
|
|
563
|
+
* - false: fails if any tracked message is received (post-ack scenario);
|
|
564
|
+
* also asserts the total received count equals @p max_total_msgs.
|
|
565
|
+
* - true: fails unless every tracked message is received (post-release
|
|
566
|
+
* scenario); stops early once all tracked messages have been
|
|
567
|
+
* matched.
|
|
568
|
+
*
|
|
569
|
+
* @param rkshare Consumer handle to check
|
|
570
|
+
* @param consumer_name Name for logging
|
|
571
|
+
* @param max_total_msgs Number of messages to consume (also the exact-count
|
|
572
|
+
* assertion in the not-redelivered case)
|
|
573
|
+
* @param tracked_msgs Array of tracked messages to check against
|
|
574
|
+
* @param tracked_cnt Number of tracked messages
|
|
575
|
+
* @param expect_redelivery true = expect all tracked redelivered; false =
|
|
576
|
+
* expect none redelivered
|
|
577
|
+
* @param context_label Free-form label included in failure messages
|
|
578
|
+
* (e.g., commit mode name)
|
|
579
|
+
*/
|
|
580
|
+
static void verify_tracked_messages(rd_kafka_share_t *rkshare,
|
|
581
|
+
const char *consumer_name,
|
|
582
|
+
int max_total_msgs,
|
|
583
|
+
const tracked_msg_t *tracked_msgs,
|
|
584
|
+
int tracked_cnt,
|
|
585
|
+
rd_bool_t expect_redelivery,
|
|
586
|
+
const char *context_label) {
|
|
587
|
+
rd_kafka_messages_t *batch = NULL;
|
|
588
|
+
size_t total_rcvd = 0;
|
|
589
|
+
int attempt;
|
|
590
|
+
rd_kafka_error_t *error;
|
|
591
|
+
int matched_count = 0;
|
|
592
|
+
rd_bool_t *tracked_seen =
|
|
593
|
+
tracked_cnt > 0 ? rd_calloc(tracked_cnt, sizeof(*tracked_seen))
|
|
594
|
+
: NULL;
|
|
595
|
+
|
|
596
|
+
TEST_SAY(
|
|
597
|
+
"%s: Consuming for verification (up to %d messages, max %d "
|
|
598
|
+
"attempts, expect_redelivery=%s)...\n",
|
|
599
|
+
consumer_name, max_total_msgs, MAX_CONSUME_ATTEMPTS,
|
|
600
|
+
expect_redelivery ? "true" : "false");
|
|
601
|
+
|
|
602
|
+
for (attempt = 0; attempt < MAX_CONSUME_ATTEMPTS &&
|
|
603
|
+
(int)total_rcvd < max_total_msgs &&
|
|
604
|
+
(!expect_redelivery || matched_count < tracked_cnt);
|
|
605
|
+
attempt++) {
|
|
606
|
+
size_t rcvd_msgs = 0;
|
|
607
|
+
size_t i;
|
|
608
|
+
|
|
609
|
+
error = rd_kafka_share_poll(rkshare, 3000, &batch);
|
|
610
|
+
|
|
611
|
+
if (error) {
|
|
612
|
+
TEST_SAY("%s: Attempt %d/%d: error: %s\n",
|
|
613
|
+
consumer_name, attempt + 1,
|
|
614
|
+
MAX_CONSUME_ATTEMPTS,
|
|
615
|
+
rd_kafka_error_string(error));
|
|
616
|
+
rd_kafka_error_destroy(error);
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
rcvd_msgs = rd_kafka_messages_count(batch);
|
|
621
|
+
|
|
622
|
+
if (rcvd_msgs == 0) {
|
|
623
|
+
rd_kafka_messages_destroy(batch);
|
|
624
|
+
batch = NULL;
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
TEST_SAY(
|
|
629
|
+
"%s: Attempt %d/%d: Received %d messages (total: %d)\n",
|
|
630
|
+
consumer_name, attempt + 1, MAX_CONSUME_ATTEMPTS,
|
|
631
|
+
(int)rcvd_msgs, (int)(total_rcvd + rcvd_msgs));
|
|
632
|
+
|
|
633
|
+
/* Match each new message against the tracked list */
|
|
634
|
+
for (i = 0; i < rcvd_msgs; i++) {
|
|
635
|
+
rd_kafka_message_t *rkm =
|
|
636
|
+
rd_kafka_messages_get(batch, i);
|
|
637
|
+
const char *topic;
|
|
638
|
+
int32_t partition;
|
|
639
|
+
int64_t offset;
|
|
640
|
+
int j;
|
|
641
|
+
|
|
642
|
+
if (!rkm || rkm->err)
|
|
643
|
+
continue;
|
|
644
|
+
|
|
645
|
+
topic = rd_kafka_topic_name(rkm->rkt);
|
|
646
|
+
partition = rkm->partition;
|
|
647
|
+
offset = rkm->offset;
|
|
648
|
+
|
|
649
|
+
for (j = 0; j < tracked_cnt; j++) {
|
|
650
|
+
if (tracked_seen && tracked_seen[j])
|
|
651
|
+
continue;
|
|
652
|
+
if (strcmp(topic, tracked_msgs[j].topic) == 0 &&
|
|
653
|
+
partition == tracked_msgs[j].partition &&
|
|
654
|
+
offset == tracked_msgs[j].offset) {
|
|
655
|
+
if (tracked_seen)
|
|
656
|
+
tracked_seen[j] = rd_true;
|
|
657
|
+
matched_count++;
|
|
658
|
+
if (expect_redelivery) {
|
|
659
|
+
TEST_SAY(
|
|
660
|
+
"%s: Matched tracked "
|
|
661
|
+
"message %d/%d: %s [%d] "
|
|
662
|
+
"@ offset %" PRId64 "\n",
|
|
663
|
+
consumer_name,
|
|
664
|
+
matched_count, tracked_cnt,
|
|
665
|
+
topic, partition, offset);
|
|
666
|
+
} else {
|
|
667
|
+
TEST_WARN(
|
|
668
|
+
"%s: Received previously "
|
|
669
|
+
"acknowledged message: "
|
|
670
|
+
"%s [%d] @ offset %" PRId64
|
|
671
|
+
"\n",
|
|
672
|
+
consumer_name, topic,
|
|
673
|
+
partition, offset);
|
|
674
|
+
}
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
total_rcvd += rcvd_msgs;
|
|
681
|
+
rd_kafka_messages_destroy(batch);
|
|
682
|
+
batch = NULL;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
TEST_SAY("%s: Received %d messages, matched %d/%d tracked\n",
|
|
686
|
+
consumer_name, (int)total_rcvd, matched_count, tracked_cnt);
|
|
687
|
+
|
|
688
|
+
if (expect_redelivery) {
|
|
689
|
+
int j;
|
|
690
|
+
if (matched_count != tracked_cnt) {
|
|
691
|
+
for (j = 0; j < tracked_cnt; j++) {
|
|
692
|
+
if (!tracked_seen[j]) {
|
|
693
|
+
TEST_FAIL(
|
|
694
|
+
"%s: Did not receive tracked "
|
|
695
|
+
"message: %s [%d] @ offset "
|
|
696
|
+
"%" PRId64 " (context: %s)",
|
|
697
|
+
consumer_name,
|
|
698
|
+
tracked_msgs[j].topic,
|
|
699
|
+
tracked_msgs[j].partition,
|
|
700
|
+
tracked_msgs[j].offset,
|
|
701
|
+
context_label);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
TEST_SAY(
|
|
706
|
+
"%s: Verification passed - all %d tracked messages "
|
|
707
|
+
"redelivered\n",
|
|
708
|
+
consumer_name, matched_count);
|
|
709
|
+
} else {
|
|
710
|
+
if ((int)total_rcvd != max_total_msgs) {
|
|
711
|
+
TEST_FAIL("%s: Expected to receive %d messages, got %d",
|
|
712
|
+
consumer_name, max_total_msgs,
|
|
713
|
+
(int)total_rcvd);
|
|
714
|
+
}
|
|
715
|
+
if (matched_count > 0) {
|
|
716
|
+
TEST_FAIL(
|
|
717
|
+
"%s received %d messages that were acknowledged "
|
|
718
|
+
"(context: %s)",
|
|
719
|
+
consumer_name, matched_count, context_label);
|
|
720
|
+
}
|
|
721
|
+
TEST_SAY(
|
|
722
|
+
"%s: Verification passed - no acknowledged messages "
|
|
723
|
+
"were redelivered\n",
|
|
724
|
+
consumer_name);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
if (tracked_seen)
|
|
728
|
+
rd_free(tracked_seen);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* @brief Free tracked messages (modular helper)
|
|
733
|
+
*
|
|
734
|
+
* @param tracked_msgs Array of tracked messages
|
|
735
|
+
* @param tracked_cnt Number of tracked messages
|
|
736
|
+
*/
|
|
737
|
+
static void free_tracked_messages(tracked_msg_t *tracked_msgs,
|
|
738
|
+
int tracked_cnt) {
|
|
739
|
+
for (int i = 0; i < tracked_cnt; i++) {
|
|
740
|
+
if (tracked_msgs[i].topic)
|
|
741
|
+
rd_free(tracked_msgs[i].topic);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* @brief Helper: assert the given rd_kafka_error_t* signals closed/closing.
|
|
747
|
+
*/
|
|
748
|
+
static void assert_state_error(rd_kafka_error_t *error, const char *api_name) {
|
|
749
|
+
TEST_ASSERT(error != NULL, "%s: expected error, got NULL", api_name);
|
|
750
|
+
TEST_ASSERT(rd_kafka_error_code(error) == RD_KAFKA_RESP_ERR__STATE,
|
|
751
|
+
"%s: expected __STATE, got %s", api_name,
|
|
752
|
+
rd_kafka_err2name(rd_kafka_error_code(error)));
|
|
753
|
+
TEST_ASSERT(strstr(rd_kafka_error_string(error), "closed") != NULL,
|
|
754
|
+
"%s: expected error string to contain 'closed', got '%s'",
|
|
755
|
+
api_name, rd_kafka_error_string(error));
|
|
756
|
+
rd_kafka_error_destroy(error);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* @brief Invoke every share-consumer API and assert each returns a
|
|
761
|
+
* closed state error.
|
|
762
|
+
*
|
|
763
|
+
* @param consumer Share consumer (already closed or closing).
|
|
764
|
+
* @param topic Topic name (for subscribe/acknowledge_offset).
|
|
765
|
+
*/
|
|
766
|
+
static void verify_all_apis_return_error(rd_kafka_share_t *consumer,
|
|
767
|
+
const char *topic) {
|
|
768
|
+
rd_kafka_error_t *error;
|
|
769
|
+
rd_kafka_resp_err_t err;
|
|
770
|
+
rd_kafka_messages_t *batch = NULL;
|
|
771
|
+
rd_kafka_topic_partition_list_t *subs, *sub_result = NULL;
|
|
772
|
+
rd_kafka_topic_partition_list_t *commit_results = NULL;
|
|
773
|
+
rd_kafka_queue_t *queue = NULL;
|
|
774
|
+
|
|
775
|
+
/* 1. share_poll */
|
|
776
|
+
error = rd_kafka_share_poll(consumer, 100, &batch);
|
|
777
|
+
assert_state_error(error, "share_poll");
|
|
778
|
+
if (batch) {
|
|
779
|
+
rd_kafka_messages_destroy(batch);
|
|
780
|
+
batch = NULL;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/* 2. commit_async */
|
|
784
|
+
error = rd_kafka_share_commit_async(consumer);
|
|
785
|
+
assert_state_error(error, "commit_async");
|
|
786
|
+
|
|
787
|
+
/* 3. commit_sync */
|
|
788
|
+
error = rd_kafka_share_commit_sync(consumer, 1000, &commit_results);
|
|
789
|
+
assert_state_error(error, "commit_sync");
|
|
790
|
+
TEST_ASSERT(commit_results == NULL,
|
|
791
|
+
"commit_sync: expected no partitions on error");
|
|
792
|
+
|
|
793
|
+
/* 4. acknowledge_offset */
|
|
794
|
+
err = rd_kafka_share_acknowledge_offset(
|
|
795
|
+
consumer, topic, 0, 0, RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
|
|
796
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE,
|
|
797
|
+
"acknowledge_offset: expected __STATE, got %s",
|
|
798
|
+
rd_kafka_err2name(err));
|
|
799
|
+
|
|
800
|
+
/* 5. subscribe */
|
|
801
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
802
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
803
|
+
err = rd_kafka_share_subscribe(consumer, subs);
|
|
804
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE,
|
|
805
|
+
"subscribe: expected __STATE, got %s",
|
|
806
|
+
rd_kafka_err2name(err));
|
|
807
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
808
|
+
|
|
809
|
+
/* 6. unsubscribe */
|
|
810
|
+
err = rd_kafka_share_unsubscribe(consumer);
|
|
811
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE,
|
|
812
|
+
"unsubscribe: expected __STATE, got %s",
|
|
813
|
+
rd_kafka_err2name(err));
|
|
814
|
+
|
|
815
|
+
/* 7. subscription */
|
|
816
|
+
err = rd_kafka_share_subscription(consumer, &sub_result);
|
|
817
|
+
TEST_ASSERT(err == RD_KAFKA_RESP_ERR__STATE,
|
|
818
|
+
"subscription: expected __STATE, got %s",
|
|
819
|
+
rd_kafka_err2name(err));
|
|
820
|
+
TEST_ASSERT(sub_result == NULL, "subscription: expected NULL result");
|
|
821
|
+
|
|
822
|
+
/* 8. close */
|
|
823
|
+
error = rd_kafka_share_consumer_close(consumer);
|
|
824
|
+
assert_state_error(error, "close");
|
|
825
|
+
|
|
826
|
+
/* 9. async close */
|
|
827
|
+
queue = rd_kafka_queue_new(test_share_consumer_get_rk(consumer));
|
|
828
|
+
error = rd_kafka_share_consumer_close_queue(consumer, queue);
|
|
829
|
+
rd_kafka_queue_destroy(queue);
|
|
830
|
+
assert_state_error(error, "close_queue");
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* @brief Common setup for 3-broker mock close-tests.
|
|
835
|
+
*
|
|
836
|
+
* Creates a 3-broker mock cluster, a topic with one partition per broker,
|
|
837
|
+
* produces 10 messages to each partition, then creates a share consumer
|
|
838
|
+
* (with optional socket.timeout.ms), subscribes, and consumes all
|
|
839
|
+
* @p partition_cnt * @p msgs_per_partition messages so the share session
|
|
840
|
+
* is established with every partition leader.
|
|
841
|
+
*
|
|
842
|
+
* @param test_name Used to derive unique topic and group names.
|
|
843
|
+
* @param socket_timeout_ms Pass 0 to leave socket.timeout.ms at default,
|
|
844
|
+
* or a positive value to override it.
|
|
845
|
+
* @param out_mcluster Output: created cluster (caller destroys).
|
|
846
|
+
* @param out_consumer Output: subscribed share consumer (caller destroys).
|
|
847
|
+
*/
|
|
848
|
+
static void setup_3broker_share_consumer(const char *test_name,
|
|
849
|
+
int socket_timeout_ms,
|
|
850
|
+
rd_kafka_mock_cluster_t **out_mcluster,
|
|
851
|
+
rd_kafka_share_t **out_consumer) {
|
|
852
|
+
const int partition_cnt = 3;
|
|
853
|
+
const int msgs_per_partition = 10;
|
|
854
|
+
const int total_msgs = partition_cnt * msgs_per_partition;
|
|
855
|
+
rd_kafka_mock_cluster_t *mcluster;
|
|
856
|
+
const char *bootstraps;
|
|
857
|
+
rd_kafka_share_t *consumer;
|
|
858
|
+
rd_kafka_conf_t *conf;
|
|
859
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
860
|
+
rd_kafka_messages_t *batch = NULL;
|
|
861
|
+
rd_kafka_error_t *error;
|
|
862
|
+
char topic[64], group[64], errstr[512];
|
|
863
|
+
int p, consumed = 0, attempts = 0;
|
|
864
|
+
size_t i, rcvd;
|
|
865
|
+
|
|
866
|
+
rd_snprintf(topic, sizeof(topic), "mock-%s", test_name);
|
|
867
|
+
rd_snprintf(group, sizeof(group), "sg-%s", test_name);
|
|
868
|
+
|
|
869
|
+
mcluster = test_mock_cluster_new(3, &bootstraps);
|
|
870
|
+
rd_kafka_mock_sharegroup_set_auto_offset_reset(mcluster, 1);
|
|
871
|
+
|
|
872
|
+
TEST_ASSERT(rd_kafka_mock_topic_create(mcluster, topic, partition_cnt,
|
|
873
|
+
1) == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
874
|
+
"Failed to create mock topic");
|
|
875
|
+
|
|
876
|
+
/* Produce msgs_per_partition msgs to each partition via test helper. */
|
|
877
|
+
for (p = 0; p < partition_cnt; p++) {
|
|
878
|
+
test_produce_msgs_easy_v(topic, 0, p, 0, msgs_per_partition, 16,
|
|
879
|
+
"bootstrap.servers", bootstraps, NULL);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/* Consumer */
|
|
883
|
+
test_conf_init(&conf, NULL, 0);
|
|
884
|
+
test_conf_set(conf, "bootstrap.servers", bootstraps);
|
|
885
|
+
test_conf_set(conf, "group.id", group);
|
|
886
|
+
if (socket_timeout_ms > 0) {
|
|
887
|
+
rd_snprintf(errstr, sizeof(errstr), "%d", socket_timeout_ms);
|
|
888
|
+
test_conf_set(conf, "socket.timeout.ms", errstr);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
consumer = rd_kafka_share_consumer_new(conf, errstr, sizeof(errstr));
|
|
892
|
+
TEST_ASSERT(consumer, "Failed to create consumer: %s", errstr);
|
|
893
|
+
|
|
894
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
895
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
896
|
+
TEST_ASSERT(!rd_kafka_share_subscribe(consumer, subs),
|
|
897
|
+
"Subscribe failed");
|
|
898
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
899
|
+
|
|
900
|
+
/* Consume all messages so share session is established with every
|
|
901
|
+
* partition leader (i.e. all 3 brokers). */
|
|
902
|
+
TEST_SAY("Consuming %d messages across %d partitions...\n", total_msgs,
|
|
903
|
+
partition_cnt);
|
|
904
|
+
while (consumed < total_msgs && attempts++ < 30) {
|
|
905
|
+
error = rd_kafka_share_poll(consumer, 3000, &batch);
|
|
906
|
+
if (error) {
|
|
907
|
+
rd_kafka_error_destroy(error);
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
910
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
911
|
+
for (i = 0; i < rcvd; i++) {
|
|
912
|
+
rd_kafka_message_t *rkm =
|
|
913
|
+
rd_kafka_messages_get(batch, i);
|
|
914
|
+
if (rkm && !rkm->err)
|
|
915
|
+
consumed++;
|
|
916
|
+
}
|
|
917
|
+
rd_kafka_messages_destroy(batch);
|
|
918
|
+
batch = NULL;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
TEST_ASSERT(consumed == total_msgs, "Expected %d messages, got %d",
|
|
922
|
+
total_msgs, consumed);
|
|
923
|
+
TEST_SAY("Consumed all %d messages\n", consumed);
|
|
924
|
+
|
|
925
|
+
*out_mcluster = mcluster;
|
|
926
|
+
*out_consumer = consumer;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
/** is_fatal_cb hook scoped to test_close_with_broker_down: ignores
|
|
930
|
+
* the transport error and cascading ALL_BROKERS_DOWN that result from
|
|
931
|
+
* taking the mock broker down mid-close. */
|
|
932
|
+
static int test_close_with_broker_down_is_fatal_cb(rd_kafka_t *rk,
|
|
933
|
+
rd_kafka_resp_err_t err,
|
|
934
|
+
const char *reason) {
|
|
935
|
+
if (err == RD_KAFKA_RESP_ERR__TRANSPORT ||
|
|
936
|
+
err == RD_KAFKA_RESP_ERR__ALL_BROKERS_DOWN) {
|
|
937
|
+
TEST_SAY("Ignoring expected error: %s: %s\n",
|
|
938
|
+
rd_kafka_err2name(err), reason);
|
|
939
|
+
return 0;
|
|
940
|
+
}
|
|
941
|
+
return 1;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/*#################################################################################*/
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* @brief Close with acknowledge test scenarios
|
|
948
|
+
*
|
|
949
|
+
* Tests consumer close behavior with different commit modes and topologies.
|
|
950
|
+
* Verifies that acknowledged messages are not redelivered to a second
|
|
951
|
+
consumer.
|
|
952
|
+
*/
|
|
953
|
+
static void do_test_close_with_acknowledge(void) {
|
|
954
|
+
/**
|
|
955
|
+
* @brief Test configuration for close with acknowledge scenarios
|
|
956
|
+
*/
|
|
957
|
+
typedef struct {
|
|
958
|
+
const char *test_name;
|
|
959
|
+
int topic_cnt;
|
|
960
|
+
int partitions[MAX_TOPICS];
|
|
961
|
+
int msgs_per_partition;
|
|
962
|
+
commit_mode_t commit_mode;
|
|
963
|
+
int ack_count;
|
|
964
|
+
} close_ack_test_config_t;
|
|
965
|
+
|
|
966
|
+
/* Test matrix: 3 commit modes × 4 topologies = 12 tests */
|
|
967
|
+
close_ack_test_config_t tests[] = {
|
|
968
|
+
/* 1 topic, 1 partition */
|
|
969
|
+
{"close-1t1p-no-commit", 1, {1}, 20, COMMIT_MODE_NONE, 10},
|
|
970
|
+
{"close-1t1p-commit-async", 1, {1}, 20, COMMIT_MODE_ASYNC, 10},
|
|
971
|
+
{"close-1t1p-commit-sync", 1, {1}, 20, COMMIT_MODE_SYNC, 10},
|
|
972
|
+
|
|
973
|
+
/* 1 topic, multiple partitions */
|
|
974
|
+
{"close-1t3p-no-commit", 1, {3}, 10, COMMIT_MODE_NONE, 20},
|
|
975
|
+
{"close-1t3p-commit-async", 1, {3}, 10, COMMIT_MODE_ASYNC, 20},
|
|
976
|
+
{"close-1t3p-commit-sync", 1, {3}, 10, COMMIT_MODE_SYNC, 15},
|
|
977
|
+
|
|
978
|
+
/* Multiple topics, 1 partition each */
|
|
979
|
+
{"close-3t1p-no-commit", 3, {1, 1, 1}, 10, COMMIT_MODE_NONE, 20},
|
|
980
|
+
{"close-3t1p-commit-async",
|
|
981
|
+
3,
|
|
982
|
+
{1, 1, 1},
|
|
983
|
+
10,
|
|
984
|
+
COMMIT_MODE_ASYNC,
|
|
985
|
+
20},
|
|
986
|
+
{"close-3t1p-commit-sync", 3, {1, 1, 1}, 10, COMMIT_MODE_SYNC, 20},
|
|
987
|
+
|
|
988
|
+
/* Multiple topics, multiple partitions */
|
|
989
|
+
{"close-2t2p-no-commit", 2, {2, 2}, 10, COMMIT_MODE_NONE, 20},
|
|
990
|
+
{"close-2t2p-commit-async", 2, {2, 2}, 10, COMMIT_MODE_ASYNC, 20},
|
|
991
|
+
{"close-2t2p-commit-sync", 2, {2, 2}, 10, COMMIT_MODE_SYNC, 20},
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
SUB_TEST();
|
|
995
|
+
|
|
996
|
+
for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
|
|
997
|
+
close_ack_test_config_t *config = &tests[i];
|
|
998
|
+
test_context_t ctx = {0};
|
|
999
|
+
rd_kafka_share_t *c1, *c2;
|
|
1000
|
+
tracked_msg_t tracked_msgs[BATCH_SIZE];
|
|
1001
|
+
int tracked_cnt = 0;
|
|
1002
|
+
ack_receipts_t receipts;
|
|
1003
|
+
|
|
1004
|
+
ack_receipts_init(&receipts);
|
|
1005
|
+
|
|
1006
|
+
TEST_SAY("\n========================================\n");
|
|
1007
|
+
TEST_SAY("Test: %s\n", config->test_name);
|
|
1008
|
+
TEST_SAY("Topology: %d topic(s), partitions: [",
|
|
1009
|
+
config->topic_cnt);
|
|
1010
|
+
for (int j = 0; j < config->topic_cnt; j++) {
|
|
1011
|
+
TEST_SAY("%d%s", config->partitions[j],
|
|
1012
|
+
j < config->topic_cnt - 1 ? ", " : "");
|
|
1013
|
+
}
|
|
1014
|
+
TEST_SAY("]\n");
|
|
1015
|
+
TEST_SAY("Commit mode: %s\n",
|
|
1016
|
+
commit_mode_str(config->commit_mode));
|
|
1017
|
+
TEST_SAY("========================================\n\n");
|
|
1018
|
+
|
|
1019
|
+
ctx.group_id = "0178-group";
|
|
1020
|
+
setup_topics_and_produce(&ctx, config->topic_cnt,
|
|
1021
|
+
config->partitions,
|
|
1022
|
+
config->msgs_per_partition);
|
|
1023
|
+
|
|
1024
|
+
/* Set group offset to earliest */
|
|
1025
|
+
test_share_set_auto_offset_reset(ctx.group_id, "earliest");
|
|
1026
|
+
|
|
1027
|
+
/* Create C1 with explicit ack mode (will call acknowledge()
|
|
1028
|
+
* explicitly). C2 will be created after C1 closes. */
|
|
1029
|
+
c1 = create_share_consumer_with_receipts(ctx.group_id,
|
|
1030
|
+
"explicit", &receipts);
|
|
1031
|
+
|
|
1032
|
+
/* Subscribe C1 only - C2 will subscribe after C1 closes */
|
|
1033
|
+
subscribe_consumer(c1, ctx.topic_names, ctx.topic_cnt);
|
|
1034
|
+
|
|
1035
|
+
/* C1: Consume and acknowledge */
|
|
1036
|
+
consume_and_track(c1, "C1", config->ack_count, rd_true,
|
|
1037
|
+
tracked_msgs, &tracked_cnt);
|
|
1038
|
+
|
|
1039
|
+
/* Execute commit */
|
|
1040
|
+
perform_commit(c1, "C1", config->commit_mode, &receipts);
|
|
1041
|
+
|
|
1042
|
+
/* Close C1 - drains any outstanding ack callbacks
|
|
1043
|
+
* synchronously, so receipts are settled by the time close
|
|
1044
|
+
* returns. */
|
|
1045
|
+
TEST_SAY("C1: Closing consumer\n");
|
|
1046
|
+
rd_kafka_error_t *c1_close_err =
|
|
1047
|
+
rd_kafka_share_consumer_close(c1);
|
|
1048
|
+
TEST_ASSERT(c1_close_err == NULL,
|
|
1049
|
+
"C1: close returned error: %s",
|
|
1050
|
+
rd_kafka_error_string(c1_close_err));
|
|
1051
|
+
TEST_SAY("C1: Closed successfully\n");
|
|
1052
|
+
|
|
1053
|
+
/* Verify the union of callback + sync receipts equals the
|
|
1054
|
+
* set of messages C1 acknowledged. */
|
|
1055
|
+
verify_receipts_match(&receipts, tracked_msgs, tracked_cnt,
|
|
1056
|
+
commit_mode_str(config->commit_mode));
|
|
1057
|
+
|
|
1058
|
+
/* Create C2 with implicit ack mode after C1 is fully destroyed
|
|
1059
|
+
*/
|
|
1060
|
+
TEST_SAY("C2: Creating and subscribing after C1 close\n");
|
|
1061
|
+
c2 = test_create_share_consumer(ctx.group_id, "implicit");
|
|
1062
|
+
subscribe_consumer(c2, ctx.topic_names, ctx.topic_cnt);
|
|
1063
|
+
|
|
1064
|
+
/* C2: Consume and verify no redelivery */
|
|
1065
|
+
verify_tracked_messages(c2, "C2",
|
|
1066
|
+
ctx.total_msgs_produced - tracked_cnt,
|
|
1067
|
+
tracked_msgs, tracked_cnt, rd_false,
|
|
1068
|
+
commit_mode_str(config->commit_mode));
|
|
1069
|
+
|
|
1070
|
+
/* Close C2 */
|
|
1071
|
+
TEST_SAY("C2: Closing consumer\n");
|
|
1072
|
+
rd_kafka_share_consumer_close(c2);
|
|
1073
|
+
TEST_SAY("C2: Closed successfully\n");
|
|
1074
|
+
test_share_destroy(c2);
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
/* Cleanup */
|
|
1078
|
+
free_tracked_messages(tracked_msgs, tracked_cnt);
|
|
1079
|
+
ack_receipts_destroy(&receipts);
|
|
1080
|
+
|
|
1081
|
+
for (int t = 0; t < ctx.topic_cnt; t++) {
|
|
1082
|
+
rd_free(ctx.topic_names[t]);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
TEST_SAY("Test %s completed successfully\n\n",
|
|
1086
|
+
config->test_name);
|
|
1087
|
+
test_share_destroy(c1);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
SUB_TEST_PASS();
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* @brief Test close without acknowledge
|
|
1095
|
+
*
|
|
1096
|
+
* Verifies that when a consumer closes without acknowledging consumed records,
|
|
1097
|
+
* those records are released back to the share group and can be consumed by
|
|
1098
|
+
* another consumer.
|
|
1099
|
+
*
|
|
1100
|
+
* Test flow:
|
|
1101
|
+
* 1. C1 consumes records but does NOT acknowledge them
|
|
1102
|
+
* 2. C1 closes (should release the unacknowledged records)
|
|
1103
|
+
* 3. C2 should be able to consume those same records
|
|
1104
|
+
*
|
|
1105
|
+
* Tests multiple topologies: 1t1p, 1t3p, 3t1p, 2t2p
|
|
1106
|
+
*/
|
|
1107
|
+
static void do_test_close_without_acknowledge() {
|
|
1108
|
+
/**
|
|
1109
|
+
* @brief Test configuration for close without acknowledge scenarios
|
|
1110
|
+
*/
|
|
1111
|
+
typedef struct {
|
|
1112
|
+
const char *test_name;
|
|
1113
|
+
int topic_cnt;
|
|
1114
|
+
int partitions[MAX_TOPICS];
|
|
1115
|
+
int msgs_per_partition;
|
|
1116
|
+
int track_count;
|
|
1117
|
+
} close_no_ack_test_config_t;
|
|
1118
|
+
|
|
1119
|
+
/* Test matrix: various topologies */
|
|
1120
|
+
close_no_ack_test_config_t tests[] = {
|
|
1121
|
+
/* 1 topic, 1 partition */
|
|
1122
|
+
{"close-no-ack-1t1p", 1, {1}, 20, 5},
|
|
1123
|
+
|
|
1124
|
+
/* 1 topic, multiple partitions */
|
|
1125
|
+
{"close-no-ack-1t3p", 1, {3}, 10, 5},
|
|
1126
|
+
|
|
1127
|
+
/* Multiple topics, 1 partition each */
|
|
1128
|
+
{"close-no-ack-3t1p", 3, {1, 1, 1}, 10, 5},
|
|
1129
|
+
|
|
1130
|
+
/* Multiple topics, multiple partitions */
|
|
1131
|
+
{"close-no-ack-2t2p", 2, {2, 2}, 10, 5},
|
|
1132
|
+
};
|
|
1133
|
+
|
|
1134
|
+
SUB_TEST();
|
|
1135
|
+
|
|
1136
|
+
for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
|
|
1137
|
+
close_no_ack_test_config_t *config = &tests[i];
|
|
1138
|
+
test_context_t ctx = {0};
|
|
1139
|
+
rd_kafka_share_t *c1, *c2;
|
|
1140
|
+
tracked_msg_t tracked_msgs[BATCH_SIZE];
|
|
1141
|
+
int tracked_cnt = 0;
|
|
1142
|
+
char group_id[64];
|
|
1143
|
+
ack_receipts_t receipts;
|
|
1144
|
+
|
|
1145
|
+
ack_receipts_init(&receipts);
|
|
1146
|
+
|
|
1147
|
+
TEST_SAY("\n========================================\n");
|
|
1148
|
+
TEST_SAY("Topology: %d topic(s), partitions: [",
|
|
1149
|
+
config->topic_cnt);
|
|
1150
|
+
for (int j = 0; j < config->topic_cnt; j++) {
|
|
1151
|
+
TEST_SAY("%d%s", config->partitions[j],
|
|
1152
|
+
j < config->topic_cnt - 1 ? ", " : "");
|
|
1153
|
+
}
|
|
1154
|
+
TEST_SAY("]\n");
|
|
1155
|
+
TEST_SAY("========================================\n\n");
|
|
1156
|
+
|
|
1157
|
+
rd_snprintf(group_id, sizeof(group_id),
|
|
1158
|
+
"0178-group-no-ack-%" PRIu64, test_id_generate());
|
|
1159
|
+
ctx.group_id = group_id;
|
|
1160
|
+
setup_topics_and_produce(&ctx, config->topic_cnt,
|
|
1161
|
+
config->partitions,
|
|
1162
|
+
config->msgs_per_partition);
|
|
1163
|
+
|
|
1164
|
+
test_share_set_auto_offset_reset(ctx.group_id, "earliest");
|
|
1165
|
+
|
|
1166
|
+
c1 = create_share_consumer_with_receipts(ctx.group_id,
|
|
1167
|
+
"implicit", &receipts);
|
|
1168
|
+
subscribe_consumer(c1, ctx.topic_names, ctx.topic_cnt);
|
|
1169
|
+
|
|
1170
|
+
/* C1: Consume and track without acknowledging. */
|
|
1171
|
+
consume_and_track(c1, "C1", config->track_count, rd_false,
|
|
1172
|
+
tracked_msgs, &tracked_cnt);
|
|
1173
|
+
|
|
1174
|
+
/* Close C1 - unacked records must be released back to the
|
|
1175
|
+
* share group. No acks were issued, so we expect zero
|
|
1176
|
+
* receipts after close completes. */
|
|
1177
|
+
TEST_SAY("C1: Closing without acknowledging\n");
|
|
1178
|
+
rd_kafka_error_t *c1_close_err =
|
|
1179
|
+
rd_kafka_share_consumer_close(c1);
|
|
1180
|
+
TEST_ASSERT(c1_close_err == NULL,
|
|
1181
|
+
"C1: close returned error: %s",
|
|
1182
|
+
rd_kafka_error_string(c1_close_err));
|
|
1183
|
+
|
|
1184
|
+
/* No acks were issued, so the receipts sink must be empty. */
|
|
1185
|
+
verify_receipts_match(&receipts, NULL, 0, "no-ack-close");
|
|
1186
|
+
|
|
1187
|
+
c2 = test_create_share_consumer(ctx.group_id, "implicit");
|
|
1188
|
+
subscribe_consumer(c2, ctx.topic_names, ctx.topic_cnt);
|
|
1189
|
+
|
|
1190
|
+
/* C2: Verify every tracked message is redelivered. Cap the
|
|
1191
|
+
* scan at total produced so we don't loop forever if redelivery
|
|
1192
|
+
* is broken. */
|
|
1193
|
+
verify_tracked_messages(c2, "C2", ctx.total_msgs_produced,
|
|
1194
|
+
tracked_msgs, tracked_cnt, rd_true,
|
|
1195
|
+
"no-ack-close");
|
|
1196
|
+
|
|
1197
|
+
TEST_SAY("C2: Closing consumer\n");
|
|
1198
|
+
rd_kafka_share_consumer_close(c2);
|
|
1199
|
+
test_share_destroy(c2);
|
|
1200
|
+
|
|
1201
|
+
free_tracked_messages(tracked_msgs, tracked_cnt);
|
|
1202
|
+
ack_receipts_destroy(&receipts);
|
|
1203
|
+
|
|
1204
|
+
for (int t = 0; t < ctx.topic_cnt; t++) {
|
|
1205
|
+
rd_free(ctx.topic_names[t]);
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
TEST_SAY("Test %s completed successfully\n\n",
|
|
1209
|
+
config->test_name);
|
|
1210
|
+
test_share_destroy(c1);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
SUB_TEST_PASS();
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* @brief Test close with slow broker response
|
|
1218
|
+
*
|
|
1219
|
+
* Verifies that close() waits for the broker to respond to the
|
|
1220
|
+
* session close request (sent to partition leader), even when
|
|
1221
|
+
* the broker is slow to respond.
|
|
1222
|
+
*
|
|
1223
|
+
* Tests 3 scenarios with a 3-broker setup:
|
|
1224
|
+
* 1. Only broker 1 has delayed response (10s)
|
|
1225
|
+
* 2. Brokers 1 and 2 have delayed responses (10s each)
|
|
1226
|
+
* 3. All 3 brokers have delayed responses (10s each)
|
|
1227
|
+
*
|
|
1228
|
+
* In each case, close() should wait for the response and complete
|
|
1229
|
+
* successfully after the delay.
|
|
1230
|
+
*/
|
|
1231
|
+
static void do_test_close_with_slow_broker_response(void) {
|
|
1232
|
+
typedef struct {
|
|
1233
|
+
const char *test_name;
|
|
1234
|
+
int delayed_broker_cnt;
|
|
1235
|
+
int32_t delayed_brokers[3];
|
|
1236
|
+
} delay_test_config_t;
|
|
1237
|
+
|
|
1238
|
+
delay_test_config_t tests[] = {
|
|
1239
|
+
{"1-broker-delayed", 1, {1, 0, 0}},
|
|
1240
|
+
{"2-brokers-delayed", 2, {1, 2, 0}},
|
|
1241
|
+
{"3-brokers-delayed", 3, {1, 2, 3}},
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
for (size_t test_idx = 0; test_idx < sizeof(tests) / sizeof(tests[0]);
|
|
1245
|
+
test_idx++) {
|
|
1246
|
+
delay_test_config_t *config = &tests[test_idx];
|
|
1247
|
+
rd_kafka_mock_cluster_t *mcluster;
|
|
1248
|
+
rd_kafka_share_t *consumer;
|
|
1249
|
+
const int rtt_delay_ms = 10000; /* 10 seconds */
|
|
1250
|
+
rd_ts_t t_start, t_elapsed_ms;
|
|
1251
|
+
int i;
|
|
1252
|
+
|
|
1253
|
+
TEST_SAY("\n========================================\n");
|
|
1254
|
+
TEST_SAY("Test: %s\n", config->test_name);
|
|
1255
|
+
TEST_SAY("Delayed brokers: %d\n", config->delayed_broker_cnt);
|
|
1256
|
+
TEST_SAY("========================================\n\n");
|
|
1257
|
+
|
|
1258
|
+
SUB_TEST("%s", config->test_name);
|
|
1259
|
+
|
|
1260
|
+
setup_3broker_share_consumer(config->test_name, 0, &mcluster,
|
|
1261
|
+
&consumer);
|
|
1262
|
+
|
|
1263
|
+
/* Inject RTT delay for ShareAck request on specified brokers;
|
|
1264
|
+
* the session-close request */
|
|
1265
|
+
for (i = 0; i < config->delayed_broker_cnt; i++) {
|
|
1266
|
+
TEST_ASSERT(
|
|
1267
|
+
rd_kafka_mock_broker_push_request_error_rtts(
|
|
1268
|
+
mcluster, config->delayed_brokers[i],
|
|
1269
|
+
RD_KAFKAP_ShareAcknowledge, 1,
|
|
1270
|
+
RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1271
|
+
rtt_delay_ms) == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1272
|
+
"Failed to inject ShareAcknowledge delay");
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
TEST_SAY(
|
|
1276
|
+
"Calling close() with delayed broker response(s)...\n");
|
|
1277
|
+
t_start = test_clock();
|
|
1278
|
+
rd_kafka_share_consumer_close(consumer);
|
|
1279
|
+
t_elapsed_ms = (test_clock() - t_start) / 1000;
|
|
1280
|
+
|
|
1281
|
+
TEST_SAY("Close completed after %" PRId64 " ms\n",
|
|
1282
|
+
t_elapsed_ms);
|
|
1283
|
+
|
|
1284
|
+
/* close() should wait ~rtt_delay_ms for the slowest delayed
|
|
1285
|
+
* broker. Allow (rtt - 1s) to (rtt + 2s). */
|
|
1286
|
+
int64_t min_expected_ms = rtt_delay_ms - 1000;
|
|
1287
|
+
int64_t max_expected_ms = rtt_delay_ms + 2000;
|
|
1288
|
+
|
|
1289
|
+
TEST_ASSERT(t_elapsed_ms >= min_expected_ms &&
|
|
1290
|
+
t_elapsed_ms <= max_expected_ms,
|
|
1291
|
+
"Close took %" PRId64
|
|
1292
|
+
" ms, expected between %" PRId64 " and %" PRId64
|
|
1293
|
+
" ms (with %d broker(s) delayed by %dms)",
|
|
1294
|
+
t_elapsed_ms, min_expected_ms, max_expected_ms,
|
|
1295
|
+
config->delayed_broker_cnt, rtt_delay_ms);
|
|
1296
|
+
|
|
1297
|
+
TEST_SAY(
|
|
1298
|
+
"SUCCESS: Close waited approximately %dms for "
|
|
1299
|
+
"delayed broker response(s)\n",
|
|
1300
|
+
rtt_delay_ms);
|
|
1301
|
+
|
|
1302
|
+
test_share_destroy(consumer);
|
|
1303
|
+
test_mock_cluster_destroy(mcluster);
|
|
1304
|
+
|
|
1305
|
+
SUB_TEST_PASS();
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
/**
|
|
1310
|
+
* @brief Test close respects socket timeout with very slow broker(s).
|
|
1311
|
+
*
|
|
1312
|
+
* Verifies that when broker(s) take longer than socket.timeout.ms to
|
|
1313
|
+
* respond to the session close request, close() times out at
|
|
1314
|
+
* socket.timeout.ms and does not wait for the full broker delay.
|
|
1315
|
+
*
|
|
1316
|
+
* Tests 3 scenarios with a 3-broker setup:
|
|
1317
|
+
* 1. Only broker 1 has delayed response (40s, exceeds 20s socket timeout)
|
|
1318
|
+
* 2. Brokers 1 and 2 have delayed responses
|
|
1319
|
+
* 3. All 3 brokers have delayed responses
|
|
1320
|
+
*/
|
|
1321
|
+
static void do_test_close_respects_socket_timeout(void) {
|
|
1322
|
+
typedef struct {
|
|
1323
|
+
const char *test_name;
|
|
1324
|
+
int delayed_broker_cnt;
|
|
1325
|
+
int32_t delayed_brokers[3];
|
|
1326
|
+
} delay_test_config_t;
|
|
1327
|
+
|
|
1328
|
+
delay_test_config_t tests[] = {
|
|
1329
|
+
{"close-timeout-1-broker", 1, {1, 0, 0}},
|
|
1330
|
+
{"close-timeout-2-brokers", 2, {1, 2, 0}},
|
|
1331
|
+
{"close-timeout-3-brokers", 3, {1, 2, 3}},
|
|
1332
|
+
};
|
|
1333
|
+
|
|
1334
|
+
const int rtt_delay_ms = 40000; /* 40s — exceeds socket.timeout */
|
|
1335
|
+
const int socket_timeout_ms = 20000; /* 20s */
|
|
1336
|
+
|
|
1337
|
+
for (size_t test_idx = 0; test_idx < sizeof(tests) / sizeof(tests[0]);
|
|
1338
|
+
test_idx++) {
|
|
1339
|
+
delay_test_config_t *config = &tests[test_idx];
|
|
1340
|
+
rd_kafka_mock_cluster_t *mcluster;
|
|
1341
|
+
rd_kafka_share_t *consumer;
|
|
1342
|
+
rd_ts_t t_start, t_elapsed_ms;
|
|
1343
|
+
int i;
|
|
1344
|
+
|
|
1345
|
+
TEST_SAY("\n========================================\n");
|
|
1346
|
+
TEST_SAY("Test: %s\n", config->test_name);
|
|
1347
|
+
TEST_SAY(
|
|
1348
|
+
"Delayed brokers: %d, RTT: %dms, Socket timeout: %dms\n",
|
|
1349
|
+
config->delayed_broker_cnt, rtt_delay_ms,
|
|
1350
|
+
socket_timeout_ms);
|
|
1351
|
+
TEST_SAY("========================================\n\n");
|
|
1352
|
+
|
|
1353
|
+
SUB_TEST("%s", config->test_name);
|
|
1354
|
+
|
|
1355
|
+
setup_3broker_share_consumer(
|
|
1356
|
+
config->test_name, socket_timeout_ms, &mcluster, &consumer);
|
|
1357
|
+
|
|
1358
|
+
for (i = 0; i < config->delayed_broker_cnt; i++) {
|
|
1359
|
+
TEST_SAY(
|
|
1360
|
+
"Injecting %dms RTT delay on broker %d "
|
|
1361
|
+
"(exceeds socket timeout %dms)\n",
|
|
1362
|
+
rtt_delay_ms, config->delayed_brokers[i],
|
|
1363
|
+
socket_timeout_ms);
|
|
1364
|
+
rd_kafka_mock_broker_set_rtt(
|
|
1365
|
+
mcluster, config->delayed_brokers[i], rtt_delay_ms);
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
TEST_SAY("Calling close() - should timeout around %dms...\n",
|
|
1369
|
+
socket_timeout_ms);
|
|
1370
|
+
t_start = test_clock();
|
|
1371
|
+
rd_kafka_share_consumer_close(consumer);
|
|
1372
|
+
t_elapsed_ms = (test_clock() - t_start) / 1000;
|
|
1373
|
+
|
|
1374
|
+
TEST_SAY("Close completed after %" PRId64 " ms\n",
|
|
1375
|
+
t_elapsed_ms);
|
|
1376
|
+
|
|
1377
|
+
/* close() should timeout around socket.timeout.ms.
|
|
1378
|
+
* Allow ±5s margin. */
|
|
1379
|
+
int64_t min_expected_ms = socket_timeout_ms - 5000;
|
|
1380
|
+
int64_t max_expected_ms = socket_timeout_ms + 5000;
|
|
1381
|
+
|
|
1382
|
+
TEST_ASSERT(t_elapsed_ms >= min_expected_ms &&
|
|
1383
|
+
t_elapsed_ms <= max_expected_ms,
|
|
1384
|
+
"Close took %" PRId64
|
|
1385
|
+
" ms, expected ~%dms (between %" PRId64
|
|
1386
|
+
" and %" PRId64
|
|
1387
|
+
" ms). Should NOT wait for full broker delay "
|
|
1388
|
+
"of %dms",
|
|
1389
|
+
t_elapsed_ms, socket_timeout_ms, min_expected_ms,
|
|
1390
|
+
max_expected_ms, rtt_delay_ms);
|
|
1391
|
+
|
|
1392
|
+
/* Defensively verify it did not wait the full broker delay. */
|
|
1393
|
+
TEST_ASSERT(t_elapsed_ms < (rtt_delay_ms - 10000),
|
|
1394
|
+
"Close took %" PRId64
|
|
1395
|
+
" ms — too close to broker delay %dms. "
|
|
1396
|
+
"Should have timed out at socket.timeout.ms=%dms",
|
|
1397
|
+
t_elapsed_ms, rtt_delay_ms, socket_timeout_ms);
|
|
1398
|
+
|
|
1399
|
+
TEST_SAY(
|
|
1400
|
+
"SUCCESS: Close respected socket timeout (%dms) with "
|
|
1401
|
+
"%d delayed broker(s)\n",
|
|
1402
|
+
socket_timeout_ms, config->delayed_broker_cnt);
|
|
1403
|
+
|
|
1404
|
+
test_share_destroy(consumer);
|
|
1405
|
+
test_mock_cluster_destroy(mcluster);
|
|
1406
|
+
|
|
1407
|
+
SUB_TEST_PASS();
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* @brief Test close with broker error response.
|
|
1413
|
+
*
|
|
1414
|
+
* Verifies that close() handles error responses from the broker
|
|
1415
|
+
* gracefully. When the broker(s) respond with an error to the
|
|
1416
|
+
* ShareAcknowledge request (session close request), close() should
|
|
1417
|
+
* complete without retrying.
|
|
1418
|
+
*
|
|
1419
|
+
* Tests 3 scenarios with a 3-broker setup:
|
|
1420
|
+
* 1. Only broker 1 returns LEADER_NOT_AVAILABLE
|
|
1421
|
+
* 2. Brokers 1 and 2 return the error
|
|
1422
|
+
* 3. All 3 brokers return the error
|
|
1423
|
+
*/
|
|
1424
|
+
static void do_test_close_with_broker_error_response(void) {
|
|
1425
|
+
typedef struct {
|
|
1426
|
+
const char *test_name;
|
|
1427
|
+
int erroring_broker_cnt;
|
|
1428
|
+
int32_t erroring_brokers[3];
|
|
1429
|
+
} error_test_config_t;
|
|
1430
|
+
|
|
1431
|
+
error_test_config_t tests[] = {
|
|
1432
|
+
{"close-error-1-broker", 1, {1, 0, 0}},
|
|
1433
|
+
{"close-error-2-brokers", 2, {1, 2, 0}},
|
|
1434
|
+
{"close-error-3-brokers", 3, {1, 2, 3}},
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
const rd_kafka_resp_err_t error_code =
|
|
1438
|
+
RD_KAFKA_RESP_ERR_LEADER_NOT_AVAILABLE;
|
|
1439
|
+
|
|
1440
|
+
for (size_t test_idx = 0; test_idx < sizeof(tests) / sizeof(tests[0]);
|
|
1441
|
+
test_idx++) {
|
|
1442
|
+
error_test_config_t *config = &tests[test_idx];
|
|
1443
|
+
rd_kafka_mock_cluster_t *mcluster;
|
|
1444
|
+
rd_kafka_share_t *consumer;
|
|
1445
|
+
int i;
|
|
1446
|
+
|
|
1447
|
+
TEST_SAY("\n========================================\n");
|
|
1448
|
+
TEST_SAY("Test: %s\n", config->test_name);
|
|
1449
|
+
TEST_SAY("Erroring brokers: %d, error code: %s\n",
|
|
1450
|
+
config->erroring_broker_cnt,
|
|
1451
|
+
rd_kafka_err2str(error_code));
|
|
1452
|
+
TEST_SAY("========================================\n\n");
|
|
1453
|
+
|
|
1454
|
+
SUB_TEST("%s", config->test_name);
|
|
1455
|
+
|
|
1456
|
+
setup_3broker_share_consumer(config->test_name, 0, &mcluster,
|
|
1457
|
+
&consumer);
|
|
1458
|
+
|
|
1459
|
+
/* Push the error onto the specified brokers' next
|
|
1460
|
+
* ShareAcknowledge request. */
|
|
1461
|
+
for (i = 0; i < config->erroring_broker_cnt; i++) {
|
|
1462
|
+
TEST_SAY("Injecting %s error on broker %d\n",
|
|
1463
|
+
rd_kafka_err2str(error_code),
|
|
1464
|
+
config->erroring_brokers[i]);
|
|
1465
|
+
rd_kafka_mock_broker_push_request_error_rtts(
|
|
1466
|
+
mcluster, config->erroring_brokers[i],
|
|
1467
|
+
RD_KAFKAP_ShareAcknowledge, 1, error_code, 0);
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
TEST_SAY(
|
|
1471
|
+
"Calling close() - should complete despite error(s)...\n");
|
|
1472
|
+
rd_kafka_share_consumer_close(consumer);
|
|
1473
|
+
TEST_SAY("Close completed\n");
|
|
1474
|
+
|
|
1475
|
+
TEST_SAY(
|
|
1476
|
+
"SUCCESS: Close handled error %s gracefully on %d "
|
|
1477
|
+
"broker(s) (no retry)\n",
|
|
1478
|
+
rd_kafka_err2str(error_code), config->erroring_broker_cnt);
|
|
1479
|
+
|
|
1480
|
+
test_share_destroy(consumer);
|
|
1481
|
+
test_mock_cluster_destroy(mcluster);
|
|
1482
|
+
|
|
1483
|
+
SUB_TEST_PASS();
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
|
|
1488
|
+
/**
|
|
1489
|
+
* @brief Test close() when brokers have pending acks queued.
|
|
1490
|
+
*
|
|
1491
|
+
* Setup:
|
|
1492
|
+
* - 3-broker mock cluster, topic with 3 partitions (one leader per broker).
|
|
1493
|
+
* - Inject 5s RTT delay on ShareAcknowledge for all brokers — this makes
|
|
1494
|
+
* every ack the consumer sends take 5s broker-side.
|
|
1495
|
+
* - Produce 30 msgs (10/partition), consume them all with an implicit-ack
|
|
1496
|
+
* consumer. Implicit-ack piggybacks acks on the next ShareFetch, so by
|
|
1497
|
+
* the end of the first round there are still acks in flight or queued.
|
|
1498
|
+
* - Repeat: produce another 30, consume them all (same consumer).
|
|
1499
|
+
* - Call close(). close() should drain the in-flight ShareAcknowledges
|
|
1500
|
+
* and send the session-leave; with the 5s delay this should take
|
|
1501
|
+
* roughly 5s (remaining ack RTT) + 5s (leave RTT) = ~10s.
|
|
1502
|
+
* - Remove the RTT delay, start a second consumer (also implicit ack)
|
|
1503
|
+
* and verify it receives 0 messages over up to 5 fetch attempts. If
|
|
1504
|
+
* any message is delivered, close() failed to send the acks.
|
|
1505
|
+
*/
|
|
1506
|
+
static void do_test_close_with_broker_busy(void) {
|
|
1507
|
+
const char *test_name = "close-broker-busy";
|
|
1508
|
+
const int partition_cnt = 3;
|
|
1509
|
+
const int msgs_per_partition = 10;
|
|
1510
|
+
const int total_msgs = partition_cnt * msgs_per_partition;
|
|
1511
|
+
const int rtt_delay_ms = 5000;
|
|
1512
|
+
rd_kafka_mock_cluster_t *mcluster;
|
|
1513
|
+
const char *bootstraps;
|
|
1514
|
+
rd_kafka_share_t *consumer, *c2;
|
|
1515
|
+
rd_kafka_conf_t *conf;
|
|
1516
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
1517
|
+
rd_kafka_messages_t *batch = NULL;
|
|
1518
|
+
rd_kafka_error_t *error, *close_err;
|
|
1519
|
+
char topic[64], group[64], errstr[512];
|
|
1520
|
+
int iter, p, i;
|
|
1521
|
+
size_t rcvd;
|
|
1522
|
+
rd_ts_t t_start, t_elapsed_ms;
|
|
1523
|
+
|
|
1524
|
+
SUB_TEST("%s", test_name);
|
|
1525
|
+
|
|
1526
|
+
rd_snprintf(topic, sizeof(topic), "mock-%s", test_name);
|
|
1527
|
+
rd_snprintf(group, sizeof(group), "sg-%s", test_name);
|
|
1528
|
+
|
|
1529
|
+
TEST_SAY("\n========================================\n");
|
|
1530
|
+
TEST_SAY("Test: %s\n", test_name);
|
|
1531
|
+
TEST_SAY("ShareAck RTT: %dms on all brokers\n", rtt_delay_ms);
|
|
1532
|
+
TEST_SAY("========================================\n\n");
|
|
1533
|
+
|
|
1534
|
+
/* Cluster + APIs + topic */
|
|
1535
|
+
mcluster = test_mock_cluster_new(3, &bootstraps);
|
|
1536
|
+
rd_kafka_mock_sharegroup_set_auto_offset_reset(mcluster, 1);
|
|
1537
|
+
|
|
1538
|
+
TEST_ASSERT(rd_kafka_mock_topic_create(mcluster, topic, partition_cnt,
|
|
1539
|
+
1) == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1540
|
+
"Failed to create mock topic");
|
|
1541
|
+
|
|
1542
|
+
/* Implicit-ack consumer */
|
|
1543
|
+
test_conf_init(&conf, NULL, 0);
|
|
1544
|
+
test_conf_set(conf, "bootstrap.servers", bootstraps);
|
|
1545
|
+
test_conf_set(conf, "group.id", group);
|
|
1546
|
+
test_conf_set(conf, "share.acknowledgement.mode", "implicit");
|
|
1547
|
+
consumer = rd_kafka_share_consumer_new(conf, errstr, sizeof(errstr));
|
|
1548
|
+
TEST_ASSERT(consumer, "Failed to create consumer: %s", errstr);
|
|
1549
|
+
|
|
1550
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
1551
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1552
|
+
TEST_ASSERT(!rd_kafka_share_subscribe(consumer, subs),
|
|
1553
|
+
"Subscribe failed");
|
|
1554
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1555
|
+
|
|
1556
|
+
/* Inject 5s RTT delay on the next 20 ShareAcknowledge responses on
|
|
1557
|
+
* each broker (no error, just delay) */
|
|
1558
|
+
TEST_SAY(
|
|
1559
|
+
"Injecting %dms RTT delay on ShareAcknowledge "
|
|
1560
|
+
"(20 entries/broker)\n",
|
|
1561
|
+
rtt_delay_ms);
|
|
1562
|
+
for (i = 1; i <= 3; i++) {
|
|
1563
|
+
int j;
|
|
1564
|
+
for (j = 0; j < 20; j++) {
|
|
1565
|
+
TEST_ASSERT(
|
|
1566
|
+
rd_kafka_mock_broker_push_request_error_rtts(
|
|
1567
|
+
mcluster, i, RD_KAFKAP_ShareAcknowledge, 1,
|
|
1568
|
+
(rd_kafka_resp_err_t)0,
|
|
1569
|
+
rtt_delay_ms) == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1570
|
+
"Failed to push RTT delay on broker %d", i);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
/* Two rounds of produce+consume so that by the end there are acks
|
|
1575
|
+
* queued/in-flight on every broker. */
|
|
1576
|
+
for (iter = 1; iter <= 2; iter++) {
|
|
1577
|
+
int consumed = 0, attempts = 0;
|
|
1578
|
+
TEST_SAY(
|
|
1579
|
+
"Iteration %d: producing %d msgs across %d "
|
|
1580
|
+
"partitions\n",
|
|
1581
|
+
iter, total_msgs, partition_cnt);
|
|
1582
|
+
for (p = 0; p < partition_cnt; p++) {
|
|
1583
|
+
test_produce_msgs_easy_v(
|
|
1584
|
+
topic, 0, p, iter * msgs_per_partition,
|
|
1585
|
+
msgs_per_partition, 16, "bootstrap.servers",
|
|
1586
|
+
bootstraps, NULL);
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
TEST_SAY("Iteration %d: consuming %d msgs\n", iter, total_msgs);
|
|
1590
|
+
while (consumed < total_msgs && attempts++ < 30) {
|
|
1591
|
+
error = rd_kafka_share_poll(consumer, 3000, &batch);
|
|
1592
|
+
if (error) {
|
|
1593
|
+
rd_kafka_error_destroy(error);
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1596
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1597
|
+
for (i = 0; i < (int)rcvd; i++) {
|
|
1598
|
+
rd_kafka_message_t *rkm =
|
|
1599
|
+
rd_kafka_messages_get(batch, i);
|
|
1600
|
+
if (rkm && !rkm->err)
|
|
1601
|
+
consumed++;
|
|
1602
|
+
}
|
|
1603
|
+
rd_kafka_messages_destroy(batch);
|
|
1604
|
+
batch = NULL;
|
|
1605
|
+
TEST_ASSERT(rd_kafka_share_commit_async(consumer) ==
|
|
1606
|
+
NULL,
|
|
1607
|
+
"fail to call commit async");
|
|
1608
|
+
}
|
|
1609
|
+
TEST_ASSERT(consumed == total_msgs,
|
|
1610
|
+
"Iteration %d: expected %d msgs, got %d", iter,
|
|
1611
|
+
total_msgs, consumed);
|
|
1612
|
+
TEST_SAY("Iteration %d: consumed all %d msgs\n", iter,
|
|
1613
|
+
consumed);
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
/* Call close. Expect ~10s: ~5s for in-flight ack to drain, then
|
|
1617
|
+
* ~5s for the session-leave ShareAcknowledge to come back. */
|
|
1618
|
+
TEST_SAY("Calling close() - expecting ~10s\n");
|
|
1619
|
+
t_start = test_clock();
|
|
1620
|
+
close_err = rd_kafka_share_consumer_close(consumer);
|
|
1621
|
+
t_elapsed_ms = (test_clock() - t_start) / 1000;
|
|
1622
|
+
|
|
1623
|
+
TEST_SAY("Close completed after %" PRId64 " ms\n", t_elapsed_ms);
|
|
1624
|
+
TEST_ASSERT(close_err == NULL, "Close returned error: %s",
|
|
1625
|
+
rd_kafka_error_string(close_err));
|
|
1626
|
+
TEST_ASSERT(t_elapsed_ms >= 8000 && t_elapsed_ms <= 12000,
|
|
1627
|
+
"Close took %" PRId64 " ms, expected 8000-12000 ms",
|
|
1628
|
+
t_elapsed_ms);
|
|
1629
|
+
|
|
1630
|
+
test_share_destroy(consumer);
|
|
1631
|
+
|
|
1632
|
+
/* Verify nothing was redelivered: c2 should consume 0 messages
|
|
1633
|
+
* because c1's close() flushed all acks. */
|
|
1634
|
+
test_conf_init(&conf, NULL, 0);
|
|
1635
|
+
test_conf_set(conf, "bootstrap.servers", bootstraps);
|
|
1636
|
+
test_conf_set(conf, "group.id", group);
|
|
1637
|
+
test_conf_set(conf, "share.acknowledgement.mode", "implicit");
|
|
1638
|
+
c2 = rd_kafka_share_consumer_new(conf, errstr, sizeof(errstr));
|
|
1639
|
+
TEST_ASSERT(c2, "Failed to create c2: %s", errstr);
|
|
1640
|
+
|
|
1641
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
1642
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1643
|
+
TEST_ASSERT(!rd_kafka_share_subscribe(c2, subs), "c2 subscribe failed");
|
|
1644
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1645
|
+
|
|
1646
|
+
TEST_SAY("c2: verifying no msgs redelivered (5 fetch attempts)\n");
|
|
1647
|
+
for (i = 0; i < 5; i++) {
|
|
1648
|
+
error = rd_kafka_share_poll(c2, 2000, &batch);
|
|
1649
|
+
if (error) {
|
|
1650
|
+
TEST_SAY("c2 attempt %d: error: %s\n", i + 1,
|
|
1651
|
+
rd_kafka_error_string(error));
|
|
1652
|
+
rd_kafka_error_destroy(error);
|
|
1653
|
+
continue;
|
|
1654
|
+
}
|
|
1655
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1656
|
+
rd_kafka_messages_destroy(batch);
|
|
1657
|
+
batch = NULL;
|
|
1658
|
+
TEST_ASSERT(
|
|
1659
|
+
rcvd == 0,
|
|
1660
|
+
"c2 attempt %d: received %d msgs (expected 0 — close "
|
|
1661
|
+
"did not flush acks)",
|
|
1662
|
+
i + 1, (int)rcvd);
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
TEST_SAY("SUCCESS: close() flushed acks; c2 received no msgs\n");
|
|
1666
|
+
|
|
1667
|
+
test_share_destroy(c2);
|
|
1668
|
+
test_mock_cluster_destroy(mcluster);
|
|
1669
|
+
|
|
1670
|
+
SUB_TEST_PASS();
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
/**
|
|
1674
|
+
* @brief Test close() when the broker is down.
|
|
1675
|
+
*
|
|
1676
|
+
* Verifies that close() returns immediately without an error
|
|
1677
|
+
* when the broker is down
|
|
1678
|
+
*
|
|
1679
|
+
* Setup:
|
|
1680
|
+
* - Consumer subscribes, consumes at least one batch, then we set the
|
|
1681
|
+
* broker down and call close().
|
|
1682
|
+
* - close() should return immediately and return NULL (no error).
|
|
1683
|
+
*/
|
|
1684
|
+
static void do_test_close_with_broker_down(void) {
|
|
1685
|
+
rd_kafka_mock_cluster_t *mcluster;
|
|
1686
|
+
const char *bootstraps;
|
|
1687
|
+
rd_kafka_share_t *consumer;
|
|
1688
|
+
rd_kafka_conf_t *conf;
|
|
1689
|
+
const char *topic = "mock-close-broker-down";
|
|
1690
|
+
const char *group = "sg-close-broker-down";
|
|
1691
|
+
const int msgcnt = 10;
|
|
1692
|
+
const int socket_timeout_ms = 20000;
|
|
1693
|
+
rd_kafka_messages_t *batch = NULL;
|
|
1694
|
+
rd_kafka_error_t *error;
|
|
1695
|
+
rd_kafka_error_t *close_err;
|
|
1696
|
+
size_t rcvd;
|
|
1697
|
+
int attempts = 0;
|
|
1698
|
+
rd_bool_t got_msgs = rd_false;
|
|
1699
|
+
rd_ts_t t_start, t_elapsed_ms;
|
|
1700
|
+
char errstr[512];
|
|
1701
|
+
|
|
1702
|
+
SUB_TEST("close-with-broker-down");
|
|
1703
|
+
|
|
1704
|
+
/* Suppress the transport-error / all-brokers-down events that the
|
|
1705
|
+
* test framework's default error_cb would otherwise fail on once we
|
|
1706
|
+
* set the broker down. Scoped to this test only. */
|
|
1707
|
+
test_curr->is_fatal_cb = test_close_with_broker_down_is_fatal_cb;
|
|
1708
|
+
|
|
1709
|
+
TEST_SAY("\n========================================\n");
|
|
1710
|
+
TEST_SAY("Test: close with broker down\n");
|
|
1711
|
+
TEST_SAY("Socket timeout: %dms\n", socket_timeout_ms);
|
|
1712
|
+
TEST_SAY("========================================\n\n");
|
|
1713
|
+
|
|
1714
|
+
mcluster = test_mock_cluster_new(1, &bootstraps);
|
|
1715
|
+
rd_kafka_mock_sharegroup_set_auto_offset_reset(mcluster, 1);
|
|
1716
|
+
|
|
1717
|
+
TEST_ASSERT(rd_kafka_mock_topic_create(mcluster, topic, 1, 1) ==
|
|
1718
|
+
RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1719
|
+
"Failed to create mock topic");
|
|
1720
|
+
|
|
1721
|
+
/* Produce msgcnt messages via test helper. */
|
|
1722
|
+
test_produce_msgs_easy_v(topic, 0, 0, 0, msgcnt, 16,
|
|
1723
|
+
"bootstrap.servers", bootstraps, NULL);
|
|
1724
|
+
|
|
1725
|
+
/* Consumer with implicit ack mode and explicit socket timeout. */
|
|
1726
|
+
test_conf_init(&conf, NULL, 0);
|
|
1727
|
+
test_conf_set(conf, "bootstrap.servers", bootstraps);
|
|
1728
|
+
test_conf_set(conf, "group.id", group);
|
|
1729
|
+
test_conf_set(conf, "share.acknowledgement.mode", "implicit");
|
|
1730
|
+
|
|
1731
|
+
consumer = rd_kafka_share_consumer_new(conf, errstr, sizeof(errstr));
|
|
1732
|
+
TEST_ASSERT(consumer, "Failed to create consumer: %s", errstr);
|
|
1733
|
+
|
|
1734
|
+
rd_kafka_topic_partition_list_t *subs =
|
|
1735
|
+
rd_kafka_topic_partition_list_new(1);
|
|
1736
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1737
|
+
TEST_ASSERT(!rd_kafka_share_subscribe(consumer, subs),
|
|
1738
|
+
"Subscribe failed");
|
|
1739
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1740
|
+
|
|
1741
|
+
/* Consume until we get at least one batch of messages, then break.
|
|
1742
|
+
*/
|
|
1743
|
+
TEST_SAY("Consuming until first non-empty batch...\n");
|
|
1744
|
+
while (!got_msgs && attempts++ < 30) {
|
|
1745
|
+
error = rd_kafka_share_poll(consumer, 3000, &batch);
|
|
1746
|
+
if (error) {
|
|
1747
|
+
rd_kafka_error_destroy(error);
|
|
1748
|
+
continue;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1752
|
+
if (rcvd > 0) {
|
|
1753
|
+
TEST_SAY("Received %d messages\n", (int)rcvd);
|
|
1754
|
+
rd_kafka_messages_destroy(batch);
|
|
1755
|
+
batch = NULL;
|
|
1756
|
+
got_msgs = rd_true;
|
|
1757
|
+
break;
|
|
1758
|
+
}
|
|
1759
|
+
rd_kafka_messages_destroy(batch);
|
|
1760
|
+
batch = NULL;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
TEST_ASSERT(got_msgs, "Expected to receive at least one message");
|
|
1764
|
+
|
|
1765
|
+
/* Bring the broker down before calling close(). */
|
|
1766
|
+
TEST_SAY("Setting broker 1 down\n");
|
|
1767
|
+
TEST_ASSERT(rd_kafka_mock_broker_set_down(mcluster, 1) ==
|
|
1768
|
+
RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1769
|
+
"Failed to set broker down");
|
|
1770
|
+
|
|
1771
|
+
/* close() should fail fast (broker connection was closed) */
|
|
1772
|
+
TEST_SAY("Calling close() with broker down\n");
|
|
1773
|
+
t_start = test_clock();
|
|
1774
|
+
close_err = rd_kafka_share_consumer_close(consumer);
|
|
1775
|
+
t_elapsed_ms = (test_clock() - t_start) / 1000;
|
|
1776
|
+
|
|
1777
|
+
TEST_SAY("Close completed after %" PRId64 " ms (err=%s)\n",
|
|
1778
|
+
t_elapsed_ms,
|
|
1779
|
+
close_err ? rd_kafka_error_string(close_err) : "NULL");
|
|
1780
|
+
|
|
1781
|
+
if (close_err)
|
|
1782
|
+
rd_kafka_error_destroy(close_err);
|
|
1783
|
+
|
|
1784
|
+
TEST_SAY("SUCCESS: close() returned in %" PRId64
|
|
1785
|
+
"ms after broker down\n",
|
|
1786
|
+
t_elapsed_ms);
|
|
1787
|
+
|
|
1788
|
+
/* Bring the broker back up so the consumer's network threads can
|
|
1789
|
+
* finish their shutdown handshake cleanly during destroy. */
|
|
1790
|
+
TEST_ASSERT(rd_kafka_mock_broker_set_up(mcluster, 1) ==
|
|
1791
|
+
RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1792
|
+
"Failed to set broker up");
|
|
1793
|
+
|
|
1794
|
+
test_share_destroy(consumer);
|
|
1795
|
+
test_mock_cluster_destroy(mcluster);
|
|
1796
|
+
|
|
1797
|
+
/* Restore default error-fatal behavior for subsequent tests. */
|
|
1798
|
+
test_curr->is_fatal_cb = NULL;
|
|
1799
|
+
|
|
1800
|
+
SUB_TEST_PASS();
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
/**
|
|
1804
|
+
* @brief Test: calling share-consumer APIs after close() completes.
|
|
1805
|
+
*
|
|
1806
|
+
* Verifies every guarded API returns RD_KAFKA_RESP_ERR__STATE with
|
|
1807
|
+
* "closed" in the error string.
|
|
1808
|
+
*/
|
|
1809
|
+
static void do_test_api_calls_on_closed_consumer(void) {
|
|
1810
|
+
rd_kafka_mock_cluster_t *mcluster;
|
|
1811
|
+
const char *bootstraps;
|
|
1812
|
+
rd_kafka_conf_t *conf;
|
|
1813
|
+
rd_kafka_share_t *consumer;
|
|
1814
|
+
const char *topic = "0178-api-after-close";
|
|
1815
|
+
const char *group = "grp-0178-api-after-close";
|
|
1816
|
+
char errstr[512];
|
|
1817
|
+
rd_kafka_error_t *close_error;
|
|
1818
|
+
|
|
1819
|
+
SUB_TEST_QUICK();
|
|
1820
|
+
|
|
1821
|
+
mcluster = test_mock_cluster_new(1, &bootstraps);
|
|
1822
|
+
|
|
1823
|
+
TEST_ASSERT(rd_kafka_mock_topic_create(mcluster, topic, 1, 1) ==
|
|
1824
|
+
RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1825
|
+
"Create mock topic");
|
|
1826
|
+
|
|
1827
|
+
/* Produce a single message via test helper (creates an internal
|
|
1828
|
+
* producer for the duration of the call). */
|
|
1829
|
+
test_produce_msgs_easy_v(topic, 0, 0, 0, 1, 3, "bootstrap.servers",
|
|
1830
|
+
bootstraps, NULL);
|
|
1831
|
+
|
|
1832
|
+
/* Consumer */
|
|
1833
|
+
test_conf_init(&conf, NULL, 0);
|
|
1834
|
+
test_conf_set(conf, "bootstrap.servers", bootstraps);
|
|
1835
|
+
test_conf_set(conf, "group.id", group);
|
|
1836
|
+
consumer = rd_kafka_share_consumer_new(conf, errstr, sizeof(errstr));
|
|
1837
|
+
TEST_ASSERT(consumer, "consumer: %s", errstr);
|
|
1838
|
+
|
|
1839
|
+
rd_kafka_topic_partition_list_t *subs =
|
|
1840
|
+
rd_kafka_topic_partition_list_new(1);
|
|
1841
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1842
|
+
TEST_ASSERT(!rd_kafka_share_subscribe(consumer, subs), "subscribe");
|
|
1843
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1844
|
+
|
|
1845
|
+
/* Close (blocking), then verify all APIs reject further calls. */
|
|
1846
|
+
TEST_SAY("Calling close() and waiting for completion\n");
|
|
1847
|
+
close_error = rd_kafka_share_consumer_close(consumer);
|
|
1848
|
+
TEST_ASSERT(close_error == NULL, "initial close: %s",
|
|
1849
|
+
close_error ? rd_kafka_error_string(close_error) : "");
|
|
1850
|
+
TEST_ASSERT(rd_kafka_share_consumer_closed(consumer),
|
|
1851
|
+
"consumer should report closed");
|
|
1852
|
+
|
|
1853
|
+
TEST_SAY("Exercising APIs on closed consumer\n");
|
|
1854
|
+
verify_all_apis_return_error(consumer, topic);
|
|
1855
|
+
|
|
1856
|
+
test_share_destroy(consumer);
|
|
1857
|
+
test_mock_cluster_destroy(mcluster);
|
|
1858
|
+
|
|
1859
|
+
SUB_TEST_PASS();
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
/**
|
|
1863
|
+
* @brief Test: once close_queue() returns successfully, all subsequent API
|
|
1864
|
+
* calls must be rejected with RD_KAFKA_RESP_ERR__STATE.
|
|
1865
|
+
*
|
|
1866
|
+
* A 5s RTT delay is injected on ShareAcknowledge so the consumer remains
|
|
1867
|
+
* in the "closing" state (close_queue returns immediately, actual close
|
|
1868
|
+
* completes later), giving us a deterministic window to exercise every
|
|
1869
|
+
* guarded API.
|
|
1870
|
+
*/
|
|
1871
|
+
static void do_test_api_calls_during_closing(void) {
|
|
1872
|
+
rd_kafka_mock_cluster_t *mcluster;
|
|
1873
|
+
const char *bootstraps;
|
|
1874
|
+
rd_kafka_conf_t *conf;
|
|
1875
|
+
rd_kafka_share_t *consumer;
|
|
1876
|
+
const char *topic = "0178-api-during-closing";
|
|
1877
|
+
const char *group = "grp-0178-api-during-closing";
|
|
1878
|
+
char errstr[512];
|
|
1879
|
+
rd_kafka_queue_t *queue;
|
|
1880
|
+
rd_kafka_error_t *close_error;
|
|
1881
|
+
const int rtt_delay_ms = 5000;
|
|
1882
|
+
|
|
1883
|
+
SUB_TEST_QUICK();
|
|
1884
|
+
|
|
1885
|
+
mcluster = test_mock_cluster_new(1, &bootstraps);
|
|
1886
|
+
|
|
1887
|
+
TEST_ASSERT(rd_kafka_mock_topic_create(mcluster, topic, 1, 1) ==
|
|
1888
|
+
RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
1889
|
+
"Create mock topic");
|
|
1890
|
+
|
|
1891
|
+
/* Produce one message via test helper. */
|
|
1892
|
+
test_produce_msgs_easy_v(topic, 0, 0, 0, 1, 3, "bootstrap.servers",
|
|
1893
|
+
bootstraps, NULL);
|
|
1894
|
+
|
|
1895
|
+
test_conf_init(&conf, NULL, 0);
|
|
1896
|
+
test_conf_set(conf, "bootstrap.servers", bootstraps);
|
|
1897
|
+
test_conf_set(conf, "group.id", group);
|
|
1898
|
+
consumer = rd_kafka_share_consumer_new(conf, errstr, sizeof(errstr));
|
|
1899
|
+
TEST_ASSERT(consumer, "consumer: %s", errstr);
|
|
1900
|
+
|
|
1901
|
+
rd_kafka_topic_partition_list_t *subs =
|
|
1902
|
+
rd_kafka_topic_partition_list_new(1);
|
|
1903
|
+
rd_kafka_topic_partition_list_add(subs, topic, RD_KAFKA_PARTITION_UA);
|
|
1904
|
+
TEST_ASSERT(!rd_kafka_share_subscribe(consumer, subs), "subscribe");
|
|
1905
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
1906
|
+
|
|
1907
|
+
/* Consume one batch so there's state to flush on close. */
|
|
1908
|
+
{
|
|
1909
|
+
rd_kafka_messages_t *batch = NULL;
|
|
1910
|
+
size_t rcvd = 0;
|
|
1911
|
+
int attempts = 0;
|
|
1912
|
+
rd_kafka_error_t *cerr = NULL;
|
|
1913
|
+
while (attempts++ < 20 && rcvd == 0) {
|
|
1914
|
+
cerr = rd_kafka_share_poll(consumer, 500, &batch);
|
|
1915
|
+
if (cerr) {
|
|
1916
|
+
rd_kafka_error_destroy(cerr);
|
|
1917
|
+
continue;
|
|
1918
|
+
}
|
|
1919
|
+
rcvd = rd_kafka_messages_count(batch);
|
|
1920
|
+
if (rcvd == 0) {
|
|
1921
|
+
rd_kafka_messages_destroy(batch);
|
|
1922
|
+
batch = NULL;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
if (batch) {
|
|
1926
|
+
rd_kafka_messages_destroy(batch);
|
|
1927
|
+
batch = NULL;
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
/* Inject 5s delay on ShareAcknowledge so close() stays in flight. */
|
|
1932
|
+
TEST_SAY("Injecting %dms RTT delay on broker\n", rtt_delay_ms);
|
|
1933
|
+
rd_kafka_mock_broker_set_rtt(mcluster, 1, rtt_delay_ms);
|
|
1934
|
+
|
|
1935
|
+
queue = rd_kafka_queue_new(test_share_consumer_get_rk(consumer));
|
|
1936
|
+
|
|
1937
|
+
TEST_SAY("Calling close_queue() to initiate async close\n");
|
|
1938
|
+
close_error = rd_kafka_share_consumer_close_queue(consumer, queue);
|
|
1939
|
+
TEST_ASSERT(close_error == NULL, "close_queue: %s",
|
|
1940
|
+
close_error ? rd_kafka_error_string(close_error) : "");
|
|
1941
|
+
|
|
1942
|
+
/* close_queue has returned. Consumer must now be in closing state
|
|
1943
|
+
* (not fully closed yet, since ShareAcknowledge response is still
|
|
1944
|
+
* delayed). Every subsequent API call must be rejected. */
|
|
1945
|
+
TEST_ASSERT(!rd_kafka_share_consumer_closed(consumer),
|
|
1946
|
+
"consumer should still be closing, not closed");
|
|
1947
|
+
|
|
1948
|
+
TEST_SAY("Exercising APIs on closing consumer\n");
|
|
1949
|
+
verify_all_apis_return_error(consumer, topic);
|
|
1950
|
+
|
|
1951
|
+
/* Wait for async close to complete before destroying. */
|
|
1952
|
+
TEST_SAY("Waiting for consumer to finish closing\n");
|
|
1953
|
+
while (!rd_kafka_share_consumer_closed(consumer)) {
|
|
1954
|
+
rd_usleep(500 * 1000, NULL); /* 500ms */
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
rd_kafka_queue_destroy(queue);
|
|
1958
|
+
test_share_destroy(consumer);
|
|
1959
|
+
test_mock_cluster_destroy(mcluster);
|
|
1960
|
+
|
|
1961
|
+
SUB_TEST_PASS();
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
/**
|
|
1965
|
+
* @brief Test that the share-ack callback fires for un-committed implicit
|
|
1966
|
+
* acks during close.
|
|
1967
|
+
*
|
|
1968
|
+
* In implicit mode, records consumed in the first poll are auto-acked via
|
|
1969
|
+
* piggyback on the next ShareFetch. After polling twice (first to fetch,
|
|
1970
|
+
* second to drive the piggyback ack) and closing without an explicit
|
|
1971
|
+
* commit, the ack callback must have fired with the consumed offsets.
|
|
1972
|
+
*/
|
|
1973
|
+
static void do_test_implicit_ack_callback_fires_on_close(void) {
|
|
1974
|
+
const char *topic_name;
|
|
1975
|
+
const char *group;
|
|
1976
|
+
char group_id[64];
|
|
1977
|
+
rd_kafka_share_t *rkshare;
|
|
1978
|
+
rd_kafka_messages_t *raw_batch = NULL;
|
|
1979
|
+
rd_kafka_topic_partition_list_t *subs;
|
|
1980
|
+
rd_kafka_error_t *error;
|
|
1981
|
+
ack_receipts_t receipts;
|
|
1982
|
+
size_t rcvd, j;
|
|
1983
|
+
int consumed = 0;
|
|
1984
|
+
int attempts = 0;
|
|
1985
|
+
|
|
1986
|
+
SUB_TEST();
|
|
1987
|
+
|
|
1988
|
+
ack_receipts_init(&receipts);
|
|
1989
|
+
|
|
1990
|
+
topic_name = test_mk_topic_name("0178-impl-ack-on-close", 1);
|
|
1991
|
+
test_create_topic_wait_exists(common_admin, topic_name, 1, -1,
|
|
1992
|
+
60 * 1000);
|
|
1993
|
+
test_produce_msgs_simple(common_producer, topic_name, 0, 1);
|
|
1994
|
+
|
|
1995
|
+
rd_snprintf(group_id, sizeof(group_id),
|
|
1996
|
+
"0178-group-impl-ack-close-%" PRIu64, test_id_generate());
|
|
1997
|
+
group = group_id;
|
|
1998
|
+
|
|
1999
|
+
test_share_set_auto_offset_reset(group, "earliest");
|
|
2000
|
+
rkshare =
|
|
2001
|
+
create_share_consumer_with_receipts(group, "implicit", &receipts);
|
|
2002
|
+
|
|
2003
|
+
subs = rd_kafka_topic_partition_list_new(1);
|
|
2004
|
+
rd_kafka_topic_partition_list_add(subs, topic_name,
|
|
2005
|
+
RD_KAFKA_PARTITION_UA);
|
|
2006
|
+
rd_kafka_share_subscribe(rkshare, subs);
|
|
2007
|
+
rd_kafka_topic_partition_list_destroy(subs);
|
|
2008
|
+
|
|
2009
|
+
/* First poll: fetch the record (auto-ack pending for next poll) */
|
|
2010
|
+
while (consumed < 1 && attempts++ < 30) {
|
|
2011
|
+
error = rd_kafka_share_poll(rkshare, 2000, &raw_batch);
|
|
2012
|
+
if (error) {
|
|
2013
|
+
rd_kafka_error_destroy(error);
|
|
2014
|
+
continue;
|
|
2015
|
+
}
|
|
2016
|
+
rcvd = rd_kafka_messages_count(raw_batch);
|
|
2017
|
+
for (j = 0; j < rcvd; j++) {
|
|
2018
|
+
rd_kafka_message_t *rkm =
|
|
2019
|
+
rd_kafka_messages_get(raw_batch, j);
|
|
2020
|
+
if (rkm && !rkm->err)
|
|
2021
|
+
consumed++;
|
|
2022
|
+
}
|
|
2023
|
+
rd_kafka_messages_destroy(raw_batch);
|
|
2024
|
+
raw_batch = NULL;
|
|
2025
|
+
}
|
|
2026
|
+
TEST_ASSERT(consumed == 1, "Expected 1 record, got %d", consumed);
|
|
2027
|
+
|
|
2028
|
+
/* Second poll: drives the piggybacked implicit ack to the broker */
|
|
2029
|
+
attempts = 5;
|
|
2030
|
+
while (attempts-- > 0) {
|
|
2031
|
+
error = rd_kafka_share_poll(rkshare, 1000, &raw_batch);
|
|
2032
|
+
if (error)
|
|
2033
|
+
rd_kafka_error_destroy(error);
|
|
2034
|
+
rd_kafka_messages_destroy(raw_batch);
|
|
2035
|
+
raw_batch = NULL;
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
/* Close - any pending ack-completion callbacks must be flushed */
|
|
2039
|
+
TEST_SAY("Closing share consumer without explicit commit\n");
|
|
2040
|
+
error = rd_kafka_share_consumer_close(rkshare);
|
|
2041
|
+
TEST_ASSERT(error == NULL, "close returned error: %s",
|
|
2042
|
+
rd_kafka_error_string(error));
|
|
2043
|
+
|
|
2044
|
+
TEST_SAY(
|
|
2045
|
+
"After close: callback_invocations=%d, receipts=%d, "
|
|
2046
|
+
"last_cb_err=%s\n",
|
|
2047
|
+
receipts.callback_invocations, receipts.receipt_cnt,
|
|
2048
|
+
rd_kafka_err2name(receipts.last_cb_err));
|
|
2049
|
+
|
|
2050
|
+
TEST_ASSERT(receipts.callback_invocations >= 1,
|
|
2051
|
+
"Expected ack callback to fire at least once "
|
|
2052
|
+
"by the time close returns, got %d invocations",
|
|
2053
|
+
receipts.callback_invocations);
|
|
2054
|
+
TEST_ASSERT(receipts.receipt_cnt >= 1,
|
|
2055
|
+
"Expected at least 1 acked offset reported via "
|
|
2056
|
+
"the callback by close, got %d",
|
|
2057
|
+
receipts.receipt_cnt);
|
|
2058
|
+
TEST_ASSERT(receipts.last_cb_err == RD_KAFKA_RESP_ERR_NO_ERROR,
|
|
2059
|
+
"Expected NO_ERROR in ack callback, got %s",
|
|
2060
|
+
rd_kafka_err2name(receipts.last_cb_err));
|
|
2061
|
+
|
|
2062
|
+
ack_receipts_destroy(&receipts);
|
|
2063
|
+
test_share_destroy(rkshare);
|
|
2064
|
+
|
|
2065
|
+
SUB_TEST_PASS();
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
|
|
2069
|
+
int main_0178_share_consumer_close(int argc, char **argv) {
|
|
2070
|
+
/* Set overall timeout for all tests */
|
|
2071
|
+
test_timeout_set(600);
|
|
2072
|
+
|
|
2073
|
+
/* Create common handles reused across all real-broker tests */
|
|
2074
|
+
common_producer = test_create_producer();
|
|
2075
|
+
common_admin = test_create_producer();
|
|
2076
|
+
|
|
2077
|
+
/* Real broker tests */
|
|
2078
|
+
do_test_close_with_acknowledge();
|
|
2079
|
+
do_test_close_without_acknowledge();
|
|
2080
|
+
do_test_implicit_ack_callback_fires_on_close();
|
|
2081
|
+
|
|
2082
|
+
/* Cleanup common handles */
|
|
2083
|
+
rd_kafka_destroy(common_admin);
|
|
2084
|
+
rd_kafka_destroy(common_producer);
|
|
2085
|
+
|
|
2086
|
+
return 0;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
int main_0178_share_consumer_close_local(int argc, char **argv) {
|
|
2090
|
+
/* Mock broker tests only (no real broker needed) */
|
|
2091
|
+
TEST_SKIP_MOCK_CLUSTER(0);
|
|
2092
|
+
test_timeout_set(300);
|
|
2093
|
+
|
|
2094
|
+
do_test_close_with_slow_broker_response();
|
|
2095
|
+
do_test_close_respects_socket_timeout();
|
|
2096
|
+
do_test_close_with_broker_error_response();
|
|
2097
|
+
do_test_close_with_broker_busy();
|
|
2098
|
+
do_test_close_with_broker_down();
|
|
2099
|
+
do_test_api_calls_on_closed_consumer();
|
|
2100
|
+
do_test_api_calls_during_closing();
|
|
2101
|
+
return 0;
|
|
2102
|
+
}
|