@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,1434 @@
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
+
32
+ /**
33
+ * @name Share Consumer Concurrency and Stress Tests
34
+ *
35
+ * Tests share consumer behavior under concurrent producer/consumer scenarios.
36
+ * Each test uses a config-based structure. Producers and consumers each run
37
+ * in their own dedicated threads — there is no main-thread round-robin
38
+ * polling. The main test thread orchestrates start/stop and verifies
39
+ * end-state counters. The per-record invariant validated is first-delivery
40
+ * count (each produced record is first-delivered exactly once; redeliveries
41
+ * are counted separately).
42
+ */
43
+
44
+ #define MAX_TOPICS 16
45
+ #define MAX_PARTITIONS 16
46
+ #define MAX_CONSUMERS 16
47
+ #define MAX_PRODUCERS 10
48
+ #define MAX_CONSUMER_POOL 32
49
+ #define BATCH_SIZE 10000
50
+
51
+ /* Save test_curr for threads (test_curr is TLS) */
52
+ static struct test *this_test;
53
+
54
+ /***************************************************************************
55
+ * Test Configuration and State
56
+ ***************************************************************************/
57
+
58
+ /**
59
+ * @brief Configuration for a concurrent share consumer test
60
+ */
61
+ typedef struct {
62
+ int consumer_cnt; /**< Number of consumers to create */
63
+ int producer_cnt; /**< Number of producer threads */
64
+ int topic_cnt; /**< Number of topics */
65
+ int partitions[MAX_TOPICS]; /**< Partitions per topic */
66
+ int msgs_per_partition; /**< Messages to produce per partition */
67
+ const char *group_name; /**< Share group name */
68
+ const char *test_name; /**< Test description */
69
+ int max_attempts; /**< Max poll attempts (0 = default) */
70
+ int consumer_delay_ms; /**< Delay between consumer polls */
71
+ int producer_delay_ms; /**< Delay between produces */
72
+ rd_bool_t explicit_ack; /**< Use explicit acknowledgement */
73
+ rd_bool_t staggered_start; /**< Start producers/consumers at
74
+ different times */
75
+ } concurrent_test_config_t;
76
+
77
+ /**
78
+ * @brief Shared state for concurrent test threads
79
+ */
80
+ typedef struct {
81
+ mtx_t lock; /**< Mutex for state access */
82
+ int total_produced; /**< Total messages produced */
83
+ int total_consumed; /**< Total messages consumed
84
+ * (includes redeliveries) */
85
+ int total_first_delivery; /**< Messages with delivery_count == 1 */
86
+ int total_duplicates; /**< Messages with delivery_count > 1 */
87
+ int expected_total; /**< Expected total messages */
88
+ rd_bool_t producers_done; /**< All producers finished */
89
+ int producers_remaining; /**< Producer threads still running */
90
+ rd_bool_t test_failed; /**< Test failure flag */
91
+ char topics[MAX_TOPICS][128]; /**< Topic names */
92
+ int topic_cnt; /**< Number of topics */
93
+ const char *group_name; /**< Share group name */
94
+ rd_bool_t explicit_ack; /**< Use explicit acknowledgement */
95
+ } concurrent_test_state_t;
96
+
97
+ /**
98
+ * @brief Arguments for producer thread
99
+ */
100
+ typedef struct {
101
+ concurrent_test_state_t *state;
102
+ int producer_id;
103
+ int msgs_to_produce;
104
+ int delay_ms;
105
+ int partitions[MAX_TOPICS];
106
+ } producer_thread_args_t;
107
+
108
+ /**
109
+ * @brief Per-consumer-thread context.
110
+ *
111
+ * One share consumer per thread; main thread sets @c run to rd_false
112
+ * (under state->lock) to ask the consumer to wind down. The consumer
113
+ * thread sets @c done = rd_true under the same lock right before it
114
+ * returns from consumer_thread_func, so the main thread can poll for a
115
+ * clean exit instead of blocking forever in thrd_join when a consumer
116
+ * is wedged inside librdkafka.
117
+ */
118
+ typedef struct {
119
+ concurrent_test_state_t *state;
120
+ int consumer_id;
121
+ rd_bool_t run;
122
+ rd_bool_t done; /**< Set true just before consumer thread exits */
123
+ int poll_delay_ms; /**< Sleep between polls (from config) */
124
+ } consumer_thread_args_t;
125
+
126
+ /***************************************************************************
127
+ * Thread Functions
128
+ ***************************************************************************/
129
+
130
+ /**
131
+ * @brief Producer thread function
132
+ *
133
+ * Produces messages to all topics/partitions in round-robin fashion.
134
+ */
135
+ static int producer_thread_func(void *arg) {
136
+ producer_thread_args_t *args = (producer_thread_args_t *)arg;
137
+ concurrent_test_state_t *state = args->state;
138
+ rd_kafka_t *producer;
139
+ rd_kafka_conf_t *conf;
140
+ int produced = 0;
141
+ int t, p;
142
+ rd_kafka_resp_err_t err;
143
+ char value[64];
144
+
145
+ /* Restore the TLS test_curr pointer for this thread. The
146
+ * exp_dr_status / ignore_dr_err fields on the struct itself are
147
+ * set once by the main thread before any worker spawns
148
+ * (see run_concurrent_test / do_test_chaos_consumer_lifecycle)
149
+ * — touching them here would race against every other producer
150
+ * thread that aliases the same global tests[] entry. */
151
+ test_curr = this_test;
152
+
153
+ /* Enable idempotent producer so retries do not result in duplicate
154
+ * broker-side writes — without this, transient broker/network jitter
155
+ * under the heavy concurrent load these tests generate (e.g.
156
+ * test_max_concurrent with 10 producers × 5000 msgs) causes the
157
+ * broker to store extra records that the share consumer then
158
+ * receives as new offsets with delivery_count=1, inflating the
159
+ * consumed count above expected_total. */
160
+ test_conf_init(&conf, NULL, 0);
161
+ test_conf_set(conf, "enable.idempotence", "true");
162
+ rd_kafka_conf_set_dr_msg_cb(conf, test_dr_msg_cb);
163
+ producer = test_create_handle(RD_KAFKA_PRODUCER, conf);
164
+
165
+ TEST_SAY("Producer %d: starting, will produce %d messages\n",
166
+ args->producer_id, args->msgs_to_produce);
167
+
168
+ while (produced < args->msgs_to_produce) {
169
+ for (t = 0;
170
+ t < state->topic_cnt && produced < args->msgs_to_produce;
171
+ t++) {
172
+ for (p = 0; p < args->partitions[t] &&
173
+ produced < args->msgs_to_produce;
174
+ p++) {
175
+ snprintf(value, sizeof(value), "prod%d-msg%d",
176
+ args->producer_id, produced);
177
+
178
+ err = rd_kafka_producev(
179
+ producer,
180
+ RD_KAFKA_V_TOPIC(state->topics[t]),
181
+ RD_KAFKA_V_PARTITION(p),
182
+ RD_KAFKA_V_VALUE(value, strlen(value)),
183
+ RD_KAFKA_V_MSGFLAGS(RD_KAFKA_MSG_F_COPY),
184
+ RD_KAFKA_V_END);
185
+
186
+ if (err) {
187
+ TEST_SAY(
188
+ "Producer %d: produce failed: %s\n",
189
+ args->producer_id,
190
+ rd_kafka_err2str(err));
191
+ mtx_lock(&state->lock);
192
+ state->test_failed = rd_true;
193
+ mtx_unlock(&state->lock);
194
+ goto done;
195
+ }
196
+
197
+ produced++;
198
+
199
+ if (args->delay_ms > 0 && produced % 100 == 0)
200
+ rd_usleep(args->delay_ms * 1000, NULL);
201
+ }
202
+ }
203
+
204
+ rd_kafka_flush(producer, 1000);
205
+ }
206
+
207
+ rd_kafka_flush(producer, 10000);
208
+
209
+ TEST_SAY("Producer %d: finished, produced %d messages\n",
210
+ args->producer_id, produced);
211
+
212
+ done:
213
+ mtx_lock(&state->lock);
214
+ state->total_produced += produced;
215
+ if (--state->producers_remaining == 0)
216
+ state->producers_done = rd_true;
217
+ mtx_unlock(&state->lock);
218
+
219
+ rd_kafka_destroy(producer);
220
+ free(args);
221
+
222
+ return thrd_success;
223
+ }
224
+
225
+ /**
226
+ * @brief Per-thread share consumer poll loop.
227
+ *
228
+ * One share consumer per thread. Creates the consumer, subscribes to all
229
+ * configured topics, then polls until @c args->run is cleared by the main
230
+ * thread. Records first-time deliveries vs redeliveries via
231
+ * rd_kafka_message_delivery_count() into shared counters.
232
+ */
233
+ static int consumer_thread_func(void *arg) {
234
+ consumer_thread_args_t *args = (consumer_thread_args_t *)arg;
235
+ concurrent_test_state_t *state = args->state;
236
+ rd_kafka_share_t *consumer;
237
+ rd_kafka_topic_partition_list_t *subs;
238
+ rd_kafka_messages_t *batch = NULL;
239
+ rd_kafka_error_t *err;
240
+ int t;
241
+ size_t m;
242
+ size_t rcvd;
243
+ rd_bool_t keep_running;
244
+
245
+ test_curr = this_test;
246
+
247
+ consumer = test_create_share_consumer(
248
+ state->group_name, state->explicit_ack ? "explicit" : NULL);
249
+
250
+ subs = rd_kafka_topic_partition_list_new(state->topic_cnt);
251
+ for (t = 0; t < state->topic_cnt; t++) {
252
+ rd_kafka_topic_partition_list_add(subs, state->topics[t],
253
+ RD_KAFKA_PARTITION_UA);
254
+ }
255
+ rd_kafka_share_subscribe(consumer, subs);
256
+ rd_kafka_topic_partition_list_destroy(subs);
257
+
258
+ TEST_SAY("Consumer thread %d: subscribed\n", args->consumer_id);
259
+
260
+ while (1) {
261
+ int acked_in_batch = 0;
262
+
263
+ mtx_lock(&state->lock);
264
+ keep_running = args->run;
265
+ mtx_unlock(&state->lock);
266
+ if (!keep_running)
267
+ break;
268
+
269
+ err = rd_kafka_share_poll(consumer, 500, &batch);
270
+ if (err) {
271
+ TEST_SAY("Consumer thread %d: share_poll error: %s\n",
272
+ args->consumer_id, rd_kafka_error_string(err));
273
+ rd_kafka_error_destroy(err);
274
+ rd_kafka_messages_destroy(batch);
275
+ batch = NULL;
276
+ continue;
277
+ }
278
+ rcvd = rd_kafka_messages_count(batch);
279
+
280
+ /* Per-record atomic step:
281
+ * ACK → process (count into shared state under lock) →
282
+ * destroy. ack + process happen in the same iteration
283
+ * so there is no window where the broker can see an
284
+ * ACK for a record that this application has not also
285
+ * recorded as consumed in total_first_delivery /
286
+ * total_duplicates. The per-batch commit_sync below
287
+ * flushes the acks to the broker. */
288
+ for (m = 0; m < rcvd; m++) {
289
+ rd_kafka_message_t *msg =
290
+ rd_kafka_messages_get(batch, m);
291
+
292
+ if (!msg)
293
+ continue;
294
+
295
+ if (msg->err) {
296
+ const char *msg_topic =
297
+ msg->rkt ? rd_kafka_topic_name(msg->rkt)
298
+ : "(no-topic)";
299
+ TEST_SAY(
300
+ "Consumer thread %d: SKIPPING record "
301
+ "%s[%" PRId32 "] off=%" PRId64
302
+ " because msg->err=%s\n",
303
+ args->consumer_id, msg_topic,
304
+ msg->partition, msg->offset,
305
+ rd_kafka_err2name(msg->err));
306
+ continue;
307
+ }
308
+
309
+ if (state->explicit_ack) {
310
+ rd_kafka_resp_err_t ack_err =
311
+ rd_kafka_share_acknowledge_type(
312
+ consumer, msg,
313
+ RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT);
314
+ if (ack_err != RD_KAFKA_RESP_ERR_NO_ERROR) {
315
+ TEST_SAY(
316
+ "Consumer thread %d: "
317
+ "acknowledge offset %" PRId64
318
+ " failed: %s — skipping count "
319
+ "for this record\n",
320
+ args->consumer_id, msg->offset,
321
+ rd_kafka_err2name(ack_err));
322
+ continue;
323
+ }
324
+ acked_in_batch++;
325
+ }
326
+
327
+ /* Process the record at the same instant we
328
+ * acknowledged it. */
329
+ {
330
+ int16_t dc =
331
+ rd_kafka_message_delivery_count(msg);
332
+ mtx_lock(&state->lock);
333
+ if (dc > 1)
334
+ state->total_duplicates++;
335
+ else
336
+ state->total_first_delivery++;
337
+ state->total_consumed++;
338
+ mtx_unlock(&state->lock);
339
+ }
340
+ }
341
+
342
+ rd_kafka_messages_destroy(batch);
343
+ batch = NULL;
344
+
345
+ /* Flush the per-record acks to the broker before the
346
+ * next consume_batch or stop check. Per-partition
347
+ * results are inspected for errors. */
348
+ if (state->explicit_ack && acked_in_batch > 0) {
349
+ rd_kafka_topic_partition_list_t *cs_result = NULL;
350
+ rd_kafka_error_t *commit_err =
351
+ rd_kafka_share_commit_sync(consumer, 5000,
352
+ &cs_result);
353
+ if (commit_err) {
354
+ TEST_SAY(
355
+ "Consumer thread %d: commit_sync failed "
356
+ "(acked_in_batch=%d): %s\n",
357
+ args->consumer_id, acked_in_batch,
358
+ rd_kafka_error_string(commit_err));
359
+ rd_kafka_error_destroy(commit_err);
360
+ } else if (cs_result) {
361
+ int i;
362
+ for (i = 0; i < cs_result->cnt; i++) {
363
+ if (cs_result->elems[i].err !=
364
+ RD_KAFKA_RESP_ERR_NO_ERROR) {
365
+ TEST_SAY(
366
+ "Consumer thread %d: "
367
+ "commit_sync per-part "
368
+ "err %s [%" PRId32
369
+ "]: %s\n",
370
+ args->consumer_id,
371
+ cs_result->elems[i].topic,
372
+ cs_result->elems[i]
373
+ .partition,
374
+ rd_kafka_err2name(
375
+ cs_result->elems[i]
376
+ .err));
377
+ }
378
+ }
379
+ }
380
+ if (cs_result)
381
+ rd_kafka_topic_partition_list_destroy(
382
+ cs_result);
383
+ }
384
+
385
+ if (args->poll_delay_ms > 0)
386
+ rd_usleep(args->poll_delay_ms * 1000, NULL);
387
+ }
388
+
389
+ TEST_SAY("Consumer thread %d: closing\n", args->consumer_id);
390
+ test_share_consumer_close(consumer);
391
+ test_share_destroy(consumer);
392
+
393
+ /* Mark this thread as cleanly exited so the main thread's bounded
394
+ * wait can detect it without blocking in thrd_join. */
395
+ mtx_lock(&state->lock);
396
+ args->done = rd_true;
397
+ mtx_unlock(&state->lock);
398
+
399
+ return thrd_success;
400
+ }
401
+
402
+ /***************************************************************************
403
+ * Test Runner — fully threaded
404
+ *
405
+ * Every share consumer and every producer runs in its own dedicated
406
+ * thread. The main thread only orchestrates start/stop and verifies
407
+ * final counters. No round-robin main-thread polling.
408
+ ***************************************************************************/
409
+
410
+ /**
411
+ * @brief Run a concurrent share consumer test with every consumer in its
412
+ * own thread.
413
+ *
414
+ * @c config->max_attempts is interpreted as an upper bound on the total
415
+ * wait-for-completion time, measured in 500ms ticks (so max_attempts=100
416
+ * gives a 50 s bound). When unset (0), the default is 240 ticks = 120 s.
417
+ */
418
+ static void run_concurrent_test(const concurrent_test_config_t *config) {
419
+ concurrent_test_state_t state = {0};
420
+ thrd_t producer_threads[MAX_PRODUCERS];
421
+ thrd_t consumer_threads[MAX_CONSUMERS];
422
+ consumer_thread_args_t consumer_args[MAX_CONSUMERS];
423
+ rd_kafka_share_t *dummy_consumer;
424
+ int t, c, p;
425
+ int total_partitions = 0;
426
+ int msgs_per_producer;
427
+ int max_wait_ticks;
428
+ int wait_ticks;
429
+ int final_produced;
430
+ int final_consumed;
431
+ int final_first_delivery;
432
+ int final_duplicates;
433
+ rd_bool_t final_failed;
434
+ char unique_suffix[64];
435
+ char unique_group[128];
436
+ char unique_test_name[256];
437
+
438
+ TEST_ASSERT(config->consumer_cnt <= MAX_CONSUMERS,
439
+ "consumer_cnt %d exceeds MAX_CONSUMERS %d",
440
+ config->consumer_cnt, MAX_CONSUMERS);
441
+
442
+ /* Generate a per-invocation unique suffix and append it to both
443
+ * the group name and the displayed test name. Avoids collisions
444
+ * across re-runs / parallel runs that share the same broker. */
445
+ rd_snprintf(unique_suffix, sizeof(unique_suffix), "rnd%" PRIx64,
446
+ test_id_generate());
447
+ rd_snprintf(unique_group, sizeof(unique_group), "%s-%s",
448
+ config->group_name, unique_suffix);
449
+ rd_snprintf(unique_test_name, sizeof(unique_test_name), "%s [%s]",
450
+ config->test_name, unique_suffix);
451
+
452
+ TEST_SAY("\n");
453
+ TEST_SAY(
454
+ "============================================================\n");
455
+ TEST_SAY("=== %s ===\n", unique_test_name);
456
+ TEST_SAY(
457
+ "============================================================\n");
458
+ TEST_SAY(
459
+ "Threaded: %d consumer threads, %d producer threads, %d topics\n",
460
+ config->consumer_cnt, config->producer_cnt, config->topic_cnt);
461
+
462
+ /* Save test context for threads (test_curr is TLS) */
463
+ this_test = test_curr;
464
+
465
+ /* Set the DR-callback expectations on the shared test struct
466
+ * ONCE on the main thread, before spawning any worker threads.
467
+ * test_curr is a TLS pointer but the struct it points at lives
468
+ * in the global tests[] array, so writing these fields from
469
+ * each producer thread (as it used to) is a benign-but-noisy
470
+ * data race that TSAN flags. */
471
+ test_curr->exp_dr_status = (rd_kafka_msg_status_t)-1;
472
+ test_curr->ignore_dr_err = rd_true;
473
+
474
+ /* Initialize state */
475
+ mtx_init(&state.lock, mtx_plain);
476
+ state.topic_cnt = config->topic_cnt;
477
+ state.group_name = unique_group;
478
+ state.explicit_ack = config->explicit_ack;
479
+ state.producers_remaining = config->producer_cnt;
480
+
481
+ for (t = 0; t < config->topic_cnt; t++)
482
+ total_partitions += config->partitions[t];
483
+ state.expected_total = total_partitions * config->msgs_per_partition;
484
+ TEST_SAY(
485
+ "Total partitions: %d, msgs/partition: %d, expected total: %d\n",
486
+ total_partitions, config->msgs_per_partition, state.expected_total);
487
+
488
+ /* Create topics */
489
+ for (t = 0; t < config->topic_cnt; t++) {
490
+ rd_snprintf(state.topics[t], sizeof(state.topics[t]), "%s",
491
+ test_mk_topic_name("0174-concurrent", 1));
492
+ test_create_topic_wait_exists(NULL, state.topics[t],
493
+ config->partitions[t], -1,
494
+ 60 * 1000);
495
+ TEST_SAY("Created topic %s with %d partitions\n",
496
+ state.topics[t], config->partitions[t]);
497
+ }
498
+
499
+ /* Apply broker-side share group config (auto.offset.reset=earliest)
500
+ * via a throwaway consumer registration so the alter sticks before
501
+ * any worker subscribes. */
502
+ dummy_consumer = test_create_share_consumer(unique_group, NULL);
503
+ test_share_set_auto_offset_reset(unique_group, "earliest");
504
+ test_share_consumer_close(dummy_consumer);
505
+ test_share_destroy(dummy_consumer);
506
+
507
+ /* Start producer threads */
508
+ msgs_per_producer = state.expected_total / config->producer_cnt;
509
+ for (p = 0; p < config->producer_cnt; p++) {
510
+ producer_thread_args_t *args = rd_calloc(1, sizeof(*args));
511
+ args->state = &state;
512
+ args->producer_id = p;
513
+ args->msgs_to_produce = msgs_per_producer;
514
+ if (p == config->producer_cnt - 1)
515
+ args->msgs_to_produce +=
516
+ state.expected_total % config->producer_cnt;
517
+ args->delay_ms = config->producer_delay_ms;
518
+ for (t = 0; t < config->topic_cnt; t++)
519
+ args->partitions[t] = config->partitions[t];
520
+
521
+ if (thrd_create(&producer_threads[p], producer_thread_func,
522
+ args) != thrd_success) {
523
+ TEST_FAIL("Failed to create producer thread %d", p);
524
+ }
525
+ }
526
+
527
+ /* Optional staggered start: give producers a head start before
528
+ * spinning up consumer threads. */
529
+ if (config->staggered_start) {
530
+ TEST_SAY("Staggered start: producers run alone for 2 s\n");
531
+ rd_sleep(2);
532
+ }
533
+
534
+ /* Start consumer threads — one per consumer */
535
+ for (c = 0; c < config->consumer_cnt; c++) {
536
+ consumer_args[c].state = &state;
537
+ consumer_args[c].consumer_id = c;
538
+ consumer_args[c].run = rd_true;
539
+ consumer_args[c].done = rd_false;
540
+ consumer_args[c].poll_delay_ms = config->consumer_delay_ms;
541
+
542
+ if (thrd_create(&consumer_threads[c], consumer_thread_func,
543
+ &consumer_args[c]) != thrd_success) {
544
+ TEST_FAIL("Failed to create consumer thread %d", c);
545
+ }
546
+ }
547
+
548
+ /* Wait for all expected first deliveries, bounded by max_attempts
549
+ * ticks of 500ms each (default 240 ticks = 120 s). */
550
+ max_wait_ticks = config->max_attempts > 0 ? config->max_attempts : 240;
551
+ wait_ticks = max_wait_ticks;
552
+
553
+ while (wait_ticks-- > 0) {
554
+ int first_seen;
555
+ int consumed_so_far;
556
+ int dups;
557
+ rd_bool_t producers_done;
558
+
559
+ mtx_lock(&state.lock);
560
+ first_seen = state.total_first_delivery;
561
+ consumed_so_far = state.total_consumed;
562
+ dups = state.total_duplicates;
563
+ producers_done = state.producers_done;
564
+ mtx_unlock(&state.lock);
565
+
566
+ if (first_seen >= state.expected_total)
567
+ break;
568
+
569
+ if (wait_ticks % 20 == 0)
570
+ TEST_SAY(
571
+ "Progress: consumed %d/%d (first=%d, dup=%d, "
572
+ "producers_done=%d)\n",
573
+ consumed_so_far, state.expected_total, first_seen,
574
+ dups, (int)producers_done);
575
+
576
+ rd_usleep(500 * 1000, NULL);
577
+ }
578
+
579
+ /* Join producers even if drain timed out. */
580
+ for (p = 0; p < config->producer_cnt; p++)
581
+ thrd_join(producer_threads[p], NULL);
582
+
583
+ /* Tell consumer threads to stop and join. */
584
+ mtx_lock(&state.lock);
585
+ for (c = 0; c < config->consumer_cnt; c++)
586
+ consumer_args[c].run = rd_false;
587
+ mtx_unlock(&state.lock);
588
+
589
+ for (c = 0; c < config->consumer_cnt; c++)
590
+ thrd_join(consumer_threads[c], NULL);
591
+
592
+ /* Snapshot results under lock */
593
+ mtx_lock(&state.lock);
594
+ final_produced = state.total_produced;
595
+ final_consumed = state.total_consumed;
596
+ final_first_delivery = state.total_first_delivery;
597
+ final_duplicates = state.total_duplicates;
598
+ final_failed = state.test_failed;
599
+ mtx_unlock(&state.lock);
600
+
601
+ TEST_SAY(
602
+ "Final: produced=%d, consumed=%d (first=%d, dup=%d), "
603
+ "expected=%d\n",
604
+ final_produced, final_consumed, final_first_delivery,
605
+ final_duplicates, state.expected_total);
606
+
607
+ TEST_ASSERT(final_produced == state.expected_total,
608
+ "Expected to produce %d, actually produced %d",
609
+ state.expected_total, final_produced);
610
+
611
+ /* A record can be redelivered if the broker-side acquisition lock
612
+ * expires before an ACCEPT arrives. We distinguish first
613
+ * deliveries (delivery_count == 1) from redeliveries via
614
+ * rd_kafka_message_delivery_count() and assert strict equality on
615
+ * first deliveries — every produced record must have been
616
+ * delivered at least once. Duplicates are tracked separately so a
617
+ * regression in delivery semantics still shows up in the
618
+ * diagnostic output. */
619
+ TEST_ASSERT(final_first_delivery == state.expected_total,
620
+ "Expected %d first-time deliveries, got %d "
621
+ "(consumed=%d, duplicates=%d)",
622
+ state.expected_total, final_first_delivery, final_consumed,
623
+ final_duplicates);
624
+ TEST_ASSERT(!final_failed, "Producer thread reported failure");
625
+
626
+ TEST_SAY("SUCCESS: %s\n", unique_test_name);
627
+
628
+ mtx_destroy(&state.lock);
629
+ }
630
+
631
+ /***************************************************************************
632
+ * Test Cases - Basic Concurrency
633
+ ***************************************************************************/
634
+
635
+ /**
636
+ * @brief Single producer, single consumer, single topic
637
+ */
638
+ static void do_test_1p_1c_1t_1part(void) {
639
+ concurrent_test_config_t config = {
640
+ .consumer_cnt = 1,
641
+ .producer_cnt = 1,
642
+ .topic_cnt = 1,
643
+ .partitions = {1},
644
+ .msgs_per_partition = 5000,
645
+ .group_name = "share-conc-1p1c1t1p",
646
+ .test_name = "1 producer, 1 consumer, 1 topic, 1 partition"};
647
+
648
+ SUB_TEST();
649
+ run_concurrent_test(&config);
650
+
651
+ SUB_TEST_PASS();
652
+ }
653
+
654
+ /**
655
+ * @brief Single producer, multiple consumers, single topic
656
+ */
657
+ static void do_test_1p_4c_1t_4part(void) {
658
+ concurrent_test_config_t config = {
659
+ .consumer_cnt = 4,
660
+ .producer_cnt = 1,
661
+ .topic_cnt = 1,
662
+ .partitions = {4},
663
+ .msgs_per_partition = 5000,
664
+ .group_name = "share-conc-1p4c1t4p",
665
+ .test_name = "1 producer, 4 consumers, 1 topic, 4 partitions"};
666
+
667
+ SUB_TEST();
668
+ run_concurrent_test(&config);
669
+
670
+ SUB_TEST_PASS();
671
+ }
672
+
673
+ /**
674
+ * @brief Multiple producers, single consumer
675
+ */
676
+ static void do_test_4p_1c_1t_4part(void) {
677
+ concurrent_test_config_t config = {
678
+ .consumer_cnt = 1,
679
+ .producer_cnt = 4,
680
+ .topic_cnt = 1,
681
+ .partitions = {4},
682
+ .msgs_per_partition = 1250,
683
+ .group_name = "share-conc-4p1c1t4p",
684
+ .test_name = "4 producers, 1 consumer, 1 topic, 4 partitions"};
685
+
686
+ SUB_TEST();
687
+ run_concurrent_test(&config);
688
+
689
+ SUB_TEST_PASS();
690
+ }
691
+
692
+ /**
693
+ * @brief Multiple producers, multiple consumers, single topic
694
+ */
695
+ static void do_test_4p_4c_1t_4part(void) {
696
+ concurrent_test_config_t config = {
697
+ .consumer_cnt = 4,
698
+ .producer_cnt = 4,
699
+ .topic_cnt = 1,
700
+ .partitions = {4},
701
+ .msgs_per_partition = 5000,
702
+ .group_name = "share-conc-4p4c1t4p",
703
+ .test_name = "4 producers, 4 consumers, 1 topic, 4 partitions"};
704
+
705
+ SUB_TEST();
706
+ run_concurrent_test(&config);
707
+
708
+ SUB_TEST_PASS();
709
+ }
710
+
711
+ /***************************************************************************
712
+ * Test Cases - Multi-Topic Concurrency
713
+ ***************************************************************************/
714
+
715
+ /**
716
+ * @brief Multiple topics with concurrent access
717
+ */
718
+ static void do_test_2p_2c_3t_2part(void) {
719
+ concurrent_test_config_t config = {
720
+ .consumer_cnt = 2,
721
+ .producer_cnt = 2,
722
+ .topic_cnt = 3,
723
+ .partitions = {2, 2, 2},
724
+ .msgs_per_partition = 1666,
725
+ .group_name = "share-conc-2p2c3t2p",
726
+ .test_name =
727
+ "2 producers, 2 consumers, 3 topics, 2 partitions each"};
728
+
729
+ SUB_TEST();
730
+ run_concurrent_test(&config);
731
+
732
+ SUB_TEST_PASS();
733
+ }
734
+
735
+ /**
736
+ * @brief Many topics with single partition each
737
+ */
738
+ static void do_test_2p_2c_8t_1part(void) {
739
+ concurrent_test_config_t config = {
740
+ .consumer_cnt = 2,
741
+ .producer_cnt = 2,
742
+ .topic_cnt = 8,
743
+ .partitions = {1, 1, 1, 1, 1, 1, 1, 1},
744
+ .msgs_per_partition = 1250,
745
+ .group_name = "share-conc-2p2c8t1p",
746
+ .test_name = "2 producers, 2 consumers, 8 topics, 1 partition each",
747
+ .max_attempts = 150};
748
+
749
+ SUB_TEST();
750
+ run_concurrent_test(&config);
751
+
752
+ SUB_TEST_PASS();
753
+ }
754
+
755
+ /***************************************************************************
756
+ * Test Cases - High Contention
757
+ ***************************************************************************/
758
+
759
+ /**
760
+ * @brief Many consumers competing for single partition
761
+ */
762
+ static void do_test_1p_8c_1t_1part(void) {
763
+ concurrent_test_config_t config = {
764
+ .consumer_cnt = 8,
765
+ .producer_cnt = 1,
766
+ .topic_cnt = 1,
767
+ .partitions = {1},
768
+ .msgs_per_partition = 10000,
769
+ .group_name = "share-conc-1p8c1t1p",
770
+ .test_name =
771
+ "1 producer, 8 consumers, 1 partition (high contention)"};
772
+
773
+ SUB_TEST();
774
+ run_concurrent_test(&config);
775
+
776
+ SUB_TEST_PASS();
777
+ }
778
+
779
+ /**
780
+ * @brief More consumers than partitions
781
+ */
782
+ static void do_test_2p_6c_1t_2part(void) {
783
+ concurrent_test_config_t config = {
784
+ .consumer_cnt = 6,
785
+ .producer_cnt = 2,
786
+ .topic_cnt = 1,
787
+ .partitions = {2},
788
+ .msgs_per_partition = 15000,
789
+ .group_name = "share-conc-2p6c1t2p",
790
+ .test_name =
791
+ "2 producers, 6 consumers, 2 partitions (3:1 consumer ratio)"};
792
+
793
+ SUB_TEST();
794
+ run_concurrent_test(&config);
795
+
796
+ SUB_TEST_PASS();
797
+ }
798
+
799
+ /***************************************************************************
800
+ * Test Cases - Explicit Acknowledgement
801
+ ***************************************************************************/
802
+
803
+ /**
804
+ * @brief Concurrent with explicit acknowledgement
805
+ */
806
+ static void do_test_explicit_ack_4p_4c(void) {
807
+ concurrent_test_config_t config = {
808
+ .consumer_cnt = 4,
809
+ .producer_cnt = 4,
810
+ .topic_cnt = 2,
811
+ .partitions = {2, 2},
812
+ .msgs_per_partition = 5000,
813
+ .group_name = "share-conc-explicit-4p4c",
814
+ .test_name = "4 producers, 4 consumers, explicit ack",
815
+ .explicit_ack = rd_true};
816
+
817
+ SUB_TEST();
818
+ run_concurrent_test(&config);
819
+
820
+ SUB_TEST_PASS();
821
+ }
822
+
823
+ /***************************************************************************
824
+ * Test Cases - Staggered Start
825
+ ***************************************************************************/
826
+
827
+ /**
828
+ * @brief Consumers start before producers
829
+ */
830
+ static void do_test_staggered_start(void) {
831
+ concurrent_test_config_t config = {
832
+ .consumer_cnt = 2,
833
+ .producer_cnt = 2,
834
+ .topic_cnt = 1,
835
+ .partitions = {2},
836
+ .msgs_per_partition = 5000,
837
+ .group_name = "share-conc-staggered",
838
+ .test_name = "Staggered start: consumers before producers",
839
+ .staggered_start = rd_true};
840
+
841
+ SUB_TEST();
842
+ run_concurrent_test(&config);
843
+
844
+ SUB_TEST_PASS();
845
+ }
846
+
847
+ /***************************************************************************
848
+ * Test Cases - High Volume Stress
849
+ ***************************************************************************/
850
+
851
+ /**
852
+ * @brief High volume concurrent test
853
+ */
854
+ static void do_test_high_volume_20k(void) {
855
+ concurrent_test_config_t config = {
856
+ .consumer_cnt = 4,
857
+ .producer_cnt = 4,
858
+ .topic_cnt = 1,
859
+ .partitions = {4},
860
+ .msgs_per_partition = 5000,
861
+ .group_name = "share-conc-highvol-20k",
862
+ .test_name = "High volume: 4p x 4c x 20k messages",
863
+ .max_attempts = 150};
864
+
865
+ SUB_TEST();
866
+ run_concurrent_test(&config);
867
+
868
+ SUB_TEST_PASS();
869
+ }
870
+
871
+ /**
872
+ * @brief High volume with many partitions
873
+ */
874
+ static void do_test_high_volume_many_partitions(void) {
875
+ concurrent_test_config_t config = {
876
+ .consumer_cnt = 4,
877
+ .producer_cnt = 4,
878
+ .topic_cnt = 1,
879
+ .partitions = {8},
880
+ .msgs_per_partition = 2500,
881
+ .group_name = "share-conc-highvol-8p",
882
+ .test_name = "High volume: 8 partitions x 2.5k messages each",
883
+ .max_attempts = 150};
884
+
885
+ SUB_TEST();
886
+ run_concurrent_test(&config);
887
+
888
+ SUB_TEST_PASS();
889
+ }
890
+
891
+ /***************************************************************************
892
+ * Test Cases - Asymmetric Configurations
893
+ ***************************************************************************/
894
+
895
+ /**
896
+ * @brief Many producers, few consumers
897
+ */
898
+ static void do_test_8p_2c(void) {
899
+ concurrent_test_config_t config = {
900
+ .consumer_cnt = 2,
901
+ .producer_cnt = 8,
902
+ .topic_cnt = 1,
903
+ .partitions = {4},
904
+ .msgs_per_partition = 2500,
905
+ .group_name = "share-conc-8p2c",
906
+ .test_name = "8 producers, 2 consumers (producer heavy)"};
907
+
908
+ SUB_TEST();
909
+ run_concurrent_test(&config);
910
+
911
+ SUB_TEST_PASS();
912
+ }
913
+
914
+ /**
915
+ * @brief Few producers, many consumers
916
+ */
917
+ static void do_test_2p_8c(void) {
918
+ concurrent_test_config_t config = {
919
+ .consumer_cnt = 8,
920
+ .producer_cnt = 2,
921
+ .topic_cnt = 1,
922
+ .partitions = {4},
923
+ .msgs_per_partition = 10000,
924
+ .group_name = "share-conc-2p8c",
925
+ .test_name = "2 producers, 8 consumers (consumer heavy)"};
926
+
927
+ SUB_TEST();
928
+ run_concurrent_test(&config);
929
+
930
+ SUB_TEST_PASS();
931
+ }
932
+
933
+ /***************************************************************************
934
+ * Test Cases - Complex Multi-Topic Multi-Partition
935
+ ***************************************************************************/
936
+
937
+ /**
938
+ * @brief Complex scenario with varied partition counts
939
+ */
940
+ static void do_test_complex_varied_partitions(void) {
941
+ concurrent_test_config_t config = {
942
+ .consumer_cnt = 4,
943
+ .producer_cnt = 4,
944
+ .topic_cnt = 4,
945
+ .partitions = {1, 2, 3, 4},
946
+ .msgs_per_partition = 2000,
947
+ .group_name = "share-conc-complex-varied",
948
+ .test_name = "4 topics with 1,2,3,4 partitions respectively",
949
+ .max_attempts = 150};
950
+
951
+ SUB_TEST();
952
+ run_concurrent_test(&config);
953
+
954
+ SUB_TEST_PASS();
955
+ }
956
+
957
+ /**
958
+ * @brief Maximum concurrent scenario
959
+ */
960
+ static void do_test_max_concurrent(void) {
961
+ concurrent_test_config_t config = {
962
+ .consumer_cnt = MAX_CONSUMERS,
963
+ .producer_cnt = MAX_PRODUCERS,
964
+ .topic_cnt = 4,
965
+ .partitions = {4, 4, 4, 4},
966
+ .msgs_per_partition = 3125,
967
+ .group_name = "share-conc-max",
968
+ .test_name = "Maximum: 10 producers, 10 consumers, 4 topics",
969
+ .max_attempts = 200};
970
+
971
+ SUB_TEST();
972
+ run_concurrent_test(&config);
973
+
974
+ SUB_TEST_PASS();
975
+ }
976
+
977
+ /***************************************************************************
978
+ * Test Cases - Slow Consumer/Producer Scenarios
979
+ ***************************************************************************/
980
+
981
+ /**
982
+ * @brief Slow consumers with fast producers
983
+ */
984
+ static void do_test_slow_consumers(void) {
985
+ concurrent_test_config_t config = {
986
+ .consumer_cnt = 2,
987
+ .producer_cnt = 4,
988
+ .topic_cnt = 1,
989
+ .partitions = {2},
990
+ .msgs_per_partition = 5000,
991
+ .group_name = "share-conc-slow-consumer",
992
+ .test_name = "Fast producers, slow consumers",
993
+ .consumer_delay_ms = 50,
994
+ .max_attempts = 200};
995
+
996
+ SUB_TEST();
997
+ run_concurrent_test(&config);
998
+
999
+ SUB_TEST_PASS();
1000
+ }
1001
+
1002
+ /**
1003
+ * @brief Fast consumers with slow producers
1004
+ */
1005
+ static void do_test_slow_producers(void) {
1006
+ concurrent_test_config_t config = {
1007
+ .consumer_cnt = 4,
1008
+ .producer_cnt = 2,
1009
+ .topic_cnt = 1,
1010
+ .partitions = {2},
1011
+ .msgs_per_partition = 500,
1012
+ .group_name = "share-conc-slow-producer",
1013
+ .test_name = "Slow producers, fast consumers",
1014
+ .producer_delay_ms = 10000,
1015
+ .max_attempts = 200};
1016
+
1017
+ SUB_TEST();
1018
+ run_concurrent_test(&config);
1019
+
1020
+ SUB_TEST_PASS();
1021
+ }
1022
+
1023
+ /**
1024
+ * @brief Chaos test: consumer churn during sustained production.
1025
+ *
1026
+ * Setup:
1027
+ * - 4 producers in dedicated threads producing fixed total messages.
1028
+ * - Pool of CONSUMER_POOL slots; only ACTIVE_CONSUMERS run concurrently.
1029
+ * - Initially start ACTIVE_CONSUMERS threads.
1030
+ * - For ITERATIONS rounds: sleep ITERATION_MS, then stop a random number
1031
+ * of the currently running consumers (>= 1) and start the same number
1032
+ * of fresh ones from the pool. Old threads are joined at the very end.
1033
+ * - After iterations, drain remaining messages and shut everyone down.
1034
+ *
1035
+ * Invariant for share consumers: every produced record is first-delivered
1036
+ * exactly once. Records that a closing consumer hadn't acked are released
1037
+ * back to the group and re-delivered with delivery_count > 1 (counted as
1038
+ * duplicates, not first deliveries).
1039
+ */
1040
+ static void do_test_chaos_consumer_lifecycle(rd_bool_t explicit_ack) {
1041
+ concurrent_test_state_t state = {0};
1042
+ const concurrent_test_config_t config = {
1043
+ .consumer_cnt = 4, /* informational; pool size below */
1044
+ .producer_cnt = 4,
1045
+ .topic_cnt = 1,
1046
+ .partitions = {4},
1047
+ .msgs_per_partition = 1000,
1048
+ .group_name = explicit_ack ? "share-chaos-lifecycle-explicit"
1049
+ : "share-chaos-lifecycle-implicit",
1050
+ .test_name = explicit_ack ? "Chaos (explicit ack): consumer "
1051
+ "churn during production"
1052
+ : "Chaos (implicit ack): consumer "
1053
+ "churn during production",
1054
+ .explicit_ack = explicit_ack};
1055
+ const int ACTIVE_CONSUMERS = 4;
1056
+ const int CONSUMER_POOL = 12;
1057
+ const int ITERATIONS = 3;
1058
+ const int ITERATION_MS = 6000;
1059
+ const int join_poll_ticks = 10; /* 10 * 500ms = 5 s */
1060
+ thrd_t producer_threads[MAX_PRODUCERS];
1061
+ thrd_t consumer_threads[MAX_CONSUMER_POOL];
1062
+ consumer_thread_args_t consumer_args[MAX_CONSUMER_POOL];
1063
+ int started_threads = 0;
1064
+ int first_running = 0;
1065
+ int last_running;
1066
+ int t, c, p, iter;
1067
+ int total_partitions = 0;
1068
+ int msgs_per_producer;
1069
+ int wait_attempts;
1070
+ int dangling = 0;
1071
+ int final_produced;
1072
+ int final_first_delivery;
1073
+ int final_duplicates;
1074
+ int final_consumed;
1075
+ rd_bool_t final_failed;
1076
+ rd_kafka_share_t *dummy_consumer;
1077
+
1078
+ SUB_TEST();
1079
+
1080
+ TEST_ASSERT(CONSUMER_POOL <= MAX_CONSUMER_POOL,
1081
+ "CONSUMER_POOL %d > MAX_CONSUMER_POOL", CONSUMER_POOL);
1082
+ TEST_ASSERT(ACTIVE_CONSUMERS <= CONSUMER_POOL, "ACTIVE > POOL");
1083
+
1084
+ TEST_SAY("\n");
1085
+ TEST_SAY(
1086
+ "============================================================\n");
1087
+ TEST_SAY("=== %s ===\n", config.test_name);
1088
+ TEST_SAY(
1089
+ "============================================================\n");
1090
+ TEST_SAY("Active %d, pool %d, iterations %d × %d ms\n",
1091
+ ACTIVE_CONSUMERS, CONSUMER_POOL, ITERATIONS, ITERATION_MS);
1092
+
1093
+ this_test = test_curr;
1094
+
1095
+ /* See note in run_concurrent_test: set these on the main thread
1096
+ * before spawning worker threads to avoid TSAN-flagged races on
1097
+ * the shared test struct that test_curr aliases. */
1098
+ test_curr->exp_dr_status = (rd_kafka_msg_status_t)-1;
1099
+ test_curr->ignore_dr_err = rd_true;
1100
+
1101
+ mtx_init(&state.lock, mtx_plain);
1102
+ state.topic_cnt = config.topic_cnt;
1103
+ state.group_name = config.group_name;
1104
+ state.explicit_ack = config.explicit_ack;
1105
+ state.producers_remaining = config.producer_cnt;
1106
+
1107
+ for (t = 0; t < config.topic_cnt; t++)
1108
+ total_partitions += config.partitions[t];
1109
+ state.expected_total = total_partitions * config.msgs_per_partition;
1110
+ TEST_SAY("Expected messages: %d\n", state.expected_total);
1111
+
1112
+ for (t = 0; t < config.topic_cnt; t++) {
1113
+ rd_snprintf(state.topics[t], sizeof(state.topics[t]), "%s",
1114
+ test_mk_topic_name("0174-chaos", 1));
1115
+ test_create_topic_wait_exists(
1116
+ NULL, state.topics[t], config.partitions[t], -1, 60 * 1000);
1117
+ }
1118
+
1119
+ /* Apply broker-side group config (auto.offset.reset=earliest) via
1120
+ * a throwaway consumer registration, so the alter sticks before
1121
+ * any chaos worker subscribes. */
1122
+ dummy_consumer = test_create_share_consumer(config.group_name, NULL);
1123
+ test_share_set_auto_offset_reset(config.group_name, "earliest");
1124
+ test_share_consumer_close(dummy_consumer);
1125
+ test_share_destroy(dummy_consumer);
1126
+
1127
+ /* Producer threads */
1128
+ msgs_per_producer = state.expected_total / config.producer_cnt;
1129
+ for (p = 0; p < config.producer_cnt; p++) {
1130
+ producer_thread_args_t *args = rd_calloc(1, sizeof(*args));
1131
+ args->state = &state;
1132
+ args->producer_id = p;
1133
+ args->msgs_to_produce = msgs_per_producer;
1134
+ if (p == config.producer_cnt - 1)
1135
+ args->msgs_to_produce +=
1136
+ state.expected_total % config.producer_cnt;
1137
+ /* Light pacing so production stretches across the chaos
1138
+ * iterations rather than finishing before the first churn. */
1139
+ args->delay_ms = 5;
1140
+ for (t = 0; t < config.topic_cnt; t++)
1141
+ args->partitions[t] = config.partitions[t];
1142
+
1143
+ if (thrd_create(&producer_threads[p], producer_thread_func,
1144
+ args) != thrd_success) {
1145
+ TEST_FAIL("Failed to create producer thread %d", p);
1146
+ }
1147
+ }
1148
+
1149
+ /* Pre-init the entire pool */
1150
+ for (c = 0; c < CONSUMER_POOL; c++) {
1151
+ consumer_args[c].state = &state;
1152
+ consumer_args[c].consumer_id = c;
1153
+ consumer_args[c].run = rd_false;
1154
+ consumer_args[c].done = rd_false;
1155
+ consumer_args[c].poll_delay_ms = 0;
1156
+ }
1157
+
1158
+ /* Start the initial active set */
1159
+ for (c = 0; c < ACTIVE_CONSUMERS; c++) {
1160
+ mtx_lock(&state.lock);
1161
+ consumer_args[c].run = rd_true;
1162
+ mtx_unlock(&state.lock);
1163
+ if (thrd_create(&consumer_threads[c], consumer_thread_func,
1164
+ &consumer_args[c]) != thrd_success) {
1165
+ TEST_FAIL(
1166
+ "Failed to create initial consumer "
1167
+ "thread %d",
1168
+ c);
1169
+ }
1170
+ started_threads++;
1171
+ }
1172
+ last_running = ACTIVE_CONSUMERS - 1;
1173
+
1174
+ srand((unsigned int)time(NULL));
1175
+
1176
+ for (iter = 0; iter < ITERATIONS; iter++) {
1177
+ int running;
1178
+ int churn;
1179
+ int can_start;
1180
+ int s;
1181
+
1182
+ TEST_SAY("--- Iteration %d/%d: sleeping %d ms ---\n", iter + 1,
1183
+ ITERATIONS, ITERATION_MS);
1184
+ rd_usleep(ITERATION_MS * 1000, NULL);
1185
+
1186
+ running = last_running - first_running + 1;
1187
+ /* Stop at least 1, at most floor(running/2) for stability */
1188
+ churn = (running > 1) ? (rand() % ((running / 2) + 1) + 1) : 1;
1189
+ TEST_SAY("Iteration %d: stopping %d/%d running consumers\n",
1190
+ iter + 1, churn, running);
1191
+
1192
+ mtx_lock(&state.lock);
1193
+ for (s = 0; s < churn && first_running <= last_running;
1194
+ s++, first_running++) {
1195
+ consumer_args[first_running].run = rd_false;
1196
+ }
1197
+ mtx_unlock(&state.lock);
1198
+
1199
+ /* Replenish with new pool slots (don't reuse stopped slots) */
1200
+ can_start = CONSUMER_POOL - started_threads;
1201
+ if (can_start <= 0) {
1202
+ TEST_SAY(
1203
+ "Pool exhausted (%d threads spawned); no more "
1204
+ "starts this iteration\n",
1205
+ started_threads);
1206
+ continue;
1207
+ }
1208
+ if (churn > can_start)
1209
+ churn = can_start;
1210
+
1211
+ TEST_SAY("Iteration %d: starting %d fresh consumers\n",
1212
+ iter + 1, churn);
1213
+
1214
+ for (s = 0; s < churn; s++) {
1215
+ int idx = started_threads;
1216
+ if (idx >= CONSUMER_POOL)
1217
+ break;
1218
+ mtx_lock(&state.lock);
1219
+ consumer_args[idx].run = rd_true;
1220
+ mtx_unlock(&state.lock);
1221
+ if (thrd_create(&consumer_threads[idx],
1222
+ consumer_thread_func,
1223
+ &consumer_args[idx]) != thrd_success) {
1224
+ TEST_FAIL(
1225
+ "Failed to create chaos consumer "
1226
+ "thread %d",
1227
+ idx);
1228
+ }
1229
+ started_threads++;
1230
+ last_running = idx;
1231
+ }
1232
+ }
1233
+
1234
+ TEST_SAY(
1235
+ "Iterations done; waiting for production to drain, then "
1236
+ "shutting down consumers\n");
1237
+
1238
+ /* Drain loop, bounded so we don't sit for minutes on a stuck
1239
+ * test:
1240
+ * - 60 ticks of 500 ms = 30 s absolute cap
1241
+ * - early exit when producers_done AND first_delivery has not
1242
+ * advanced for 10 consecutive ticks (~5 s of no progress).
1243
+ * If the chaos test has stalled, we report and move on
1244
+ * rather than waiting for the full window. */
1245
+ wait_attempts = 60; /* ~30 seconds absolute cap */
1246
+ int prev_first_seen = -1;
1247
+ int stale_ticks = 0;
1248
+ const int stale_limit = 10; /* ~5 s with no progress */
1249
+
1250
+ while (wait_attempts-- > 0) {
1251
+ int first_seen;
1252
+ rd_bool_t producers_done;
1253
+
1254
+ mtx_lock(&state.lock);
1255
+ first_seen = state.total_first_delivery;
1256
+ producers_done = state.producers_done;
1257
+ mtx_unlock(&state.lock);
1258
+
1259
+ if (producers_done && first_seen >= state.expected_total)
1260
+ break;
1261
+
1262
+ if (first_seen == prev_first_seen) {
1263
+ stale_ticks++;
1264
+ if (producers_done && stale_ticks >= stale_limit) {
1265
+ TEST_SAY(
1266
+ "Drain: no progress for "
1267
+ "~%d s after producers done; "
1268
+ "exiting at %d/%d "
1269
+ "(test will fail in assertion)\n",
1270
+ stale_ticks / 2, first_seen,
1271
+ state.expected_total);
1272
+ break;
1273
+ }
1274
+ } else {
1275
+ stale_ticks = 0;
1276
+ prev_first_seen = first_seen;
1277
+ }
1278
+
1279
+ if (wait_attempts % 10 == 0)
1280
+ TEST_SAY(
1281
+ "Drain: %d/%d first deliveries "
1282
+ "(producers_done=%d)\n",
1283
+ first_seen, state.expected_total,
1284
+ (int)producers_done);
1285
+
1286
+ rd_usleep(500 * 1000, NULL);
1287
+ }
1288
+
1289
+ /* Join producers - these always exit cleanly so a hard join is
1290
+ * safe. */
1291
+ for (p = 0; p < config.producer_cnt; p++)
1292
+ thrd_join(producer_threads[p], NULL);
1293
+
1294
+ /* Stop all consumer threads. */
1295
+ mtx_lock(&state.lock);
1296
+ for (c = 0; c < started_threads; c++)
1297
+ consumer_args[c].run = rd_false;
1298
+ mtx_unlock(&state.lock);
1299
+
1300
+ /* Bounded wait for consumers to exit cleanly. A wedged consumer
1301
+ * (eg blocked inside consume_batch waiting on a stale share
1302
+ * session) won't return from rd_kafka_share_consumer_close, so
1303
+ * thrd_join would block indefinitely. We poll each consumer's
1304
+ * done flag for up to ~5 s; any thread that hasn't set it by
1305
+ * then is left dangling for the OS to reclaim at process exit
1306
+ * and we move straight to the assertions. This matters only
1307
+ * when the test is failing — once the underlying librdkafka
1308
+ * issue is fixed, every consumer thread reaches its `done = true`
1309
+ * within tens of milliseconds. */
1310
+ for (c = 0; c < started_threads; c++) {
1311
+ rd_bool_t done = rd_false;
1312
+ for (t = 0; t < join_poll_ticks; t++) {
1313
+ mtx_lock(&state.lock);
1314
+ done = consumer_args[c].done;
1315
+ mtx_unlock(&state.lock);
1316
+ if (done)
1317
+ break;
1318
+ rd_usleep(500 * 1000, NULL);
1319
+ }
1320
+ if (done) {
1321
+ thrd_join(consumer_threads[c], NULL);
1322
+ } else {
1323
+ /* Detach so the C runtime won't leak the
1324
+ * thrd_t handle when the process exits;
1325
+ * the OS will tear down the still-running
1326
+ * thread when the process terminates. */
1327
+ thrd_detach(consumer_threads[c]);
1328
+ dangling++;
1329
+ TEST_SAY(
1330
+ "Consumer thread %d: did not exit within "
1331
+ "5 s of stop signal — detaching and "
1332
+ "proceeding (likely wedged inside "
1333
+ "librdkafka close path)\n",
1334
+ consumer_args[c].consumer_id);
1335
+ }
1336
+ }
1337
+
1338
+ if (dangling > 0)
1339
+ TEST_SAY(
1340
+ "WARNING: %d/%d consumer thread(s) left "
1341
+ "dangling at test exit\n",
1342
+ dangling, started_threads);
1343
+
1344
+ mtx_lock(&state.lock);
1345
+ final_produced = state.total_produced;
1346
+ final_first_delivery = state.total_first_delivery;
1347
+ final_duplicates = state.total_duplicates;
1348
+ final_consumed = state.total_consumed;
1349
+ final_failed = state.test_failed;
1350
+ mtx_unlock(&state.lock);
1351
+
1352
+ TEST_SAY(
1353
+ "Chaos final: produced=%d, consumed=%d (first=%d, dup=%d), "
1354
+ "expected=%d, threads spawned=%d\n",
1355
+ final_produced, final_consumed, final_first_delivery,
1356
+ final_duplicates, state.expected_total, started_threads);
1357
+
1358
+ TEST_ASSERT(final_produced == state.expected_total,
1359
+ "Expected to produce %d, actually produced %d",
1360
+ state.expected_total, final_produced);
1361
+ TEST_ASSERT(final_first_delivery == state.expected_total,
1362
+ "Expected %d first-time deliveries, got %d "
1363
+ "(consumed=%d, duplicates=%d)",
1364
+ state.expected_total, final_first_delivery, final_consumed,
1365
+ final_duplicates);
1366
+ TEST_ASSERT(!final_failed, "Producer thread reported failure");
1367
+ TEST_SAY(
1368
+ "SUCCESS: chaos test - %d threads churned, "
1369
+ "every record first-delivered exactly once\n",
1370
+ started_threads);
1371
+
1372
+ mtx_destroy(&state.lock);
1373
+
1374
+ SUB_TEST_PASS();
1375
+ }
1376
+
1377
+
1378
+ /***************************************************************************
1379
+ * Main Entry Point
1380
+ ***************************************************************************/
1381
+
1382
+ int main_0174_share_consumer_concurrency(int argc, char **argv) {
1383
+
1384
+ test_timeout_set(1500);
1385
+
1386
+ /* Every test below runs producers AND consumers in dedicated
1387
+ * threads via run_concurrent_test(). There is no main-thread
1388
+ * polling — consumer_thread_func handles the poll loop per
1389
+ * consumer. */
1390
+
1391
+ /* Basic concurrency tests */
1392
+ do_test_1p_1c_1t_1part(); /* Baseline: 1 producer, 1 consumer */
1393
+ do_test_1p_4c_1t_4part(); /* Fan out: 1 producer, 4 consumers */
1394
+ do_test_4p_1c_1t_4part(); /* Fan in: 4 producers, 1 consumer */
1395
+ do_test_4p_4c_1t_4part(); /* Symmetric: 4 producers, 4 consumers */
1396
+
1397
+ /* Multi-topic tests */
1398
+ do_test_2p_2c_3t_2part(); /* Multiple topics */
1399
+ do_test_2p_2c_8t_1part(); /* Many topics */
1400
+
1401
+ /* High contention tests */
1402
+ do_test_1p_8c_1t_1part(); /* Many consumers, 1 partition */
1403
+ do_test_2p_6c_1t_2part(); /* More consumers than partitions */
1404
+
1405
+ /* Explicit acknowledgement */
1406
+ do_test_explicit_ack_4p_4c();
1407
+
1408
+ /* Staggered start */
1409
+ do_test_staggered_start();
1410
+
1411
+ /* High volume stress tests */
1412
+ do_test_high_volume_20k();
1413
+ do_test_high_volume_many_partitions();
1414
+
1415
+ /* Asymmetric configurations */
1416
+ do_test_8p_2c(); /* Producer heavy */
1417
+ do_test_2p_8c(); /* Consumer heavy */
1418
+
1419
+ /* Complex scenarios */
1420
+ do_test_complex_varied_partitions();
1421
+ do_test_max_concurrent();
1422
+
1423
+ /* Slow consumer/producer scenarios */
1424
+ do_test_slow_consumers();
1425
+ do_test_slow_producers();
1426
+
1427
+ /* Chaos test: consumer lifecycle churn during sustained production.
1428
+ * Run once with explicit acknowledgement and once with implicit
1429
+ * acknowledgement to cover both ack flows under churn. */
1430
+ do_test_chaos_consumer_lifecycle(rd_true);
1431
+ do_test_chaos_consumer_lifecycle(rd_false);
1432
+
1433
+ return 0;
1434
+ }