@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.
Files changed (628) hide show
  1. package/CHANGELOG.md +457 -0
  2. package/LICENSE.kafkajs +31 -0
  3. package/LICENSE.node-rdkafka +25 -0
  4. package/LICENSE.txt +20 -0
  5. package/README.md +133 -0
  6. package/binding.gyp +184 -0
  7. package/build/Release/confluent-kafka-javascript.node +0 -0
  8. package/build/deps/librdkafka++.so.1 +0 -0
  9. package/build/deps/librdkafka.Makefile +6 -0
  10. package/build/deps/librdkafka.so.1 +0 -0
  11. package/build/deps/librdkafka.target.mk +55 -0
  12. package/deps/librdkafka/.clang-format +136 -0
  13. package/deps/librdkafka/.clang-format-cpp +103 -0
  14. package/deps/librdkafka/.dir-locals.el +10 -0
  15. package/deps/librdkafka/.formatignore +35 -0
  16. package/deps/librdkafka/.gdbmacros +19 -0
  17. package/deps/librdkafka/CHANGELOG.md +2477 -0
  18. package/deps/librdkafka/CMakeLists.txt +291 -0
  19. package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
  20. package/deps/librdkafka/CONFIGURATION.md +212 -0
  21. package/deps/librdkafka/CONTRIBUTING.md +431 -0
  22. package/deps/librdkafka/Doxyfile +2375 -0
  23. package/deps/librdkafka/INTRODUCTION.md +2752 -0
  24. package/deps/librdkafka/LICENSE +26 -0
  25. package/deps/librdkafka/LICENSE.cjson +22 -0
  26. package/deps/librdkafka/LICENSE.crc32c +28 -0
  27. package/deps/librdkafka/LICENSE.fnv1a +18 -0
  28. package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
  29. package/deps/librdkafka/LICENSE.lz4 +26 -0
  30. package/deps/librdkafka/LICENSE.murmur2 +25 -0
  31. package/deps/librdkafka/LICENSE.nanopb +22 -0
  32. package/deps/librdkafka/LICENSE.opentelemetry +203 -0
  33. package/deps/librdkafka/LICENSE.pycrc +23 -0
  34. package/deps/librdkafka/LICENSE.queue +31 -0
  35. package/deps/librdkafka/LICENSE.regexp +5 -0
  36. package/deps/librdkafka/LICENSE.snappy +36 -0
  37. package/deps/librdkafka/LICENSE.tinycthread +26 -0
  38. package/deps/librdkafka/LICENSE.wingetopt +49 -0
  39. package/deps/librdkafka/LICENSES.txt +625 -0
  40. package/deps/librdkafka/Makefile +125 -0
  41. package/deps/librdkafka/README.md +201 -0
  42. package/deps/librdkafka/README.win32 +26 -0
  43. package/deps/librdkafka/STATISTICS.md +624 -0
  44. package/deps/librdkafka/configure +214 -0
  45. package/deps/librdkafka/configure.self +341 -0
  46. package/deps/librdkafka/dev-conf.sh +123 -0
  47. package/deps/librdkafka/lds-gen.py +73 -0
  48. package/deps/librdkafka/mainpage.doxy +40 -0
  49. package/deps/librdkafka/mklove/Makefile.base +329 -0
  50. package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
  51. package/deps/librdkafka/mklove/modules/configure.base +2484 -0
  52. package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
  53. package/deps/librdkafka/mklove/modules/configure.cc +186 -0
  54. package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
  55. package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
  56. package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
  57. package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
  58. package/deps/librdkafka/mklove/modules/configure.host +132 -0
  59. package/deps/librdkafka/mklove/modules/configure.lib +49 -0
  60. package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
  61. package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
  62. package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
  63. package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
  64. package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
  65. package/deps/librdkafka/mklove/modules/configure.pic +16 -0
  66. package/deps/librdkafka/mklove/modules/configure.socket +20 -0
  67. package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
  68. package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
  69. package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
  70. package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
  71. package/deps/librdkafka/service.yml +182 -0
  72. package/deps/librdkafka/src/CMakeLists.txt +379 -0
  73. package/deps/librdkafka/src/Makefile +105 -0
  74. package/deps/librdkafka/src/README.lz4.md +30 -0
  75. package/deps/librdkafka/src/cJSON.c +3191 -0
  76. package/deps/librdkafka/src/cJSON.h +306 -0
  77. package/deps/librdkafka/src/crc32c.c +430 -0
  78. package/deps/librdkafka/src/crc32c.h +38 -0
  79. package/deps/librdkafka/src/generate_proto.sh +66 -0
  80. package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
  81. package/deps/librdkafka/src/lz4.c +2727 -0
  82. package/deps/librdkafka/src/lz4.h +842 -0
  83. package/deps/librdkafka/src/lz4frame.c +2078 -0
  84. package/deps/librdkafka/src/lz4frame.h +692 -0
  85. package/deps/librdkafka/src/lz4frame_static.h +47 -0
  86. package/deps/librdkafka/src/lz4hc.c +1631 -0
  87. package/deps/librdkafka/src/lz4hc.h +413 -0
  88. package/deps/librdkafka/src/nanopb/pb.h +917 -0
  89. package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
  90. package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
  91. package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
  92. package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
  93. package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
  94. package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
  95. package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
  96. package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
  97. package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
  98. package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
  99. package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
  100. package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
  101. package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
  102. package/deps/librdkafka/src/queue.h +850 -0
  103. package/deps/librdkafka/src/rd.h +592 -0
  104. package/deps/librdkafka/src/rdaddr.c +255 -0
  105. package/deps/librdkafka/src/rdaddr.h +202 -0
  106. package/deps/librdkafka/src/rdatomic.h +262 -0
  107. package/deps/librdkafka/src/rdavg.h +260 -0
  108. package/deps/librdkafka/src/rdavl.c +210 -0
  109. package/deps/librdkafka/src/rdavl.h +250 -0
  110. package/deps/librdkafka/src/rdbase64.c +200 -0
  111. package/deps/librdkafka/src/rdbase64.h +43 -0
  112. package/deps/librdkafka/src/rdbuf.c +1884 -0
  113. package/deps/librdkafka/src/rdbuf.h +375 -0
  114. package/deps/librdkafka/src/rdcrc32.c +114 -0
  115. package/deps/librdkafka/src/rdcrc32.h +170 -0
  116. package/deps/librdkafka/src/rddl.c +179 -0
  117. package/deps/librdkafka/src/rddl.h +43 -0
  118. package/deps/librdkafka/src/rdendian.h +175 -0
  119. package/deps/librdkafka/src/rdfloat.h +67 -0
  120. package/deps/librdkafka/src/rdfnv1a.c +113 -0
  121. package/deps/librdkafka/src/rdfnv1a.h +35 -0
  122. package/deps/librdkafka/src/rdgz.c +120 -0
  123. package/deps/librdkafka/src/rdgz.h +46 -0
  124. package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
  125. package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
  126. package/deps/librdkafka/src/rdhttp.c +831 -0
  127. package/deps/librdkafka/src/rdhttp.h +101 -0
  128. package/deps/librdkafka/src/rdinterval.h +177 -0
  129. package/deps/librdkafka/src/rdkafka.c +7287 -0
  130. package/deps/librdkafka/src/rdkafka.h +11795 -0
  131. package/deps/librdkafka/src/rdkafka_admin.c +10165 -0
  132. package/deps/librdkafka/src/rdkafka_admin.h +658 -0
  133. package/deps/librdkafka/src/rdkafka_assignment.c +1282 -0
  134. package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
  135. package/deps/librdkafka/src/rdkafka_assignor.c +1800 -0
  136. package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
  137. package/deps/librdkafka/src/rdkafka_aux.c +409 -0
  138. package/deps/librdkafka/src/rdkafka_aux.h +174 -0
  139. package/deps/librdkafka/src/rdkafka_background.c +222 -0
  140. package/deps/librdkafka/src/rdkafka_broker.c +6736 -0
  141. package/deps/librdkafka/src/rdkafka_broker.h +851 -0
  142. package/deps/librdkafka/src/rdkafka_buf.c +543 -0
  143. package/deps/librdkafka/src/rdkafka_buf.h +1525 -0
  144. package/deps/librdkafka/src/rdkafka_cert.c +576 -0
  145. package/deps/librdkafka/src/rdkafka_cert.h +62 -0
  146. package/deps/librdkafka/src/rdkafka_cgrp.c +8310 -0
  147. package/deps/librdkafka/src/rdkafka_cgrp.h +589 -0
  148. package/deps/librdkafka/src/rdkafka_conf.c +5177 -0
  149. package/deps/librdkafka/src/rdkafka_conf.h +746 -0
  150. package/deps/librdkafka/src/rdkafka_confval.h +97 -0
  151. package/deps/librdkafka/src/rdkafka_coord.c +623 -0
  152. package/deps/librdkafka/src/rdkafka_coord.h +132 -0
  153. package/deps/librdkafka/src/rdkafka_error.c +228 -0
  154. package/deps/librdkafka/src/rdkafka_error.h +80 -0
  155. package/deps/librdkafka/src/rdkafka_event.c +502 -0
  156. package/deps/librdkafka/src/rdkafka_event.h +126 -0
  157. package/deps/librdkafka/src/rdkafka_feature.c +898 -0
  158. package/deps/librdkafka/src/rdkafka_feature.h +104 -0
  159. package/deps/librdkafka/src/rdkafka_fetcher.c +3820 -0
  160. package/deps/librdkafka/src/rdkafka_fetcher.h +62 -0
  161. package/deps/librdkafka/src/rdkafka_header.c +220 -0
  162. package/deps/librdkafka/src/rdkafka_header.h +76 -0
  163. package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
  164. package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
  165. package/deps/librdkafka/src/rdkafka_int.h +1505 -0
  166. package/deps/librdkafka/src/rdkafka_interceptor.c +842 -0
  167. package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
  168. package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
  169. package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
  170. package/deps/librdkafka/src/rdkafka_metadata.c +2347 -0
  171. package/deps/librdkafka/src/rdkafka_metadata.h +350 -0
  172. package/deps/librdkafka/src/rdkafka_metadata_cache.c +1183 -0
  173. package/deps/librdkafka/src/rdkafka_mock.c +4514 -0
  174. package/deps/librdkafka/src/rdkafka_mock.h +867 -0
  175. package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1877 -0
  176. package/deps/librdkafka/src/rdkafka_mock_handlers.c +5255 -0
  177. package/deps/librdkafka/src/rdkafka_mock_int.h +1005 -0
  178. package/deps/librdkafka/src/rdkafka_mock_sharegrp.c +1207 -0
  179. package/deps/librdkafka/src/rdkafka_msg.c +2619 -0
  180. package/deps/librdkafka/src/rdkafka_msg.h +629 -0
  181. package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
  182. package/deps/librdkafka/src/rdkafka_msgset.h +105 -0
  183. package/deps/librdkafka/src/rdkafka_msgset_reader.c +2099 -0
  184. package/deps/librdkafka/src/rdkafka_msgset_writer.c +1474 -0
  185. package/deps/librdkafka/src/rdkafka_offset.c +1565 -0
  186. package/deps/librdkafka/src/rdkafka_offset.h +150 -0
  187. package/deps/librdkafka/src/rdkafka_op.c +1219 -0
  188. package/deps/librdkafka/src/rdkafka_op.h +1065 -0
  189. package/deps/librdkafka/src/rdkafka_partition.c +5109 -0
  190. package/deps/librdkafka/src/rdkafka_partition.h +1215 -0
  191. package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
  192. package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
  193. package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
  194. package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
  195. package/deps/librdkafka/src/rdkafka_proto.h +739 -0
  196. package/deps/librdkafka/src/rdkafka_protocol.h +131 -0
  197. package/deps/librdkafka/src/rdkafka_queue.c +1351 -0
  198. package/deps/librdkafka/src/rdkafka_queue.h +1235 -0
  199. package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
  200. package/deps/librdkafka/src/rdkafka_request.c +7298 -0
  201. package/deps/librdkafka/src/rdkafka_request.h +761 -0
  202. package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
  203. package/deps/librdkafka/src/rdkafka_sasl.c +589 -0
  204. package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
  205. package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
  206. package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
  207. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1833 -0
  208. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
  209. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1827 -0
  210. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +52 -0
  211. package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
  212. package/deps/librdkafka/src/rdkafka_sasl_scram.c +858 -0
  213. package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
  214. package/deps/librdkafka/src/rdkafka_share_acknowledgement.c +1445 -0
  215. package/deps/librdkafka/src/rdkafka_share_acknowledgement.h +373 -0
  216. package/deps/librdkafka/src/rdkafka_ssl.c +2235 -0
  217. package/deps/librdkafka/src/rdkafka_ssl.h +86 -0
  218. package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4785 -0
  219. package/deps/librdkafka/src/rdkafka_subscription.c +411 -0
  220. package/deps/librdkafka/src/rdkafka_telemetry.c +761 -0
  221. package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
  222. package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1307 -0
  223. package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
  224. package/deps/librdkafka/src/rdkafka_telemetry_encode.c +1309 -0
  225. package/deps/librdkafka/src/rdkafka_telemetry_encode.h +459 -0
  226. package/deps/librdkafka/src/rdkafka_timer.c +407 -0
  227. package/deps/librdkafka/src/rdkafka_timer.h +117 -0
  228. package/deps/librdkafka/src/rdkafka_topic.c +2382 -0
  229. package/deps/librdkafka/src/rdkafka_topic.h +369 -0
  230. package/deps/librdkafka/src/rdkafka_transport.c +1309 -0
  231. package/deps/librdkafka/src/rdkafka_transport.h +99 -0
  232. package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
  233. package/deps/librdkafka/src/rdkafka_txnmgr.c +3256 -0
  234. package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
  235. package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
  236. package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
  237. package/deps/librdkafka/src/rdlist.c +593 -0
  238. package/deps/librdkafka/src/rdlist.h +444 -0
  239. package/deps/librdkafka/src/rdlog.c +89 -0
  240. package/deps/librdkafka/src/rdlog.h +41 -0
  241. package/deps/librdkafka/src/rdmap.c +508 -0
  242. package/deps/librdkafka/src/rdmap.h +492 -0
  243. package/deps/librdkafka/src/rdmurmur2.c +167 -0
  244. package/deps/librdkafka/src/rdmurmur2.h +35 -0
  245. package/deps/librdkafka/src/rdports.c +61 -0
  246. package/deps/librdkafka/src/rdports.h +38 -0
  247. package/deps/librdkafka/src/rdposix.h +250 -0
  248. package/deps/librdkafka/src/rdrand.c +151 -0
  249. package/deps/librdkafka/src/rdrand.h +72 -0
  250. package/deps/librdkafka/src/rdregex.c +156 -0
  251. package/deps/librdkafka/src/rdregex.h +43 -0
  252. package/deps/librdkafka/src/rdsignal.h +57 -0
  253. package/deps/librdkafka/src/rdstring.c +645 -0
  254. package/deps/librdkafka/src/rdstring.h +98 -0
  255. package/deps/librdkafka/src/rdsysqueue.h +404 -0
  256. package/deps/librdkafka/src/rdtime.h +356 -0
  257. package/deps/librdkafka/src/rdtypes.h +86 -0
  258. package/deps/librdkafka/src/rdunittest.c +564 -0
  259. package/deps/librdkafka/src/rdunittest.h +232 -0
  260. package/deps/librdkafka/src/rdunittest_acknowledge.c +1177 -0
  261. package/deps/librdkafka/src/rdunittest_fetcher.c +1211 -0
  262. package/deps/librdkafka/src/rdunittest_msgset_errors.c +1521 -0
  263. package/deps/librdkafka/src/rdvarint.c +134 -0
  264. package/deps/librdkafka/src/rdvarint.h +165 -0
  265. package/deps/librdkafka/src/rdwin32.h +382 -0
  266. package/deps/librdkafka/src/rdxxhash.c +1030 -0
  267. package/deps/librdkafka/src/rdxxhash.h +328 -0
  268. package/deps/librdkafka/src/regexp.c +1352 -0
  269. package/deps/librdkafka/src/regexp.h +41 -0
  270. package/deps/librdkafka/src/snappy.c +1866 -0
  271. package/deps/librdkafka/src/snappy.h +62 -0
  272. package/deps/librdkafka/src/snappy_compat.h +138 -0
  273. package/deps/librdkafka/src/statistics_schema.json +444 -0
  274. package/deps/librdkafka/src/tinycthread.c +932 -0
  275. package/deps/librdkafka/src/tinycthread.h +503 -0
  276. package/deps/librdkafka/src/tinycthread_extra.c +210 -0
  277. package/deps/librdkafka/src/tinycthread_extra.h +218 -0
  278. package/deps/librdkafka/src/win32_config.h +58 -0
  279. package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
  280. package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
  281. package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
  282. package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
  283. package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
  284. package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
  285. package/deps/librdkafka/src-cpp/Makefile +55 -0
  286. package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
  287. package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
  288. package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
  289. package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
  290. package/deps/librdkafka/src-cpp/README.md +16 -0
  291. package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
  292. package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
  293. package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
  294. package/deps/librdkafka/src-cpp/rdkafkacpp.h +3797 -0
  295. package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
  296. package/deps/librdkafka/tests/0000-unittests.c +72 -0
  297. package/deps/librdkafka/tests/0001-multiobj.c +102 -0
  298. package/deps/librdkafka/tests/0002-unkpart.c +244 -0
  299. package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
  300. package/deps/librdkafka/tests/0004-conf.c +934 -0
  301. package/deps/librdkafka/tests/0005-order.c +133 -0
  302. package/deps/librdkafka/tests/0006-symbols.c +163 -0
  303. package/deps/librdkafka/tests/0007-autotopic.c +136 -0
  304. package/deps/librdkafka/tests/0008-reqacks.c +179 -0
  305. package/deps/librdkafka/tests/0009-mock_cluster.c +272 -0
  306. package/deps/librdkafka/tests/0011-produce_batch.c +753 -0
  307. package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
  308. package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
  309. package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
  310. package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
  311. package/deps/librdkafka/tests/0016-client_swname.c +181 -0
  312. package/deps/librdkafka/tests/0017-compression.c +140 -0
  313. package/deps/librdkafka/tests/0018-cgrp_term.c +444 -0
  314. package/deps/librdkafka/tests/0019-list_groups.c +289 -0
  315. package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
  316. package/deps/librdkafka/tests/0021-rkt_destroy.c +72 -0
  317. package/deps/librdkafka/tests/0022-consume_batch.c +331 -0
  318. package/deps/librdkafka/tests/0025-timers.c +147 -0
  319. package/deps/librdkafka/tests/0026-consume_pause.c +547 -0
  320. package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
  321. package/deps/librdkafka/tests/0029-assign_offset.c +202 -0
  322. package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
  323. package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
  324. package/deps/librdkafka/tests/0033-regex_subscribe.c +536 -0
  325. package/deps/librdkafka/tests/0034-offset_reset.c +398 -0
  326. package/deps/librdkafka/tests/0035-api_version.c +73 -0
  327. package/deps/librdkafka/tests/0036-partial_fetch.c +87 -0
  328. package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
  329. package/deps/librdkafka/tests/0038-performance.c +121 -0
  330. package/deps/librdkafka/tests/0039-event.c +284 -0
  331. package/deps/librdkafka/tests/0040-io_event.c +257 -0
  332. package/deps/librdkafka/tests/0041-fetch_max_bytes.c +97 -0
  333. package/deps/librdkafka/tests/0042-many_topics.c +252 -0
  334. package/deps/librdkafka/tests/0043-no_connection.c +77 -0
  335. package/deps/librdkafka/tests/0044-partition_cnt.c +94 -0
  336. package/deps/librdkafka/tests/0045-subscribe_update.c +1010 -0
  337. package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
  338. package/deps/librdkafka/tests/0047-partial_buf_tmout.c +98 -0
  339. package/deps/librdkafka/tests/0048-partitioner.c +283 -0
  340. package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
  341. package/deps/librdkafka/tests/0050-subscribe_adds.c +145 -0
  342. package/deps/librdkafka/tests/0051-assign_adds.c +126 -0
  343. package/deps/librdkafka/tests/0052-msg_timestamps.c +238 -0
  344. package/deps/librdkafka/tests/0053-stats_cb.cpp +527 -0
  345. package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
  346. package/deps/librdkafka/tests/0055-producer_latency.c +539 -0
  347. package/deps/librdkafka/tests/0056-balanced_group_mt.c +315 -0
  348. package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
  349. package/deps/librdkafka/tests/0058-log.cpp +123 -0
  350. package/deps/librdkafka/tests/0059-bsearch.cpp +241 -0
  351. package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
  352. package/deps/librdkafka/tests/0061-consumer_lag.cpp +295 -0
  353. package/deps/librdkafka/tests/0062-stats_event.c +126 -0
  354. package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
  355. package/deps/librdkafka/tests/0064-interceptors.c +529 -0
  356. package/deps/librdkafka/tests/0065-yield.cpp +140 -0
  357. package/deps/librdkafka/tests/0066-plugins.cpp +143 -0
  358. package/deps/librdkafka/tests/0067-empty_topic.cpp +151 -0
  359. package/deps/librdkafka/tests/0068-produce_timeout.c +136 -0
  360. package/deps/librdkafka/tests/0069-consumer_add_parts.c +119 -0
  361. package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
  362. package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
  363. package/deps/librdkafka/tests/0073-headers.c +381 -0
  364. package/deps/librdkafka/tests/0074-producev.c +87 -0
  365. package/deps/librdkafka/tests/0075-retry.c +290 -0
  366. package/deps/librdkafka/tests/0076-produce_retry.c +452 -0
  367. package/deps/librdkafka/tests/0077-compaction.c +366 -0
  368. package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
  369. package/deps/librdkafka/tests/0079-fork.c +93 -0
  370. package/deps/librdkafka/tests/0080-admin_ut.c +3095 -0
  371. package/deps/librdkafka/tests/0081-admin.c +5633 -0
  372. package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +137 -0
  373. package/deps/librdkafka/tests/0083-cb_event.c +233 -0
  374. package/deps/librdkafka/tests/0084-destroy_flags.c +208 -0
  375. package/deps/librdkafka/tests/0085-headers.cpp +392 -0
  376. package/deps/librdkafka/tests/0086-purge.c +368 -0
  377. package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
  378. package/deps/librdkafka/tests/0089-max_poll_interval.c +511 -0
  379. package/deps/librdkafka/tests/0090-idempotence.c +171 -0
  380. package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +295 -0
  381. package/deps/librdkafka/tests/0092-mixed_msgver.c +103 -0
  382. package/deps/librdkafka/tests/0093-holb.c +200 -0
  383. package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +231 -0
  384. package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
  385. package/deps/librdkafka/tests/0097-ssl_verify.cpp +674 -0
  386. package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
  387. package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
  388. package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
  389. package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
  390. package/deps/librdkafka/tests/0102-static_group_rebalance.c +836 -0
  391. package/deps/librdkafka/tests/0103-transactions.c +1383 -0
  392. package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +625 -0
  393. package/deps/librdkafka/tests/0105-transactions_mock.c +3930 -0
  394. package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +318 -0
  395. package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
  396. package/deps/librdkafka/tests/0109-auto_create_topics.cpp +278 -0
  397. package/deps/librdkafka/tests/0110-batch_size.cpp +182 -0
  398. package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
  399. package/deps/librdkafka/tests/0112-assign_unknown_part.c +87 -0
  400. package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3473 -0
  401. package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
  402. package/deps/librdkafka/tests/0115-producer_auth.cpp +182 -0
  403. package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +216 -0
  404. package/deps/librdkafka/tests/0117-mock_errors.c +331 -0
  405. package/deps/librdkafka/tests/0118-commit_rebalance.c +154 -0
  406. package/deps/librdkafka/tests/0119-consumer_auth.cpp +167 -0
  407. package/deps/librdkafka/tests/0120-asymmetric_subscription.c +185 -0
  408. package/deps/librdkafka/tests/0121-clusterid.c +115 -0
  409. package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
  410. package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
  411. package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
  412. package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
  413. package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +1164 -0
  414. package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
  415. package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +217 -0
  416. package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +79 -0
  417. package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
  418. package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
  419. package/deps/librdkafka/tests/0132-strategy_ordering.c +179 -0
  420. package/deps/librdkafka/tests/0133-ssl_keys.c +150 -0
  421. package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
  422. package/deps/librdkafka/tests/0135-sasl_credentials.cpp +279 -0
  423. package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
  424. package/deps/librdkafka/tests/0137-barrier_batch_consume.c +752 -0
  425. package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
  426. package/deps/librdkafka/tests/0139-offset_validation_mock.c +950 -0
  427. package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
  428. package/deps/librdkafka/tests/0142-reauthentication.c +931 -0
  429. package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +552 -0
  430. package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
  431. package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
  432. package/deps/librdkafka/tests/0146-metadata_mock.c +505 -0
  433. package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +1210 -0
  434. package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +569 -0
  435. package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
  436. package/deps/librdkafka/tests/0150-telemetry_mock.c +651 -0
  437. package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
  438. package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
  439. package/deps/librdkafka/tests/0153-memberid.c +128 -0
  440. package/deps/librdkafka/tests/0155-share_group_heartbeat_mock.c +2695 -0
  441. package/deps/librdkafka/tests/0156-share_consumer_fetch_mock.c +1551 -0
  442. package/deps/librdkafka/tests/0157-share_consumer_ack_mock.c +1788 -0
  443. package/deps/librdkafka/tests/0158-share_consumer_transactions_mock.c +467 -0
  444. package/deps/librdkafka/tests/0170-share_consumer_subscription.c +2192 -0
  445. package/deps/librdkafka/tests/0171-share_consumer_consume.c +2150 -0
  446. package/deps/librdkafka/tests/0172-share_consumer_acknowledge.c +1919 -0
  447. package/deps/librdkafka/tests/0173-share_consumer_commit_async.c +2735 -0
  448. package/deps/librdkafka/tests/0174-share_consumer_concurrency.c +1434 -0
  449. package/deps/librdkafka/tests/0175-share_consumer_groups.c +574 -0
  450. package/deps/librdkafka/tests/0176-share_consumer_commit_sync.c +2986 -0
  451. package/deps/librdkafka/tests/0177-share_consumer_transactions.c +1815 -0
  452. package/deps/librdkafka/tests/0178-share_consumer_close.c +2102 -0
  453. package/deps/librdkafka/tests/0179-share_consumer_destroy.c +2482 -0
  454. package/deps/librdkafka/tests/0180-share_consumer_config.c +1677 -0
  455. package/deps/librdkafka/tests/0181-share_consumer_topic_delete.c +354 -0
  456. package/deps/librdkafka/tests/0182-share_consumer_error_handling_mock.c +3358 -0
  457. package/deps/librdkafka/tests/0183-share_consumer_leader_change_mock.c +1234 -0
  458. package/deps/librdkafka/tests/0184-share_consumer_topic_recreate.c +1356 -0
  459. package/deps/librdkafka/tests/0185-share_consumer_max_poll_interval.c +557 -0
  460. package/deps/librdkafka/tests/0186-share_consumer_fatal_error.c +360 -0
  461. package/deps/librdkafka/tests/0190-share_consumer_telemetry.c +387 -0
  462. package/deps/librdkafka/tests/1000-unktopic.c +164 -0
  463. package/deps/librdkafka/tests/8000-idle.cpp +60 -0
  464. package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
  465. package/deps/librdkafka/tests/CMakeLists.txt +193 -0
  466. package/deps/librdkafka/tests/LibrdkafkaTestApp.py +291 -0
  467. package/deps/librdkafka/tests/Makefile +182 -0
  468. package/deps/librdkafka/tests/README.md +514 -0
  469. package/deps/librdkafka/tests/autotest.sh +33 -0
  470. package/deps/librdkafka/tests/backtrace.gdb +30 -0
  471. package/deps/librdkafka/tests/broker_version_tests.py +315 -0
  472. package/deps/librdkafka/tests/buildbox.sh +17 -0
  473. package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
  474. package/deps/librdkafka/tests/cluster_testing.py +203 -0
  475. package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
  476. package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
  477. package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
  478. package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
  479. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
  480. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
  481. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
  482. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +50 -0
  483. package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
  484. package/deps/librdkafka/tests/fixtures/ssl/client2.key +46 -0
  485. package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +168 -0
  486. package/deps/librdkafka/tests/fuzzers/Makefile +12 -0
  487. package/deps/librdkafka/tests/fuzzers/README.md +31 -0
  488. package/deps/librdkafka/tests/fuzzers/fuzz_regex.c +74 -0
  489. package/deps/librdkafka/tests/fuzzers/helpers.h +90 -0
  490. package/deps/librdkafka/tests/gen-ssl-certs.sh +165 -0
  491. package/deps/librdkafka/tests/interactive_broker_version.py +170 -0
  492. package/deps/librdkafka/tests/interceptor_test/CMakeLists.txt +16 -0
  493. package/deps/librdkafka/tests/interceptor_test/Makefile +22 -0
  494. package/deps/librdkafka/tests/interceptor_test/interceptor_test.c +314 -0
  495. package/deps/librdkafka/tests/interceptor_test/interceptor_test.h +54 -0
  496. package/deps/librdkafka/tests/java/IncrementalRebalanceCli.java +97 -0
  497. package/deps/librdkafka/tests/java/Makefile +13 -0
  498. package/deps/librdkafka/tests/java/Murmur2Cli.java +46 -0
  499. package/deps/librdkafka/tests/java/README.md +14 -0
  500. package/deps/librdkafka/tests/java/TransactionProducerCli.java +162 -0
  501. package/deps/librdkafka/tests/java/run-class.sh +11 -0
  502. package/deps/librdkafka/tests/librdkafka.suppressions +483 -0
  503. package/deps/librdkafka/tests/lz4_manual_test.sh +59 -0
  504. package/deps/librdkafka/tests/multi-broker-version-test.sh +50 -0
  505. package/deps/librdkafka/tests/parse-refcnt.sh +43 -0
  506. package/deps/librdkafka/tests/performance_plot.py +115 -0
  507. package/deps/librdkafka/tests/plugin_test/Makefile +19 -0
  508. package/deps/librdkafka/tests/plugin_test/plugin_test.c +58 -0
  509. package/deps/librdkafka/tests/requirements.txt +2 -0
  510. package/deps/librdkafka/tests/run-all-tests.sh +81 -0
  511. package/deps/librdkafka/tests/run-consumer-tests.sh +16 -0
  512. package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
  513. package/deps/librdkafka/tests/run-test-batches.py +157 -0
  514. package/deps/librdkafka/tests/run-test.sh +141 -0
  515. package/deps/librdkafka/tests/rusage.c +249 -0
  516. package/deps/librdkafka/tests/sasl_test.py +289 -0
  517. package/deps/librdkafka/tests/scenarios/README.md +6 -0
  518. package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
  519. package/deps/librdkafka/tests/scenarios/default.json +5 -0
  520. package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
  521. package/deps/librdkafka/tests/share_telemetry_verify/share-otel-collector-config.yaml +28 -0
  522. package/deps/librdkafka/tests/sockem.c +801 -0
  523. package/deps/librdkafka/tests/sockem.h +85 -0
  524. package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
  525. package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
  526. package/deps/librdkafka/tests/test.c +8376 -0
  527. package/deps/librdkafka/tests/test.conf.example +27 -0
  528. package/deps/librdkafka/tests/test.h +1150 -0
  529. package/deps/librdkafka/tests/testcpp.cpp +131 -0
  530. package/deps/librdkafka/tests/testcpp.h +388 -0
  531. package/deps/librdkafka/tests/testshared.h +416 -0
  532. package/deps/librdkafka/tests/tools/README.md +4 -0
  533. package/deps/librdkafka/tests/tools/stats/README.md +21 -0
  534. package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
  535. package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
  536. package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
  537. package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
  538. package/deps/librdkafka/tests/trivup/trivup-0.15.0.tar.gz +0 -0
  539. package/deps/librdkafka/tests/until-fail.sh +87 -0
  540. package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
  541. package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
  542. package/deps/librdkafka/vcpkg.json +23 -0
  543. package/deps/librdkafka/win32/README.md +5 -0
  544. package/deps/librdkafka/win32/build-package.bat +3 -0
  545. package/deps/librdkafka/win32/build.bat +19 -0
  546. package/deps/librdkafka/win32/common.vcxproj +84 -0
  547. package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
  548. package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
  549. package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
  550. package/deps/librdkafka/win32/librdkafka.sln +226 -0
  551. package/deps/librdkafka/win32/librdkafka.vcxproj +282 -0
  552. package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
  553. package/deps/librdkafka/win32/msbuild.ps1 +58 -0
  554. package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
  555. package/deps/librdkafka/win32/package-zip.ps1 +46 -0
  556. package/deps/librdkafka/win32/packages/repositories.config +4 -0
  557. package/deps/librdkafka/win32/push-package.bat +4 -0
  558. package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
  559. package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
  560. package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
  561. package/deps/librdkafka/win32/setup-msys2.ps1 +47 -0
  562. package/deps/librdkafka/win32/setup-vcpkg.ps1 +34 -0
  563. package/deps/librdkafka/win32/tests/test.conf.example +25 -0
  564. package/deps/librdkafka/win32/tests/tests.vcxproj +278 -0
  565. package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
  566. package/deps/librdkafka/win32/wingetopt.c +564 -0
  567. package/deps/librdkafka/win32/wingetopt.h +101 -0
  568. package/deps/librdkafka/win32/wintime.h +33 -0
  569. package/deps/librdkafka.gyp +83 -0
  570. package/deps/windows-install.py +80 -0
  571. package/index.d.ts +3 -0
  572. package/lib/admin.js +732 -0
  573. package/lib/client.js +679 -0
  574. package/lib/error.js +501 -0
  575. package/lib/index.js +8 -0
  576. package/lib/kafka-consumer-stream.js +399 -0
  577. package/lib/kafka-consumer.js +798 -0
  578. package/lib/kafkajs/_admin.js +1052 -0
  579. package/lib/kafkajs/_common.js +887 -0
  580. package/lib/kafkajs/_consumer.js +2156 -0
  581. package/lib/kafkajs/_consumer_cache.js +310 -0
  582. package/lib/kafkajs/_error.js +298 -0
  583. package/lib/kafkajs/_kafka.js +125 -0
  584. package/lib/kafkajs/_linked-list.js +220 -0
  585. package/lib/kafkajs/_producer.js +863 -0
  586. package/lib/kafkajs/index.js +5 -0
  587. package/lib/producer/high-level-producer.js +400 -0
  588. package/lib/producer-stream.js +337 -0
  589. package/lib/producer.js +405 -0
  590. package/lib/rdkafka.js +44 -0
  591. package/lib/tools/ref-counter.js +53 -0
  592. package/lib/topic-partition.js +91 -0
  593. package/lib/topic.js +43 -0
  594. package/lib/util.js +55 -0
  595. package/librdkafka.js +12 -0
  596. package/package.json +85 -0
  597. package/shim/source_location +54 -0
  598. package/src/admin.cc +1597 -0
  599. package/src/admin.h +112 -0
  600. package/src/binding.cc +76 -0
  601. package/src/binding.h +25 -0
  602. package/src/callbacks.cc +676 -0
  603. package/src/callbacks.h +302 -0
  604. package/src/common.cc +1628 -0
  605. package/src/common.h +192 -0
  606. package/src/config.cc +219 -0
  607. package/src/config.h +61 -0
  608. package/src/connection.cc +703 -0
  609. package/src/connection.h +117 -0
  610. package/src/errors.cc +119 -0
  611. package/src/errors.h +60 -0
  612. package/src/kafka-consumer.cc +1539 -0
  613. package/src/kafka-consumer.h +147 -0
  614. package/src/producer.cc +917 -0
  615. package/src/producer.h +124 -0
  616. package/src/topic.cc +173 -0
  617. package/src/topic.h +54 -0
  618. package/src/workers.cc +1714 -0
  619. package/src/workers.h +690 -0
  620. package/types/config.d.ts +1269 -0
  621. package/types/errors.d.ts +373 -0
  622. package/types/kafkajs.d.ts +568 -0
  623. package/types/rdkafka.d.ts +571 -0
  624. package/util/configure.js +32 -0
  625. package/util/generate-docs.sh +18 -0
  626. package/util/get-env.js +6 -0
  627. package/util/test-compile.js +11 -0
  628. package/util/test-producer-delivery.js +100 -0
