@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,1210 @@
1
+ /*
2
+ * librdkafka - Apache Kafka C library
3
+ *
4
+ * Copyright (c) 2024, 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
+ #include <stdarg.h>
34
+
35
+
36
+ /**
37
+ * @name Mock tests specific of the KIP-848 group consumer protocol
38
+ */
39
+
40
+
41
+ /**
42
+ * @enum test_variation_t
43
+ * @brief Variations for most error case tests.
44
+ */
45
+ typedef enum test_variation_t {
46
+ /* Error happens on first HB */
47
+ TEST_VARIATION_ERROR_FIRST_HB = 0,
48
+ /* Error happens on second HB */
49
+ TEST_VARIATION_ERROR_SECOND_HB = 1,
50
+ TEST_VARIATION__CNT,
51
+ } test_variation_t;
52
+
53
+ static const char *test_variation_name(test_variation_t variation) {
54
+ rd_assert(variation >= TEST_VARIATION_ERROR_FIRST_HB &&
55
+ variation < TEST_VARIATION__CNT);
56
+ static const char *names[] = {"error on first heartbeat",
57
+ "error on second heartbeat"};
58
+ return names[variation];
59
+ }
60
+
61
+ static int allowed_error;
62
+ static int rebalance_cnt;
63
+ static rd_kafka_resp_err_t rebalance_exp_event;
64
+ static rd_bool_t rebalance_exp_lost = rd_false;
65
+
66
+ /**
67
+ * @brief Decide what error_cb's will cause the test to fail.
68
+ */
69
+ static int
70
+ error_is_fatal_cb(rd_kafka_t *rk, rd_kafka_resp_err_t err, const char *reason) {
71
+ if (err == allowed_error ||
72
+ /* If transport errors are allowed then it is likely
73
+ * that we'll also see ALL_BROKERS_DOWN. */
74
+ (allowed_error == RD_KAFKA_RESP_ERR__TRANSPORT &&
75
+ err == RD_KAFKA_RESP_ERR__ALL_BROKERS_DOWN)) {
76
+ TEST_SAY("Ignoring allowed error: %s: %s\n",
77
+ rd_kafka_err2name(err), reason);
78
+ return 0;
79
+ }
80
+ return 1;
81
+ }
82
+
83
+ /**
84
+ * @brief Rebalance callback saving number of calls and verifying expected
85
+ * event.
86
+ */
87
+ static void rebalance_cb(rd_kafka_t *rk,
88
+ rd_kafka_resp_err_t err,
89
+ rd_kafka_topic_partition_list_t *parts,
90
+ void *opaque) {
91
+
92
+ rebalance_cnt++;
93
+ TEST_SAY("Rebalance #%d: %s: %d partition(s)\n", rebalance_cnt,
94
+ rd_kafka_err2name(err), parts->cnt);
95
+
96
+ TEST_ASSERT(
97
+ err == rebalance_exp_event, "Expected rebalance event %s, not %s",
98
+ rd_kafka_err2name(rebalance_exp_event), rd_kafka_err2name(err));
99
+
100
+ if (rebalance_exp_lost) {
101
+ TEST_ASSERT(rd_kafka_assignment_lost(rk),
102
+ "Expected partitions lost");
103
+ TEST_SAY("Partitions were lost\n");
104
+ }
105
+
106
+ test_rebalance_cb(rk, err, parts, opaque);
107
+
108
+ rebalance_exp_event = RD_KAFKA_RESP_ERR_NO_ERROR;
109
+ /* Make sure only one rebalance callback is served per poll()
110
+ * so that expect_rebalance() returns to the test logic on each
111
+ * rebalance. */
112
+ rd_kafka_yield(rk);
113
+ }
114
+
115
+ static rd_bool_t is_heartbeat_request(rd_kafka_mock_request_t *request,
116
+ void *opaque) {
117
+ return rd_kafka_mock_request_api_key(request) ==
118
+ RD_KAFKAP_ConsumerGroupHeartbeat;
119
+ }
120
+
121
+ /**
122
+ * @brief Wait at least \p num heartbeats
123
+ * have been received by the mock cluster
124
+ * plus \p confidence_interval has passed
125
+ *
126
+ * @return Number of heartbeats received.
127
+ */
128
+ static int wait_all_heartbeats_done(rd_kafka_mock_cluster_t *mcluster,
129
+ int num,
130
+ int confidence_interval) {
131
+ return test_mock_wait_matching_requests(
132
+ mcluster, num, confidence_interval, is_heartbeat_request, NULL);
133
+ }
134
+
135
+ static rd_kafka_t *create_consumer(const char *bootstraps,
136
+ const char *group_id,
137
+ rd_bool_t with_rebalance_cb) {
138
+ rd_kafka_conf_t *conf;
139
+ test_conf_init(&conf, NULL, 0);
140
+ test_conf_set(conf, "bootstrap.servers", bootstraps);
141
+ test_conf_set(conf, "auto.offset.reset", "earliest");
142
+ return test_create_consumer(
143
+ group_id, with_rebalance_cb ? rebalance_cb : NULL, conf, NULL);
144
+ }
145
+
146
+ /**
147
+ * @brief Test heartbeat behavior with fatal errors,
148
+ * ensuring:
149
+ * - a fatal error is received on poll and consumer close
150
+ * - sequence:
151
+ * - in TEST_VARIATION_ERROR_FIRST_HB (1 HBs, 0 callbacks):
152
+ * - first HB returns a fatal error
153
+ * - no rebalance callbacks are called after that
154
+ * - all operations on the consumer fail with fatal error \p err
155
+ * - no final leave group HB is sent
156
+ *
157
+ * - in TEST_VARIATION_ERROR_SECOND_HB (2 HBs, 1 assignment callback):
158
+ * - first HB receives assignment
159
+ * - an assignment callback is called
160
+ * - second HB acknowledges the assignment and returns a fatal error.
161
+ * - no rebalance callbacks are called after that
162
+ * - all operations on the consumer fail with fatal error \p err.
163
+ * - no final leave group HB is sent
164
+ *
165
+ * @param err The error code to test.
166
+ * @param variation Test variation, see `test_variation_t`.
167
+ */
168
+ static void
169
+ do_test_consumer_group_heartbeat_fatal_error(rd_kafka_resp_err_t err,
170
+ test_variation_t variation) {
171
+ rd_kafka_mock_cluster_t *mcluster;
172
+ const char *bootstraps;
173
+ rd_kafka_topic_partition_list_t *subscription;
174
+ rd_kafka_t *c;
175
+ rd_kafka_message_t *rkmessage;
176
+ rd_kafka_resp_err_t fatal_error;
177
+ int expected_heartbeats, found_heartbeats, expected_rebalance_cnt;
178
+ test_timing_t timing;
179
+ rebalance_cnt = 0;
180
+ rebalance_exp_lost = rd_false;
181
+ rebalance_exp_event = RD_KAFKA_RESP_ERR_NO_ERROR;
182
+ const char *topic = test_mk_topic_name(__FUNCTION__, 0);
183
+ char errstr[512];
184
+
185
+ SUB_TEST_QUICK("%s, variation: %s", rd_kafka_err2name(err),
186
+ test_variation_name(variation));
187
+
188
+ mcluster = test_mock_cluster_new(1, &bootstraps);
189
+ rd_kafka_mock_set_group_consumer_heartbeat_interval_ms(mcluster, 1000);
190
+ rd_kafka_mock_topic_create(mcluster, topic, 1, 1);
191
+
192
+ TIMING_START(&timing, "consumer_group_heartbeat_fatal_error");
193
+
194
+ if (variation == TEST_VARIATION_ERROR_SECOND_HB) {
195
+ /* First HB returns assignment */
196
+ rd_kafka_mock_broker_push_request_error_rtts(
197
+ mcluster, 1, RD_KAFKAP_ConsumerGroupHeartbeat, 1,
198
+ RD_KAFKA_RESP_ERR_NO_ERROR, 0);
199
+ }
200
+
201
+ rd_kafka_mock_broker_push_request_error_rtts(
202
+ mcluster, 1, RD_KAFKAP_ConsumerGroupHeartbeat, 1, err, 0);
203
+
204
+ c = create_consumer(bootstraps, topic, rd_true);
205
+
206
+ /* Subscribe to the input topic */
207
+ subscription = rd_kafka_topic_partition_list_new(1);
208
+ rd_kafka_topic_partition_list_add(subscription, topic,
209
+ /* The partition is ignored in
210
+ * rd_kafka_subscribe() */
211
+ RD_KAFKA_PARTITION_UA);
212
+
213
+ TEST_SAY("Subscribing to topic\n");
214
+ rd_kafka_mock_start_request_tracking(mcluster);
215
+ TEST_CALL_ERR__(rd_kafka_subscribe(c, subscription));
216
+ rd_kafka_topic_partition_list_destroy(subscription);
217
+
218
+ expected_heartbeats = 1;
219
+
220
+ TEST_SAY("Awaiting all HBs\n");
221
+ TEST_ASSERT((found_heartbeats =
222
+ wait_all_heartbeats_done(mcluster, expected_heartbeats,
223
+ 200)) == expected_heartbeats,
224
+ "Expected %d heartbeats, got %d", expected_heartbeats,
225
+ found_heartbeats);
226
+
227
+ expected_rebalance_cnt = 0;
228
+ if (variation == TEST_VARIATION_ERROR_SECOND_HB) {
229
+ expected_rebalance_cnt++;
230
+ rebalance_exp_event = RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS;
231
+
232
+ /* Trigger rebalance cb */
233
+ rkmessage = rd_kafka_consumer_poll(c, 500);
234
+ TEST_ASSERT(!rkmessage, "No message should be returned");
235
+ TEST_ASSERT(
236
+ rebalance_exp_event == RD_KAFKA_RESP_ERR_NO_ERROR,
237
+ "Expected assign callback to be processed, but it wasn't");
238
+
239
+ /* Expect the acknowledge HB*/
240
+ expected_heartbeats++;
241
+ TEST_ASSERT((found_heartbeats = wait_all_heartbeats_done(
242
+ mcluster, expected_heartbeats, 200)) ==
243
+ expected_heartbeats,
244
+ "Expected %d heartbeats, got %d",
245
+ expected_heartbeats, found_heartbeats);
246
+ }
247
+
248
+ rd_kafka_mock_clear_requests(mcluster);
249
+ TEST_SAY("Consume from c, a fatal error is returned\n");
250
+ rkmessage = rd_kafka_consumer_poll(c, 500);
251
+ TEST_ASSERT(rkmessage != NULL, "An error message should be returned");
252
+ TEST_ASSERT(rkmessage->err == RD_KAFKA_RESP_ERR__FATAL,
253
+ "Expected a _FATAL error, got %s",
254
+ rd_kafka_err2name(rkmessage->err));
255
+ fatal_error = rd_kafka_fatal_error(c, errstr, sizeof(errstr));
256
+ TEST_ASSERT(fatal_error == err, "Expected fatal error %s, got %s",
257
+ rd_kafka_err2name(err), rd_kafka_err2name(fatal_error));
258
+ rd_kafka_message_destroy(rkmessage);
259
+
260
+ TEST_ASSERT(rebalance_cnt == expected_rebalance_cnt,
261
+ "Expected %d rebalance events, got %d",
262
+ expected_rebalance_cnt, rebalance_cnt);
263
+
264
+ /* Close c, a fatal error is returned */
265
+ TEST_ASSERT(rd_kafka_consumer_close(c) == RD_KAFKA_RESP_ERR__FATAL,
266
+ "Expected a _FATAL error, got %s", rd_kafka_err2name(err));
267
+ fatal_error = rd_kafka_fatal_error(c, errstr, sizeof(errstr));
268
+ TEST_ASSERT(fatal_error == err, "Expected fatal error %s, got %s",
269
+ rd_kafka_err2name(err), rd_kafka_err2name(fatal_error));
270
+
271
+ TEST_ASSERT(rebalance_cnt == expected_rebalance_cnt,
272
+ "Expected %d rebalance events, got %d",
273
+ expected_rebalance_cnt, rebalance_cnt);
274
+
275
+ rd_kafka_destroy(c);
276
+
277
+ TEST_SAY("Ensuring there are no leave group HBs\n");
278
+ TEST_ASSERT(
279
+ (found_heartbeats = wait_all_heartbeats_done(mcluster, 0, 0)) == 0,
280
+ "Expected no leave group heartbeat, got %d", found_heartbeats);
281
+ rd_kafka_mock_stop_request_tracking(mcluster);
282
+ test_mock_cluster_destroy(mcluster);
283
+
284
+ TIMING_ASSERT(&timing, 100, 1500);
285
+ SUB_TEST_PASS();
286
+ }
287
+
288
+ /**
289
+ * @brief Test all kind of fatal errors in a ConsumerGroupHeartbeat call.
290
+ * @sa test_variation_t
291
+ */
292
+ static void do_test_consumer_group_heartbeat_fatal_errors(void) {
293
+ rd_kafka_resp_err_t fatal_errors[] = {
294
+ RD_KAFKA_RESP_ERR_INVALID_REQUEST,
295
+ RD_KAFKA_RESP_ERR_GROUP_MAX_SIZE_REACHED,
296
+ RD_KAFKA_RESP_ERR_UNSUPPORTED_ASSIGNOR,
297
+ RD_KAFKA_RESP_ERR_UNSUPPORTED_VERSION,
298
+ RD_KAFKA_RESP_ERR_UNRELEASED_INSTANCE_ID,
299
+ RD_KAFKA_RESP_ERR_GROUP_AUTHORIZATION_FAILED,
300
+ RD_KAFKA_RESP_ERR_GROUP_ID_NOT_FOUND,
301
+ RD_KAFKA_RESP_ERR_CLUSTER_AUTHORIZATION_FAILED};
302
+ size_t i;
303
+ test_variation_t j;
304
+ for (i = 0; i < RD_ARRAY_SIZE(fatal_errors); i++) {
305
+ /* Only these errors can happen on a second HB. */
306
+ test_variation_t last_variation =
307
+ ((fatal_errors[i] == RD_KAFKA_RESP_ERR_INVALID_REQUEST) ||
308
+ (fatal_errors[i] ==
309
+ RD_KAFKA_RESP_ERR_GROUP_AUTHORIZATION_FAILED))
310
+ ? TEST_VARIATION_ERROR_SECOND_HB
311
+ : TEST_VARIATION_ERROR_FIRST_HB;
312
+
313
+ for (j = TEST_VARIATION_ERROR_FIRST_HB; j <= last_variation;
314
+ j++)
315
+ do_test_consumer_group_heartbeat_fatal_error(
316
+ fatal_errors[i], j);
317
+ }
318
+ }
319
+
320
+ /**
321
+ * @brief Test heartbeat behavior with retriable errors,
322
+ * ensuring:
323
+ * - no error is received on poll and consumer close
324
+ * - sequence:
325
+ * - in TEST_VARIATION_ERROR_FIRST_HB (4 HBs, 1 assignment callback, 1
326
+ * revocation callback):
327
+ * - first HB is retried
328
+ * - second HB receives assignment
329
+ * - rebalance callback with an assignment
330
+ * - third HB for the acknowledgment
331
+ * - assignment revoked with a callback on consumer close
332
+ * - final leave group HB
333
+ *
334
+ * - in TEST_VARIATION_ERROR_SECOND_HB (4 HBs, 1 assignment callback, 1
335
+ * revocation callback):
336
+ * - first HB receives assignment
337
+ * - assignment callback is called
338
+ * - second HB acknowledges the assignment and
339
+ * returns a retriable error
340
+ * - the HB is retried (third one)
341
+ * - assignment revoked with a callback on consumer close
342
+ * - final leave group HB
343
+ *
344
+ * @param err The error code to test.
345
+ * @param variation Test variation, see `test_variation_t`.
346
+ */
347
+ static void
348
+ do_test_consumer_group_heartbeat_retriable_error(rd_kafka_resp_err_t err,
349
+ test_variation_t variation) {
350
+ rd_kafka_mock_cluster_t *mcluster;
351
+ const char *bootstraps;
352
+ rd_kafka_topic_partition_list_t *subscription;
353
+ rd_kafka_t *c;
354
+ int expected_heartbeats, found_heartbeats;
355
+ test_timing_t timing;
356
+ const char *topic = test_mk_topic_name(__FUNCTION__, 0);
357
+ test_curr->is_fatal_cb = error_is_fatal_cb;
358
+ rebalance_cnt = 0;
359
+ rebalance_exp_lost = rd_false;
360
+ allowed_error = RD_KAFKA_RESP_ERR__TRANSPORT;
361
+
362
+ SUB_TEST_QUICK("%s, variation: %s", rd_kafka_err2name(err),
363
+ test_variation_name(variation));
364
+
365
+
366
+ mcluster = test_mock_cluster_new(1, &bootstraps);
367
+ rd_kafka_mock_set_group_consumer_heartbeat_interval_ms(mcluster, 1000);
368
+ rd_kafka_mock_topic_create(mcluster, topic, 1, 1);
369
+
370
+ c = create_consumer(bootstraps, topic, rd_true);
371
+
372
+ TIMING_START(&timing, "consumer_group_heartbeat_retriable_error");
373
+
374
+ if (variation == TEST_VARIATION_ERROR_SECOND_HB) {
375
+ /* First HB returns assignment */
376
+ rd_kafka_mock_broker_push_request_error_rtts(
377
+ mcluster, 1, RD_KAFKAP_ConsumerGroupHeartbeat, 1,
378
+ RD_KAFKA_RESP_ERR_NO_ERROR, 0);
379
+ }
380
+
381
+ rd_kafka_mock_broker_push_request_error_rtts(
382
+ mcluster, 1, RD_KAFKAP_ConsumerGroupHeartbeat, 1, err, 0);
383
+
384
+ /* Subscribe to the input topic */
385
+ subscription = rd_kafka_topic_partition_list_new(1);
386
+ rd_kafka_topic_partition_list_add(subscription, topic,
387
+ /* The partition is ignored in
388
+ * rd_kafka_subscribe() */
389
+ RD_KAFKA_PARTITION_UA);
390
+
391
+ TEST_SAY("Subscribing to topic\n");
392
+ rd_kafka_mock_start_request_tracking(mcluster);
393
+ TEST_CALL_ERR__(rd_kafka_subscribe(c, subscription));
394
+ rd_kafka_topic_partition_list_destroy(subscription);
395
+
396
+ /* TEST_VARIATION_ERROR_FIRST_HB First HB and its retry + ACK. */
397
+ /* TEST_VARIATION_ERROR_SECOND_HB First HB + ACK and retry. */
398
+ expected_heartbeats = 3;
399
+ rebalance_exp_event = RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS;
400
+ TEST_SAY(
401
+ "Consume from c, no message is returned, "
402
+ "but assign callback is processed\n");
403
+ test_consumer_poll_no_msgs("after heartbeat", c, 0, 500);
404
+ TEST_ASSERT(rebalance_cnt > 0, "Expected > 0 rebalance events, got %d",
405
+ rebalance_cnt);
406
+ TEST_ASSERT(rebalance_exp_event == RD_KAFKA_RESP_ERR_NO_ERROR,
407
+ "Expected assign callback to be processed, but it wasn't");
408
+
409
+ TEST_SAY("Awaiting first HBs\n");
410
+ TEST_ASSERT((found_heartbeats =
411
+ wait_all_heartbeats_done(mcluster, expected_heartbeats,
412
+ 200)) == expected_heartbeats,
413
+ "Expected %d heartbeats, got %d", expected_heartbeats,
414
+ found_heartbeats);
415
+
416
+ rebalance_exp_event = RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS;
417
+
418
+ /* Close c without errors */
419
+ expected_heartbeats++;
420
+ TEST_ASSERT(rd_kafka_consumer_close(c) == RD_KAFKA_RESP_ERR_NO_ERROR,
421
+ "Expected NO_ERROR, got %s", rd_kafka_err2name(err));
422
+ TEST_ASSERT(rebalance_cnt > 0, "Expected > 0 rebalance events, got %d",
423
+ rebalance_cnt);
424
+ TEST_ASSERT(rebalance_exp_event == RD_KAFKA_RESP_ERR_NO_ERROR,
425
+ "Expected revoke callback to be processed, but it wasn't");
426
+
427
+ rd_kafka_destroy(c);
428
+
429
+ TEST_SAY("Awaiting leave group HB\n");
430
+ TEST_ASSERT((found_heartbeats =
431
+ wait_all_heartbeats_done(mcluster, expected_heartbeats,
432
+ 0)) == expected_heartbeats,
433
+ "Expected %d heartbeats, got %d", expected_heartbeats,
434
+ found_heartbeats);
435
+
436
+ rd_kafka_mock_stop_request_tracking(mcluster);
437
+ test_mock_cluster_destroy(mcluster);
438
+
439
+ TIMING_ASSERT(&timing, 100, 1500);
440
+
441
+ test_curr->is_fatal_cb = NULL;
442
+ allowed_error = RD_KAFKA_RESP_ERR_NO_ERROR;
443
+
444
+ SUB_TEST_PASS();
445
+ }
446
+
447
+ /**
448
+ * @brief Test all kind of retriable errors in a ConsumerGroupHeartbeat call.
449
+ * @sa test_variation_t
450
+ */
451
+ static void do_test_consumer_group_heartbeat_retriable_errors(void) {
452
+ rd_kafka_resp_err_t retriable_errors[] = {
453
+ RD_KAFKA_RESP_ERR_COORDINATOR_LOAD_IN_PROGRESS,
454
+ RD_KAFKA_RESP_ERR__SSL, RD_KAFKA_RESP_ERR__TIMED_OUT_QUEUE};
455
+ size_t i;
456
+ test_variation_t j;
457
+ for (i = 0; i < RD_ARRAY_SIZE(retriable_errors); i++) {
458
+ for (j = TEST_VARIATION_ERROR_FIRST_HB; j < TEST_VARIATION__CNT;
459
+ j++)
460
+ do_test_consumer_group_heartbeat_retriable_error(
461
+ retriable_errors[i], j);
462
+ }
463
+ }
464
+
465
+ /**
466
+ * @brief Test heartbeat behavior with consumer fenced errors,
467
+ * ensuring:
468
+ * - no error is received on poll and consumer close
469
+ * - sequence:
470
+ *
471
+ * - in TEST_VARIATION_ERROR_FIRST_HB (4 HBs, 1 assignment callback, 1
472
+ * revocation callback):
473
+ * - first HB fences the member
474
+ * it does not receives assignment
475
+ * or revoke any partitions
476
+ * - second HB receives assignment
477
+ * - there's an assignment callback
478
+ * - assignment is acknowledged (third HB)
479
+ * - assignment is revoked on close (fourth HB)
480
+ * - last revoke callback
481
+ *
482
+ * - in TEST_VARIATION_ERROR_SECOND_HB (5 HBs, 2 assignment callbacks,
483
+ * 2 revocation callbacks of which 1 as lost):
484
+ * - first HB receives assignment
485
+ * - assignment callback is called
486
+ * - second HB acknowledges the assignment, fences the consumer
487
+ * - a lost callback is called (lost partitions)
488
+ * - partitions are assigned again on re-joining (third HB)
489
+ * - second assignment callback
490
+ * - acknowledgment of the assignment (fourth HB)
491
+ * - partitions are revoked on close (fifth HB)
492
+ * - last revoke callback
493
+ *
494
+ * @param err The error code to test.
495
+ * @param variation Test variation, see `test_variation_t`.
496
+ */
497
+ static void
498
+ do_test_consumer_group_heartbeat_fenced_error(rd_kafka_resp_err_t err,
499
+ test_variation_t variation) {
500
+ rd_kafka_mock_cluster_t *mcluster;
501
+ const char *bootstraps;
502
+ rd_kafka_topic_partition_list_t *subscription;
503
+ rd_kafka_t *c;
504
+ rd_kafka_message_t *rkmessage;
505
+ int expected_heartbeats, found_heartbeats, expected_rebalance_cnt;
506
+ test_timing_t timing;
507
+ rebalance_cnt = 0;
508
+ rebalance_exp_lost = rd_false;
509
+ rebalance_exp_event = RD_KAFKA_RESP_ERR_NO_ERROR;
510
+ const char *topic = test_mk_topic_name(__FUNCTION__, 0);
511
+
512
+ SUB_TEST_QUICK("%s, variation: %s", rd_kafka_err2name(err),
513
+ test_variation_name(variation));
514
+
515
+ mcluster = test_mock_cluster_new(1, &bootstraps);
516
+ rd_kafka_mock_set_group_consumer_heartbeat_interval_ms(mcluster, 1000);
517
+ rd_kafka_mock_topic_create(mcluster, topic, 1, 1);
518
+
519
+ if (variation == TEST_VARIATION_ERROR_SECOND_HB) {
520
+ /* First HB returns assignment */
521
+ rd_kafka_mock_broker_push_request_error_rtts(
522
+ mcluster, 1, RD_KAFKAP_ConsumerGroupHeartbeat, 1,
523
+ RD_KAFKA_RESP_ERR_NO_ERROR, 0);
524
+ }
525
+
526
+ rd_kafka_mock_broker_push_request_error_rtts(
527
+ mcluster, 1, RD_KAFKAP_ConsumerGroupHeartbeat, 1, err, 0);
528
+
529
+ c = create_consumer(bootstraps, topic, rd_true);
530
+
531
+ TIMING_START(&timing, "consumer_group_heartbeat_fenced_error");
532
+
533
+ /* Subscribe to the input topic */
534
+ subscription = rd_kafka_topic_partition_list_new(1);
535
+ rd_kafka_topic_partition_list_add(subscription, topic,
536
+ /* The partition is ignored in
537
+ * rd_kafka_subscribe() */
538
+ RD_KAFKA_PARTITION_UA);
539
+
540
+ TEST_SAY("Subscribing to topic\n");
541
+ rd_kafka_mock_start_request_tracking(mcluster);
542
+ TEST_CALL_ERR__(rd_kafka_subscribe(c, subscription));
543
+ rd_kafka_topic_partition_list_destroy(subscription);
544
+
545
+ /* variation ERROR_FIRST_HB: First HB fences and second receives
546
+ * the assignment*/
547
+ expected_heartbeats = 2;
548
+ if (variation == TEST_VARIATION_ERROR_SECOND_HB)
549
+ /* variation ERROR_SECOND_HB: First HB receives assignment,
550
+ * second HB fences the consumer.
551
+ * We only await one here as we need to process the assignment
552
+ * callback. */
553
+ expected_heartbeats = 1;
554
+
555
+ TEST_SAY("Awaiting initial HBs\n");
556
+ TEST_ASSERT((found_heartbeats =
557
+ wait_all_heartbeats_done(mcluster, expected_heartbeats,
558
+ 200)) == expected_heartbeats,
559
+ "Expected %d heartbeats, got %d", expected_heartbeats,
560
+ found_heartbeats);
561
+
562
+ expected_rebalance_cnt = 0;
563
+ /* variation ERROR_FIRST_HB: Second HB receives the assignment */
564
+ if (variation == TEST_VARIATION_ERROR_SECOND_HB) {
565
+ expected_rebalance_cnt++;
566
+ rebalance_exp_event = RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS;
567
+
568
+ /* variation ERROR_SECOND_HB: first HB assigned the partitions
569
+ * and second one acknowledges them and receives the
570
+ * fencing error. */
571
+ rkmessage = rd_kafka_consumer_poll(c, 100);
572
+ TEST_ASSERT(!rkmessage, "No message should be returned");
573
+ TEST_ASSERT(
574
+ rebalance_exp_event == RD_KAFKA_RESP_ERR_NO_ERROR,
575
+ "Expected assign callback to be processed, but it wasn't");
576
+
577
+ TEST_ASSERT(rebalance_cnt == expected_rebalance_cnt,
578
+ "Expected %d rebalance events after assign "
579
+ "callback, got %d",
580
+ expected_rebalance_cnt, rebalance_cnt);
581
+ /* Ack is sent immediately after assignment completes. */
582
+ expected_heartbeats++;
583
+
584
+ TEST_SAY("Awaiting partition lost callback\n");
585
+ /* Second HB acks receives the fenced error
586
+ * and loses partitions */
587
+ expected_rebalance_cnt++;
588
+ rebalance_exp_event = RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS;
589
+ rebalance_exp_lost = rd_true;
590
+
591
+ rkmessage = rd_kafka_consumer_poll(c, 100);
592
+ TEST_ASSERT(!rkmessage, "No message should be returned");
593
+ TEST_ASSERT(
594
+ rebalance_exp_event == RD_KAFKA_RESP_ERR_NO_ERROR,
595
+ "Expected revoke callback to be processed, but it wasn't");
596
+
597
+ TEST_ASSERT(
598
+ rebalance_cnt == expected_rebalance_cnt,
599
+ "Expected %d rebalance events after lost callback, got %d",
600
+ expected_rebalance_cnt, rebalance_cnt);
601
+
602
+ /* Third HB assigns the partitions again */
603
+ expected_heartbeats++;
604
+ }
605
+
606
+ expected_rebalance_cnt++;
607
+ rebalance_exp_event = RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS;
608
+ rebalance_exp_lost = rd_false;
609
+
610
+ TEST_SAY("Awaiting rebalance callback\n");
611
+ /* Consume from c, partitions are lost if assigned */
612
+ rkmessage = rd_kafka_consumer_poll(c, 500);
613
+ TEST_ASSERT(!rkmessage, "No message should be returned");
614
+ TEST_ASSERT(rebalance_exp_event == RD_KAFKA_RESP_ERR_NO_ERROR,
615
+ "Expected assign callback to be processed, but it wasn't");
616
+
617
+ TEST_ASSERT(rebalance_cnt == expected_rebalance_cnt,
618
+ "Expected %d total rebalance events, got %d",
619
+ expected_rebalance_cnt, rebalance_cnt);
620
+
621
+ /* Ack for last assignment HB */
622
+ expected_heartbeats++;
623
+
624
+ TEST_SAY("Awaiting acknowledge heartbeat\n");
625
+ TEST_ASSERT((found_heartbeats =
626
+ wait_all_heartbeats_done(mcluster, expected_heartbeats,
627
+ 100)) == expected_heartbeats,
628
+ "Expected %d heartbeats, got %d", expected_heartbeats,
629
+ found_heartbeats);
630
+
631
+ expected_rebalance_cnt++;
632
+ rebalance_exp_event = RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS;
633
+
634
+ /* Leave group HB */
635
+ expected_heartbeats++;
636
+ /* Close c, no error is returned */
637
+ TEST_CALL_ERR__(rd_kafka_consumer_close(c));
638
+ TEST_ASSERT(rebalance_exp_event == RD_KAFKA_RESP_ERR_NO_ERROR,
639
+ "Expected revoke callback to be processed, but it wasn't");
640
+ TEST_ASSERT(rebalance_cnt == expected_rebalance_cnt,
641
+ "Expected %d rebalance events, got %d",
642
+ expected_rebalance_cnt, rebalance_cnt);
643
+
644
+ rd_kafka_destroy(c);
645
+
646
+ TEST_SAY("Verifying leave group heartbeat\n");
647
+ /* After closing the consumer, 1 heartbeat should been sent */
648
+ TEST_ASSERT((found_heartbeats =
649
+ wait_all_heartbeats_done(mcluster, expected_heartbeats,
650
+ 0)) == expected_heartbeats,
651
+ "Expected %d heartbeats, got %d", expected_heartbeats,
652
+ found_heartbeats);
653
+
654
+ rd_kafka_mock_stop_request_tracking(mcluster);
655
+ test_mock_cluster_destroy(mcluster);
656
+
657
+ TIMING_ASSERT(&timing, 100, 1500);
658
+ SUB_TEST_PASS();
659
+ }
660
+
661
+ /**
662
+ * @brief Test all kind of consumer fenced errors in a ConsumerGroupHeartbeat
663
+ * call.
664
+ * @sa test_variation_t
665
+ */
666
+ static void do_test_consumer_group_heartbeat_fenced_errors(void) {
667
+ rd_kafka_resp_err_t fenced_errors[] = {
668
+ RD_KAFKA_RESP_ERR_UNKNOWN_MEMBER_ID,
669
+ RD_KAFKA_RESP_ERR_FENCED_MEMBER_EPOCH};
670
+ size_t i;
671
+ test_variation_t j;
672
+ for (i = 0; i < RD_ARRAY_SIZE(fenced_errors); i++) {
673
+ for (j = TEST_VARIATION_ERROR_FIRST_HB; j < TEST_VARIATION__CNT;
674
+ j++)
675
+ do_test_consumer_group_heartbeat_fenced_error(
676
+ fenced_errors[i], j);
677
+ }
678
+ }
679
+
680
+ /**
681
+ * @enum test_variation_unknown_topic_id_t
682
+ * @brief Variations for `do_test_metadata_unknown_topic_id_tests`.
683
+ */
684
+ typedef enum test_variation_unknown_topic_id_t {
685
+ /* One topic, UNKNOWN_TOPIC_ID is given until it's not. */
686
+ TEST_VARIATION_UNKNOWN_TOPIC_ID_ONE_TOPIC = 0,
687
+ /* Two topics, first has UNKNOWN_TOPIC_ID error, second one exists. */
688
+ TEST_VARIATION_UNKNOWN_TOPIC_ID_TWO_TOPICS = 1,
689
+ TEST_VARIATION_UNKNOWN_TOPIC_ID__CNT,
690
+ } test_variation_unknown_topic_id_t;
691
+
692
+ static const char *
693
+ test_variation_unknown_topic_id_name(test_variation_t variation) {
694
+ switch (variation) {
695
+ case TEST_VARIATION_UNKNOWN_TOPIC_ID_ONE_TOPIC:
696
+ return "one topic";
697
+ case TEST_VARIATION_UNKNOWN_TOPIC_ID_TWO_TOPICS:
698
+ return "two topics";
699
+ default:
700
+ rd_assert(!*"Unknown test variation (unknown topic id)");
701
+ return NULL;
702
+ }
703
+ }
704
+
705
+ /**
706
+ * @brief Test consumer group behavior with missing topic id when retrieving
707
+ * metadata for assigned topics.
708
+ * ensuring:
709
+ * - initially a partial acknoledgement is started, with an empty list
710
+ * (variation 0) or a single topic (variation 1)
711
+ * - fetch doesn't start until broker returns an unknown topic id error
712
+ * - when error isn't returned anymore the client finishes assigning
713
+ * the partition and reads a message.
714
+ *
715
+ * @param variation Test variation, see `test_variation_unknown_topic_id_t`.
716
+ */
717
+ static void do_test_metadata_unknown_topic_id_error(
718
+ test_variation_unknown_topic_id_t variation) {
719
+ rd_kafka_mock_cluster_t *mcluster;
720
+ const char *bootstraps;
721
+ rd_kafka_topic_partition_list_t *subscription, *assignment;
722
+ rd_kafka_t *c;
723
+ test_timing_t timing;
724
+ const char *topic = "do_test_metadata_unknown_topic_id_error";
725
+ const char *topic2 = "do_test_metadata_unknown_topic_id_error2";
726
+ rd_kafka_topic_partition_list_t *expected_assignment;
727
+
728
+ SUB_TEST_QUICK("variation: %s",
729
+ test_variation_unknown_topic_id_name(variation));
730
+
731
+ expected_assignment = rd_kafka_topic_partition_list_new(1);
732
+ rd_kafka_topic_partition_list_add(expected_assignment, topic, 0);
733
+ if (variation == TEST_VARIATION_UNKNOWN_TOPIC_ID_TWO_TOPICS) {
734
+ rd_kafka_topic_partition_list_add(expected_assignment, topic2,
735
+ 0);
736
+ }
737
+
738
+ mcluster = test_mock_cluster_new(1, &bootstraps);
739
+ rd_kafka_mock_set_group_consumer_heartbeat_interval_ms(mcluster, 500);
740
+ rd_kafka_mock_topic_create(mcluster, topic, 1, 1);
741
+ if (variation == TEST_VARIATION_UNKNOWN_TOPIC_ID_TWO_TOPICS) {
742
+ rd_kafka_mock_topic_create(mcluster, topic2, 1, 1);
743
+ }
744
+
745
+ c = create_consumer(bootstraps, topic, rd_false);
746
+
747
+ /* Seed the topic with messages */
748
+ test_produce_msgs_easy_v(topic, 0, 0, 0, 1, 1000, "bootstrap.servers",
749
+ bootstraps, NULL);
750
+
751
+ TIMING_START(&timing, "do_test_metadata_unknown_topic_id_error");
752
+
753
+ subscription = rd_kafka_topic_partition_list_new(1);
754
+ rd_kafka_topic_partition_list_add(subscription, topic,
755
+ RD_KAFKA_PARTITION_UA);
756
+ if (variation == TEST_VARIATION_UNKNOWN_TOPIC_ID_TWO_TOPICS) {
757
+ rd_kafka_topic_partition_list_add(subscription, topic2,
758
+ RD_KAFKA_PARTITION_UA);
759
+ }
760
+
761
+ rd_kafka_mock_topic_set_error(mcluster, topic,
762
+ RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_ID);
763
+
764
+ TEST_SAY("Subscribing to topic\n");
765
+ TEST_CALL_ERR__(rd_kafka_subscribe(c, subscription));
766
+ rd_kafka_topic_partition_list_destroy(subscription);
767
+
768
+ TEST_SAY(
769
+ "Cannot fetch until Metadata calls replies with "
770
+ "UNKNOWN_TOPIC_ID\n");
771
+ test_consumer_poll_no_msgs("no messages", c, 0, 1000);
772
+
773
+ rd_kafka_mock_topic_set_error(mcluster, topic,
774
+ RD_KAFKA_RESP_ERR_NO_ERROR);
775
+
776
+ TEST_SAY("Reconciliation and fetch is now possible\n");
777
+ test_consumer_poll_timeout("message", c, 0, 0, 0, 1, NULL, 2000);
778
+
779
+ TEST_CALL_ERR__(rd_kafka_assignment(c, &assignment));
780
+ TEST_ASSERT(assignment != NULL);
781
+ TEST_ASSERT(!test_partition_list_cmp(assignment, expected_assignment),
782
+ "Expected assignment not seen, got %d partitions",
783
+ assignment->cnt);
784
+ rd_kafka_topic_partition_list_destroy(assignment);
785
+ rd_kafka_topic_partition_list_destroy(expected_assignment);
786
+
787
+ rd_kafka_destroy(c);
788
+ test_mock_cluster_destroy(mcluster);
789
+
790
+ TIMING_ASSERT(&timing, 500, 4000);
791
+ SUB_TEST_PASS();
792
+ }
793
+
794
+ /**
795
+ * @brief Test these variations of a UNKNOWN_TOPIC_ID in a Metadata call
796
+ * before reconciliation.
797
+ * @sa test_variation_unknown_topic_id_t
798
+ */
799
+ static void do_test_metadata_unknown_topic_id_tests(void) {
800
+ test_variation_unknown_topic_id_t i;
801
+ for (i = TEST_VARIATION_UNKNOWN_TOPIC_ID_ONE_TOPIC;
802
+ i < TEST_VARIATION_UNKNOWN_TOPIC_ID__CNT; i++) {
803
+ do_test_metadata_unknown_topic_id_error(i);
804
+ }
805
+ }
806
+
807
+ static void do_test_adherence_to_hb_interval(void) {
808
+ rd_kafka_mock_cluster_t *mcluster;
809
+ const char *bootstraps;
810
+ rd_kafka_topic_partition_list_t *subscription;
811
+ rd_kafka_t *c;
812
+ const char *topic =
813
+ test_mk_topic_name("do_test_adherence_to_hb_interval", 1);
814
+ rd_kafka_conf_t *conf;
815
+ size_t heartbeat_request_count = 0;
816
+
817
+ SUB_TEST_QUICK("do_test_adherence_to_hb_interval");
818
+
819
+ mcluster = test_mock_cluster_new(1, &bootstraps);
820
+ rd_kafka_mock_set_group_consumer_heartbeat_interval_ms(mcluster, 1000);
821
+ rd_kafka_mock_topic_create(mcluster, topic, 3, 1);
822
+
823
+ test_conf_init(&conf, NULL, 0);
824
+ test_conf_set(conf, "bootstrap.servers", bootstraps);
825
+ test_conf_set(conf, "auto.offset.reset", "earliest");
826
+ test_conf_set(conf, "auto.commit.interval.ms", "100");
827
+ c = test_create_consumer(topic, NULL, conf, NULL);
828
+
829
+ subscription = rd_kafka_topic_partition_list_new(1);
830
+ rd_kafka_topic_partition_list_add(subscription, topic,
831
+ RD_KAFKA_PARTITION_UA);
832
+
833
+ rd_kafka_mock_start_request_tracking(mcluster);
834
+ TEST_SAY("Subscribing to topic\n");
835
+ TEST_CALL_ERR__(rd_kafka_subscribe(c, subscription));
836
+ rd_kafka_topic_partition_list_destroy(subscription);
837
+
838
+ TEST_SAY("Subscription done, waiting for heartbeats\n");
839
+
840
+ rd_sleep(2); /* Sleep to ensure that some HB are sent */
841
+
842
+ heartbeat_request_count = test_mock_get_matching_request_cnt(
843
+ mcluster, is_heartbeat_request, NULL);
844
+ TEST_SAY("Heartbeat request count: %zu\n", heartbeat_request_count);
845
+
846
+ /* Assert that we received the expected number of heartbeats */
847
+ TEST_ASSERT(heartbeat_request_count >= 3 &&
848
+ heartbeat_request_count <= 5,
849
+ "Expected between 3 and 5 heartbeats, got %zu",
850
+ heartbeat_request_count);
851
+
852
+ rd_kafka_mock_stop_request_tracking(mcluster);
853
+
854
+ rd_kafka_destroy(c);
855
+ test_mock_cluster_destroy(mcluster);
856
+
857
+ SUB_TEST_PASS();
858
+ }
859
+
860
+ typedef enum do_test_quick_unsubscribe_variation_t {
861
+ /* No mock cluster, no coordinator available. */
862
+ DO_TEST_QUICK_UNSUBSCRIBE_VARIATION_NO_CLUSTER = 0,
863
+ /* Mock cluster is ready */
864
+ DO_TEST_QUICK_UNSUBSCRIBE_VARIATION_CLUSTER_READY = 1,
865
+ DO_TEST_QUICK_UNSUBSCRIBE_VARIATION__CNT
866
+ } do_test_quick_unsubscribe_variation_t;
867
+
868
+ /**
869
+ * @brief A series of subscribe and unsubscribe call shouldn't cause
870
+ * assert failures.
871
+ *
872
+ * @param variation Test variation.
873
+ *
874
+ * @sa `do_test_quick_unsubscribe_variation_t`
875
+ */
876
+ static void
877
+ do_test_quick_unsubscribe(do_test_quick_unsubscribe_variation_t variation) {
878
+ int i;
879
+ rd_kafka_t *c;
880
+ rd_kafka_topic_partition_list_t *subscription;
881
+ rd_kafka_mock_cluster_t *mcluster = NULL;
882
+ const char *bootstraps = "localhost:9999";
883
+ const char *topic = test_mk_topic_name(__FUNCTION__, 0);
884
+
885
+ SUB_TEST_QUICK(
886
+ "%s", variation == DO_TEST_QUICK_UNSUBSCRIBE_VARIATION_NO_CLUSTER
887
+ ? "no cluster"
888
+ : "mock cluster ready");
889
+
890
+ if (variation == DO_TEST_QUICK_UNSUBSCRIBE_VARIATION_NO_CLUSTER) {
891
+ test_curr->is_fatal_cb = error_is_fatal_cb;
892
+ allowed_error = RD_KAFKA_RESP_ERR__TRANSPORT;
893
+ } else if (variation ==
894
+ DO_TEST_QUICK_UNSUBSCRIBE_VARIATION_CLUSTER_READY) {
895
+ mcluster = test_mock_cluster_new(1, &bootstraps);
896
+ rd_kafka_mock_topic_create(mcluster, topic, 1, 1);
897
+ }
898
+
899
+ c = create_consumer(bootstraps, topic, rd_true);
900
+
901
+ subscription = rd_kafka_topic_partition_list_new(1);
902
+ rd_kafka_topic_partition_list_add(subscription, topic,
903
+ RD_KAFKA_PARTITION_UA);
904
+
905
+ for (i = 0; i < 2; i++) {
906
+ TEST_CALL_ERR__(rd_kafka_subscribe(c, subscription));
907
+ TEST_CALL_ERR__(rd_kafka_unsubscribe(c));
908
+ }
909
+
910
+ rd_kafka_topic_partition_list_destroy(subscription);
911
+ rd_kafka_destroy(c);
912
+ RD_IF_FREE(mcluster, test_mock_cluster_destroy);
913
+
914
+ test_curr->is_fatal_cb = NULL;
915
+ allowed_error = RD_KAFKA_RESP_ERR_NO_ERROR;
916
+ SUB_TEST_PASS();
917
+ }
918
+
919
+ /**
920
+ * @brief Test all `do_test_quick_unsubscribe` variations.
921
+ *
922
+ * @sa `do_test_quick_unsubscribe_variation_t`
923
+ */
924
+ static void do_test_quick_unsubscribe_tests(void) {
925
+ do_test_quick_unsubscribe_variation_t variation;
926
+ for (variation = DO_TEST_QUICK_UNSUBSCRIBE_VARIATION_NO_CLUSTER;
927
+ variation < DO_TEST_QUICK_UNSUBSCRIBE_VARIATION__CNT;
928
+ variation++) {
929
+ do_test_quick_unsubscribe(variation);
930
+ }
931
+ }
932
+
933
+ static int max_poll_inject_done = 0;
934
+
935
+ /**
936
+ * @brief Log interception used to deterministically force the max-poll rejoin
937
+ * race from the test, without modifying library code.
938
+ *
939
+ * The "Expediting next heartbeat ... max poll interval exceeded" line is
940
+ * emitted on the main thread when the poll interval is exceeded and
941
+ * F_WAIT_REJOIN is set. This sleep reproduces the *pre-fix* race: back then the
942
+ * leave-group heartbeat was sent immediately at that point, and sleeping here
943
+ * (synchronously, on the main thread) let the broker thread deliver the leave
944
+ * reply, which was then processed on the next serve -- running consumer_reset
945
+ * and clearing F_WAIT_REJOIN BEFORE consumer_serve acted on it -- stranding the
946
+ * member steady at epoch 0 so its next heartbeat was a malformed (re-)join.
947
+ * The fix defers the leave until the assignment is revoked, so the consumer
948
+ * now rejoins cleanly even with this injected delay.
949
+ */
950
+ static void max_poll_rejoin_delay_log_cb(const rd_kafka_t *rk,
951
+ int level,
952
+ const char *fac,
953
+ const char *buf) {
954
+ if (!max_poll_inject_done && strstr(buf, "Expediting next heartbeat") &&
955
+ strstr(buf, "max poll interval exceeded")) {
956
+ max_poll_inject_done = 1;
957
+ fprintf(stderr,
958
+ "### TEST: injecting 500ms delay after leave to force "
959
+ "the rejoin race\n");
960
+ rd_usleep(500 * 1000, NULL);
961
+ }
962
+ }
963
+
964
+ /**
965
+ * @brief After the poll timer (max.poll.interval.ms) expires the consumer
966
+ * leaves the group and must rejoin once polling resumes. Verify the
967
+ * rejoin is performed as a proper (re-)join, the consumer does not end
968
+ * up in a fatal state, and it re-acquires its assignment and consumes
969
+ * all the records.
970
+ *
971
+ * The topic is kept empty while the rejoin race is forced (so active fetching
972
+ * does not perturb the timing); the records are produced only afterwards. A
973
+ * regression strands the member at epoch 0 and the next heartbeat is rejected
974
+ * with a fatal INVALID_REQUEST -- which is detected first in the poll loop and
975
+ * fails the test fast. With the fix the consumer rejoins and (auto-commit
976
+ * disabled -> earliest) consumes the full set of records.
977
+ */
978
+ static void do_test_max_poll_interval_rejoin_consume(void) {
979
+ rd_kafka_mock_cluster_t *mcluster;
980
+ const char *bootstraps;
981
+ rd_kafka_t *c;
982
+ rd_kafka_conf_t *conf;
983
+ const char *topic = test_mk_topic_name(__FUNCTION__, 0);
984
+ uint64_t testid = test_id_generate();
985
+ const int msgcnt = 100;
986
+ rd_kafka_resp_err_t fatal_err;
987
+ char errstr[512];
988
+ int64_t deadline;
989
+ rd_kafka_message_t *rkm;
990
+ rd_kafka_topic_partition_list_t *assignment = NULL;
991
+ rd_bool_t assigned = rd_false;
992
+ int received = 0;
993
+
994
+ SUB_TEST_QUICK();
995
+
996
+ mcluster = test_mock_cluster_new(1, &bootstraps);
997
+ rd_kafka_mock_set_group_consumer_heartbeat_interval_ms(mcluster, 500);
998
+ rd_kafka_mock_topic_create(mcluster, topic, 1, 1);
999
+
1000
+ max_poll_inject_done = 0;
1001
+ test_conf_init(&conf, NULL, 30);
1002
+ test_conf_set(conf, "bootstrap.servers", bootstraps);
1003
+ test_conf_set(conf, "auto.offset.reset", "earliest");
1004
+ /* Disable auto-commit so the re-assigned partition has no committed
1005
+ * offset after the rejoin and deterministically resets to earliest. */
1006
+ test_conf_set(conf, "enable.auto.commit", "false");
1007
+ test_conf_set(conf, "max.poll.interval.ms", "3000");
1008
+ /* Intercept logs to force the rejoin race, see
1009
+ * max_poll_rejoin_delay_log_cb(). The interceptor enables the "cgrp"
1010
+ * debug context on top of any set via the TEST_DEBUG env variable. */
1011
+ const char *debug_contexts[2] = {"cgrp", NULL};
1012
+ test_conf_set_log_interceptor(conf, max_poll_rejoin_delay_log_cb,
1013
+ debug_contexts);
1014
+ c = test_create_consumer(topic, NULL, conf, NULL);
1015
+
1016
+ test_consumer_subscribe(c, topic);
1017
+
1018
+ /* Reach steady membership on an empty topic: the partition is assigned
1019
+ * but there is nothing to fetch, so the forced rejoin race below is
1020
+ * not perturbed by fetch traffic. */
1021
+ TEST_SAY("Waiting for steady assignment\n");
1022
+ deadline = test_clock() + 10 * 1000000;
1023
+ while (test_clock() < deadline) {
1024
+ rkm = rd_kafka_consumer_poll(c, 200);
1025
+ if (rkm)
1026
+ rd_kafka_message_destroy(rkm);
1027
+ if (!rd_kafka_assignment(c, &assignment) && assignment &&
1028
+ assignment->cnt > 0) {
1029
+ rd_kafka_topic_partition_list_destroy(assignment);
1030
+ assignment = NULL;
1031
+ assigned = rd_true;
1032
+ break;
1033
+ }
1034
+ RD_IF_FREE(assignment, rd_kafka_topic_partition_list_destroy);
1035
+ assignment = NULL;
1036
+ }
1037
+ TEST_ASSERT(assigned,
1038
+ "Timed out waiting for steady assignment before the test "
1039
+ "could proceed");
1040
+
1041
+ TEST_SAY("Stalling for 4s (> max.poll.interval.ms=3s)\n");
1042
+ rd_sleep(4);
1043
+
1044
+ /* Produce only now, after the race window, so the records are consumed
1045
+ * by the (re-)joined member rather than prefetched during the race. */
1046
+ test_produce_msgs_easy_v(topic, testid, RD_KAFKA_PARTITION_UA, 0,
1047
+ msgcnt, 64, "bootstrap.servers", bootstraps,
1048
+ NULL);
1049
+
1050
+ /* Resume: a regression goes fatal here (detected first, fails fast);
1051
+ * with the fix the consumer rejoins and consumes all records. */
1052
+ TEST_SAY(
1053
+ "Resuming poll; consumer must rejoin and consume all %d "
1054
+ "records\n",
1055
+ msgcnt);
1056
+ deadline = test_clock() + 20 * 1000000;
1057
+ while (received < msgcnt && test_clock() < deadline) {
1058
+ fatal_err = rd_kafka_fatal_error(c, errstr, sizeof(errstr));
1059
+ if (fatal_err)
1060
+ TEST_FAIL(
1061
+ "Consumer went fatal after max.poll.interval.ms "
1062
+ "expiry instead of rejoining: %s: %s",
1063
+ rd_kafka_err2name(fatal_err), errstr);
1064
+ rkm = rd_kafka_consumer_poll(c, 200);
1065
+ if (!rkm)
1066
+ continue;
1067
+ if (!rkm->err)
1068
+ received++;
1069
+ rd_kafka_message_destroy(rkm);
1070
+ }
1071
+
1072
+ TEST_ASSERT(received == msgcnt,
1073
+ "Expected to consume all %d records after rejoining, "
1074
+ "got %d: consumer failed to fully recover",
1075
+ msgcnt, received);
1076
+
1077
+ test_consumer_close(c);
1078
+ rd_kafka_destroy(c);
1079
+ test_mock_cluster_destroy(mcluster);
1080
+ SUB_TEST_PASS();
1081
+ }
1082
+
1083
+ /**
1084
+ * @brief A GROUP_ID_NOT_FOUND received on a regular heartbeat that is still in
1085
+ * flight when the leave heartbeat has already been sent must be ignored
1086
+ * (the member is on its way out of the group), not turned into a fatal
1087
+ * error.
1088
+ *
1089
+ * The window is forced deterministically: the next regular heartbeat is
1090
+ * answered with GROUP_ID_NOT_FOUND, but its response is held back with a large
1091
+ * RTT. While it is in flight the consumer unsubscribes, which sends the leave
1092
+ * heartbeat and enters the leaving state. The mock sends a connection's
1093
+ * responses in order (head-of-line), so the delayed GROUP_ID_NOT_FOUND is
1094
+ * processed before the leave response leaves the leaving state -- exercising
1095
+ * the skip path. A regression treats it as fatal instead.
1096
+ */
1097
+ static void do_test_group_id_not_found_while_leaving(void) {
1098
+ rd_kafka_mock_cluster_t *mcluster;
1099
+ const char *bootstraps;
1100
+ rd_kafka_t *c;
1101
+ const char *topic = test_mk_topic_name(__FUNCTION__, 0);
1102
+ rd_kafka_topic_partition_list_t *assignment = NULL;
1103
+ rd_bool_t assigned = rd_false;
1104
+ rd_kafka_resp_err_t fatal_err;
1105
+ char errstr[512];
1106
+ int64_t deadline;
1107
+ rd_kafka_message_t *rkm;
1108
+ int found_heartbeats;
1109
+
1110
+ SUB_TEST_QUICK();
1111
+
1112
+ mcluster = test_mock_cluster_new(1, &bootstraps);
1113
+ rd_kafka_mock_set_group_consumer_heartbeat_interval_ms(mcluster, 500);
1114
+ rd_kafka_mock_topic_create(mcluster, topic, 1, 1);
1115
+
1116
+ c = create_consumer(bootstraps, topic, rd_false);
1117
+ test_consumer_subscribe(c, topic);
1118
+
1119
+ TEST_SAY("Waiting for steady assignment\n");
1120
+ deadline = test_clock() + 10 * 1000000;
1121
+ while (test_clock() < deadline) {
1122
+ rkm = rd_kafka_consumer_poll(c, 200);
1123
+ if (rkm)
1124
+ rd_kafka_message_destroy(rkm);
1125
+ if (!rd_kafka_assignment(c, &assignment) && assignment &&
1126
+ assignment->cnt > 0) {
1127
+ rd_kafka_topic_partition_list_destroy(assignment);
1128
+ assignment = NULL;
1129
+ assigned = rd_true;
1130
+ break;
1131
+ }
1132
+ RD_IF_FREE(assignment, rd_kafka_topic_partition_list_destroy);
1133
+ assignment = NULL;
1134
+ }
1135
+ TEST_ASSERT(assigned,
1136
+ "Timed out waiting for steady assignment before the test "
1137
+ "could proceed");
1138
+ TEST_SAY("Steady assignment reached\n");
1139
+
1140
+ /* Answer the next regular heartbeat with GROUP_ID_NOT_FOUND, holding
1141
+ * its response back long enough to land after the leave heartbeat is
1142
+ * sent (which happens within milliseconds of unsubscribe) but well
1143
+ * below the in-flight request timeout so the response is not discarded
1144
+ * as a client-side timeout. While that heartbeat is in flight no
1145
+ * further regular heartbeat is sent, so it is the one that will carry
1146
+ * the error. */
1147
+ rd_kafka_mock_start_request_tracking(mcluster);
1148
+ rd_kafka_mock_broker_push_request_error_rtts(
1149
+ mcluster, 1, RD_KAFKAP_ConsumerGroupHeartbeat, 1,
1150
+ RD_KAFKA_RESP_ERR_GROUP_ID_NOT_FOUND, 500);
1151
+
1152
+ TEST_SAY("Driving the poisoned heartbeat in flight\n");
1153
+ found_heartbeats = wait_all_heartbeats_done(mcluster, 1, 100);
1154
+ TEST_ASSERT(found_heartbeats == 1, "Expected 1 heartbeat, got %d",
1155
+ found_heartbeats);
1156
+
1157
+ TEST_SAY("Unsubscribing while the heartbeat is in flight\n");
1158
+ TEST_CALL_ERR__(rd_kafka_unsubscribe(c));
1159
+
1160
+ /* Poll past the RTT so the delayed GROUP_ID_NOT_FOUND is processed
1161
+ * (must be skipped) followed by the leave response. */
1162
+ deadline = test_clock() + 4 * 1000000;
1163
+ fatal_err = RD_KAFKA_RESP_ERR_NO_ERROR;
1164
+ while (test_clock() < deadline) {
1165
+ rkm = rd_kafka_consumer_poll(c, 200);
1166
+ if (rkm)
1167
+ rd_kafka_message_destroy(rkm);
1168
+ fatal_err = rd_kafka_fatal_error(c, errstr, sizeof(errstr));
1169
+ if (fatal_err)
1170
+ break;
1171
+ }
1172
+
1173
+ TEST_ASSERT(!fatal_err,
1174
+ "GROUP_ID_NOT_FOUND while leaving must be ignored, but the "
1175
+ "consumer went fatal: %s: %s",
1176
+ rd_kafka_err2name(fatal_err), errstr);
1177
+
1178
+ rd_kafka_mock_stop_request_tracking(mcluster);
1179
+ test_consumer_close(c);
1180
+ rd_kafka_destroy(c);
1181
+ test_mock_cluster_destroy(mcluster);
1182
+ SUB_TEST_PASS();
1183
+ }
1184
+
1185
+ int main_0147_consumer_group_consumer_mock(int argc, char **argv) {
1186
+ TEST_SKIP_MOCK_CLUSTER(0);
1187
+
1188
+ if (test_consumer_group_protocol_classic()) {
1189
+ TEST_SKIP("Test only for group.protocol=consumer\n");
1190
+ return 0;
1191
+ }
1192
+
1193
+ do_test_max_poll_interval_rejoin_consume();
1194
+
1195
+ do_test_consumer_group_heartbeat_fatal_errors();
1196
+
1197
+ do_test_group_id_not_found_while_leaving();
1198
+
1199
+ do_test_consumer_group_heartbeat_retriable_errors();
1200
+
1201
+ do_test_consumer_group_heartbeat_fenced_errors();
1202
+
1203
+ do_test_metadata_unknown_topic_id_tests();
1204
+
1205
+ do_test_adherence_to_hb_interval();
1206
+
1207
+ do_test_quick_unsubscribe_tests();
1208
+
1209
+ return 0;
1210
+ }