@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,1551 @@
1
+ /*
2
+ * librdkafka - Apache Kafka C library
3
+ *
4
+ * Copyright (c) 2025, Confluent Inc.
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ * this list of conditions and the following disclaimer in the documentation
14
+ * and/or other materials provided with the distribution.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ * POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ #include "test.h"
30
+
31
+ #include "../src/rdkafka_proto.h"
32
+
33
+ /**
34
+ * @name ShareFetch mock broker tests using the share consumer API.
35
+ *
36
+ * Exercises the ShareFetch path via mock broker. There is no coordinator
37
+ * or ShareAcknowledge support in the mock broker, so group management and
38
+ * ack-based state transitions are not validated here.
39
+ */
40
+
41
+ typedef struct test_ctx_s {
42
+ rd_kafka_t *producer;
43
+ rd_kafka_mock_cluster_t *mcluster;
44
+ const char *bootstraps;
45
+ } test_ctx_t;
46
+
47
+ static test_ctx_t test_ctx_new(void) {
48
+ test_ctx_t ctx;
49
+ rd_kafka_conf_t *conf;
50
+ char errstr[512];
51
+
52
+ memset(&ctx, 0, sizeof(ctx));
53
+
54
+ ctx.mcluster = test_mock_cluster_new(3, &ctx.bootstraps);
55
+
56
+ TEST_ASSERT(rd_kafka_mock_set_apiversion(
57
+ ctx.mcluster, RD_KAFKAP_ShareGroupHeartbeat, 1, 1) ==
58
+ RD_KAFKA_RESP_ERR_NO_ERROR,
59
+ "Failed to enable ShareGroupHeartbeat");
60
+ TEST_ASSERT(rd_kafka_mock_set_apiversion(ctx.mcluster,
61
+ RD_KAFKAP_ShareFetch, 1, 1) ==
62
+ RD_KAFKA_RESP_ERR_NO_ERROR,
63
+ "Failed to enable ShareFetch");
64
+
65
+ /* Set auto.offset.reset=earliest so tests that produce
66
+ * before consuming see all records. */
67
+ rd_kafka_mock_sharegroup_set_auto_offset_reset(ctx.mcluster, 1);
68
+
69
+ /* Create a producer targeting the mock cluster */
70
+ test_conf_init(&conf, NULL, 0);
71
+ test_conf_set(conf, "bootstrap.servers", ctx.bootstraps);
72
+ rd_kafka_conf_set_dr_msg_cb(conf, test_dr_msg_cb);
73
+
74
+ ctx.producer =
75
+ rd_kafka_new(RD_KAFKA_PRODUCER, conf, errstr, sizeof(errstr));
76
+ TEST_ASSERT(ctx.producer != NULL, "Failed to create producer: %s",
77
+ errstr);
78
+
79
+ return ctx;
80
+ }
81
+
82
+ static void test_ctx_destroy(test_ctx_t *ctx) {
83
+ if (ctx->producer)
84
+ rd_kafka_destroy(ctx->producer);
85
+ if (ctx->mcluster)
86
+ test_mock_cluster_destroy(ctx->mcluster);
87
+ memset(ctx, 0, sizeof(*ctx));
88
+ }
89
+
90
+ static rd_kafka_share_t *new_share_consumer(const char *bootstraps,
91
+ const char *group_id) {
92
+ rd_kafka_conf_t *conf;
93
+ rd_kafka_share_t *consumer;
94
+
95
+ test_conf_init(&conf, NULL, 0);
96
+ test_conf_set(conf, "bootstrap.servers", bootstraps);
97
+ test_conf_set(conf, "group.id", group_id);
98
+
99
+ consumer = rd_kafka_share_consumer_new(conf, NULL, 0);
100
+ TEST_ASSERT(consumer != NULL, "Failed to create share consumer");
101
+ return consumer;
102
+ }
103
+
104
+ static void subscribe_topics(rd_kafka_share_t *consumer,
105
+ const char **topics,
106
+ int topic_cnt) {
107
+ rd_kafka_topic_partition_list_t *tpl =
108
+ rd_kafka_topic_partition_list_new(topic_cnt);
109
+ for (int i = 0; i < topic_cnt; i++) {
110
+ rd_kafka_topic_partition_list_add(tpl, topics[i],
111
+ RD_KAFKA_PARTITION_UA);
112
+ }
113
+ TEST_ASSERT(!rd_kafka_share_subscribe(consumer, tpl),
114
+ "Subscribe failed");
115
+ rd_kafka_topic_partition_list_destroy(tpl);
116
+ }
117
+
118
+ static void do_test_basic_consume(void) {
119
+ const char *topic = "kip932_pos_basic";
120
+ const int msgcnt = 5;
121
+ test_ctx_t ctx = test_ctx_new();
122
+ rd_kafka_share_t *consumer;
123
+ int consumed;
124
+
125
+ SUB_TEST_QUICK();
126
+
127
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
128
+ RD_KAFKA_RESP_ERR_NO_ERROR,
129
+ "Failed to create mock topic");
130
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
131
+ msgcnt);
132
+
133
+ consumer = new_share_consumer(ctx.bootstraps, "sg-pos-basic");
134
+ subscribe_topics(consumer, &topic, 1);
135
+ consumed = test_share_consume_msgs(consumer, msgcnt, 50, 500, NULL, 0);
136
+
137
+ test_share_consumer_close(consumer);
138
+ test_share_destroy(consumer);
139
+ test_ctx_destroy(&ctx);
140
+
141
+ TEST_ASSERT(consumed == msgcnt, "Expected %d consumed, got %d", msgcnt,
142
+ consumed);
143
+ SUB_TEST_PASS();
144
+ }
145
+
146
+ static void do_test_followup_fetch(void) {
147
+ const char *topic = "kip932_pos_followup";
148
+ test_ctx_t ctx = test_ctx_new();
149
+ rd_kafka_share_t *consumer;
150
+ int consumed;
151
+
152
+ SUB_TEST_QUICK();
153
+
154
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
155
+ RD_KAFKA_RESP_ERR_NO_ERROR,
156
+ "Failed to create mock topic");
157
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA, 5);
158
+
159
+ consumer = new_share_consumer(ctx.bootstraps, "sg-pos-followup");
160
+ subscribe_topics(consumer, &topic, 1);
161
+ consumed = test_share_consume_msgs(consumer, 3, 30, 500, NULL, 0);
162
+ consumed += test_share_consume_msgs(consumer, 2, 30, 500, NULL, 0);
163
+
164
+ test_share_consumer_close(consumer);
165
+ test_share_destroy(consumer);
166
+ test_ctx_destroy(&ctx);
167
+
168
+ TEST_ASSERT(consumed == 5, "Expected 5 consumed, got %d", consumed);
169
+ SUB_TEST_PASS();
170
+ }
171
+
172
+ static void do_test_multi_partition(void) {
173
+ const char *topic = "kip932_pos_multi_part";
174
+ const int msgcnt = 6;
175
+ test_ctx_t ctx = test_ctx_new();
176
+ rd_kafka_share_t *consumer;
177
+ int consumed;
178
+
179
+ SUB_TEST_QUICK();
180
+
181
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 2, 1) ==
182
+ RD_KAFKA_RESP_ERR_NO_ERROR,
183
+ "Failed to create mock topic");
184
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
185
+ msgcnt);
186
+
187
+ consumer = new_share_consumer(ctx.bootstraps, "sg-pos-multipart");
188
+ subscribe_topics(consumer, &topic, 1);
189
+ consumed = test_share_consume_msgs(consumer, msgcnt, 60, 500, NULL, 0);
190
+
191
+ test_share_consumer_close(consumer);
192
+ test_share_destroy(consumer);
193
+ test_ctx_destroy(&ctx);
194
+
195
+ TEST_ASSERT(consumed == msgcnt, "Expected %d consumed, got %d", msgcnt,
196
+ consumed);
197
+ SUB_TEST_PASS();
198
+ }
199
+
200
+ static void do_test_multi_topic(void) {
201
+ const char *topic_a = "kip932_pos_topic_a";
202
+ const char *topic_b = "kip932_pos_topic_b";
203
+ const char *topics[] = {topic_a, topic_b};
204
+ test_ctx_t ctx = test_ctx_new();
205
+ rd_kafka_share_t *consumer;
206
+ int consumed;
207
+
208
+ SUB_TEST_QUICK();
209
+
210
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic_a, 1, 1) ==
211
+ RD_KAFKA_RESP_ERR_NO_ERROR,
212
+ "Failed to create mock topic A");
213
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic_b, 1, 1) ==
214
+ RD_KAFKA_RESP_ERR_NO_ERROR,
215
+ "Failed to create mock topic B");
216
+
217
+ test_produce_msgs_simple(ctx.producer, topic_a, RD_KAFKA_PARTITION_UA,
218
+ 2);
219
+ test_produce_msgs_simple(ctx.producer, topic_b, RD_KAFKA_PARTITION_UA,
220
+ 2);
221
+ consumer = new_share_consumer(ctx.bootstraps, "sg-pos-multitopic");
222
+ subscribe_topics(consumer, topics, 2);
223
+ consumed = test_share_consume_msgs(consumer, 4, 40, 500, NULL, 0);
224
+
225
+ test_share_consumer_close(consumer);
226
+ test_share_destroy(consumer);
227
+ test_ctx_destroy(&ctx);
228
+
229
+ TEST_ASSERT(consumed == 4, "Expected 4 consumed, got %d", consumed);
230
+ SUB_TEST_PASS();
231
+ }
232
+
233
+ static void do_test_empty_topic_no_records(void) {
234
+ const char *topic = "kip932_pos_empty";
235
+ test_ctx_t ctx = test_ctx_new();
236
+ rd_kafka_share_t *consumer;
237
+ int consumed;
238
+
239
+ SUB_TEST_QUICK();
240
+
241
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
242
+ RD_KAFKA_RESP_ERR_NO_ERROR,
243
+ "Failed to create mock topic");
244
+
245
+ consumer = new_share_consumer(ctx.bootstraps, "sg-pos-empty");
246
+ subscribe_topics(consumer, &topic, 1);
247
+ consumed = test_share_consume_msgs(consumer, 1, 5, 500, NULL, 0);
248
+
249
+ test_share_consumer_close(consumer);
250
+ test_share_destroy(consumer);
251
+ test_ctx_destroy(&ctx);
252
+
253
+ TEST_ASSERT(consumed == 0, "Expected 0 consumed, got %d", consumed);
254
+ SUB_TEST_PASS();
255
+ }
256
+
257
+ static int do_test_negative_sharefetch_error(rd_kafka_resp_err_t err) {
258
+ const char *topic = "kip932_neg_sharefetch_error";
259
+ test_ctx_t ctx = test_ctx_new();
260
+ rd_kafka_share_t *consumer;
261
+ int consumed;
262
+
263
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
264
+ RD_KAFKA_RESP_ERR_NO_ERROR,
265
+ "Failed to create mock topic");
266
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA, 1);
267
+
268
+ rd_kafka_mock_push_request_errors(ctx.mcluster, RD_KAFKAP_ShareFetch, 1,
269
+ err);
270
+
271
+ consumer = new_share_consumer(ctx.bootstraps, "sg-neg-sharefetch");
272
+ subscribe_topics(consumer, &topic, 1);
273
+ consumed = test_share_consume_msgs(consumer, 1, 30, 500, NULL, 0);
274
+
275
+ test_share_consumer_close(consumer);
276
+ test_share_destroy(consumer);
277
+ test_ctx_destroy(&ctx);
278
+
279
+ return consumed;
280
+ }
281
+
282
+ static void do_test_sharefetch_invalid_session_epoch(void) {
283
+ SUB_TEST_QUICK();
284
+ do_test_negative_sharefetch_error(
285
+ RD_KAFKA_RESP_ERR_INVALID_SHARE_SESSION_EPOCH);
286
+ SUB_TEST_PASS();
287
+ }
288
+
289
+ static void do_test_sharefetch_unknown_topic_or_part(void) {
290
+ SUB_TEST_QUICK();
291
+ do_test_negative_sharefetch_error(
292
+ RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART);
293
+ SUB_TEST_PASS();
294
+ }
295
+
296
+ static void do_test_sghb_error(rd_kafka_resp_err_t err, int count) {
297
+ const char *topic = "kip932_neg_sghb";
298
+ test_ctx_t ctx = test_ctx_new();
299
+ rd_kafka_share_t *consumer;
300
+ int consumed;
301
+ rd_kafka_resp_err_t *errs;
302
+ int i;
303
+
304
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
305
+ RD_KAFKA_RESP_ERR_NO_ERROR,
306
+ "Failed to create mock topic");
307
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA, 1);
308
+
309
+ /* Build an array of 'count' identical errors and push them all.
310
+ * Using the array variant avoids UB from mismatched varargs count. */
311
+ errs = malloc(sizeof(*errs) * count);
312
+ TEST_ASSERT(errs != NULL, "malloc failed");
313
+ for (i = 0; i < count; i++)
314
+ errs[i] = err;
315
+ rd_kafka_mock_push_request_errors_array(
316
+ ctx.mcluster, RD_KAFKAP_ShareGroupHeartbeat, (size_t)count, errs);
317
+ free(errs);
318
+
319
+ consumer = new_share_consumer(ctx.bootstraps, "sg-neg-sghb");
320
+ subscribe_topics(consumer, &topic, 1);
321
+ consumed = test_share_consume_msgs(consumer, 1, 5, 500, NULL, 0);
322
+
323
+ test_share_consumer_close(consumer);
324
+ test_share_destroy(consumer);
325
+ test_ctx_destroy(&ctx);
326
+
327
+ TEST_ASSERT(consumed == 0, "Expected 0 consumed, got %d", consumed);
328
+ }
329
+
330
+ static void do_test_sghb_coord_unavailable(void) {
331
+ SUB_TEST_QUICK();
332
+ do_test_sghb_error(RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE, 50);
333
+ SUB_TEST_PASS();
334
+ }
335
+
336
+ static void do_test_topic_error(rd_kafka_resp_err_t err) {
337
+ const char *topic = "kip932_neg_topic_error";
338
+ test_ctx_t ctx = test_ctx_new();
339
+ rd_kafka_share_t *consumer;
340
+ int consumed;
341
+
342
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
343
+ RD_KAFKA_RESP_ERR_NO_ERROR,
344
+ "Failed to create mock topic");
345
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA, 1);
346
+ rd_kafka_mock_topic_set_error(ctx.mcluster, topic, err);
347
+
348
+ consumer = new_share_consumer(ctx.bootstraps, "sg-neg-topicerr");
349
+ subscribe_topics(consumer, &topic, 1);
350
+ consumed = test_share_consume_msgs(consumer, 1, 5, 500, NULL, 0);
351
+
352
+ test_share_consumer_close(consumer);
353
+ test_share_destroy(consumer);
354
+ test_ctx_destroy(&ctx);
355
+
356
+ TEST_ASSERT(consumed == 0, "Expected 0 consumed, got %d", consumed);
357
+ }
358
+
359
+ static void do_test_topic_error_unknown_topic_or_part(void) {
360
+ SUB_TEST_QUICK();
361
+ do_test_topic_error(RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART);
362
+ SUB_TEST_PASS();
363
+ }
364
+
365
+ static void do_test_unknown_topic_subscription(void) {
366
+ const char *topic = "kip932_neg_unknown_topic";
367
+ test_ctx_t ctx = test_ctx_new();
368
+ rd_kafka_share_t *consumer;
369
+ int consumed;
370
+
371
+ SUB_TEST_QUICK();
372
+
373
+ consumer = new_share_consumer(ctx.bootstraps, "sg-neg-unknown-topic");
374
+ subscribe_topics(consumer, &topic, 1);
375
+ consumed = test_share_consume_msgs(consumer, 1, 5, 500, NULL, 0);
376
+
377
+ test_share_consumer_close(consumer);
378
+ test_share_destroy(consumer);
379
+ test_ctx_destroy(&ctx);
380
+
381
+ TEST_ASSERT(consumed == 0, "Expected 0 consumed, got %d", consumed);
382
+ SUB_TEST_PASS();
383
+ }
384
+
385
+ static void do_test_empty_fetch_no_records(void) {
386
+ const char *topic = "kip932_neg_empty_fetch";
387
+ test_ctx_t ctx = test_ctx_new();
388
+ rd_kafka_share_t *consumer;
389
+ int consumed;
390
+
391
+ SUB_TEST_QUICK();
392
+
393
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
394
+ RD_KAFKA_RESP_ERR_NO_ERROR,
395
+ "Failed to create mock topic");
396
+
397
+ consumer = new_share_consumer(ctx.bootstraps, "sg-neg-empty");
398
+ subscribe_topics(consumer, &topic, 1);
399
+ consumed = test_share_consume_msgs(consumer, 1, 5, 500, NULL, 0);
400
+
401
+ test_share_consumer_close(consumer);
402
+ test_share_destroy(consumer);
403
+ test_ctx_destroy(&ctx);
404
+
405
+ TEST_ASSERT(consumed == 0, "Expected 0 consumed, got %d", consumed);
406
+ SUB_TEST_PASS();
407
+ }
408
+
409
+ /**
410
+ * @brief Verify that ShareFetch rejects requests from an unregistered member
411
+ * (SHARE_SESSION_NOT_FOUND), and that after the member re-joins it can
412
+ * consume again.
413
+ *
414
+ * Phase 1: Consumer joins normally via SGHB -> consumes messages OK.
415
+ * Phase 2: Push SGHB errors -> heartbeats fail -> member expires -> broker
416
+ * rejects ShareFetch with SHARE_SESSION_NOT_FOUND.
417
+ * Phase 3: SGHB errors drain -> member re-joins -> consumes again.
418
+ */
419
+ static void do_test_member_validation(void) {
420
+ const char *topic = "kip932_member_validation";
421
+ const int msgcnt = 4;
422
+ test_ctx_t ctx;
423
+ rd_kafka_share_t *consumer;
424
+ int consumed_p1, consumed_p3;
425
+
426
+ SUB_TEST();
427
+ ctx = test_ctx_new();
428
+
429
+ /* Short session timeout so the member is evicted quickly once
430
+ * heartbeats stop succeeding. */
431
+ rd_kafka_mock_sharegroup_set_session_timeout(ctx.mcluster, 500);
432
+
433
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
434
+ RD_KAFKA_RESP_ERR_NO_ERROR,
435
+ "Failed to create mock topic");
436
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
437
+ msgcnt);
438
+
439
+ consumer = new_share_consumer(ctx.bootstraps, "sg-member-val");
440
+ subscribe_topics(consumer, &topic, 1);
441
+
442
+ /* Phase 1: Consume normally -- member is registered via SGHB. */
443
+ consumed_p1 = test_share_consume_msgs(consumer, 2, 30, 500, NULL, 0);
444
+ TEST_SAY("member_validation: phase1 consumed %d/2\n", consumed_p1);
445
+
446
+ /* Phase 2: Block SGHB so heartbeats fail.
447
+ * Push enough errors to cover the window while we wait for the
448
+ * member to be evicted. */
449
+ rd_kafka_mock_push_request_errors(
450
+ ctx.mcluster, RD_KAFKAP_ShareGroupHeartbeat, 20,
451
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
452
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
453
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
454
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
455
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
456
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
457
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
458
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
459
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
460
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
461
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
462
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
463
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
464
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
465
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
466
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
467
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
468
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
469
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE,
470
+ RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE);
471
+
472
+ /* Wait for the member to be evicted (500ms session timeout + margin).
473
+ */
474
+ rd_usleep(1500 * 1000, 0);
475
+
476
+ /* Phase 3: SGHB errors will eventually drain. Once a SGHB
477
+ * succeeds, the member re-joins and the remaining records
478
+ * become fetchable again. */
479
+ consumed_p3 = test_share_consume_msgs(consumer, 2, 50, 500, NULL, 0);
480
+ TEST_SAY("member_validation: phase3 consumed %d/2\n", consumed_p3);
481
+
482
+ test_share_consumer_close(consumer);
483
+ test_share_destroy(consumer);
484
+ test_ctx_destroy(&ctx);
485
+
486
+ TEST_ASSERT(consumed_p1 >= 2 && (consumed_p1 + consumed_p3) >= msgcnt,
487
+ "Expected at least 2+2, got %d+%d", consumed_p1,
488
+ consumed_p3);
489
+ SUB_TEST_PASS();
490
+ }
491
+
492
+ static void do_test_sharefetch_session_expiry_rtt(void) {
493
+ const char *topic = "kip932_rtt_expiry";
494
+ test_ctx_t ctx;
495
+ rd_kafka_share_t *consumer;
496
+ int consumed;
497
+
498
+ SUB_TEST();
499
+ ctx = test_ctx_new();
500
+
501
+ /* Session timeout must be long enough for normal requests
502
+ * to complete, but short enough to expire during high RTT. */
503
+ rd_kafka_mock_sharegroup_set_session_timeout(ctx.mcluster, 1000);
504
+
505
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
506
+ RD_KAFKA_RESP_ERR_NO_ERROR,
507
+ "Failed to create mock topic");
508
+ /* Produce only 1 message so a single batch cannot over-consume
509
+ * past the requested count in test_share_consume_msgs(). */
510
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA, 1);
511
+
512
+ consumer = new_share_consumer(ctx.bootstraps, "sg-rtt-expiry");
513
+ subscribe_topics(consumer, &topic, 1);
514
+
515
+ /* Phase 1: consume one message with normal RTT (no injection). */
516
+ consumed = test_share_consume_msgs(consumer, 1, 20, 500, NULL, 0);
517
+ TEST_SAY("rtt_expiry: phase1 consumed %d/1\n", consumed);
518
+
519
+ /* Phase 2: inject RTT >> session timeout to force session expiry.
520
+ * All requests to broker 1 now take 3s, but the session
521
+ * expires after 1s of inactivity. The record from phase 1
522
+ * was acquired but not acked, so it becomes available again
523
+ * after the session expires. */
524
+ rd_kafka_mock_broker_set_rtt(ctx.mcluster, 1, 3000);
525
+ rd_usleep(2000 * 1000, 0); /* wait for session to expire */
526
+
527
+ /* Phase 3: clear RTT and let the consumer recover.
528
+ * The same record should be re-delivered after session expiry. */
529
+ rd_kafka_mock_broker_set_rtt(ctx.mcluster, 1, 0);
530
+ consumed += test_share_consume_msgs(consumer, 1, 30, 500, NULL, 0);
531
+ TEST_SAY("rtt_expiry: phase3 consumed %d/2 total\n", consumed);
532
+
533
+ test_share_consumer_close(consumer);
534
+ test_share_destroy(consumer);
535
+ test_ctx_destroy(&ctx);
536
+
537
+ TEST_ASSERT(consumed == 2, "Expected 2 consumed, got %d", consumed);
538
+ SUB_TEST_PASS();
539
+ }
540
+
541
+ static void do_test_forgotten_topics(void) {
542
+ const char *topic_a = "kip932_forgotten_a";
543
+ const char *topic_b = "kip932_forgotten_b";
544
+ const char *both[] = {topic_a, topic_b};
545
+ test_ctx_t ctx = test_ctx_new();
546
+ rd_kafka_share_t *consumer;
547
+ int consumed;
548
+
549
+ SUB_TEST_QUICK();
550
+
551
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic_a, 1, 1) ==
552
+ RD_KAFKA_RESP_ERR_NO_ERROR,
553
+ "Failed to create mock topic A");
554
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic_b, 1, 1) ==
555
+ RD_KAFKA_RESP_ERR_NO_ERROR,
556
+ "Failed to create mock topic B");
557
+
558
+ /* Produce 2 messages to each topic */
559
+ test_produce_msgs_simple(ctx.producer, topic_a, RD_KAFKA_PARTITION_UA,
560
+ 2);
561
+ test_produce_msgs_simple(ctx.producer, topic_b, RD_KAFKA_PARTITION_UA,
562
+ 2);
563
+
564
+ /* Subscribe to both topics and consume all 4 messages */
565
+ consumer = new_share_consumer(ctx.bootstraps, "sg-forgotten");
566
+ subscribe_topics(consumer, both, 2);
567
+ consumed = test_share_consume_msgs(consumer, 4, 40, 500, NULL, 0);
568
+ TEST_SAY("forgotten_topics: consumed %d/4 from both topics\n",
569
+ consumed);
570
+
571
+ /* Re-subscribe to only topic_a (topic_b becomes forgotten) */
572
+ subscribe_topics(consumer, &topic_a, 1);
573
+
574
+ /* Produce 2 more messages to topic_a */
575
+ test_produce_msgs_simple(ctx.producer, topic_a, RD_KAFKA_PARTITION_UA,
576
+ 2);
577
+
578
+ /* Consume the 2 new messages -- only topic_a should deliver */
579
+ consumed += test_share_consume_msgs(consumer, 2, 30, 500, NULL, 0);
580
+ TEST_SAY("forgotten_topics: consumed %d/6 total after forget\n",
581
+ consumed);
582
+
583
+ test_share_consumer_close(consumer);
584
+ test_share_destroy(consumer);
585
+ test_ctx_destroy(&ctx);
586
+
587
+ /* We expect at least the 4 initial + 2 from topic_a = 6.
588
+ * Depending on timing the consumer may or may not have already
589
+ * received all messages from the first round, so we accept >= 4. */
590
+ TEST_ASSERT(consumed >= 4, "Expected at least 4 consumed, got %d",
591
+ consumed);
592
+ SUB_TEST_PASS();
593
+ }
594
+
595
+ /**
596
+ * @brief Produce messages one-at-a-time (each flush creates a separate
597
+ * msgset on the mock partition), then consume and verify all are
598
+ * received. This validates that the ShareFetch response includes
599
+ * records from *all* acquired msgsets, not just the first one.
600
+ */
601
+ static void do_test_multi_batch_consume(void) {
602
+ const char *topic = "kip932_multi_batch";
603
+ const int msgcnt = 5;
604
+ test_ctx_t ctx = test_ctx_new();
605
+ rd_kafka_share_t *consumer;
606
+ int consumed;
607
+
608
+ SUB_TEST_QUICK();
609
+
610
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
611
+ RD_KAFKA_RESP_ERR_NO_ERROR,
612
+ "Failed to create mock topic");
613
+
614
+ /* Produce each message individually with a flush in between,
615
+ * guaranteeing separate msgsets on the mock partition. */
616
+ for (int i = 0; i < msgcnt; i++) {
617
+ char payload[64];
618
+ snprintf(payload, sizeof(payload), "batch-%d", i);
619
+ TEST_ASSERT(rd_kafka_producev(
620
+ ctx.producer, RD_KAFKA_V_TOPIC(topic),
621
+ RD_KAFKA_V_VALUE(payload, strlen(payload)),
622
+ RD_KAFKA_V_MSGFLAGS(RD_KAFKA_MSG_F_COPY),
623
+ RD_KAFKA_V_END) == RD_KAFKA_RESP_ERR_NO_ERROR,
624
+ "Produce failed");
625
+ rd_kafka_flush(ctx.producer, 5000);
626
+ }
627
+
628
+ consumer = new_share_consumer(ctx.bootstraps, "sg-multi-batch");
629
+ subscribe_topics(consumer, &topic, 1);
630
+ consumed = test_share_consume_msgs(consumer, msgcnt, 50, 500, NULL, 0);
631
+ TEST_SAY("multi_batch: consumed %d/%d\n", consumed, msgcnt);
632
+
633
+ test_share_consumer_close(consumer);
634
+ test_share_destroy(consumer);
635
+ test_ctx_destroy(&ctx);
636
+
637
+ TEST_ASSERT(consumed == msgcnt, "Expected %d consumed, got %d", msgcnt,
638
+ consumed);
639
+ SUB_TEST_PASS();
640
+ }
641
+
642
+ /**
643
+ * @brief Verify that max_delivery_attempts causes records to be archived
644
+ * after the limit is exceeded. Consumer A acquires all records, then
645
+ * its session times out (releasing locks). Consumer B acquires them
646
+ * again, and its session also times out. After the delivery limit is
647
+ * exhausted, Consumer C should see 0 available records.
648
+ */
649
+ static void do_test_max_delivery_attempts(void) {
650
+ const char *topic = "kip932_max_delivery";
651
+ const int msgcnt = 3;
652
+ test_ctx_t ctx;
653
+ rd_kafka_share_t *consumer;
654
+ int consumed_a, consumed_b, consumed_c;
655
+
656
+ SUB_TEST();
657
+ ctx = test_ctx_new();
658
+
659
+ /* Set max delivery attempts to 2 and a short session timeout
660
+ * so locks expire quickly after consumer destruction. */
661
+ rd_kafka_mock_sharegroup_set_max_delivery_attempts(ctx.mcluster, 2);
662
+ rd_kafka_mock_sharegroup_set_session_timeout(ctx.mcluster, 500);
663
+
664
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
665
+ RD_KAFKA_RESP_ERR_NO_ERROR,
666
+ "Failed to create mock topic");
667
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
668
+ msgcnt);
669
+
670
+ /* Delivery 1: Consumer A acquires and "crashes" (no ack). */
671
+ consumer = new_share_consumer(ctx.bootstraps, "sg-max-delivery");
672
+ subscribe_topics(consumer, &topic, 1);
673
+ consumed_a =
674
+ test_share_consume_msgs(consumer, msgcnt, 50, 500, NULL, 0);
675
+ TEST_SAY("max_delivery: A consumed %d/%d (delivery 1)\n", consumed_a,
676
+ msgcnt);
677
+ test_share_destroy(consumer);
678
+ rd_usleep(1500 * 1000, 0); /* wait for lock expiry */
679
+
680
+ /* Delivery 2: Consumer B acquires same records again (delivery_count
681
+ * reaches 2 = limit) and "crashes". */
682
+ consumer = new_share_consumer(ctx.bootstraps, "sg-max-delivery");
683
+ subscribe_topics(consumer, &topic, 1);
684
+ consumed_b =
685
+ test_share_consume_msgs(consumer, msgcnt, 50, 500, NULL, 0);
686
+ TEST_SAY("max_delivery: B consumed %d/%d (delivery 2)\n", consumed_b,
687
+ msgcnt);
688
+ test_share_destroy(consumer);
689
+ rd_usleep(1500 * 1000, 0); /* wait for lock expiry */
690
+
691
+ /* Delivery 3 attempt: Consumer C should get 0 records because
692
+ * all records have been archived (delivery_count >= max). */
693
+ consumer = new_share_consumer(ctx.bootstraps, "sg-max-delivery");
694
+ subscribe_topics(consumer, &topic, 1);
695
+ consumed_c = test_share_consume_msgs(consumer, 1, 10, 500, NULL, 0);
696
+ TEST_SAY("max_delivery: C consumed %d/0 (should be archived)\n",
697
+ consumed_c);
698
+
699
+ test_share_consumer_close(consumer);
700
+ test_share_destroy(consumer);
701
+ test_ctx_destroy(&ctx);
702
+
703
+ TEST_ASSERT(consumed_a == msgcnt && consumed_b == msgcnt &&
704
+ consumed_c == 0,
705
+ "Expected A=%d B=%d C=0, got A=%d B=%d C=%d", msgcnt,
706
+ msgcnt, consumed_a, consumed_b, consumed_c);
707
+ SUB_TEST_PASS();
708
+ }
709
+
710
+ /**
711
+ * @brief Verify that record_lock_duration_ms controls how long acquired
712
+ * records stay locked, independently of session_timeout_ms.
713
+ * Sets a short lock duration (300ms) with a longer session timeout
714
+ * (10s). Consumer A acquires records and "crashes". After the short
715
+ * lock duration expires, Consumer B should be able to acquire them
716
+ * even though A's session hasn't timed out yet.
717
+ */
718
+ static void do_test_record_lock_duration(void) {
719
+ const char *topic = "kip932_lock_duration";
720
+ const int msgcnt = 3;
721
+ test_ctx_t ctx;
722
+ rd_kafka_share_t *consumer;
723
+ int consumed_a, consumed_b;
724
+
725
+ SUB_TEST();
726
+ ctx = test_ctx_new();
727
+
728
+ /* Long session timeout, short record lock duration. */
729
+ rd_kafka_mock_sharegroup_set_session_timeout(ctx.mcluster, 10000);
730
+ rd_kafka_mock_sharegroup_set_record_lock_duration(ctx.mcluster, 300);
731
+
732
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
733
+ RD_KAFKA_RESP_ERR_NO_ERROR,
734
+ "Failed to create mock topic");
735
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
736
+ msgcnt);
737
+
738
+ /* Consumer A acquires records, then crashes (no close). */
739
+ consumer = new_share_consumer(ctx.bootstraps, "sg-lock-duration");
740
+ subscribe_topics(consumer, &topic, 1);
741
+ consumed_a =
742
+ test_share_consume_msgs(consumer, msgcnt, 50, 500, NULL, 0);
743
+ TEST_SAY("lock_duration: A consumed %d/%d\n", consumed_a, msgcnt);
744
+ test_share_destroy(consumer);
745
+
746
+ /* Wait for record lock to expire (300ms + margin).
747
+ * test_share_destroy sends SGHB LEAVE which releases
748
+ * locks immediately, but we still need to wait for the
749
+ * client's internal rejoin cycle to settle. */
750
+ rd_usleep(1000 * 1000, 0);
751
+
752
+ /* Consumer B should get the records because locks have expired
753
+ * even though A's session is still technically alive.
754
+ * Use higher max_attempts to account for the mock broker's
755
+ * SGHB LEAVE->rejoin cycle delay. */
756
+ consumer = new_share_consumer(ctx.bootstraps, "sg-lock-duration");
757
+ subscribe_topics(consumer, &topic, 1);
758
+ consumed_b =
759
+ test_share_consume_msgs(consumer, msgcnt, 100, 500, NULL, 0);
760
+ TEST_SAY("lock_duration: B consumed %d/%d\n", consumed_b, msgcnt);
761
+
762
+ test_share_consumer_close(consumer);
763
+ test_share_destroy(consumer);
764
+ test_ctx_destroy(&ctx);
765
+
766
+ TEST_ASSERT(consumed_a == msgcnt && consumed_b == msgcnt,
767
+ "Expected A=%d B=%d, got A=%d B=%d", msgcnt, msgcnt,
768
+ consumed_a, consumed_b);
769
+ SUB_TEST_PASS();
770
+ }
771
+
772
+ /**
773
+ * @brief Multi-consumer lock expiry test.
774
+ *
775
+ * Consumer A acquires records, then crashes (destroyed without close).
776
+ * After the lock expiry timeout, consumer B should be able to pick up
777
+ * the same records because the proactive lock-expiry scan releases them.
778
+ */
779
+ static void do_test_multi_consumer_lock_expiry(void) {
780
+ const char *topic = "kip932_multi_consumer_lock";
781
+ const int msgcnt = 3;
782
+ test_ctx_t ctx;
783
+ rd_kafka_share_t *consumer_a, *consumer_b;
784
+ int consumed_a, consumed_b;
785
+
786
+ SUB_TEST();
787
+ ctx = test_ctx_new();
788
+
789
+ /* Use a short session/lock timeout so the test runs quickly. */
790
+ rd_kafka_mock_sharegroup_set_session_timeout(ctx.mcluster, 500);
791
+
792
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
793
+ RD_KAFKA_RESP_ERR_NO_ERROR,
794
+ "Failed to create mock topic");
795
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
796
+ msgcnt);
797
+
798
+ /* Consumer A: subscribe and consume all records (acquires locks). */
799
+ consumer_a =
800
+ new_share_consumer(ctx.bootstraps, "sg-multi-consumer-lock");
801
+ subscribe_topics(consumer_a, &topic, 1);
802
+ consumed_a =
803
+ test_share_consume_msgs(consumer_a, msgcnt, 50, 500, NULL, 0);
804
+ TEST_SAY("multi_consumer: A consumed %d/%d\n", consumed_a, msgcnt);
805
+
806
+ /* Simulate crash: destroy consumer A without calling close.
807
+ * The session will time out and the proactive lock-expiry
808
+ * timer will release A's locks. */
809
+ test_share_destroy(consumer_a);
810
+
811
+ /* Wait for locks to expire (session_timeout=500ms, add margin). */
812
+ rd_usleep(1500 * 1000, 0);
813
+
814
+ /* Consumer B: joins the same share group, should get the same
815
+ * records once the locks have been released.
816
+ * Use higher max_attempts to account for the mock broker's
817
+ * SGHB LEAVE->rejoin cycle delay. */
818
+ consumer_b =
819
+ new_share_consumer(ctx.bootstraps, "sg-multi-consumer-lock");
820
+ subscribe_topics(consumer_b, &topic, 1);
821
+ consumed_b =
822
+ test_share_consume_msgs(consumer_b, msgcnt, 100, 500, NULL, 0);
823
+ TEST_SAY("multi_consumer: B consumed %d/%d\n", consumed_b, msgcnt);
824
+
825
+ test_share_consumer_close(consumer_b);
826
+ test_share_destroy(consumer_b);
827
+ test_ctx_destroy(&ctx);
828
+
829
+ TEST_ASSERT(consumed_a == msgcnt && consumed_b == msgcnt,
830
+ "Expected A=%d B=%d, got A=%d B=%d", msgcnt, msgcnt,
831
+ consumed_a, consumed_b);
832
+ SUB_TEST_PASS();
833
+ }
834
+
835
+
836
+ /*
837
+ * TODO KIP-932: The functions below inject errors using
838
+ * rd_kafka_mock_push_request_errors(), which only sets the top-level
839
+ * ShareFetch error code. The error codes tested here are per-partition
840
+ * errors that the broker never emits at the top level. Re-enable
841
+ * once partition-level mock error injection is available.
842
+ *
843
+ static void do_test_sharefetch_fetch_error(rd_kafka_resp_err_t err) {
844
+ const char *topic = "kip932_fetch_error";
845
+ test_ctx_t ctx = test_ctx_new();
846
+ rd_kafka_share_t *consumer;
847
+ rd_kafka_messages_t *batch = NULL;
848
+ size_t rcvd = 0;
849
+ int consumed = 0;
850
+ size_t i;
851
+
852
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
853
+ RD_KAFKA_RESP_ERR_NO_ERROR,
854
+ "Failed to create mock topic");
855
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA, 3);
856
+
857
+ rd_kafka_mock_push_request_errors(ctx.mcluster, RD_KAFKAP_ShareFetch, 1,
858
+ err);
859
+
860
+ consumer = new_share_consumer(ctx.bootstraps, "sg-fetch-error");
861
+ subscribe_topics(consumer, &topic, 1);
862
+
863
+ rd_kafka_share_poll(consumer, 2000, &batch);
864
+ rcvd = rd_kafka_messages_count(batch);
865
+ for (i = 0; i < rcvd; i++) {
866
+ rd_kafka_message_t *msg = rd_kafka_messages_get(batch, i);
867
+ if (!msg->err)
868
+ consumed++;
869
+ }
870
+ rd_kafka_messages_destroy(batch);
871
+ batch = NULL;
872
+
873
+ TEST_SAY("fetch_error(%s): consumed=%d rcvd=%zu\n",
874
+ rd_kafka_err2name(err), consumed, rcvd);
875
+
876
+ test_share_consumer_close(consumer);
877
+ test_share_destroy(consumer);
878
+ test_ctx_destroy(&ctx);
879
+
880
+ TEST_ASSERT(consumed == 0, "Expected 0 consumed with %s, got %d",
881
+ rd_kafka_err2name(err), consumed);
882
+ }
883
+
884
+ static void do_test_sharefetch_fetch_error_not_leader(void) {
885
+ SUB_TEST();
886
+ do_test_sharefetch_fetch_error(
887
+ RD_KAFKA_RESP_ERR_NOT_LEADER_OR_FOLLOWER);
888
+ SUB_TEST_PASS();
889
+ }
890
+
891
+ static void do_test_sharefetch_fetch_error_unknown_topic_or_part(void) {
892
+ SUB_TEST();
893
+ do_test_sharefetch_fetch_error(RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART);
894
+ SUB_TEST_PASS();
895
+ }
896
+
897
+ static void do_test_sharefetch_fetch_error_unknown_topic_id(void) {
898
+ SUB_TEST();
899
+ do_test_sharefetch_fetch_error(RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_ID);
900
+ SUB_TEST_PASS();
901
+ }
902
+
903
+ static void do_test_sharefetch_fetch_error_fenced_leader_epoch(void) {
904
+ SUB_TEST();
905
+ do_test_sharefetch_fetch_error(RD_KAFKA_RESP_ERR_FENCED_LEADER_EPOCH);
906
+ SUB_TEST_PASS();
907
+ }
908
+
909
+ static void do_test_sharefetch_fetch_error_unknown_leader_epoch(void) {
910
+ SUB_TEST();
911
+ do_test_sharefetch_fetch_error(RD_KAFKA_RESP_ERR_UNKNOWN_LEADER_EPOCH);
912
+ SUB_TEST_PASS();
913
+ }
914
+
915
+ static void do_test_sharefetch_topic_authorization_failed(void) {
916
+ SUB_TEST();
917
+ do_test_sharefetch_fetch_error(
918
+ RD_KAFKA_RESP_ERR_TOPIC_AUTHORIZATION_FAILED);
919
+ SUB_TEST_PASS();
920
+ }
921
+
922
+ static void do_test_sharefetch_corrupt_message(void) {
923
+ SUB_TEST();
924
+ do_test_sharefetch_fetch_error(RD_KAFKA_RESP_ERR_INVALID_MSG);
925
+ SUB_TEST_PASS();
926
+ }
927
+ */
928
+
929
+ /*
930
+ * TODO KIP-932: This test injects FENCED_LEADER_EPOCH using
931
+ * rd_kafka_mock_push_request_errors(), which only sets the top-level
932
+ * ShareFetch error code. FENCED_LEADER_EPOCH is a per-partition error
933
+ * that the broker never emits at the top level; the top-level handler
934
+ * treats it as transient and retries, so the consumer receives records.
935
+ * Re-enable once partition-level mock error injection is available.
936
+ *
937
+ static void do_test_sharefetch_fetch_disconnected(void) {
938
+ const char *topic = "kip932_disconnect";
939
+ test_ctx_t ctx;
940
+ rd_kafka_share_t *consumer;
941
+ rd_kafka_messages_t *batch = NULL;
942
+ size_t rcvd = 0;
943
+ int consumed = 0;
944
+ size_t i;
945
+
946
+ SUB_TEST();
947
+ ctx = test_ctx_new();
948
+
949
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
950
+ RD_KAFKA_RESP_ERR_NO_ERROR,
951
+ "Failed to create mock topic");
952
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA, 3);
953
+
954
+ rd_kafka_mock_push_request_errors(
955
+ ctx.mcluster, RD_KAFKAP_ShareFetch, 1,
956
+ RD_KAFKA_RESP_ERR_FENCED_LEADER_EPOCH);
957
+
958
+ consumer = new_share_consumer(ctx.bootstraps, "sg-disconnect");
959
+ subscribe_topics(consumer, &topic, 1);
960
+
961
+ rd_kafka_share_poll(consumer, 2000, &batch);
962
+ rcvd = rd_kafka_messages_count(batch);
963
+ for (i = 0; i < rcvd; i++) {
964
+ rd_kafka_message_t *msg = rd_kafka_messages_get(batch, i);
965
+ if (!msg->err)
966
+ consumed++;
967
+ }
968
+ rd_kafka_messages_destroy(batch);
969
+ batch = NULL;
970
+
971
+ TEST_SAY("fetch_disconnected: consumed=%d rcvd=%zu\n", consumed, rcvd);
972
+
973
+ test_share_consumer_close(consumer);
974
+ test_share_destroy(consumer);
975
+ test_ctx_destroy(&ctx);
976
+
977
+ TEST_ASSERT(consumed == 0, "Expected 0 consumed on disconnect, got %d",
978
+ consumed);
979
+ SUB_TEST_PASS();
980
+ }
981
+ */
982
+
983
+ /**
984
+ * @brief Fetch records and close implicitly (no explicit ack).
985
+ *
986
+ * Verifies that a consumer can fetch records and then close successfully.
987
+ * The close sends ShareAcknowledge with epoch=-1 to release the session.
988
+ */
989
+ static void do_test_sharefetch_fetch_and_close_implicit(void) {
990
+ const char *topic = "kip932_fetch_close";
991
+ const int msgcnt = 2;
992
+ test_ctx_t ctx;
993
+ rd_kafka_share_t *consumer;
994
+ int consumed;
995
+
996
+ SUB_TEST();
997
+ ctx = test_ctx_new();
998
+
999
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
1000
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1001
+ "Failed to create mock topic");
1002
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
1003
+ msgcnt);
1004
+
1005
+ consumer = new_share_consumer(ctx.bootstraps, "sg-fetch-close");
1006
+ subscribe_topics(consumer, &topic, 1);
1007
+
1008
+ /* Fetch records */
1009
+ consumed = test_share_consume_msgs(consumer, msgcnt, 50, 500, NULL, 0);
1010
+ TEST_SAY("fetch_and_close: consumed %d/%d\n", consumed, msgcnt);
1011
+
1012
+ /* Close — sends ShareAcknowledge/ShareFetch with epoch=-1 */
1013
+ test_share_consumer_close(consumer);
1014
+ test_share_destroy(consumer);
1015
+ test_ctx_destroy(&ctx);
1016
+
1017
+ TEST_ASSERT(consumed == msgcnt, "Expected %d consumed, got %d", msgcnt,
1018
+ consumed);
1019
+ SUB_TEST_PASS();
1020
+ }
1021
+
1022
+ /**
1023
+ * @brief Test that SHARE_SESSION_LIMIT_REACHED is returned when the
1024
+ * session cache is full.
1025
+ *
1026
+ * Set max_fetch_sessions=1, open a session with consumer 1,
1027
+ * then attempt to open a second session with consumer 2.
1028
+ * Consumer 2 should fail to consume any records because every
1029
+ * ShareFetch epoch=0 attempt gets SHARE_SESSION_LIMIT_REACHED.
1030
+ */
1031
+ static void do_test_session_limit_reached(void) {
1032
+ const char *topic = "kip932_session_limit";
1033
+ const int msgcnt = 5;
1034
+ test_ctx_t ctx;
1035
+ rd_kafka_share_t *consumer1, *consumer2;
1036
+ int consumed1, consumed2;
1037
+
1038
+ SUB_TEST_QUICK();
1039
+
1040
+ ctx = test_ctx_new();
1041
+
1042
+ /* Limit to 1 session */
1043
+ rd_kafka_mock_sharegroup_set_max_fetch_sessions(ctx.mcluster, 1);
1044
+
1045
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
1046
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1047
+ "Failed to create mock topic");
1048
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
1049
+ msgcnt);
1050
+
1051
+ /* Consumer 1 opens a session successfully */
1052
+ consumer1 = new_share_consumer(ctx.bootstraps, "sg-session-limit");
1053
+ subscribe_topics(consumer1, &topic, 1);
1054
+ consumed1 =
1055
+ test_share_consume_msgs(consumer1, msgcnt, 30, 500, NULL, 0);
1056
+ TEST_ASSERT(consumed1 == msgcnt,
1057
+ "Consumer 1: expected %d consumed, got %d", msgcnt,
1058
+ consumed1);
1059
+
1060
+ /* Consumer 2 tries to open a session — cache is full */
1061
+ consumer2 = new_share_consumer(ctx.bootstraps, "sg-session-limit");
1062
+ subscribe_topics(consumer2, &topic, 1);
1063
+ consumed2 = test_share_consume_msgs(consumer2, 1, 5, 500, NULL, 0);
1064
+ TEST_ASSERT(consumed2 == 0,
1065
+ "Consumer 2: expected 0 consumed (session limit), got %d",
1066
+ consumed2);
1067
+
1068
+ rd_kafka_share_consumer_close(consumer1);
1069
+ rd_kafka_share_destroy(consumer1);
1070
+ rd_kafka_share_consumer_close(consumer2);
1071
+ rd_kafka_share_destroy(consumer2);
1072
+ test_ctx_destroy(&ctx);
1073
+
1074
+ SUB_TEST_PASS();
1075
+ }
1076
+
1077
+ /**
1078
+ * @brief Test that the session limit is enforced per broker, not globally.
1079
+ *
1080
+ * Create two single-partition topics, each with its leader on a
1081
+ * different broker. Set max_fetch_sessions=1 (per broker).
1082
+ *
1083
+ * Consumer 1 subscribes to topic_a (broker 1) and consumer 2 subscribes
1084
+ * to topic_b (broker 2). Both should succeed because each broker only
1085
+ * has 1 session despite there being 2 sessions globally.
1086
+ *
1087
+ * Then consumer 3 subscribes to topic_a — this should fail because
1088
+ * broker 1 already has 1 session (from consumer 1).
1089
+ */
1090
+ static void do_test_session_limit_per_broker(void) {
1091
+ const char *topic_a = "kip932_session_limit_pb_a";
1092
+ const char *topic_b = "kip932_session_limit_pb_b";
1093
+ const int msgcnt = 5;
1094
+ test_ctx_t ctx;
1095
+ rd_kafka_share_t *consumer1, *consumer2, *consumer3;
1096
+ int consumed1, consumed2, consumed3;
1097
+
1098
+ SUB_TEST();
1099
+
1100
+ ctx = test_ctx_new();
1101
+
1102
+ /* Create two topics, each with 1 partition on a different broker. */
1103
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic_a, 1, 1) ==
1104
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1105
+ "Failed to create mock topic A");
1106
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic_b, 1, 1) ==
1107
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1108
+ "Failed to create mock topic B");
1109
+ rd_kafka_mock_partition_set_leader(ctx.mcluster, topic_a, 0, 1);
1110
+ rd_kafka_mock_partition_set_leader(ctx.mcluster, topic_b, 0, 2);
1111
+
1112
+ test_produce_msgs_simple(ctx.producer, topic_a, RD_KAFKA_PARTITION_UA,
1113
+ msgcnt);
1114
+ test_produce_msgs_simple(ctx.producer, topic_b, RD_KAFKA_PARTITION_UA,
1115
+ msgcnt);
1116
+
1117
+ /* Limit to 1 session per broker */
1118
+ rd_kafka_mock_sharegroup_set_max_fetch_sessions(ctx.mcluster, 1);
1119
+
1120
+ /* Consumer 1 subscribes to topic_a -> session on broker 1 */
1121
+ consumer1 = new_share_consumer(ctx.bootstraps, "sg-session-limit-pb");
1122
+ subscribe_topics(consumer1, &topic_a, 1);
1123
+ consumed1 =
1124
+ test_share_consume_msgs(consumer1, msgcnt, 30, 500, NULL, 0);
1125
+ TEST_ASSERT(consumed1 == msgcnt,
1126
+ "Consumer 1: expected %d consumed, got %d", msgcnt,
1127
+ consumed1);
1128
+
1129
+ /* Consumer 2 subscribes to topic_b -> session on broker 2.
1130
+ * If the limit were global, this would fail (2 sessions > limit 1).
1131
+ * Per-broker: broker 2 has 0 sessions, so it succeeds. */
1132
+ consumer2 = new_share_consumer(ctx.bootstraps, "sg-session-limit-pb");
1133
+ subscribe_topics(consumer2, &topic_b, 1);
1134
+ consumed2 =
1135
+ test_share_consume_msgs(consumer2, msgcnt, 30, 500, NULL, 0);
1136
+ TEST_ASSERT(consumed2 == msgcnt,
1137
+ "Consumer 2: expected %d consumed, got %d", msgcnt,
1138
+ consumed2);
1139
+
1140
+ /* Consumer 3 subscribes to topic_a -> broker 1 already has
1141
+ * 1 session (from consumer 1), so this should be rejected. */
1142
+ consumer3 = new_share_consumer(ctx.bootstraps, "sg-session-limit-pb");
1143
+ subscribe_topics(consumer3, &topic_a, 1);
1144
+ consumed3 = test_share_consume_msgs(consumer3, 1, 5, 500, NULL, 0);
1145
+ TEST_ASSERT(consumed3 == 0,
1146
+ "Consumer 3: expected 0 consumed (broker 1 at limit), "
1147
+ "got %d",
1148
+ consumed3);
1149
+
1150
+ rd_kafka_share_consumer_close(consumer1);
1151
+ rd_kafka_share_destroy(consumer1);
1152
+ rd_kafka_share_consumer_close(consumer2);
1153
+ rd_kafka_share_destroy(consumer2);
1154
+ rd_kafka_share_consumer_close(consumer3);
1155
+ rd_kafka_share_destroy(consumer3);
1156
+ test_ctx_destroy(&ctx);
1157
+
1158
+ SUB_TEST_PASS();
1159
+ }
1160
+
1161
+ /**
1162
+ * @brief Test that ShareFetch with epoch=0 and acks is rejected with
1163
+ * INVALID_REQUEST via the mock broker's injected error mechanism.
1164
+ *
1165
+ * Injects SHARE_SESSION_LIMIT_REACHED errors to force the client to
1166
+ * retry with epoch=0. The client never piggybacks acks on epoch=0
1167
+ * (that's a protocol violation), so this test validates that the mock
1168
+ * broker's error injection for SHARE_SESSION_LIMIT_REACHED works and
1169
+ * the client recovers when the error clears.
1170
+ */
1171
+ static void do_test_session_limit_recovery(void) {
1172
+ const char *topic = "kip932_session_limit_recovery";
1173
+ const int msgcnt = 5;
1174
+ test_ctx_t ctx = test_ctx_new();
1175
+ rd_kafka_share_t *consumer;
1176
+ int consumed;
1177
+
1178
+ SUB_TEST_QUICK();
1179
+
1180
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
1181
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1182
+ "Failed to create mock topic");
1183
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
1184
+ msgcnt);
1185
+
1186
+ /* Push 3 SHARE_SESSION_LIMIT_REACHED errors, then let it succeed */
1187
+ rd_kafka_mock_push_request_errors(
1188
+ ctx.mcluster, RD_KAFKAP_ShareFetch, 3,
1189
+ RD_KAFKA_RESP_ERR_SHARE_SESSION_LIMIT_REACHED,
1190
+ RD_KAFKA_RESP_ERR_SHARE_SESSION_LIMIT_REACHED,
1191
+ RD_KAFKA_RESP_ERR_SHARE_SESSION_LIMIT_REACHED);
1192
+
1193
+ consumer = new_share_consumer(ctx.bootstraps, "sg-session-recovery");
1194
+ subscribe_topics(consumer, &topic, 1);
1195
+ consumed = test_share_consume_msgs(consumer, msgcnt, 30, 500, NULL, 0);
1196
+
1197
+ rd_kafka_share_consumer_close(consumer);
1198
+ rd_kafka_share_destroy(consumer);
1199
+ test_ctx_destroy(&ctx);
1200
+
1201
+ TEST_ASSERT(consumed == msgcnt,
1202
+ "Expected %d consumed after recovery, got %d", msgcnt,
1203
+ consumed);
1204
+
1205
+ SUB_TEST_PASS();
1206
+ }
1207
+
1208
+ /**
1209
+ * @brief Test that max_record_locks limits the number of in-flight
1210
+ * records per share-partition.
1211
+ *
1212
+ * Produce 10 records, set max_record_locks=3. Consumer A should get
1213
+ * only 3 records on the first fetch round (the rest are blocked by
1214
+ * the lock limit). After A acks (via second poll) and closes,
1215
+ * consumer B should get the next batch. Total consumed across both
1216
+ * should be 10.
1217
+ */
1218
+ static void do_test_max_record_locks(void) {
1219
+ const char *topic = "kip932_max_record_locks";
1220
+ const int msgcnt = 10;
1221
+ test_ctx_t ctx;
1222
+ rd_kafka_share_t *consumer;
1223
+ int total_consumed = 0;
1224
+ int rounds = 0;
1225
+
1226
+ SUB_TEST_QUICK();
1227
+ ctx = test_ctx_new();
1228
+
1229
+ rd_kafka_mock_sharegroup_set_max_record_locks(ctx.mcluster, 3);
1230
+
1231
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
1232
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1233
+ "Failed to create mock topic");
1234
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
1235
+ msgcnt);
1236
+
1237
+ /* Consume in rounds. Each round can get at most 3 records
1238
+ * (the lock limit). The implicit ack from the next poll
1239
+ * frees the locks for the next batch. */
1240
+ consumer = new_share_consumer(ctx.bootstraps, "sg-max-locks");
1241
+ subscribe_topics(consumer, &topic, 1);
1242
+
1243
+ while (total_consumed < msgcnt && rounds < 20) {
1244
+ int got =
1245
+ test_share_consume_msgs(consumer, 3, 10, 500, NULL, 0);
1246
+ if (got == 0)
1247
+ break;
1248
+ total_consumed += got;
1249
+ rounds++;
1250
+ TEST_SAY(
1251
+ "max_record_locks: round %d consumed %d (total %d/%d)\n",
1252
+ rounds, got, total_consumed, msgcnt);
1253
+ }
1254
+
1255
+ rd_kafka_share_consumer_close(consumer);
1256
+ rd_kafka_share_destroy(consumer);
1257
+ test_ctx_destroy(&ctx);
1258
+
1259
+ TEST_ASSERT(total_consumed == msgcnt,
1260
+ "Expected %d total consumed, got %d", msgcnt,
1261
+ total_consumed);
1262
+ TEST_ASSERT(rounds > 1,
1263
+ "Expected multiple rounds (lock limit=3, msgs=10), "
1264
+ "got %d rounds",
1265
+ rounds);
1266
+
1267
+ SUB_TEST_PASS();
1268
+ }
1269
+
1270
+ /**
1271
+ * @brief Verify that max_record_locks counts only ACQUIRED records,
1272
+ * not total inflight records (which includes ARCHIVED).
1273
+ *
1274
+ * Produce 6 records. Set max_record_locks=3, max_delivery_attempts=1.
1275
+ *
1276
+ * Consumer A acquires records 0-2 (lock limit), then is destroyed
1277
+ * WITHOUT close (no implicit ack). The connection close releases
1278
+ * the locks; with max_delivery_attempts=1 the released records
1279
+ * transition directly to ARCHIVED (delivery_count >= limit).
1280
+ *
1281
+ * At this point:
1282
+ * - Records 0-2: ARCHIVED, still in the inflight list
1283
+ * - SPSO = 0 (never advanced — ARCHIVED != ACKNOWLEDGED)
1284
+ * - inflight_cnt = 3, acquired_cnt = 0
1285
+ *
1286
+ * Consumer B subscribes. With the correct check (acquired_cnt),
1287
+ * records 3-5 are acquirable because only 0 records are ACQUIRED.
1288
+ * With an inflight_cnt-based check, the limit would block all
1289
+ * acquisition (inflight_cnt=3 >= max_record_locks=3).
1290
+ */
1291
+ static void do_test_max_record_locks_acquired_only(void) {
1292
+ const char *topic = "kip932_max_locks_acquired_only";
1293
+ const int msgcnt = 6;
1294
+ test_ctx_t ctx;
1295
+ rd_kafka_share_t *consumer;
1296
+ int consumed_a, consumed_b;
1297
+
1298
+ SUB_TEST();
1299
+ ctx = test_ctx_new();
1300
+
1301
+ rd_kafka_mock_sharegroup_set_max_record_locks(ctx.mcluster, 3);
1302
+ rd_kafka_mock_sharegroup_set_max_delivery_attempts(ctx.mcluster, 1);
1303
+ rd_kafka_mock_sharegroup_set_session_timeout(ctx.mcluster, 500);
1304
+
1305
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
1306
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1307
+ "Failed to create mock topic");
1308
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
1309
+ msgcnt);
1310
+
1311
+ /* Consumer A: acquire first batch (3 records due to lock limit). */
1312
+ consumer = new_share_consumer(ctx.bootstraps, "sg-acq-only");
1313
+ subscribe_topics(consumer, &topic, 1);
1314
+ consumed_a = test_share_consume_msgs(consumer, 3, 30, 500, NULL, 0);
1315
+ TEST_SAY("acquired_only: A consumed %d/3\n", consumed_a);
1316
+
1317
+ /* Destroy WITHOUT close — avoids implicit ack.
1318
+ * The connection close releases locks; with max_delivery_attempts=1
1319
+ * the released records transition to ARCHIVED (not AVAILABLE).
1320
+ * SPSO stays at 0 because ARCHIVED != ACKNOWLEDGED.
1321
+ * inflight_cnt stays 3, but acquired_cnt drops to 0. */
1322
+ rd_kafka_share_destroy(consumer);
1323
+ rd_usleep(1500 * 1000, 0); /* wait for connection close */
1324
+
1325
+ /* Consumer B subscribes. The share-partition now has:
1326
+ * - Records 0-2: ARCHIVED (inflight_cnt=3, acquired_cnt=0)
1327
+ * - Records 3-5: not yet in inflight list
1328
+ * With acquired_cnt check, Consumer B acquires records 3-5.
1329
+ * With inflight_cnt check, the limit would block acquisition. */
1330
+ consumer = new_share_consumer(ctx.bootstraps, "sg-acq-only");
1331
+ subscribe_topics(consumer, &topic, 1);
1332
+ consumed_b = test_share_consume_msgs(consumer, 3, 30, 500, NULL, 0);
1333
+ TEST_SAY("acquired_only: B consumed %d/3\n", consumed_b);
1334
+
1335
+ rd_kafka_share_consumer_close(consumer);
1336
+ rd_kafka_share_destroy(consumer);
1337
+ test_ctx_destroy(&ctx);
1338
+
1339
+ TEST_ASSERT(consumed_a == 3, "A: expected 3, got %d", consumed_a);
1340
+ TEST_ASSERT(consumed_b == 3,
1341
+ "B: expected 3 (max_record_locks should count only "
1342
+ "ACQUIRED, not ARCHIVED), got %d",
1343
+ consumed_b);
1344
+
1345
+ SUB_TEST_PASS();
1346
+ }
1347
+
1348
+ /**
1349
+ * @brief Test that SPSO advances when log retention deletes records
1350
+ * below the current SPSO.
1351
+ *
1352
+ * Produce 10 records (offsets 0-9). Consumer A acquires 0-4.
1353
+ * Then delete records before offset 5 (simulating log retention).
1354
+ * Consumer A closes (acks 0-4, but they're already archived by
1355
+ * retention). Consumer B should get records 5-9 only — SPSO
1356
+ * was advanced to 5 by the retention, and in-flight records
1357
+ * below 5 were archived.
1358
+ */
1359
+ static void do_test_spso_advances_on_log_retention(void) {
1360
+ const char *topic = "kip932_log_retention_spso";
1361
+ const int msgcnt = 10;
1362
+ test_ctx_t ctx;
1363
+ rd_kafka_share_t *consumer;
1364
+ int consumed_a, consumed_b;
1365
+
1366
+ SUB_TEST_QUICK();
1367
+ ctx = test_ctx_new();
1368
+
1369
+ /* Limit to 5 records per fetch so A gets only 0-4. */
1370
+ rd_kafka_mock_sharegroup_set_max_record_locks(ctx.mcluster, 5);
1371
+
1372
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
1373
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1374
+ "Failed to create mock topic");
1375
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
1376
+ msgcnt);
1377
+
1378
+ /* Consumer A acquires records 0-4. */
1379
+ consumer = new_share_consumer(ctx.bootstraps, "sg-log-retention");
1380
+ subscribe_topics(consumer, &topic, 1);
1381
+ consumed_a = test_share_consume_msgs(consumer, 5, 30, 500, NULL, 0);
1382
+ TEST_SAY("log_retention: A consumed %d/5\n", consumed_a);
1383
+
1384
+ rd_kafka_share_consumer_close(consumer);
1385
+ rd_kafka_share_destroy(consumer);
1386
+
1387
+ /* Simulate log retention: delete records before offset 5. */
1388
+ TEST_ASSERT(
1389
+ rd_kafka_mock_partition_delete_records(ctx.mcluster, topic, 0, 5) ==
1390
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1391
+ "Failed to delete records");
1392
+
1393
+ /* Remove lock limit. */
1394
+ rd_kafka_mock_sharegroup_set_max_record_locks(ctx.mcluster, 0);
1395
+
1396
+ /* Consumer B should get records 5-9 (SPSO advanced to 5). */
1397
+ consumer = new_share_consumer(ctx.bootstraps, "sg-log-retention");
1398
+ subscribe_topics(consumer, &topic, 1);
1399
+ consumed_b = test_share_consume_msgs(consumer, 5, 30, 500, NULL, 0);
1400
+ TEST_SAY("log_retention: B consumed %d/5\n", consumed_b);
1401
+
1402
+ rd_kafka_share_consumer_close(consumer);
1403
+ rd_kafka_share_destroy(consumer);
1404
+ test_ctx_destroy(&ctx);
1405
+
1406
+ TEST_ASSERT(consumed_a == 5, "A: expected 5 consumed, got %d",
1407
+ consumed_a);
1408
+ TEST_ASSERT(consumed_b == 5, "B: expected 5 consumed, got %d",
1409
+ consumed_b);
1410
+
1411
+ SUB_TEST_PASS();
1412
+ }
1413
+
1414
+ /**
1415
+ * @brief Test that auto.offset.reset=latest (the default)
1416
+ * causes the consumer to skip records produced before subscription.
1417
+ *
1418
+ * Produce 5 records, then subscribe with auto.offset.reset=latest.
1419
+ * Consumer should get 0 old records but should get new records
1420
+ * produced after subscription.
1421
+ */
1422
+ static void do_test_auto_offset_reset_latest(void) {
1423
+ const char *topic = "kip932_offset_reset_latest";
1424
+ const int msgcnt = 5;
1425
+ test_ctx_t ctx;
1426
+ rd_kafka_share_t *consumer;
1427
+ rd_kafka_conf_t *conf;
1428
+ char errstr[512];
1429
+ int consumed;
1430
+
1431
+ SUB_TEST_QUICK();
1432
+
1433
+ /* Create a fresh context — do NOT set auto_offset_reset=earliest
1434
+ * (the default is "latest"). */
1435
+ memset(&ctx, 0, sizeof(ctx));
1436
+ ctx.mcluster = test_mock_cluster_new(3, &ctx.bootstraps);
1437
+ TEST_ASSERT(rd_kafka_mock_set_apiversion(
1438
+ ctx.mcluster, RD_KAFKAP_ShareGroupHeartbeat, 1, 1) ==
1439
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1440
+ "Failed to enable ShareGroupHeartbeat");
1441
+ TEST_ASSERT(rd_kafka_mock_set_apiversion(ctx.mcluster,
1442
+ RD_KAFKAP_ShareFetch, 1, 1) ==
1443
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1444
+ "Failed to enable ShareFetch");
1445
+ /* Intentionally NOT calling set_auto_offset_reset — default is latest
1446
+ */
1447
+ test_conf_init(&conf, NULL, 0);
1448
+ test_conf_set(conf, "bootstrap.servers", ctx.bootstraps);
1449
+ rd_kafka_conf_set_dr_msg_cb(conf, test_dr_msg_cb);
1450
+ ctx.producer =
1451
+ rd_kafka_new(RD_KAFKA_PRODUCER, conf, errstr, sizeof(errstr));
1452
+ TEST_ASSERT(ctx.producer != NULL, "Failed to create producer: %s",
1453
+ errstr);
1454
+
1455
+ TEST_ASSERT(rd_kafka_mock_topic_create(ctx.mcluster, topic, 1, 1) ==
1456
+ RD_KAFKA_RESP_ERR_NO_ERROR,
1457
+ "Failed to create mock topic");
1458
+
1459
+ /* Produce records BEFORE subscribing */
1460
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
1461
+ msgcnt);
1462
+
1463
+ /* Subscribe — SPSO should start at end of log (latest) */
1464
+ consumer = new_share_consumer(ctx.bootstraps, "sg-offset-latest");
1465
+ subscribe_topics(consumer, &topic, 1);
1466
+ consumed = test_share_consume_msgs(consumer, 1, 5, 500, NULL, 0);
1467
+ TEST_SAY("offset_reset_latest: consumed %d (expected 0)\n", consumed);
1468
+ TEST_ASSERT(consumed == 0,
1469
+ "Expected 0 consumed with latest offset reset, got %d",
1470
+ consumed);
1471
+
1472
+ /* Produce new records AFTER subscription — these should be visible */
1473
+ test_produce_msgs_simple(ctx.producer, topic, RD_KAFKA_PARTITION_UA,
1474
+ msgcnt);
1475
+ consumed = test_share_consume_msgs(consumer, msgcnt, 30, 500, NULL, 0);
1476
+ TEST_SAY("offset_reset_latest: consumed %d new records (expected %d)\n",
1477
+ consumed, msgcnt);
1478
+
1479
+ rd_kafka_share_consumer_close(consumer);
1480
+ rd_kafka_share_destroy(consumer);
1481
+ test_ctx_destroy(&ctx);
1482
+
1483
+ TEST_ASSERT(consumed == msgcnt,
1484
+ "Expected %d new records consumed, got %d", msgcnt,
1485
+ consumed);
1486
+
1487
+ SUB_TEST_PASS();
1488
+ }
1489
+
1490
+ int main_0156_share_consumer_fetch_mock(int argc, char **argv) {
1491
+ TEST_SKIP_MOCK_CLUSTER(0);
1492
+
1493
+ /* This test suite has many subtests; set a generous timeout.
1494
+ * When running in parallel with other test suites (e.g., 0155, 0157)
1495
+ * the mock broker and consumer threads compete for CPU, which can
1496
+ * slow individual subtests by 5x or more. Use 1500s to be safe. */
1497
+ test_timeout_set(1500);
1498
+
1499
+ /* Positive scenarios */
1500
+ do_test_basic_consume();
1501
+ do_test_followup_fetch();
1502
+ do_test_multi_partition();
1503
+ do_test_multi_topic();
1504
+ do_test_empty_topic_no_records();
1505
+ do_test_sharefetch_session_expiry_rtt();
1506
+ do_test_forgotten_topics();
1507
+ do_test_multi_batch_consume();
1508
+ do_test_max_delivery_attempts();
1509
+ do_test_record_lock_duration();
1510
+ do_test_multi_consumer_lock_expiry();
1511
+
1512
+ /* Negative scenarios */
1513
+ do_test_sharefetch_invalid_session_epoch();
1514
+ do_test_sharefetch_unknown_topic_or_part();
1515
+ do_test_sghb_coord_unavailable();
1516
+ do_test_topic_error_unknown_topic_or_part();
1517
+ do_test_unknown_topic_subscription();
1518
+ do_test_empty_fetch_no_records();
1519
+ do_test_member_validation();
1520
+
1521
+ /* TODO KIP-932: These tests inject partition-level errors at the
1522
+ * top-level response field, which the broker never does for these
1523
+ * error codes. Replace with partition-level mock injection once
1524
+ * that API is available. */
1525
+ /* do_test_sharefetch_fetch_error_not_leader(); */
1526
+ /* do_test_sharefetch_fetch_error_unknown_topic_or_part(); */
1527
+ /* do_test_sharefetch_fetch_error_unknown_topic_id(); */
1528
+ /* do_test_sharefetch_fetch_error_fenced_leader_epoch(); */
1529
+ /* do_test_sharefetch_fetch_error_unknown_leader_epoch(); */
1530
+ /* do_test_sharefetch_topic_authorization_failed(); */
1531
+ /* do_test_sharefetch_corrupt_message(); */
1532
+ /* do_test_sharefetch_fetch_disconnected(); */
1533
+ do_test_sharefetch_fetch_and_close_implicit();
1534
+
1535
+ /* Session management */
1536
+ do_test_session_limit_reached();
1537
+ do_test_session_limit_per_broker();
1538
+ do_test_session_limit_recovery();
1539
+
1540
+ /* Record lock limits */
1541
+ do_test_max_record_locks();
1542
+ do_test_max_record_locks_acquired_only();
1543
+
1544
+ /* Offset reset */
1545
+ do_test_auto_offset_reset_latest();
1546
+
1547
+ /* Log retention */
1548
+ do_test_spso_advances_on_log_retention();
1549
+
1550
+ return 0;
1551
+ }