@@ -0,0 +1,1234 @@
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
+
31
+ #include "../src/rdkafka_proto.h"
32
+
33
+ /**
34
+ * @brief Share consumer leader change tests.
35
+ *
36
+ * Verifies that per-partition leader-change errors on ShareAcknowledge
37
+ * trigger metadata refresh and that unnecessary RPCs are avoided once
38
+ * the client discovers the new leader.
39
+ */
40
+
41
+ #define CONSUME_ARRAY 1024
42
+
43
+ /* ===================================================================
44
+ * Mock broker infrastructure.
45
+ * =================================================================== */
46
+ typedef struct test_ctx_s {
47
+ rd_kafka_t *producer;
48
+ rd_kafka_mock_cluster_t *mcluster;
49
+ const char *bootstraps;
50
+ } test_ctx_t;
51
+
52
+ static test_ctx_t test_ctx_new(int nbrok) {
53
+ test_ctx_t ctx;
54
+ rd_kafka_conf_t *conf;
55
+ char errstr[512];
56
+
57
+ memset(&ctx, 0, sizeof(ctx));
58
+
59
+ ctx.mcluster = test_mock_cluster_new(nbrok, &ctx.bootstraps);
60
+
61
+ TEST_ASSERT(rd_kafka_mock_set_apiversion(
62
+ ctx.mcluster, RD_KAFKAP_ShareGroupHeartbeat, 1, 1) ==
63
+ RD_KAFKA_RESP_ERR_NO_ERROR,
64
+ "Failed to enable ShareGroupHeartbeat");
65
+ TEST_ASSERT(rd_kafka_mock_set_apiversion(ctx.mcluster,
66
+ RD_KAFKAP_ShareFetch, 1, 1) ==
67
+ RD_KAFKA_RESP_ERR_NO_ERROR,
68
+ "Failed to enable ShareFetch");
69
+
70
+ rd_kafka_mock_sharegroup_set_auto_offset_reset(ctx.mcluster, 1);
71
+
72
+ test_conf_init(&conf, NULL, 0);
73
+ test_conf_set(conf, "bootstrap.servers", ctx.bootstraps);
74
+ rd_kafka_conf_set_dr_msg_cb(conf, test_dr_msg_cb);
75
+
76
+ ctx.producer =
77
+ rd_kafka_new(RD_KAFKA_PRODUCER, conf, errstr, sizeof(errstr));
78
+ TEST_ASSERT(ctx.producer != NULL, "Failed to create producer: %s",
79
+ errstr);
80
+
81
+ return ctx;
82
+ }
83
+
84
+ static void test_ctx_destroy(test_ctx_t *ctx) {
85
+ if (ctx->producer)
86
+ rd_kafka_destroy(ctx->producer);
87
+ if (ctx->mcluster)
88
+ test_mock_cluster_destroy(ctx->mcluster);
89
+ memset(ctx, 0, sizeof(*ctx));
90
+ }
91
+
92
+ static void subscribe_topics(rd_kafka_share_t *rkshare,
93
+ const char **topics,
94
+ int topic_cnt) {
95
+ rd_kafka_topic_partition_list_t *subs;
96
+ rd_kafka_resp_err_t err;
97
+ int i;
98
+
99
+ subs = rd_kafka_topic_partition_list_new(topic_cnt);
100
+ for (i = 0; i < topic_cnt; i++)
101
+ rd_kafka_topic_partition_list_add(subs, topics[i],
102
+ RD_KAFKA_PARTITION_UA);
103
+ err = rd_kafka_share_subscribe(rkshare, subs);
104
+ TEST_ASSERT(!err, "subscribe failed: %s", rd_kafka_err2str(err));
105
+ rd_kafka_topic_partition_list_destroy(subs);
106
+ }
107
+
108
+ static void subscribe_one(rd_kafka_share_t *rkshare, const char *topic) {
109
+ subscribe_topics(rkshare, &topic, 1);
110
+ }
111
+
112
+ static int mock_produce(rd_kafka_t *producer,
113
+ const char *topic,
114
+ int32_t partition,
115
+ int msgcnt) {
116
+ int i;
117
+ for (i = 0; i < msgcnt; i++) {
118
+ char payload[64];
119
+ snprintf(payload, sizeof(payload), "%s-p%" PRId32 "-%d", topic,
120
+ partition, i);
121
+ TEST_ASSERT(rd_kafka_producev(
122
+ producer, RD_KAFKA_V_TOPIC(topic),
123
+ RD_KAFKA_V_PARTITION(partition),
124
+ RD_KAFKA_V_VALUE(payload, strlen(payload)),
125
+ RD_KAFKA_V_MSGFLAGS(RD_KAFKA_MSG_F_COPY),
126
+ RD_KAFKA_V_END) == RD_KAFKA_RESP_ERR_NO_ERROR,
127
+ "Produce to %s [%" PRId32 "] failed", topic,
128
+ partition);
129
+ }
130
+ rd_kafka_flush(producer, 5000);
131
+ return msgcnt;
132
+ }
133
+
134
+ static rd_bool_t is_share_ack_request(rd_kafka_mock_request_t *request,
135
+ void *opaque) {
136
+ return rd_kafka_mock_request_api_key(request) ==
137
+ RD_KAFKAP_ShareAcknowledge;
138
+ }
139
+
140
+ static rd_bool_t is_share_fetch_request(rd_kafka_mock_request_t *request,
141
+ void *opaque) {
142
+ return rd_kafka_mock_request_api_key(request) == RD_KAFKAP_ShareFetch;
143
+ }
144
+
145
+ static rd_bool_t is_metadata_request(rd_kafka_mock_request_t *request,
146
+ void *opaque) {
147
+ return rd_kafka_mock_request_api_key(request) == RD_KAFKAP_Metadata;
148
+ }
149
+
150
+
151
+ /* ===================================================================
152
+ * Test — ShareAcknowledge per-partition NOT_LEADER_OR_FOLLOWER
153
+ * should trigger metadata refresh and avoid redundant RPCs.
154
+ *
155
+ * Setup:
156
+ * - 2 brokers, 1 topic, 1 partition on broker 1
157
+ * - Explicit ack mode, background metadata refresh disabled
158
+ * - Produce 10 records, consume one batch (expect all 10)
159
+ * - Move leader to broker 2
160
+ *
161
+ * Loop (5 iterations):
162
+ * - Acknowledge 2 records from the held batch
163
+ * - commit_sync → attempts to route the batch to the cached
164
+ * leader. Round 1 routes to broker 1 (cache is stale);
165
+ * rounds 2-5 are short-circuited locally (see Expected
166
+ * behavior below).
167
+ *
168
+ * Expected behavior with this PR:
169
+ * - The first commit_sync sends a ShareAcknowledge to broker 1
170
+ * (cache still says broker 1 is leader). The response carries
171
+ * NOT_LEADER_OR_FOLLOWER plus a CurrentLeader hint and
172
+ * NodeEndpoints; the inline metadata update applies the new
173
+ * leader to the cache without a separate Metadata RPC.
174
+ * - Rounds 2-5 are caught by the local leader-stale short-circuit
175
+ * in rd_kafka_share_ack_batch_resolve_leader_or_fail_acks and
176
+ * fail without sending an RPC.
177
+ * - All 5 commit_sync return NOT_LEADER_OR_FOLLOWER.
178
+ * - 1 ShareAcknowledge RPC total, 0 Metadata RPCs.
179
+ * =================================================================== */
180
+ static void test_shareack_leader_change_reduces_rpcs(void) {
181
+ test_ctx_t ctx;
182
+ rd_kafka_conf_t *conf;
183
+ rd_kafka_share_t *rkshare;
184
+ rd_kafka_error_t *error;
185
+ const char *topic = "0183-shareack-nlof";
186
+ const char *group = "sg-0183-shareack-nlof";
187
+ const int broker1 = 1;
188
+ const int broker2 = 2;
189
+ const int msgcnt = 10;
190
+ const int acks_per_commit = 2;
191
+ const int commit_rounds = msgcnt / acks_per_commit;
192
+ rd_kafka_messages_t *batch = NULL;
193
+ int round;
194
+ size_t rcvd = 0;
195
+ size_t consumed_idx = 0;
196
+ size_t share_ack_cnt;
197
+ size_t metadata_cnt;
198
+
199
+ SUB_TEST_QUICK();
200
+
201
+ ctx = test_ctx_new(2);
202
+
203
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
204
+ RD_KAFKA_RESP_ERR_NO_ERROR,
205
+ "create topic");
206
+
207
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(ctx.mcluster, topic, 0,
208
+ broker1) ==
209
+ RD_KAFKA_RESP_ERR_NO_ERROR,
210
+ "set initial leader to broker %d", broker1);
211
+
212
+ mock_produce(ctx.producer, topic, RD_KAFKA_PARTITION_UA, msgcnt);
213
+
214
+ test_conf_init(&conf, NULL, 0);
215
+ test_conf_set(conf, "bootstrap.servers", ctx.bootstraps);
216
+ test_conf_set(conf, "group.id", group);
217
+ test_conf_set(conf, "share.acknowledgement.mode", "explicit");
218
+ test_conf_set(conf, "topic.metadata.refresh.interval.ms", "-1");
219
+ rkshare = rd_kafka_share_consumer_new(conf, NULL, 0);
220
+ TEST_ASSERT(rkshare != NULL, "Failed to create share consumer");
221
+ subscribe_one(rkshare, topic);
222
+
223
+ /* Consume one batch — expect all 10 records in a single call. */
224
+ error = rd_kafka_share_poll(rkshare, 10000, &batch);
225
+ TEST_ASSERT(!error, "share_poll failed: %s",
226
+ error ? rd_kafka_error_string(error) : "");
227
+ rcvd = rd_kafka_messages_count(batch);
228
+ TEST_ASSERT(rcvd == (size_t)msgcnt,
229
+ "expected %d records in first batch, got %" PRIusz, msgcnt,
230
+ rcvd);
231
+
232
+ /* Move leader to broker 2 before acknowledging. */
233
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(ctx.mcluster, topic, 0,
234
+ broker2) ==
235
+ RD_KAFKA_RESP_ERR_NO_ERROR,
236
+ "set leader to broker %d", broker2);
237
+
238
+ rd_kafka_mock_start_request_tracking(ctx.mcluster);
239
+ rd_kafka_mock_clear_requests(ctx.mcluster);
240
+
241
+ /* 5 rounds: acknowledge 2 records, commitSync each time.
242
+ * Each commitSync should get NOT_LEADER_OR_FOLLOWER. */
243
+ for (round = 0; round < commit_rounds; round++) {
244
+ rd_kafka_topic_partition_list_t *results = NULL;
245
+ int k;
246
+
247
+ for (k = 0;
248
+ k < acks_per_commit && consumed_idx < (size_t)msgcnt;
249
+ k++, consumed_idx++) {
250
+ rd_kafka_resp_err_t ack_err;
251
+ ack_err = rd_kafka_share_acknowledge(
252
+ rkshare,
253
+ rd_kafka_messages_get(batch, consumed_idx));
254
+ TEST_ASSERT(ack_err == RD_KAFKA_RESP_ERR_NO_ERROR,
255
+ "round %d: acknowledge failed: %s", round,
256
+ rd_kafka_err2str(ack_err));
257
+ }
258
+
259
+ error = rd_kafka_share_commit_sync(rkshare, 500, &results);
260
+
261
+ TEST_SAY("round %d: commit_sync returned %s\n", round,
262
+ error ? rd_kafka_error_string(error) : "success");
263
+
264
+ TEST_ASSERT(results != NULL && results->cnt > 0,
265
+ "round %d: expected results from commit_sync",
266
+ round);
267
+
268
+ for (k = 0; k < results->cnt; k++) {
269
+ TEST_SAY(" round %d: partition %s [%" PRId32
270
+ "] err=%s\n",
271
+ round, results->elems[k].topic,
272
+ results->elems[k].partition,
273
+ rd_kafka_err2name(results->elems[k].err));
274
+ TEST_ASSERT(
275
+ results->elems[k].err ==
276
+ RD_KAFKA_RESP_ERR_NOT_LEADER_OR_FOLLOWER,
277
+ "round %d: expected NOT_LEADER_OR_FOLLOWER, "
278
+ "got %s",
279
+ round, rd_kafka_err2name(results->elems[k].err));
280
+ }
281
+
282
+ rd_kafka_topic_partition_list_destroy(results);
283
+
284
+ if (error)
285
+ rd_kafka_error_destroy(error);
286
+ }
287
+
288
+ share_ack_cnt = test_mock_get_matching_request_cnt(
289
+ ctx.mcluster, is_share_ack_request, NULL);
290
+ metadata_cnt = test_mock_get_matching_request_cnt(
291
+ ctx.mcluster, is_metadata_request, NULL);
292
+
293
+ TEST_SAY("ShareAcknowledge requests after leader change: %" PRIusz "\n",
294
+ share_ack_cnt);
295
+ TEST_SAY("Metadata requests after leader change: %" PRIusz "\n",
296
+ metadata_cnt);
297
+
298
+ /* The first commit_sync sends a ShareAcknowledge RPC to the
299
+ * stale broker; the response carries CurrentLeader and
300
+ * NodeEndpoints which update the metadata cache inline.
301
+ * Rounds 2-5 are caught by the local leader-stale check and
302
+ * fail without sending an RPC. No separate Metadata RPC is
303
+ * needed because the cache update is inline. */
304
+ TEST_ASSERT(share_ack_cnt == 1,
305
+ "expected 1 ShareAcknowledge RPC, got %" PRIusz,
306
+ share_ack_cnt);
307
+ TEST_ASSERT(metadata_cnt == 0,
308
+ "expected 0 Metadata RPCs (inline cache update), "
309
+ "got %" PRIusz,
310
+ metadata_cnt);
311
+
312
+ rd_kafka_mock_stop_request_tracking(ctx.mcluster);
313
+
314
+ /* Clean up held message handles. */
315
+ rd_kafka_messages_destroy(batch);
316
+ batch = NULL;
317
+
318
+ test_share_consumer_close(rkshare);
319
+ test_share_destroy(rkshare);
320
+ test_ctx_destroy(&ctx);
321
+
322
+ SUB_TEST_PASS();
323
+ }
324
+
325
+
326
+ /* ===================================================================
327
+ * Test — per-partition NOT_LEADER_OR_FOLLOWER on ShareFetch is
328
+ * handled silently: no OP_CONSUMER_ERR, consumer recovers
329
+ * and continues reading from the new leader.
330
+ *
331
+ * Two-broker mock cluster. Phase 1 produces and consumes records
332
+ * from broker1. The partition leader is moved to broker2. Phase 2
333
+ * verifies the consumer silently recovers and reads new records
334
+ * from broker2.
335
+ *
336
+ * Wire-level verification: at least 1 Metadata request is triggered
337
+ * (error handler fired metadata refresh) and ShareFetch count stays
338
+ * below 10 (no retry storm). The NOT_LEADER_OR_FOLLOWER response
339
+ * may arrive before or after request tracking starts, so a >= 2
340
+ * ShareFetch lower bound is not reliable; >= 1 is the meaningful
341
+ * minimum.
342
+ *
343
+ * TODO KIP-932: Add a real-broker companion test that triggers a
344
+ * leader change on a multi-broker cluster.
345
+ * =================================================================== */
346
+ static void test_partition_not_leader_or_follower_silent(void) {
347
+ test_ctx_t ctx;
348
+ rd_kafka_conf_t *conf;
349
+ rd_kafka_share_t *rkshare;
350
+ rd_kafka_error_t *error;
351
+ const char *topic = "0183-nlof-silent";
352
+ const char *group = "sg-0183-nlof-silent";
353
+ const int broker1 = 1;
354
+ const int broker2 = 2;
355
+ const int msgcnt = 5;
356
+ rd_kafka_messages_t *batch = NULL;
357
+ int phase1_consumed = 0;
358
+ int phase2_consumed = 0;
359
+ int error_cnt = 0;
360
+ int attempts = 0;
361
+ size_t rcvd = 0;
362
+ size_t share_fetch_cnt;
363
+ size_t metadata_cnt;
364
+ size_t j;
365
+
366
+ SUB_TEST_QUICK();
367
+
368
+ ctx = test_ctx_new(2);
369
+
370
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
371
+ RD_KAFKA_RESP_ERR_NO_ERROR,
372
+ "create topic");
373
+
374
+ /* Explicitly set the initial leader (do not assume a default). */
375
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(ctx.mcluster, topic, 0,
376
+ broker1) ==
377
+ RD_KAFKA_RESP_ERR_NO_ERROR,
378
+ "set initial leader to broker %d", broker1);
379
+
380
+ /* Phase 1: produce and consume records from broker1.
381
+ * auto.offset.reset=earliest (set by test_ctx_new) so the
382
+ * share group starts from the beginning of the log. */
383
+ mock_produce(ctx.producer, topic, RD_KAFKA_PARTITION_UA, msgcnt);
384
+
385
+ /* Disable background metadata refresh so that the only metadata
386
+ * refresh that fires is the one triggered by the per-partition
387
+ * NOT_LEADER_OR_FOLLOWER error. This makes the >= 2 ShareFetch
388
+ * assertion deterministic: background refresh would otherwise
389
+ * silently update the cached leader before Phase 2 starts. */
390
+ test_conf_init(&conf, NULL, 0);
391
+ test_conf_set(conf, "bootstrap.servers", ctx.bootstraps);
392
+ test_conf_set(conf, "group.id", group);
393
+ test_conf_set(conf, "share.acknowledgement.mode", "implicit");
394
+ test_conf_set(conf, "topic.metadata.refresh.interval.ms", "-1");
395
+ rkshare = rd_kafka_share_consumer_new(conf, NULL, 0);
396
+ TEST_ASSERT(rkshare != NULL, "Failed to create share consumer");
397
+ subscribe_one(rkshare, topic);
398
+
399
+ while (phase1_consumed < msgcnt && attempts++ < 30) {
400
+ error = rd_kafka_share_poll(rkshare, 3000, &batch);
401
+ if (error) {
402
+ rd_kafka_error_destroy(error);
403
+ continue;
404
+ }
405
+ rcvd = rd_kafka_messages_count(batch);
406
+ for (j = 0; j < rcvd; j++) {
407
+ rd_kafka_message_t *m = rd_kafka_messages_get(batch, j);
408
+ if (m && !m->err)
409
+ phase1_consumed++;
410
+ }
411
+ rd_kafka_messages_destroy(batch);
412
+ batch = NULL;
413
+ }
414
+ TEST_ASSERT(phase1_consumed == msgcnt,
415
+ "Phase 1: expected %d records from broker %d, got %d",
416
+ msgcnt, broker1, phase1_consumed);
417
+
418
+ /* Start request tracking before the leader change to capture
419
+ * ShareFetch requests sent after it. */
420
+ rd_kafka_mock_start_request_tracking(ctx.mcluster);
421
+ rd_kafka_mock_clear_requests(ctx.mcluster);
422
+
423
+ /* Move the partition leader to broker2. The consumer's next
424
+ * ShareFetch to broker1 will get NOT_LEADER_OR_FOLLOWER per
425
+ * partition, which triggers a silent metadata refresh and
426
+ * reconnect to broker2. */
427
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(ctx.mcluster, topic, 0,
428
+ broker2) ==
429
+ RD_KAFKA_RESP_ERR_NO_ERROR,
430
+ "set leader to broker %d", broker2);
431
+
432
+ /* Produce records that will be available on broker2. mock_produce
433
+ * flushes before returning, so all records are committed to
434
+ * broker2 before Phase 2 begins. */
435
+ mock_produce(ctx.producer, topic, RD_KAFKA_PARTITION_UA, msgcnt);
436
+
437
+ /* Phase 2: consume records after recovery. OP_CONSUMER_ERR
438
+ * surfaces as a non-NULL return from consume_batch; silent
439
+ * handling must keep that return NULL throughout recovery. */
440
+ attempts = 0;
441
+ while (phase2_consumed < msgcnt && attempts++ < 30) {
442
+ error = rd_kafka_share_poll(rkshare, 3000, &batch);
443
+ if (error) {
444
+ error_cnt++;
445
+ rd_kafka_error_destroy(error);
446
+ continue;
447
+ }
448
+ rcvd = rd_kafka_messages_count(batch);
449
+ for (j = 0; j < rcvd; j++) {
450
+ rd_kafka_message_t *m = rd_kafka_messages_get(batch, j);
451
+ if (m && !m->err)
452
+ phase2_consumed++;
453
+ }
454
+ rd_kafka_messages_destroy(batch);
455
+ batch = NULL;
456
+ }
457
+ TEST_ASSERT(phase2_consumed >= msgcnt,
458
+ "Phase 2: expected >= %d records from broker %d after "
459
+ "recovery, got %d",
460
+ msgcnt, broker2, phase2_consumed);
461
+ TEST_ASSERT(error_cnt == 0,
462
+ "expected 0 OP_CONSUMER_ERR (NOT_LEADER_OR_FOLLOWER "
463
+ "must be silently handled), got %d",
464
+ error_cnt);
465
+
466
+ /* Verify the error handler fired (metadata refresh triggered) and
467
+ * did not cause a retry storm. The NOT_LEADER_OR_FOLLOWER response
468
+ * may be processed before or after request tracking starts, so only
469
+ * a Metadata lower bound (not a >= 2 ShareFetch) is reliable. */
470
+ share_fetch_cnt = test_mock_get_matching_request_cnt(
471
+ ctx.mcluster, is_share_fetch_request, NULL);
472
+ metadata_cnt = test_mock_get_matching_request_cnt(
473
+ ctx.mcluster, is_metadata_request, NULL);
474
+ TEST_SAY("ShareFetch requests after leader change: %" PRIusz "\n",
475
+ share_fetch_cnt);
476
+ TEST_SAY("Metadata requests after leader change: %" PRIusz "\n",
477
+ metadata_cnt);
478
+ TEST_ASSERT(metadata_cnt >= 1,
479
+ "expected >= 1 Metadata request after leader change "
480
+ "(error handler must have triggered metadata refresh), "
481
+ "got %" PRIusz,
482
+ metadata_cnt);
483
+ TEST_ASSERT(share_fetch_cnt >= 1,
484
+ "expected >= 1 ShareFetch request after leader change, "
485
+ "got %" PRIusz,
486
+ share_fetch_cnt);
487
+ TEST_ASSERT(share_fetch_cnt < 10,
488
+ "expected < 10 ShareFetch requests (no retry storm), "
489
+ "got %" PRIusz,
490
+ share_fetch_cnt);
491
+
492
+ rd_kafka_mock_stop_request_tracking(ctx.mcluster);
493
+
494
+ test_share_consumer_close(rkshare);
495
+ test_share_destroy(rkshare);
496
+ test_ctx_destroy(&ctx);
497
+
498
+ SUB_TEST_PASS();
499
+ }
500
+
501
+
502
+ /**
503
+ * @brief Drive a consume loop until \p expected records have been read
504
+ * or the attempt budget is exhausted. In implicit mode an extra
505
+ * zero-timeout consume_batch flushes the last batch's auto-ack
506
+ * before returning.
507
+ */
508
+ static int consume_phase(rd_kafka_share_t *rkshare,
509
+ rd_bool_t explicit_mode,
510
+ rd_bool_t use_commit_sync,
511
+ int expected,
512
+ int post_first_batch_settle_ms,
513
+ const char *phase_name) {
514
+ int consumed = 0;
515
+ int attempts = 0;
516
+ int max_attempts = expected * 3 + 60;
517
+ rd_kafka_messages_t *batch = NULL;
518
+ rd_kafka_topic_partition_list_t *flush_results = NULL;
519
+ rd_kafka_error_t *flush_err;
520
+ rd_bool_t first_batch = rd_true;
521
+ int ri;
522
+
523
+ while (consumed < expected && attempts++ < max_attempts) {
524
+ size_t rcvd = 0;
525
+ rd_kafka_error_t *error;
526
+ size_t j;
527
+
528
+ error = rd_kafka_share_poll(rkshare, 3000, &batch);
529
+ if (error) {
530
+ TEST_SAY("%s: share_poll err %s\n", phase_name,
531
+ rd_kafka_error_string(error));
532
+ rd_kafka_error_destroy(error);
533
+ continue;
534
+ }
535
+
536
+ rcvd = rd_kafka_messages_count(batch);
537
+ for (j = 0; j < rcvd; j++) {
538
+ rd_kafka_message_t *m = rd_kafka_messages_get(batch, j);
539
+ if (m && !m->err) {
540
+ consumed++;
541
+ TEST_SAY("%s: record #%d: %s [%" PRId32
542
+ "] offset %" PRId64 "\n",
543
+ phase_name, consumed,
544
+ rd_kafka_topic_name(m->rkt),
545
+ m->partition, m->offset);
546
+ if (explicit_mode)
547
+ rd_kafka_share_acknowledge(rkshare, m);
548
+ }
549
+ }
550
+ rd_kafka_messages_destroy(batch);
551
+ batch = NULL;
552
+
553
+ if (explicit_mode && rcvd > 0) {
554
+ if (use_commit_sync) {
555
+ rd_kafka_topic_partition_list_t *results = NULL;
556
+ rd_kafka_error_t *cerr;
557
+ TEST_SAY(
558
+ "%s: calling commit_sync "
559
+ "(consumed %d)\n",
560
+ phase_name, consumed);
561
+ cerr = rd_kafka_share_commit_sync(rkshare, 5000,
562
+ &results);
563
+ if (cerr) {
564
+ TEST_SAY("%s: commit_sync error: %s\n",
565
+ phase_name,
566
+ rd_kafka_error_string(cerr));
567
+ rd_kafka_error_destroy(cerr);
568
+ }
569
+ RD_IF_FREE(
570
+ results,
571
+ rd_kafka_topic_partition_list_destroy);
572
+ } else {
573
+ rd_kafka_error_t *cerr =
574
+ rd_kafka_share_commit_async(rkshare);
575
+ if (cerr) {
576
+ TEST_SAY("%s: commit_async error: %s\n",
577
+ phase_name,
578
+ rd_kafka_error_string(cerr));
579
+ rd_kafka_error_destroy(cerr);
580
+ }
581
+ }
582
+ }
583
+
584
+ /* After the first consume_batch call, let any pending
585
+ * metadata refresh and per-broker session
586
+ * reconciliation triggered by the leader change settle
587
+ * before the next consume_batch picks the next broker
588
+ * in round-robin. Without this wait the next broker's
589
+ * session is still stale, producing a redundant
590
+ * NOT_LEADER_FOR_PARTITION and metadata refresh. */
591
+ if (first_batch && post_first_batch_settle_ms > 0) {
592
+ rd_usleep(post_first_batch_settle_ms * 1000, NULL);
593
+ first_batch = rd_false;
594
+ }
595
+ }
596
+
597
+ /* Flush before exiting: commit_sync auto-acks for implicit
598
+ * mode (via acknowledge_all_if_implicit) and drains pending
599
+ * acks for explicit mode. Using commit_sync for both modes
600
+ * avoids re-arming share_fetch_more_records via another
601
+ * consume_batch, which would keep the main-thread fetch loop
602
+ * spinning between phases. */
603
+ TEST_SAY("%s: calling commit_sync flush (consumed %d/%d)\n", phase_name,
604
+ consumed, expected);
605
+ flush_err = rd_kafka_share_commit_sync(rkshare, 5000, &flush_results);
606
+ if (flush_err) {
607
+ TEST_SAY("%s: commit_sync flush error: %s\n", phase_name,
608
+ rd_kafka_error_string(flush_err));
609
+ rd_kafka_error_destroy(flush_err);
610
+ } else {
611
+ TEST_SAY("%s: commit_sync flush succeeded\n", phase_name);
612
+ }
613
+ if (flush_results) {
614
+ for (ri = 0; ri < flush_results->cnt; ri++) {
615
+ rd_kafka_topic_partition_t *rp =
616
+ &flush_results->elems[ri];
617
+ TEST_SAY("%s: commit_sync result: %s [%" PRId32
618
+ "]: %s\n",
619
+ phase_name, rp->topic, rp->partition,
620
+ rd_kafka_err2str(rp->err));
621
+ }
622
+ rd_kafka_topic_partition_list_destroy(flush_results);
623
+ flush_results = NULL;
624
+ }
625
+
626
+ TEST_SAY("%s: consumed %d (expected == %d) in %d attempts\n",
627
+ phase_name, consumed, expected, attempts);
628
+ return consumed;
629
+ }
630
+
631
+
632
+ /* ===================================================================
633
+ * Test — produce / consume / leader-change / produce / consume on a
634
+ * multi-topic, multi-partition mock cluster. Verifies that
635
+ * the share consumer picks up the new leader either via the
636
+ * Share RPC error path (refresh disabled) or via background
637
+ * metadata refresh (refresh enabled).
638
+ *
639
+ * Setup:
640
+ * - 3 brokers, 2 topics ("recovery-a" with 2 partitions,
641
+ * "recovery-b" with 5 partitions). Initial leaders round-robin.
642
+ *
643
+ * Phase 1:
644
+ * - Produce a random 10-20 records per partition.
645
+ * - Consume them all, ack/commit per variant.
646
+ *
647
+ * Leader change:
648
+ * - Each partition's leader is rotated to a different broker
649
+ * (chosen randomly).
650
+ * - If \p wait_for_metadata_refresh is true the test sleeps long
651
+ * enough for the configured 500 ms background refresh to fire.
652
+ *
653
+ * Phase 2:
654
+ * - Produce a random 10-20 records per partition.
655
+ * - Consume them all.
656
+ * - Assert the consumed count equals the Phase 2 production.
657
+ *
658
+ * TODO KIP-932: once the ShareFetch response's per-partition
659
+ * CurrentLeader / NodeEndpoints hints are applied inline to the
660
+ * metadata cache (same approach as the ShareAcknowledge path), the
661
+ * refresh-disabled variant must see 0 Metadata RPCs after the
662
+ * leader change and the refresh-enabled variant must see >= 1
663
+ * (background refresh). Today both variants see >= 1 because the
664
+ * ShareFetch error path forces a metadata refresh RPC until the
665
+ * inline update lands.
666
+ * =================================================================== */
667
+ static void
668
+ do_test_leader_change_consume_recovery(rd_bool_t explicit_mode,
669
+ rd_bool_t use_commit_sync,
670
+ rd_bool_t wait_for_metadata_refresh,
671
+ const char *variant_name) {
672
+ test_ctx_t ctx;
673
+ rd_kafka_conf_t *conf;
674
+ rd_kafka_share_t *rkshare;
675
+ char *topic_a;
676
+ char *topic_b;
677
+ const char *topics[2];
678
+ const int part_a = 2;
679
+ const int part_b = 5;
680
+ const char *group = "sg-0183-recovery";
681
+ int phase1_total = 0;
682
+ int phase2_total = 0;
683
+ int phase1_consumed = 0;
684
+ int phase2_consumed = 0;
685
+ int leader_before_a[2];
686
+ int leader_before_b[5];
687
+ size_t metadata_window1;
688
+ size_t metadata_window2;
689
+ int i;
690
+ int cnt;
691
+
692
+ SUB_TEST_QUICK("%s", variant_name);
693
+
694
+ topic_a = rd_strdup(test_mk_topic_name("0183-recovery-a", 1));
695
+ topic_b = rd_strdup(test_mk_topic_name("0183-recovery-b", 1));
696
+ topics[0] = topic_a;
697
+ topics[1] = topic_b;
698
+
699
+ ctx = test_ctx_new(3);
700
+
701
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic_a, part_a,
702
+ 1) == RD_KAFKA_RESP_ERR_NO_ERROR,
703
+ "create topic a");
704
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic_b, part_b,
705
+ 1) == RD_KAFKA_RESP_ERR_NO_ERROR,
706
+ "create topic b");
707
+
708
+ for (i = 0; i < part_a; i++) {
709
+ leader_before_a[i] = (i % 3) + 1;
710
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(
711
+ ctx.mcluster, topic_a, i, leader_before_a[i]) ==
712
+ RD_KAFKA_RESP_ERR_NO_ERROR,
713
+ "set leader a[%d] -> %d", i, leader_before_a[i]);
714
+ }
715
+ for (i = 0; i < part_b; i++) {
716
+ leader_before_b[i] = (i % 3) + 1;
717
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(
718
+ ctx.mcluster, topic_b, i, leader_before_b[i]) ==
719
+ RD_KAFKA_RESP_ERR_NO_ERROR,
720
+ "set leader b[%d] -> %d", i, leader_before_b[i]);
721
+ }
722
+
723
+ srand(42);
724
+
725
+ for (i = 0; i < part_a; i++) {
726
+ cnt = 10 + (rand() % 11);
727
+ phase1_total += mock_produce(ctx.producer, topic_a, i, cnt);
728
+ TEST_SAY(
729
+ "%s: Phase 1 produce: %s [%d] = %d records "
730
+ "(offsets 0..%d)\n",
731
+ variant_name, topic_a, i, cnt, cnt - 1);
732
+ }
733
+ for (i = 0; i < part_b; i++) {
734
+ cnt = 10 + (rand() % 11);
735
+ phase1_total += mock_produce(ctx.producer, topic_b, i, cnt);
736
+ TEST_SAY(
737
+ "%s: Phase 1 produce: %s [%d] = %d records "
738
+ "(offsets 0..%d)\n",
739
+ variant_name, topic_b, i, cnt, cnt - 1);
740
+ }
741
+
742
+ test_conf_init(&conf, NULL, 0);
743
+ test_conf_set(conf, "bootstrap.servers", ctx.bootstraps);
744
+ test_conf_set(conf, "group.id", group);
745
+ test_conf_set(conf, "share.acknowledgement.mode",
746
+ explicit_mode ? "explicit" : "implicit");
747
+ test_conf_set(conf, "topic.metadata.refresh.interval.ms",
748
+ wait_for_metadata_refresh ? "10000" : "-1");
749
+ rkshare = rd_kafka_share_consumer_new(conf, NULL, 0);
750
+ TEST_ASSERT(rkshare != NULL, "create share consumer");
751
+ subscribe_topics(rkshare, topics, 2);
752
+
753
+ phase1_consumed = consume_phase(rkshare, explicit_mode, use_commit_sync,
754
+ phase1_total, 0, "Phase 1");
755
+ TEST_ASSERT(phase1_consumed == phase1_total,
756
+ "Phase 1: expected %d records, got %d", phase1_total,
757
+ phase1_consumed);
758
+
759
+ /* Let initial offset queries (ListOffsetsRequest from the
760
+ * share consumer's reused fetch-state machine on partition
761
+ * assignment) complete before changing leaders. Without this
762
+ * settle window, an in-flight ListOffsets response could race
763
+ * with the leader change and bring in an extra metadata
764
+ * refresh that pollutes Window 1.
765
+ * TODO KIP-932: this wait can be removed once the share
766
+ * consumer no longer issues ListOffsetsRequests. */
767
+ rd_usleep(2000 * 1000, NULL);
768
+
769
+ /* Window 1 — track Metadata RPCs from the leader change
770
+ * through the wait sleep. Captures any background metadata
771
+ * refresh fired while the consumer was idle. */
772
+ rd_kafka_mock_start_request_tracking(ctx.mcluster);
773
+
774
+ for (i = 0; i < part_a; i++) {
775
+ int new_leader = leader_before_a[i];
776
+ while (new_leader == leader_before_a[i])
777
+ new_leader = 1 + (rand() % 3);
778
+ TEST_SAY("%s: leader change: %s [%d]: B%d -> B%d\n",
779
+ variant_name, topic_a, i, leader_before_a[i],
780
+ new_leader);
781
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(
782
+ ctx.mcluster, topic_a, i, new_leader) ==
783
+ RD_KAFKA_RESP_ERR_NO_ERROR,
784
+ "set leader a[%d] -> %d", i, new_leader);
785
+ }
786
+ for (i = 0; i < part_b; i++) {
787
+ int new_leader = leader_before_b[i];
788
+ while (new_leader == leader_before_b[i])
789
+ new_leader = 1 + (rand() % 3);
790
+ TEST_SAY("%s: leader change: %s [%d]: B%d -> B%d\n",
791
+ variant_name, topic_b, i, leader_before_b[i],
792
+ new_leader);
793
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(
794
+ ctx.mcluster, topic_b, i, new_leader) ==
795
+ RD_KAFKA_RESP_ERR_NO_ERROR,
796
+ "set leader b[%d] -> %d", i, new_leader);
797
+ }
798
+
799
+ if (wait_for_metadata_refresh)
800
+ rd_usleep(11000 * 1000, NULL);
801
+
802
+ metadata_window1 = test_mock_get_matching_request_cnt(
803
+ ctx.mcluster, is_metadata_request, NULL);
804
+ TEST_SAY(
805
+ "%s: Window 1 (post leader change, pre Phase 2) "
806
+ "Metadata: %" PRIusz "\n",
807
+ variant_name, metadata_window1);
808
+
809
+ /* Pause tracking around Phase 2 produce so producer-driven
810
+ * metadata refreshes do not pollute the Window 2 count. */
811
+ rd_kafka_mock_stop_request_tracking(ctx.mcluster);
812
+ rd_kafka_mock_clear_requests(ctx.mcluster);
813
+
814
+ for (i = 0; i < part_a; i++) {
815
+ cnt = 10 + (rand() % 11);
816
+ phase2_total += mock_produce(ctx.producer, topic_a, i, cnt);
817
+ TEST_SAY(
818
+ "%s: Phase 2 produce: %s [%d] = %d records "
819
+ "(Phase 2 starts at offset after Phase 1)\n",
820
+ variant_name, topic_a, i, cnt);
821
+ }
822
+ for (i = 0; i < part_b; i++) {
823
+ cnt = 10 + (rand() % 11);
824
+ phase2_total += mock_produce(ctx.producer, topic_b, i, cnt);
825
+ TEST_SAY(
826
+ "%s: Phase 2 produce: %s [%d] = %d records "
827
+ "(Phase 2 starts at offset after Phase 1)\n",
828
+ variant_name, topic_b, i, cnt);
829
+ }
830
+
831
+ /* Ensure all produces and their triggered metadata refreshes
832
+ * have settled before measuring Phase 2 consume. */
833
+ rd_kafka_flush(ctx.producer, 5000);
834
+
835
+ /* Window 2 — track Metadata RPCs strictly around Phase 2
836
+ * consume. Excludes producer activity from Phase 2 produce. */
837
+ rd_kafka_mock_start_request_tracking(ctx.mcluster);
838
+
839
+ phase2_consumed = consume_phase(rkshare, explicit_mode, use_commit_sync,
840
+ phase2_total, 1000, "Phase 2");
841
+ TEST_ASSERT(phase2_consumed == phase2_total,
842
+ "Phase 2: expected %d records after leader change, "
843
+ "got %d",
844
+ phase2_total, phase2_consumed);
845
+
846
+ metadata_window2 = test_mock_get_matching_request_cnt(
847
+ ctx.mcluster, is_metadata_request, NULL);
848
+ TEST_SAY("%s: Window 2 (Phase 2 consume) Metadata: %" PRIusz "\n",
849
+ variant_name, metadata_window2);
850
+
851
+ rd_kafka_mock_stop_request_tracking(ctx.mcluster);
852
+ rd_kafka_mock_clear_requests(ctx.mcluster);
853
+
854
+ /* TODO KIP-932: the share consumer still runs the regular
855
+ * consumer's offset-query path. On leader change, the failed
856
+ * ListOffsets requests trigger extra metadata refreshes that
857
+ * inflate the wait-refresh window1 count and the no-refresh
858
+ * window2 count beyond the single refresh those windows are
859
+ * meant to capture. Once the offset-query path is removed
860
+ * from the share consumer, tighten the >= 1 checks below to
861
+ * == 1.
862
+ *
863
+ * TODO KIP-932: revisit these assertions when the ShareFetch
864
+ * response handler applies its per-partition CurrentLeader
865
+ * and NodeEndpoints hints inline to the metadata cache (same
866
+ * approach already taken for the ShareAcknowledge path). At
867
+ * that point the no-refresh variant must see 0 Metadata RPCs
868
+ * during Phase 2 consume — the cache is updated from the
869
+ * Share response, no separate Metadata RPC is needed — and
870
+ * the wait-refresh expectations stay as today. */
871
+ if (wait_for_metadata_refresh) {
872
+ TEST_ASSERT(metadata_window1 >= 1,
873
+ "%s: expected >= 1 Metadata RPC during the "
874
+ "wait window (background refresh), got %" PRIusz,
875
+ variant_name, metadata_window1);
876
+ TEST_ASSERT(metadata_window2 == 0,
877
+ "%s: expected 0 Metadata RPCs during Phase 2 "
878
+ "consume (cache already updated, no error path), "
879
+ "got %" PRIusz,
880
+ variant_name, metadata_window2);
881
+ } else {
882
+ TEST_ASSERT(metadata_window1 == 0,
883
+ "%s: expected 0 Metadata RPCs before Phase 2 "
884
+ "(background refresh disabled, no error yet), "
885
+ "got %" PRIusz,
886
+ variant_name, metadata_window1);
887
+ TEST_ASSERT(metadata_window2 >= 1,
888
+ "%s: expected >= 1 Metadata RPC during Phase 2 "
889
+ "consume (ShareFetch error path triggered "
890
+ "refresh), got %" PRIusz,
891
+ variant_name, metadata_window2);
892
+ }
893
+
894
+ test_share_consumer_close(rkshare);
895
+ test_share_destroy(rkshare);
896
+ test_ctx_destroy(&ctx);
897
+ rd_free(topic_a);
898
+ rd_free(topic_b);
899
+
900
+ SUB_TEST_PASS();
901
+ }
902
+
903
+
904
+ // /* ===================================================================
905
+ // * Test — per-partition UNKNOWN_TOPIC_OR_PARTITION on ShareFetch is
906
+ // * handled silently: no OP_CONSUMER_ERR is delivered after the
907
+ // * topic is deleted.
908
+ // *
909
+ // * Single-broker mock cluster. Phase 1 produces and consumes records
910
+ // * to establish a share session. The topic is deleted. Phase 2 polls
911
+ // * several times and verifies no error is surfaced to the application.
912
+ // *
913
+ // * Wire-level verification: ShareFetch count is between 1 and 9
914
+ // * (lower bound: error path fired; upper bound: no retry storm).
915
+ // *
916
+ // * TODO KIP-932: Add a real-broker companion test that deletes a
917
+ // * live topic and verifies the same silent behaviour.
918
+ // * =================================================================== */
919
+ // static void test_partition_unknown_topic_silent(void) {
920
+ // test_ctx_t ctx;
921
+ // rd_kafka_conf_t *conf;
922
+ // rd_kafka_share_t *rkshare;
923
+ // rd_kafka_error_t *error;
924
+ // const char *topic = "0183-utp-silent";
925
+ // const char *group = "sg-0183-utp-silent";
926
+ // const int msgcnt = 5;
927
+ // rd_kafka_message_t *rkmessages[CONSUME_ARRAY];
928
+ // int phase1_consumed = 0;
929
+ // int error_cnt = 0;
930
+ // int attempts = 0;
931
+ // int poll_cnt = 0;
932
+ // size_t rcvd = 0;
933
+ // size_t share_fetch_cnt;
934
+ // size_t metadata_cnt;
935
+ // size_t j;
936
+
937
+ // SUB_TEST_QUICK();
938
+
939
+ // ctx = test_ctx_new(1);
940
+
941
+ // TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
942
+ // RD_KAFKA_RESP_ERR_NO_ERROR,
943
+ // "create topic");
944
+
945
+ // /* Phase 1: produce and consume records to establish a share
946
+ // * session. auto.offset.reset=earliest (set by test_ctx_new) so
947
+ // * the share group starts from the beginning of the log. */
948
+ // mock_produce(ctx.producer, topic, RD_KAFKA_PARTITION_UA, msgcnt);
949
+
950
+ // /* Disable auto-create so the metadata handler does not recreate
951
+ // * the deleted topic, and disable the propagation wait so the
952
+ // * toppar is removed from the session immediately when metadata
953
+ // * confirms the topic is gone (instead of waiting 30 s). */
954
+ // test_conf_init(&conf, NULL, 0);
955
+ // test_conf_set(conf, "bootstrap.servers", ctx.bootstraps);
956
+ // test_conf_set(conf, "group.id", group);
957
+ // test_conf_set(conf, "share.acknowledgement.mode", "implicit");
958
+ // test_conf_set(conf, "allow.auto.create.topics", "false");
959
+ // test_conf_set(conf, "topic.metadata.propagation.max.ms", "0");
960
+ // rkshare = rd_kafka_share_consumer_new(conf, NULL, 0);
961
+ // TEST_ASSERT(rkshare != NULL, "Failed to create share consumer");
962
+ // subscribe_one(rkshare, topic);
963
+
964
+ // while (phase1_consumed < msgcnt && attempts++ < 30) {
965
+ // rcvd = 0;
966
+ // error = rd_kafka_share_poll(rkshare, 3000,
967
+ // rkmessages,
968
+ // &rcvd);
969
+ // if (error) {
970
+ // rd_kafka_error_destroy(error);
971
+ // continue;
972
+ // }
973
+ // for (j = 0; j < rcvd; j++) {
974
+ // if (!rkmessages[j]->err)
975
+ // phase1_consumed++;
976
+ // rd_kafka_message_destroy(rkmessages[j]);
977
+ // }
978
+ // }
979
+ // TEST_ASSERT(phase1_consumed == msgcnt,
980
+ // "Phase 1: expected %d records, got %d", msgcnt,
981
+ // phase1_consumed);
982
+
983
+ // /* Start request tracking before topic deletion to capture
984
+ // * ShareFetch requests that get UNKNOWN_TOPIC_OR_PARTITION. */
985
+ // rd_kafka_mock_start_request_tracking(ctx.mcluster);
986
+ // rd_kafka_mock_clear_requests(ctx.mcluster);
987
+
988
+ // /* Delete the topic. The consumer's next ShareFetch will receive
989
+ // * UNKNOWN_TOPIC_OR_PARTITION per partition, which must be handled
990
+ // * silently (metadata refresh, no OP_CONSUMER_ERR). */
991
+ // TEST_ASSERT(rd_kafka_mock_topic_delete(ctx.mcluster, topic) ==
992
+ // RD_KAFKA_RESP_ERR_NO_ERROR,
993
+ // "delete topic");
994
+
995
+ // /* Phase 2: poll several times. OP_CONSUMER_ERR surfaces as a
996
+ // * non-NULL return from consume_batch; count any such return as
997
+ // * an error (silent handling requires zero). */
998
+ // while (poll_cnt++ < 5) {
999
+ // rcvd = 0;
1000
+ // error = rd_kafka_share_poll(rkshare, 1000,
1001
+ // rkmessages,
1002
+ // &rcvd);
1003
+ // if (error) {
1004
+ // error_cnt++;
1005
+ // rd_kafka_error_destroy(error);
1006
+ // continue;
1007
+ // }
1008
+ // for (j = 0; j < rcvd; j++)
1009
+ // rd_kafka_message_destroy(rkmessages[j]);
1010
+ // }
1011
+ // TEST_ASSERT(error_cnt == 0,
1012
+ // "expected 0 OP_CONSUMER_ERR after topic delete "
1013
+ // "(UNKNOWN_TOPIC_OR_PARTITION must be silently handled), "
1014
+ // "got %d",
1015
+ // error_cnt);
1016
+
1017
+ // /* Verify the error path fired. The background "keep fetching" loop
1018
+ // * may send additional empty ShareFetch requests after the partition
1019
+ // * leaves the session, so only a lower bound is meaningful here. */
1020
+ // share_fetch_cnt = test_mock_get_matching_request_cnt(
1021
+ // ctx.mcluster, is_share_fetch_request, NULL);
1022
+ // TEST_SAY("ShareFetch requests after topic delete: %" PRIusz "\n",
1023
+ // share_fetch_cnt);
1024
+ // TEST_ASSERT(share_fetch_cnt >= 1,
1025
+ // "expected >= 1 ShareFetch after topic delete "
1026
+ // "(error path must have fired), got %" PRIusz,
1027
+ // share_fetch_cnt);
1028
+
1029
+ // /* Verify a metadata refresh was triggered by the error. */
1030
+ // metadata_cnt = test_mock_get_matching_request_cnt(
1031
+ // ctx.mcluster, is_metadata_request, NULL);
1032
+ // TEST_SAY("Metadata requests after topic delete: %" PRIusz "\n",
1033
+ // metadata_cnt);
1034
+ // TEST_ASSERT(metadata_cnt >= 1,
1035
+ // "expected >= 1 Metadata request after topic delete "
1036
+ // "(metadata refresh must fire), got %" PRIusz,
1037
+ // metadata_cnt);
1038
+
1039
+ // rd_kafka_mock_stop_request_tracking(ctx.mcluster);
1040
+
1041
+ // test_share_consumer_close(rkshare);
1042
+ // test_share_destroy(rkshare);
1043
+ // test_ctx_destroy(&ctx);
1044
+
1045
+ // SUB_TEST_PASS();
1046
+ // }
1047
+
1048
+ /* ===================================================================
1049
+ * Regression test: records survive a leader-less partition transit.
1050
+ * -------------------------------------------------------------------
1051
+ * Trigger: a partition becomes leader-less between two leader
1052
+ * changes (leader -> -1 -> new_leader). The leader-less period
1053
+ * makes the client briefly delegate the toppar to the :0/internal
1054
+ * pseudo-broker. Previously, that pseudo-broker thread ran the
1055
+ * regular-consumer fetch_decide path on the share-consumer rktp,
1056
+ * promoting rktp_fetch_version above 0. Subsequent share-fetch
1057
+ * parsing then stamped every parsed message rko with that
1058
+ * promoted version, after which the version-outdated filter
1059
+ * dropped them silently (because rktp_version had been bumped by
1060
+ * the initial fetch_start barrier).
1061
+ *
1062
+ * Repro shape:
1063
+ * 1. leader=1; produce phase 1; consume phase 1.
1064
+ * 2. set leader=-1; consume again briefly so the consumer
1065
+ * processes the metadata change and migrates the toppar to
1066
+ * :0/internal. This is the step that historically promoted
1067
+ * rktp_fetch_version on the share-consumer rktp.
1068
+ * 3. wait 3 s for the bad state to settle.
1069
+ * 4. set leader=2 but DO NOT consume yet — let the migration
1070
+ * to broker 2 happen quietly.
1071
+ * 5. produce phase 2 on the new leader.
1072
+ * 6. consume phase 2 and verify every produced record reaches
1073
+ * the application.
1074
+ *
1075
+ * Pre-fix: phase 2 consumed < phase 2 produced (parsed records
1076
+ * dropped by the version filter). Post-fix: phase 2 fully drained.
1077
+ * =================================================================== */
1078
+ static void
1079
+ do_test_records_survive_leaderless_transit(rd_bool_t explicit_mode) {
1080
+ test_ctx_t ctx;
1081
+ rd_kafka_conf_t *conf;
1082
+ rd_kafka_share_t *rkshare;
1083
+ rd_kafka_messages_t *drain_batch = NULL;
1084
+ size_t drain_rcvd = 0;
1085
+ char *topic;
1086
+ const int part_cnt = 1;
1087
+ const char *group = "sg-0183-leaderless-transit";
1088
+ int phase1_total = 0;
1089
+ int phase2_total = 0;
1090
+ int phase1_consumed = 0;
1091
+ int phase2_consumed = 0;
1092
+ int i;
1093
+
1094
+ SUB_TEST_QUICK("%s", explicit_mode ? "explicit" : "implicit");
1095
+
1096
+ topic = rd_strdup(test_mk_topic_name("0183-leaderless-transit", 1));
1097
+
1098
+ ctx = test_ctx_new(3);
1099
+
1100
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, part_cnt,
1101
+ 1) == RD_KAFKA_RESP_ERR_NO_ERROR,
1102
+ "create topic");
1103
+
1104
+ /* All partitions start on broker 1. */
1105
+ for (i = 0; i < part_cnt; i++)
1106
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(ctx.mcluster,
1107
+ topic, i, 1) ==
1108
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1109
+ "set initial leader [%d] -> 1", i);
1110
+
1111
+ srand(42);
1112
+ for (i = 0; i < part_cnt; i++)
1113
+ phase1_total +=
1114
+ mock_produce(ctx.producer, topic, i, 20 + (rand() % 11));
1115
+
1116
+ test_conf_init(&conf, NULL, 0);
1117
+ test_conf_set(conf, "bootstrap.servers", ctx.bootstraps);
1118
+ test_conf_set(conf, "group.id", group);
1119
+ test_conf_set(conf, "share.acknowledgement.mode",
1120
+ explicit_mode ? "explicit" : "implicit");
1121
+ /* Short refresh interval so leader-change notifications
1122
+ * land quickly. */
1123
+ test_conf_set(conf, "topic.metadata.refresh.interval.ms", "2000");
1124
+ rkshare = rd_kafka_share_consumer_new(conf, NULL, 0);
1125
+ TEST_ASSERT(rkshare != NULL, "create share consumer");
1126
+ subscribe_one(rkshare, topic);
1127
+
1128
+ /* Phase 1: consume initial batch from broker 1. This warms
1129
+ * up the consumer's view of leader=1 for every partition. */
1130
+ phase1_consumed = consume_phase(rkshare, explicit_mode, rd_true,
1131
+ phase1_total, 0, "Phase 1");
1132
+ TEST_ASSERT(phase1_consumed == phase1_total,
1133
+ "Phase 1: expected %d, got %d", phase1_total,
1134
+ phase1_consumed);
1135
+
1136
+ /* First leader change: every partition becomes leader-less.
1137
+ * The next consume call drives the share-fetch loop, which
1138
+ * will hit broker 1, get NOT_LEADER_OR_FOLLOWER, refresh
1139
+ * metadata, see leader_id=-1, and delegate the toppar to the
1140
+ * :0/internal pseudo-broker — the exact bug-trigger. */
1141
+ for (i = 0; i < part_cnt; i++)
1142
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(ctx.mcluster,
1143
+ topic, i, -1) ==
1144
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1145
+ "set leader [%d] -> -1 (leader-less)", i);
1146
+
1147
+ /* Mid consume_batch: drive the internal fetch cycle so the
1148
+ * consumer hits broker 1 with SHAREFETCH, gets
1149
+ * NOT_LEADER_OR_FOLLOWER, refreshes metadata, sees
1150
+ * leader_id=-1, and delegates the rktp to the :0/internal
1151
+ * pseudo-broker. No records expected (leader-less). */
1152
+ TEST_ASSERT(!rd_kafka_share_poll(rkshare, 500, &drain_batch),
1153
+ "mid share_poll unexpected err");
1154
+ drain_rcvd = rd_kafka_messages_count(drain_batch);
1155
+ TEST_ASSERT(drain_rcvd == 0,
1156
+ "mid share_poll expected 0 records during the "
1157
+ "leader-less window, got %" PRIusz,
1158
+ drain_rcvd);
1159
+ rd_kafka_messages_destroy(drain_batch);
1160
+ drain_batch = NULL;
1161
+
1162
+ /* Settle: pre-fix, :0/internal's broker_internal_serve loop
1163
+ * runs consumer_toppars_serve here, which calls fetch_decide
1164
+ * on the share-consumer rktp and promotes
1165
+ * rktp_fetch_version. After this point, any parsed
1166
+ * share-fetch message gets stamped with the promoted
1167
+ * version and dropped by the version-outdated filter. */
1168
+ rd_usleep(3000 * 1000, NULL);
1169
+
1170
+ /* Second leader change: leader=2. The fast-query timer
1171
+ * armed by the NOT_LEADER response is still active and will
1172
+ * fire within ~1s (capped by retry_backoff_max_ms), find
1173
+ * leader=2, and clear LEADER_UNAVAIL. No consume here — let
1174
+ * the metadata refresh happen on its own. */
1175
+ for (i = 0; i < part_cnt; i++)
1176
+ TEST_ASSERT(rd_kafka_mock_partition_set_leader(ctx.mcluster,
1177
+ topic, i, 2) ==
1178
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1179
+ "set leader [%d] -> 2", i);
1180
+
1181
+ /* Produce Phase 2 records on the new leader. */
1182
+ for (i = 0; i < part_cnt; i++)
1183
+ phase2_total +=
1184
+ mock_produce(ctx.producer, topic, i, 20 + (rand() % 11));
1185
+ rd_kafka_flush(ctx.producer, 5000);
1186
+
1187
+ /* Phase 2: every record produced post-transit must reach the
1188
+ * application. Pre-fix this assertion failed because parsed
1189
+ * SHAREFETCH messages were stamped with the promoted
1190
+ * fetch_version and then dropped by the version-outdated
1191
+ * filter against the bumped rktp_version. */
1192
+ phase2_consumed = consume_phase(rkshare, explicit_mode, rd_true,
1193
+ phase2_total, 1500, "Phase 2");
1194
+ TEST_ASSERT(phase2_consumed == phase2_total,
1195
+ "Phase 2: expected %d records after leader-less "
1196
+ "transit + new leader, got %d. If pre-fix: parsed "
1197
+ "records were silently dropped by the "
1198
+ "rktp_version filter on the share-consumer path.",
1199
+ phase2_total, phase2_consumed);
1200
+
1201
+ test_share_consumer_close(rkshare);
1202
+ test_share_destroy(rkshare);
1203
+ test_ctx_destroy(&ctx);
1204
+ rd_free(topic);
1205
+
1206
+ SUB_TEST_PASS();
1207
+ }
1208
+
1209
+
1210
+ int main_0183_share_consumer_leader_change_mock(int argc, char **argv) {
1211
+ TEST_SKIP_MOCK_CLUSTER(0);
1212
+ test_timeout_set(120);
1213
+
1214
+ test_shareack_leader_change_reduces_rpcs();
1215
+ test_partition_not_leader_or_follower_silent();
1216
+ /* test_partition_unknown_topic_silent(); */
1217
+
1218
+ do_test_records_survive_leaderless_transit(rd_false);
1219
+ do_test_records_survive_leaderless_transit(rd_true);
1220
+
1221
+ do_test_leader_change_consume_recovery(rd_false, rd_false, rd_false,
1222
+ "implicit-no-refresh");
1223
+ do_test_leader_change_consume_recovery(rd_false, rd_false, rd_true,
1224
+ "implicit-wait-refresh");
1225
+ do_test_leader_change_consume_recovery(rd_true, rd_false, rd_false,
1226
+ "explicit-async-no-refresh");
1227
+ do_test_leader_change_consume_recovery(rd_true, rd_false, rd_true,
1228
+ "explicit-async-wait-refresh");
1229
+ do_test_leader_change_consume_recovery(rd_true, rd_true, rd_false,
1230
+ "explicit-sync-no-refresh");
1231
+ do_test_leader_change_consume_recovery(rd_true, rd_true, rd_true,
1232
+ "explicit-sync-wait-refresh");
1233
+ return 0;
1234
+ }