@ohos-ports/514labs-kafka-javascript 0.0.0-stage → 1.7.1-patch-beta.0

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 (639) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/.editorconfig +5 -0
  3. package/.envrc +1 -0
  4. package/CHANGELOG.md +380 -0
  5. package/CONTRIBUTING.md +257 -0
  6. package/INTRODUCTION.md +1155 -0
  7. package/LICENSE.kafkajs +31 -0
  8. package/LICENSE.node-rdkafka +25 -0
  9. package/LICENSE.txt +20 -0
  10. package/MIGRATION.md +428 -0
  11. package/Makefile +84 -0
  12. package/QUICKSTART.md +70 -0
  13. package/README.md +127 -2
  14. package/SECURITY.md +11 -0
  15. package/binding.gyp +167 -0
  16. package/buf.gen.yaml +8 -0
  17. package/build/Release/confluent-kafka-javascript.node +0 -0
  18. package/configure +15 -0
  19. package/coverage/mocha/base.css +224 -0
  20. package/coverage/mocha/block-navigation.js +87 -0
  21. package/coverage/mocha/coverage-final.json +11 -0
  22. package/coverage/mocha/favicon.png +0 -0
  23. package/coverage/mocha/forked-kafkajs/index.html +116 -0
  24. package/coverage/mocha/forked-kafkajs/lib/client.js.html +2122 -0
  25. package/coverage/mocha/forked-kafkajs/lib/error.js.html +1588 -0
  26. package/coverage/mocha/forked-kafkajs/lib/index.html +236 -0
  27. package/coverage/mocha/forked-kafkajs/lib/kafka-consumer-stream.js.html +1282 -0
  28. package/coverage/mocha/forked-kafkajs/lib/kafka-consumer.js.html +2476 -0
  29. package/coverage/mocha/forked-kafkajs/lib/producer-stream.js.html +1096 -0
  30. package/coverage/mocha/forked-kafkajs/lib/producer.js.html +1300 -0
  31. package/coverage/mocha/forked-kafkajs/lib/topic-partition.js.html +358 -0
  32. package/coverage/mocha/forked-kafkajs/lib/topic.js.html +214 -0
  33. package/coverage/mocha/forked-kafkajs/lib/util.js.html +250 -0
  34. package/coverage/mocha/forked-kafkajs/librdkafka.js.html +121 -0
  35. package/coverage/mocha/index.html +131 -0
  36. package/coverage/mocha/prettify.css +1 -0
  37. package/coverage/mocha/prettify.js +2 -0
  38. package/coverage/mocha/sort-arrow-sprite.png +0 -0
  39. package/coverage/mocha/sorter.js +210 -0
  40. package/cpplint.py +6970 -0
  41. package/deploy.enc +0 -0
  42. package/deps/librdkafka/.clang-format +136 -0
  43. package/deps/librdkafka/.clang-format-cpp +103 -0
  44. package/deps/librdkafka/.dir-locals.el +10 -0
  45. package/deps/librdkafka/.formatignore +33 -0
  46. package/deps/librdkafka/.gdbmacros +19 -0
  47. package/deps/librdkafka/CHANGELOG.md +2225 -0
  48. package/deps/librdkafka/CMakeLists.txt +291 -0
  49. package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
  50. package/deps/librdkafka/CONFIGURATION.md +209 -0
  51. package/deps/librdkafka/CONTRIBUTING.md +431 -0
  52. package/deps/librdkafka/Doxyfile +2375 -0
  53. package/deps/librdkafka/INTRODUCTION.md +2481 -0
  54. package/deps/librdkafka/LICENSE +26 -0
  55. package/deps/librdkafka/LICENSE.cjson +22 -0
  56. package/deps/librdkafka/LICENSE.crc32c +28 -0
  57. package/deps/librdkafka/LICENSE.fnv1a +18 -0
  58. package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
  59. package/deps/librdkafka/LICENSE.lz4 +26 -0
  60. package/deps/librdkafka/LICENSE.murmur2 +25 -0
  61. package/deps/librdkafka/LICENSE.nanopb +22 -0
  62. package/deps/librdkafka/LICENSE.opentelemetry +203 -0
  63. package/deps/librdkafka/LICENSE.pycrc +23 -0
  64. package/deps/librdkafka/LICENSE.queue +31 -0
  65. package/deps/librdkafka/LICENSE.regexp +5 -0
  66. package/deps/librdkafka/LICENSE.snappy +36 -0
  67. package/deps/librdkafka/LICENSE.tinycthread +26 -0
  68. package/deps/librdkafka/LICENSE.wingetopt +49 -0
  69. package/deps/librdkafka/LICENSES.txt +625 -0
  70. package/deps/librdkafka/Makefile +125 -0
  71. package/deps/librdkafka/README.md +199 -0
  72. package/deps/librdkafka/README.win32 +26 -0
  73. package/deps/librdkafka/STATISTICS.md +624 -0
  74. package/deps/librdkafka/configure +214 -0
  75. package/deps/librdkafka/configure.self +331 -0
  76. package/deps/librdkafka/dev-conf.sh +123 -0
  77. package/deps/librdkafka/lds-gen.py +73 -0
  78. package/deps/librdkafka/mainpage.doxy +40 -0
  79. package/deps/librdkafka/mklove/Makefile.base +329 -0
  80. package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
  81. package/deps/librdkafka/mklove/modules/configure.base +2484 -0
  82. package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
  83. package/deps/librdkafka/mklove/modules/configure.cc +186 -0
  84. package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
  85. package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
  86. package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
  87. package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
  88. package/deps/librdkafka/mklove/modules/configure.host +132 -0
  89. package/deps/librdkafka/mklove/modules/configure.lib +49 -0
  90. package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
  91. package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
  92. package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
  93. package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
  94. package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
  95. package/deps/librdkafka/mklove/modules/configure.pic +16 -0
  96. package/deps/librdkafka/mklove/modules/configure.socket +20 -0
  97. package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
  98. package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
  99. package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
  100. package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
  101. package/deps/librdkafka/service.yml +172 -0
  102. package/deps/librdkafka/src/CMakeLists.txt +374 -0
  103. package/deps/librdkafka/src/Makefile +103 -0
  104. package/deps/librdkafka/src/README.lz4.md +30 -0
  105. package/deps/librdkafka/src/cJSON.c +2834 -0
  106. package/deps/librdkafka/src/cJSON.h +398 -0
  107. package/deps/librdkafka/src/crc32c.c +430 -0
  108. package/deps/librdkafka/src/crc32c.h +38 -0
  109. package/deps/librdkafka/src/generate_proto.sh +66 -0
  110. package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
  111. package/deps/librdkafka/src/lz4.c +2727 -0
  112. package/deps/librdkafka/src/lz4.h +842 -0
  113. package/deps/librdkafka/src/lz4frame.c +2078 -0
  114. package/deps/librdkafka/src/lz4frame.h +692 -0
  115. package/deps/librdkafka/src/lz4frame_static.h +47 -0
  116. package/deps/librdkafka/src/lz4hc.c +1631 -0
  117. package/deps/librdkafka/src/lz4hc.h +413 -0
  118. package/deps/librdkafka/src/nanopb/pb.h +917 -0
  119. package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
  120. package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
  121. package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
  122. package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
  123. package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
  124. package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
  125. package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
  126. package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
  127. package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
  128. package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
  129. package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
  130. package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
  131. package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
  132. package/deps/librdkafka/src/queue.h +850 -0
  133. package/deps/librdkafka/src/rd.h +584 -0
  134. package/deps/librdkafka/src/rdaddr.c +255 -0
  135. package/deps/librdkafka/src/rdaddr.h +202 -0
  136. package/deps/librdkafka/src/rdatomic.h +230 -0
  137. package/deps/librdkafka/src/rdavg.h +260 -0
  138. package/deps/librdkafka/src/rdavl.c +210 -0
  139. package/deps/librdkafka/src/rdavl.h +250 -0
  140. package/deps/librdkafka/src/rdbase64.c +200 -0
  141. package/deps/librdkafka/src/rdbase64.h +43 -0
  142. package/deps/librdkafka/src/rdbuf.c +1884 -0
  143. package/deps/librdkafka/src/rdbuf.h +375 -0
  144. package/deps/librdkafka/src/rdcrc32.c +114 -0
  145. package/deps/librdkafka/src/rdcrc32.h +170 -0
  146. package/deps/librdkafka/src/rddl.c +179 -0
  147. package/deps/librdkafka/src/rddl.h +43 -0
  148. package/deps/librdkafka/src/rdendian.h +175 -0
  149. package/deps/librdkafka/src/rdfloat.h +67 -0
  150. package/deps/librdkafka/src/rdfnv1a.c +113 -0
  151. package/deps/librdkafka/src/rdfnv1a.h +35 -0
  152. package/deps/librdkafka/src/rdgz.c +120 -0
  153. package/deps/librdkafka/src/rdgz.h +46 -0
  154. package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
  155. package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
  156. package/deps/librdkafka/src/rdhttp.c +830 -0
  157. package/deps/librdkafka/src/rdhttp.h +101 -0
  158. package/deps/librdkafka/src/rdinterval.h +177 -0
  159. package/deps/librdkafka/src/rdkafka.c +5505 -0
  160. package/deps/librdkafka/src/rdkafka.h +10686 -0
  161. package/deps/librdkafka/src/rdkafka_admin.c +9794 -0
  162. package/deps/librdkafka/src/rdkafka_admin.h +661 -0
  163. package/deps/librdkafka/src/rdkafka_assignment.c +1010 -0
  164. package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
  165. package/deps/librdkafka/src/rdkafka_assignor.c +1786 -0
  166. package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
  167. package/deps/librdkafka/src/rdkafka_aux.c +409 -0
  168. package/deps/librdkafka/src/rdkafka_aux.h +174 -0
  169. package/deps/librdkafka/src/rdkafka_background.c +221 -0
  170. package/deps/librdkafka/src/rdkafka_broker.c +6337 -0
  171. package/deps/librdkafka/src/rdkafka_broker.h +744 -0
  172. package/deps/librdkafka/src/rdkafka_buf.c +543 -0
  173. package/deps/librdkafka/src/rdkafka_buf.h +1525 -0
  174. package/deps/librdkafka/src/rdkafka_cert.c +576 -0
  175. package/deps/librdkafka/src/rdkafka_cert.h +62 -0
  176. package/deps/librdkafka/src/rdkafka_cgrp.c +7587 -0
  177. package/deps/librdkafka/src/rdkafka_cgrp.h +477 -0
  178. package/deps/librdkafka/src/rdkafka_conf.c +4880 -0
  179. package/deps/librdkafka/src/rdkafka_conf.h +732 -0
  180. package/deps/librdkafka/src/rdkafka_confval.h +97 -0
  181. package/deps/librdkafka/src/rdkafka_coord.c +623 -0
  182. package/deps/librdkafka/src/rdkafka_coord.h +132 -0
  183. package/deps/librdkafka/src/rdkafka_error.c +228 -0
  184. package/deps/librdkafka/src/rdkafka_error.h +80 -0
  185. package/deps/librdkafka/src/rdkafka_event.c +502 -0
  186. package/deps/librdkafka/src/rdkafka_event.h +126 -0
  187. package/deps/librdkafka/src/rdkafka_feature.c +898 -0
  188. package/deps/librdkafka/src/rdkafka_feature.h +104 -0
  189. package/deps/librdkafka/src/rdkafka_fetcher.c +1422 -0
  190. package/deps/librdkafka/src/rdkafka_fetcher.h +44 -0
  191. package/deps/librdkafka/src/rdkafka_header.c +220 -0
  192. package/deps/librdkafka/src/rdkafka_header.h +76 -0
  193. package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
  194. package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
  195. package/deps/librdkafka/src/rdkafka_int.h +1260 -0
  196. package/deps/librdkafka/src/rdkafka_interceptor.c +819 -0
  197. package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
  198. package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
  199. package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
  200. package/deps/librdkafka/src/rdkafka_metadata.c +2209 -0
  201. package/deps/librdkafka/src/rdkafka_metadata.h +345 -0
  202. package/deps/librdkafka/src/rdkafka_metadata_cache.c +1183 -0
  203. package/deps/librdkafka/src/rdkafka_mock.c +3661 -0
  204. package/deps/librdkafka/src/rdkafka_mock.h +610 -0
  205. package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1876 -0
  206. package/deps/librdkafka/src/rdkafka_mock_handlers.c +3113 -0
  207. package/deps/librdkafka/src/rdkafka_mock_int.h +710 -0
  208. package/deps/librdkafka/src/rdkafka_msg.c +2589 -0
  209. package/deps/librdkafka/src/rdkafka_msg.h +614 -0
  210. package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
  211. package/deps/librdkafka/src/rdkafka_msgset.h +98 -0
  212. package/deps/librdkafka/src/rdkafka_msgset_reader.c +1806 -0
  213. package/deps/librdkafka/src/rdkafka_msgset_writer.c +1474 -0
  214. package/deps/librdkafka/src/rdkafka_offset.c +1565 -0
  215. package/deps/librdkafka/src/rdkafka_offset.h +150 -0
  216. package/deps/librdkafka/src/rdkafka_op.c +997 -0
  217. package/deps/librdkafka/src/rdkafka_op.h +858 -0
  218. package/deps/librdkafka/src/rdkafka_partition.c +4896 -0
  219. package/deps/librdkafka/src/rdkafka_partition.h +1182 -0
  220. package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
  221. package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
  222. package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
  223. package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
  224. package/deps/librdkafka/src/rdkafka_proto.h +736 -0
  225. package/deps/librdkafka/src/rdkafka_protocol.h +128 -0
  226. package/deps/librdkafka/src/rdkafka_queue.c +1230 -0
  227. package/deps/librdkafka/src/rdkafka_queue.h +1220 -0
  228. package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
  229. package/deps/librdkafka/src/rdkafka_request.c +7089 -0
  230. package/deps/librdkafka/src/rdkafka_request.h +732 -0
  231. package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
  232. package/deps/librdkafka/src/rdkafka_sasl.c +530 -0
  233. package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
  234. package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
  235. package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
  236. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1833 -0
  237. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
  238. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1666 -0
  239. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +47 -0
  240. package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
  241. package/deps/librdkafka/src/rdkafka_sasl_scram.c +858 -0
  242. package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
  243. package/deps/librdkafka/src/rdkafka_ssl.c +2129 -0
  244. package/deps/librdkafka/src/rdkafka_ssl.h +86 -0
  245. package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4785 -0
  246. package/deps/librdkafka/src/rdkafka_subscription.c +278 -0
  247. package/deps/librdkafka/src/rdkafka_telemetry.c +760 -0
  248. package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
  249. package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1053 -0
  250. package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
  251. package/deps/librdkafka/src/rdkafka_telemetry_encode.c +997 -0
  252. package/deps/librdkafka/src/rdkafka_telemetry_encode.h +301 -0
  253. package/deps/librdkafka/src/rdkafka_timer.c +402 -0
  254. package/deps/librdkafka/src/rdkafka_timer.h +117 -0
  255. package/deps/librdkafka/src/rdkafka_topic.c +2161 -0
  256. package/deps/librdkafka/src/rdkafka_topic.h +334 -0
  257. package/deps/librdkafka/src/rdkafka_transport.c +1309 -0
  258. package/deps/librdkafka/src/rdkafka_transport.h +99 -0
  259. package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
  260. package/deps/librdkafka/src/rdkafka_txnmgr.c +3256 -0
  261. package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
  262. package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
  263. package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
  264. package/deps/librdkafka/src/rdlist.c +576 -0
  265. package/deps/librdkafka/src/rdlist.h +434 -0
  266. package/deps/librdkafka/src/rdlog.c +89 -0
  267. package/deps/librdkafka/src/rdlog.h +41 -0
  268. package/deps/librdkafka/src/rdmap.c +508 -0
  269. package/deps/librdkafka/src/rdmap.h +492 -0
  270. package/deps/librdkafka/src/rdmurmur2.c +167 -0
  271. package/deps/librdkafka/src/rdmurmur2.h +35 -0
  272. package/deps/librdkafka/src/rdports.c +61 -0
  273. package/deps/librdkafka/src/rdports.h +38 -0
  274. package/deps/librdkafka/src/rdposix.h +250 -0
  275. package/deps/librdkafka/src/rdrand.c +80 -0
  276. package/deps/librdkafka/src/rdrand.h +43 -0
  277. package/deps/librdkafka/src/rdregex.c +156 -0
  278. package/deps/librdkafka/src/rdregex.h +43 -0
  279. package/deps/librdkafka/src/rdsignal.h +57 -0
  280. package/deps/librdkafka/src/rdstring.c +645 -0
  281. package/deps/librdkafka/src/rdstring.h +98 -0
  282. package/deps/librdkafka/src/rdsysqueue.h +404 -0
  283. package/deps/librdkafka/src/rdtime.h +356 -0
  284. package/deps/librdkafka/src/rdtypes.h +86 -0
  285. package/deps/librdkafka/src/rdunittest.c +549 -0
  286. package/deps/librdkafka/src/rdunittest.h +232 -0
  287. package/deps/librdkafka/src/rdvarint.c +134 -0
  288. package/deps/librdkafka/src/rdvarint.h +165 -0
  289. package/deps/librdkafka/src/rdwin32.h +382 -0
  290. package/deps/librdkafka/src/rdxxhash.c +1030 -0
  291. package/deps/librdkafka/src/rdxxhash.h +328 -0
  292. package/deps/librdkafka/src/regexp.c +1352 -0
  293. package/deps/librdkafka/src/regexp.h +41 -0
  294. package/deps/librdkafka/src/snappy.c +1866 -0
  295. package/deps/librdkafka/src/snappy.h +62 -0
  296. package/deps/librdkafka/src/snappy_compat.h +138 -0
  297. package/deps/librdkafka/src/statistics_schema.json +444 -0
  298. package/deps/librdkafka/src/tinycthread.c +932 -0
  299. package/deps/librdkafka/src/tinycthread.h +503 -0
  300. package/deps/librdkafka/src/tinycthread_extra.c +199 -0
  301. package/deps/librdkafka/src/tinycthread_extra.h +212 -0
  302. package/deps/librdkafka/src/win32_config.h +58 -0
  303. package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
  304. package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
  305. package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
  306. package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
  307. package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
  308. package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
  309. package/deps/librdkafka/src-cpp/Makefile +55 -0
  310. package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
  311. package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
  312. package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
  313. package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
  314. package/deps/librdkafka/src-cpp/README.md +16 -0
  315. package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
  316. package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
  317. package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
  318. package/deps/librdkafka/src-cpp/rdkafkacpp.h +3797 -0
  319. package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
  320. package/deps/librdkafka/tests/0000-unittests.c +72 -0
  321. package/deps/librdkafka/tests/0001-multiobj.c +102 -0
  322. package/deps/librdkafka/tests/0002-unkpart.c +244 -0
  323. package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
  324. package/deps/librdkafka/tests/0004-conf.c +934 -0
  325. package/deps/librdkafka/tests/0005-order.c +133 -0
  326. package/deps/librdkafka/tests/0006-symbols.c +163 -0
  327. package/deps/librdkafka/tests/0007-autotopic.c +136 -0
  328. package/deps/librdkafka/tests/0008-reqacks.c +179 -0
  329. package/deps/librdkafka/tests/0009-mock_cluster.c +97 -0
  330. package/deps/librdkafka/tests/0011-produce_batch.c +753 -0
  331. package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
  332. package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
  333. package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
  334. package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
  335. package/deps/librdkafka/tests/0016-client_swname.c +181 -0
  336. package/deps/librdkafka/tests/0017-compression.c +140 -0
  337. package/deps/librdkafka/tests/0018-cgrp_term.c +338 -0
  338. package/deps/librdkafka/tests/0019-list_groups.c +289 -0
  339. package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
  340. package/deps/librdkafka/tests/0021-rkt_destroy.c +72 -0
  341. package/deps/librdkafka/tests/0022-consume_batch.c +279 -0
  342. package/deps/librdkafka/tests/0025-timers.c +147 -0
  343. package/deps/librdkafka/tests/0026-consume_pause.c +547 -0
  344. package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
  345. package/deps/librdkafka/tests/0029-assign_offset.c +202 -0
  346. package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
  347. package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
  348. package/deps/librdkafka/tests/0033-regex_subscribe.c +536 -0
  349. package/deps/librdkafka/tests/0034-offset_reset.c +398 -0
  350. package/deps/librdkafka/tests/0035-api_version.c +73 -0
  351. package/deps/librdkafka/tests/0036-partial_fetch.c +87 -0
  352. package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
  353. package/deps/librdkafka/tests/0038-performance.c +121 -0
  354. package/deps/librdkafka/tests/0039-event.c +284 -0
  355. package/deps/librdkafka/tests/0040-io_event.c +257 -0
  356. package/deps/librdkafka/tests/0041-fetch_max_bytes.c +97 -0
  357. package/deps/librdkafka/tests/0042-many_topics.c +252 -0
  358. package/deps/librdkafka/tests/0043-no_connection.c +77 -0
  359. package/deps/librdkafka/tests/0044-partition_cnt.c +94 -0
  360. package/deps/librdkafka/tests/0045-subscribe_update.c +1010 -0
  361. package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
  362. package/deps/librdkafka/tests/0047-partial_buf_tmout.c +98 -0
  363. package/deps/librdkafka/tests/0048-partitioner.c +283 -0
  364. package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
  365. package/deps/librdkafka/tests/0050-subscribe_adds.c +145 -0
  366. package/deps/librdkafka/tests/0051-assign_adds.c +126 -0
  367. package/deps/librdkafka/tests/0052-msg_timestamps.c +238 -0
  368. package/deps/librdkafka/tests/0053-stats_cb.cpp +527 -0
  369. package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
  370. package/deps/librdkafka/tests/0055-producer_latency.c +539 -0
  371. package/deps/librdkafka/tests/0056-balanced_group_mt.c +315 -0
  372. package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
  373. package/deps/librdkafka/tests/0058-log.cpp +123 -0
  374. package/deps/librdkafka/tests/0059-bsearch.cpp +241 -0
  375. package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
  376. package/deps/librdkafka/tests/0061-consumer_lag.cpp +295 -0
  377. package/deps/librdkafka/tests/0062-stats_event.c +126 -0
  378. package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
  379. package/deps/librdkafka/tests/0064-interceptors.c +481 -0
  380. package/deps/librdkafka/tests/0065-yield.cpp +140 -0
  381. package/deps/librdkafka/tests/0066-plugins.cpp +129 -0
  382. package/deps/librdkafka/tests/0067-empty_topic.cpp +151 -0
  383. package/deps/librdkafka/tests/0068-produce_timeout.c +136 -0
  384. package/deps/librdkafka/tests/0069-consumer_add_parts.c +119 -0
  385. package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
  386. package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
  387. package/deps/librdkafka/tests/0073-headers.c +381 -0
  388. package/deps/librdkafka/tests/0074-producev.c +87 -0
  389. package/deps/librdkafka/tests/0075-retry.c +290 -0
  390. package/deps/librdkafka/tests/0076-produce_retry.c +452 -0
  391. package/deps/librdkafka/tests/0077-compaction.c +363 -0
  392. package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
  393. package/deps/librdkafka/tests/0079-fork.c +93 -0
  394. package/deps/librdkafka/tests/0080-admin_ut.c +3095 -0
  395. package/deps/librdkafka/tests/0081-admin.c +5633 -0
  396. package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +137 -0
  397. package/deps/librdkafka/tests/0083-cb_event.c +233 -0
  398. package/deps/librdkafka/tests/0084-destroy_flags.c +208 -0
  399. package/deps/librdkafka/tests/0085-headers.cpp +392 -0
  400. package/deps/librdkafka/tests/0086-purge.c +368 -0
  401. package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
  402. package/deps/librdkafka/tests/0089-max_poll_interval.c +511 -0
  403. package/deps/librdkafka/tests/0090-idempotence.c +171 -0
  404. package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +295 -0
  405. package/deps/librdkafka/tests/0092-mixed_msgver.c +103 -0
  406. package/deps/librdkafka/tests/0093-holb.c +200 -0
  407. package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +231 -0
  408. package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
  409. package/deps/librdkafka/tests/0097-ssl_verify.cpp +658 -0
  410. package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
  411. package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
  412. package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
  413. package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
  414. package/deps/librdkafka/tests/0102-static_group_rebalance.c +836 -0
  415. package/deps/librdkafka/tests/0103-transactions.c +1383 -0
  416. package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +625 -0
  417. package/deps/librdkafka/tests/0105-transactions_mock.c +3930 -0
  418. package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +318 -0
  419. package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
  420. package/deps/librdkafka/tests/0109-auto_create_topics.cpp +278 -0
  421. package/deps/librdkafka/tests/0110-batch_size.cpp +182 -0
  422. package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
  423. package/deps/librdkafka/tests/0112-assign_unknown_part.c +87 -0
  424. package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3473 -0
  425. package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
  426. package/deps/librdkafka/tests/0115-producer_auth.cpp +182 -0
  427. package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +216 -0
  428. package/deps/librdkafka/tests/0117-mock_errors.c +331 -0
  429. package/deps/librdkafka/tests/0118-commit_rebalance.c +154 -0
  430. package/deps/librdkafka/tests/0119-consumer_auth.cpp +167 -0
  431. package/deps/librdkafka/tests/0120-asymmetric_subscription.c +185 -0
  432. package/deps/librdkafka/tests/0121-clusterid.c +115 -0
  433. package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
  434. package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
  435. package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
  436. package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
  437. package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +528 -0
  438. package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
  439. package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +125 -0
  440. package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +79 -0
  441. package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
  442. package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
  443. package/deps/librdkafka/tests/0132-strategy_ordering.c +179 -0
  444. package/deps/librdkafka/tests/0133-ssl_keys.c +150 -0
  445. package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
  446. package/deps/librdkafka/tests/0135-sasl_credentials.cpp +143 -0
  447. package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
  448. package/deps/librdkafka/tests/0137-barrier_batch_consume.c +619 -0
  449. package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
  450. package/deps/librdkafka/tests/0139-offset_validation_mock.c +950 -0
  451. package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
  452. package/deps/librdkafka/tests/0142-reauthentication.c +515 -0
  453. package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +552 -0
  454. package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
  455. package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
  456. package/deps/librdkafka/tests/0146-metadata_mock.c +505 -0
  457. package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +952 -0
  458. package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +563 -0
  459. package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
  460. package/deps/librdkafka/tests/0150-telemetry_mock.c +651 -0
  461. package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
  462. package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
  463. package/deps/librdkafka/tests/0153-memberid.c +128 -0
  464. package/deps/librdkafka/tests/1000-unktopic.c +164 -0
  465. package/deps/librdkafka/tests/8000-idle.cpp +60 -0
  466. package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
  467. package/deps/librdkafka/tests/CMakeLists.txt +170 -0
  468. package/deps/librdkafka/tests/LibrdkafkaTestApp.py +291 -0
  469. package/deps/librdkafka/tests/Makefile +182 -0
  470. package/deps/librdkafka/tests/README.md +509 -0
  471. package/deps/librdkafka/tests/autotest.sh +33 -0
  472. package/deps/librdkafka/tests/backtrace.gdb +30 -0
  473. package/deps/librdkafka/tests/broker_version_tests.py +315 -0
  474. package/deps/librdkafka/tests/buildbox.sh +17 -0
  475. package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
  476. package/deps/librdkafka/tests/cluster_testing.py +191 -0
  477. package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
  478. package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
  479. package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
  480. package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
  481. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
  482. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
  483. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
  484. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +50 -0
  485. package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
  486. package/deps/librdkafka/tests/fixtures/ssl/client2.key +46 -0
  487. package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +168 -0
  488. package/deps/librdkafka/tests/fuzzers/Makefile +12 -0
  489. package/deps/librdkafka/tests/fuzzers/README.md +31 -0
  490. package/deps/librdkafka/tests/fuzzers/fuzz_regex.c +74 -0
  491. package/deps/librdkafka/tests/fuzzers/helpers.h +90 -0
  492. package/deps/librdkafka/tests/gen-ssl-certs.sh +165 -0
  493. package/deps/librdkafka/tests/interactive_broker_version.py +170 -0
  494. package/deps/librdkafka/tests/interceptor_test/CMakeLists.txt +16 -0
  495. package/deps/librdkafka/tests/interceptor_test/Makefile +22 -0
  496. package/deps/librdkafka/tests/interceptor_test/interceptor_test.c +314 -0
  497. package/deps/librdkafka/tests/interceptor_test/interceptor_test.h +54 -0
  498. package/deps/librdkafka/tests/java/IncrementalRebalanceCli.java +97 -0
  499. package/deps/librdkafka/tests/java/Makefile +13 -0
  500. package/deps/librdkafka/tests/java/Murmur2Cli.java +46 -0
  501. package/deps/librdkafka/tests/java/README.md +14 -0
  502. package/deps/librdkafka/tests/java/TransactionProducerCli.java +162 -0
  503. package/deps/librdkafka/tests/java/run-class.sh +11 -0
  504. package/deps/librdkafka/tests/librdkafka.suppressions +483 -0
  505. package/deps/librdkafka/tests/lz4_manual_test.sh +59 -0
  506. package/deps/librdkafka/tests/multi-broker-version-test.sh +50 -0
  507. package/deps/librdkafka/tests/parse-refcnt.sh +43 -0
  508. package/deps/librdkafka/tests/performance_plot.py +115 -0
  509. package/deps/librdkafka/tests/plugin_test/Makefile +19 -0
  510. package/deps/librdkafka/tests/plugin_test/plugin_test.c +58 -0
  511. package/deps/librdkafka/tests/requirements.txt +2 -0
  512. package/deps/librdkafka/tests/run-all-tests.sh +79 -0
  513. package/deps/librdkafka/tests/run-consumer-tests.sh +16 -0
  514. package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
  515. package/deps/librdkafka/tests/run-test-batches.py +157 -0
  516. package/deps/librdkafka/tests/run-test.sh +140 -0
  517. package/deps/librdkafka/tests/rusage.c +249 -0
  518. package/deps/librdkafka/tests/sasl_test.py +289 -0
  519. package/deps/librdkafka/tests/scenarios/README.md +6 -0
  520. package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
  521. package/deps/librdkafka/tests/scenarios/default.json +5 -0
  522. package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
  523. package/deps/librdkafka/tests/sockem.c +801 -0
  524. package/deps/librdkafka/tests/sockem.h +85 -0
  525. package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
  526. package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
  527. package/deps/librdkafka/tests/test.c +7778 -0
  528. package/deps/librdkafka/tests/test.conf.example +27 -0
  529. package/deps/librdkafka/tests/test.h +1028 -0
  530. package/deps/librdkafka/tests/testcpp.cpp +131 -0
  531. package/deps/librdkafka/tests/testcpp.h +388 -0
  532. package/deps/librdkafka/tests/testshared.h +416 -0
  533. package/deps/librdkafka/tests/tools/README.md +4 -0
  534. package/deps/librdkafka/tests/tools/stats/README.md +21 -0
  535. package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
  536. package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
  537. package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
  538. package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
  539. package/deps/librdkafka/tests/trivup/trivup-0.14.0.tar.gz +0 -0
  540. package/deps/librdkafka/tests/until-fail.sh +87 -0
  541. package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
  542. package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
  543. package/deps/librdkafka/vcpkg.json +23 -0
  544. package/deps/librdkafka/win32/README.md +5 -0
  545. package/deps/librdkafka/win32/build-package.bat +3 -0
  546. package/deps/librdkafka/win32/build.bat +19 -0
  547. package/deps/librdkafka/win32/common.vcxproj +84 -0
  548. package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
  549. package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
  550. package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
  551. package/deps/librdkafka/win32/librdkafka.sln +226 -0
  552. package/deps/librdkafka/win32/librdkafka.vcxproj +276 -0
  553. package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
  554. package/deps/librdkafka/win32/msbuild.ps1 +15 -0
  555. package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
  556. package/deps/librdkafka/win32/package-zip.ps1 +46 -0
  557. package/deps/librdkafka/win32/packages/repositories.config +4 -0
  558. package/deps/librdkafka/win32/push-package.bat +4 -0
  559. package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
  560. package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
  561. package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
  562. package/deps/librdkafka/win32/setup-msys2.ps1 +47 -0
  563. package/deps/librdkafka/win32/setup-vcpkg.ps1 +34 -0
  564. package/deps/librdkafka/win32/tests/test.conf.example +25 -0
  565. package/deps/librdkafka/win32/tests/tests.vcxproj +253 -0
  566. package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
  567. package/deps/librdkafka/win32/wingetopt.c +564 -0
  568. package/deps/librdkafka/win32/wingetopt.h +101 -0
  569. package/deps/librdkafka/win32/wintime.h +33 -0
  570. package/deps/librdkafka.gyp +83 -0
  571. package/deps/windows-install.py +80 -0
  572. package/eslint.config.js +75 -0
  573. package/flake.lock +61 -0
  574. package/flake.nix +76 -0
  575. package/index.d.ts +3 -0
  576. package/jest.config.js +8 -0
  577. package/jsdoc.conf +23 -0
  578. package/lib/admin.js +732 -0
  579. package/lib/client.js +679 -0
  580. package/lib/error.js +501 -0
  581. package/lib/index.js +8 -0
  582. package/lib/kafka-consumer-stream.js +399 -0
  583. package/lib/kafka-consumer.js +798 -0
  584. package/lib/kafkajs/_admin.js +1053 -0
  585. package/lib/kafkajs/_common.js +887 -0
  586. package/lib/kafkajs/_consumer.js +2143 -0
  587. package/lib/kafkajs/_consumer_cache.js +310 -0
  588. package/lib/kafkajs/_error.js +298 -0
  589. package/lib/kafkajs/_kafka.js +125 -0
  590. package/lib/kafkajs/_linked-list.js +220 -0
  591. package/lib/kafkajs/_producer.js +863 -0
  592. package/lib/kafkajs/index.js +5 -0
  593. package/lib/producer/high-level-producer.js +400 -0
  594. package/lib/producer-stream.js +337 -0
  595. package/lib/producer.js +405 -0
  596. package/lib/rdkafka.js +44 -0
  597. package/lib/tools/ref-counter.js +53 -0
  598. package/lib/topic-partition.js +91 -0
  599. package/lib/topic.js +43 -0
  600. package/lib/util.js +55 -0
  601. package/librdkafka.js +12 -0
  602. package/make_docs.sh +57 -0
  603. package/package.json +59 -4
  604. package/run_docker.sh +42 -0
  605. package/service.yml +36 -0
  606. package/sonar-project.properties +9 -0
  607. package/src/admin.cc +1597 -0
  608. package/src/admin.h +112 -0
  609. package/src/binding.cc +76 -0
  610. package/src/binding.h +25 -0
  611. package/src/callbacks.cc +676 -0
  612. package/src/callbacks.h +302 -0
  613. package/src/common.cc +1601 -0
  614. package/src/common.h +192 -0
  615. package/src/config.cc +219 -0
  616. package/src/config.h +61 -0
  617. package/src/connection.cc +703 -0
  618. package/src/connection.h +117 -0
  619. package/src/errors.cc +119 -0
  620. package/src/errors.h +60 -0
  621. package/src/kafka-consumer.cc +1539 -0
  622. package/src/kafka-consumer.h +147 -0
  623. package/src/producer.cc +917 -0
  624. package/src/producer.h +124 -0
  625. package/src/topic.cc +173 -0
  626. package/src/topic.h +54 -0
  627. package/src/workers.cc +1714 -0
  628. package/src/workers.h +690 -0
  629. package/tsconfig.json +18 -0
  630. package/types/config.d.ts +1248 -0
  631. package/types/errors.d.ts +373 -0
  632. package/types/kafkajs.d.ts +568 -0
  633. package/types/rdkafka.d.ts +561 -0
  634. package/util/configure.js +34 -0
  635. package/util/generate-docs.sh +18 -0
  636. package/util/get-env.js +6 -0
  637. package/util/test-compile.js +11 -0
  638. package/util/test-producer-delivery.js +100 -0
  639. package/win_install.ps1 +2 -0
@@ -0,0 +1,3113 @@
1
+ /*
2
+ * librdkafka - Apache Kafka C library
3
+ *
4
+ * Copyright (c) 2019-2022, Magnus Edenhill,
5
+ * 2023, Confluent Inc.
6
+ * All rights reserved.
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without
9
+ * modification, are permitted provided that the following conditions are met:
10
+ *
11
+ * 1. Redistributions of source code must retain the above copyright notice,
12
+ * this list of conditions and the following disclaimer.
13
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
14
+ * this list of conditions and the following disclaimer in the documentation
15
+ * and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ * POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ /**
31
+ * Mocks - protocol request handlers
32
+ *
33
+ */
34
+
35
+ #include "rdkafka_int.h"
36
+ #include "rdbuf.h"
37
+ #include "rdrand.h"
38
+ #include "rdkafka_interceptor.h"
39
+ #include "rdkafka_mock_int.h"
40
+ #include "rdkafka_transport_int.h"
41
+ #include "rdkafka_offset.h"
42
+ #include "rdkafka_telemetry_decode.h"
43
+
44
+
45
+
46
+ void rd_kafka_mock_Produce_reply_tags_partition_write(
47
+ rd_kafka_buf_t *rkbuf,
48
+ int tagtype,
49
+ rd_kafka_mock_partition_t *mpart) {
50
+ switch (tagtype) {
51
+ case 0: /* CurrentLeader */
52
+ /* Leader id */
53
+ rd_kafka_buf_write_i32(rkbuf, mpart->leader->id);
54
+ /* Leader epoch */
55
+ rd_kafka_buf_write_i32(rkbuf, mpart->leader_epoch);
56
+ /* Field tags */
57
+ rd_kafka_buf_write_tags_empty(rkbuf);
58
+ break;
59
+ default:
60
+ break;
61
+ }
62
+ }
63
+
64
+ void rd_kafka_mock_Produce_reply_tags_write(
65
+ rd_kafka_buf_t *rkbuf,
66
+ int tagtype,
67
+ rd_kafka_mock_broker_t **changed_leaders,
68
+ int changed_leader_cnt) {
69
+ int i;
70
+ switch (tagtype) {
71
+ case 0: /* NodeEndpoints */
72
+ /* #NodeEndpoints */
73
+ rd_kafka_buf_write_arraycnt(rkbuf, changed_leader_cnt);
74
+ for (i = 0; i < changed_leader_cnt; i++) {
75
+ rd_kafka_mock_broker_t *changed_leader =
76
+ changed_leaders[i];
77
+ /* Leader id */
78
+ rd_kafka_buf_write_i32(rkbuf, changed_leader->id);
79
+ /* Leader Hostname */
80
+ rd_kafka_buf_write_str(
81
+ rkbuf, changed_leader->advertised_listener, -1);
82
+
83
+ /* Leader Port number */
84
+ rd_kafka_buf_write_i32(rkbuf,
85
+ (int32_t)changed_leader->port);
86
+
87
+ /* Leader Rack */
88
+ rd_kafka_buf_write_str(rkbuf, changed_leader->rack, -1);
89
+
90
+ /* Field tags */
91
+ rd_kafka_buf_write_tags_empty(rkbuf);
92
+ }
93
+ default:
94
+ break;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * @brief Handle ProduceRequest
100
+ */
101
+ static int rd_kafka_mock_handle_Produce(rd_kafka_mock_connection_t *mconn,
102
+ rd_kafka_buf_t *rkbuf) {
103
+ const rd_bool_t log_decode_errors = rd_true;
104
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
105
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
106
+ int32_t TopicsCnt;
107
+ rd_kafkap_str_t TransactionalId = RD_KAFKAP_STR_INITIALIZER;
108
+ int16_t Acks;
109
+ int32_t TimeoutMs;
110
+ rd_kafka_resp_err_t all_err;
111
+ int32_t tags_to_write[1] = {0};
112
+ size_t tags_to_write_cnt = 0;
113
+ int changed_leaders_cnt = 0;
114
+ rd_kafka_mock_broker_t **changed_leaders =
115
+ rd_calloc(mcluster->broker_cnt, sizeof(*changed_leaders));
116
+
117
+
118
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3)
119
+ rd_kafka_buf_read_str(rkbuf, &TransactionalId);
120
+
121
+ rd_kafka_buf_read_i16(rkbuf, &Acks);
122
+ rd_kafka_buf_read_i32(rkbuf, &TimeoutMs);
123
+ /* #Topics */
124
+ rd_kafka_buf_read_arraycnt(rkbuf, &TopicsCnt, RD_KAFKAP_TOPICS_MAX);
125
+
126
+ /* Response: #Topics */
127
+ rd_kafka_buf_write_arraycnt(resp, TopicsCnt);
128
+
129
+ /* Inject error, if any */
130
+ all_err = rd_kafka_mock_next_request_error(mconn, resp);
131
+
132
+ while (TopicsCnt-- > 0) {
133
+ rd_kafkap_str_t Topic;
134
+ int32_t PartitionCnt;
135
+ rd_kafka_mock_topic_t *mtopic;
136
+
137
+ rd_kafka_buf_read_str(rkbuf, &Topic);
138
+ rd_kafka_buf_read_arraycnt(rkbuf, &PartitionCnt,
139
+ RD_KAFKAP_PARTITIONS_MAX);
140
+ mtopic = rd_kafka_mock_topic_find_by_kstr(mcluster, &Topic);
141
+
142
+ /* Response: Topic */
143
+ rd_kafka_buf_write_kstr(resp, &Topic);
144
+ /* Response: #Partitions */
145
+ rd_kafka_buf_write_arraycnt(resp, PartitionCnt);
146
+
147
+ while (PartitionCnt-- > 0) {
148
+ int32_t Partition;
149
+ rd_kafka_mock_partition_t *mpart = NULL;
150
+ rd_kafkap_bytes_t records;
151
+ rd_kafka_resp_err_t err = RD_KAFKA_RESP_ERR_NO_ERROR;
152
+ int64_t BaseOffset = -1;
153
+ int32_t partition_tags_to_write[1] = {0};
154
+ size_t partition_tags_to_write_cnt = 0;
155
+
156
+ rd_kafka_buf_read_i32(rkbuf, &Partition);
157
+
158
+ if (mtopic)
159
+ mpart = rd_kafka_mock_partition_find(mtopic,
160
+ Partition);
161
+
162
+ rd_kafka_buf_read_kbytes(rkbuf, &records);
163
+ /* Partition Tags */
164
+ rd_kafka_buf_skip_tags(rkbuf);
165
+ /* Response: Partition */
166
+ rd_kafka_buf_write_i32(resp, Partition);
167
+
168
+ if (all_err)
169
+ err = all_err;
170
+ else if (!mpart)
171
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
172
+ else if (mpart->leader != mconn->broker)
173
+ err =
174
+ RD_KAFKA_RESP_ERR_NOT_LEADER_FOR_PARTITION;
175
+
176
+ /* Append to partition log */
177
+ if (!err)
178
+ err = rd_kafka_mock_partition_log_append(
179
+ mpart, &records, &TransactionalId,
180
+ &BaseOffset);
181
+
182
+ /* Response: ErrorCode */
183
+ rd_kafka_buf_write_i16(resp, err);
184
+
185
+ if (err) {
186
+ /* Response: BaseOffset */
187
+ rd_kafka_buf_write_i64(resp, BaseOffset);
188
+
189
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 2) {
190
+ /* Response: LogAppendTimeMs */
191
+ rd_kafka_buf_write_i64(resp, -1);
192
+ }
193
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 6) {
194
+ /* Response: LogStartOffset */
195
+ rd_kafka_buf_write_i64(resp, -1);
196
+ }
197
+
198
+ } else {
199
+ /* Response: BaseOffset */
200
+ rd_kafka_buf_write_i64(resp, BaseOffset);
201
+
202
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 2) {
203
+ /* Response: LogAppendTimeMs */
204
+ rd_kafka_buf_write_i64(resp, 1234);
205
+ }
206
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 6) {
207
+ /* Response: LogStartOffset */
208
+ rd_kafka_buf_write_i64(
209
+ resp, mpart->start_offset);
210
+ }
211
+ }
212
+
213
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 8) {
214
+ /* Response: #RecordErrors
215
+ * TODO: Add support for injecting RecordErrors
216
+ * 0 record errors for now */
217
+ rd_kafka_buf_write_arraycnt(resp, 0);
218
+
219
+ /* Response: ErrorMessage */
220
+ rd_kafka_buf_write_str(resp, NULL, 0);
221
+ }
222
+
223
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 10 &&
224
+ err == RD_KAFKA_RESP_ERR_NOT_LEADER_FOR_PARTITION) {
225
+ int changed_leader_idx;
226
+ /* See if this leader is already included */
227
+ for (changed_leader_idx = 0;
228
+ changed_leader_idx < changed_leaders_cnt;
229
+ changed_leader_idx++) {
230
+ if (changed_leaders[changed_leader_idx]
231
+ ->id == mpart->leader->id)
232
+ break;
233
+ }
234
+ if (changed_leader_idx == changed_leaders_cnt) {
235
+ /* Add the new leader that wasn't
236
+ * present */
237
+ changed_leaders[changed_leaders_cnt] =
238
+ mpart->leader;
239
+ changed_leaders_cnt++;
240
+ }
241
+
242
+ partition_tags_to_write
243
+ [partition_tags_to_write_cnt] =
244
+ 0 /* CurrentLeader */;
245
+ partition_tags_to_write_cnt++;
246
+ }
247
+
248
+ /* Response: Partition tags */
249
+ rd_kafka_buf_write_tags(
250
+ resp,
251
+ rd_kafka_mock_Produce_reply_tags_partition_write,
252
+ partition_tags_to_write,
253
+ partition_tags_to_write_cnt, mpart);
254
+ }
255
+
256
+ /* Topic tags */
257
+ rd_kafka_buf_skip_tags(rkbuf);
258
+ /* Response: Topic tags */
259
+ rd_kafka_buf_write_tags_empty(resp);
260
+ }
261
+
262
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
263
+ /* Response: ThrottleTime */
264
+ rd_kafka_buf_write_i32(resp, 0);
265
+ }
266
+
267
+ /* Response: Top level tags */
268
+ if (changed_leaders_cnt) {
269
+ tags_to_write[tags_to_write_cnt] = 0 /* NodeEndpoints */;
270
+ tags_to_write_cnt++;
271
+ }
272
+
273
+ rd_kafka_buf_write_tags(resp, rd_kafka_mock_Produce_reply_tags_write,
274
+ tags_to_write, tags_to_write_cnt,
275
+ changed_leaders, changed_leaders_cnt);
276
+
277
+ rd_kafka_mock_connection_send_response0(mconn, resp, rd_true);
278
+ rd_free(changed_leaders);
279
+ return 0;
280
+
281
+ err_parse:
282
+ rd_free(changed_leaders);
283
+ rd_kafka_buf_destroy(resp);
284
+ return -1;
285
+ }
286
+
287
+ void rd_kafka_mock_Fetch_reply_tags_partition_write(
288
+ rd_kafka_buf_t *rkbuf,
289
+ int tagtype,
290
+ rd_kafka_mock_partition_t *mpart) {
291
+ switch (tagtype) {
292
+ case 1: /* CurrentLeader */
293
+ {
294
+ int32_t leader_id = mpart->leader->id,
295
+ leader_epoch = mpart->leader_epoch;
296
+ rd_kafka_mock_partition_leader_t *mpart_leader =
297
+ rd_kafka_mock_partition_next_leader_response(mpart);
298
+ if (mpart_leader) {
299
+ leader_id = mpart_leader->leader_id;
300
+ leader_epoch = mpart_leader->leader_epoch;
301
+ rd_kafka_mock_partition_leader_destroy(mpart,
302
+ mpart_leader);
303
+ }
304
+
305
+ /* Leader id */
306
+ rd_kafka_buf_write_i32(rkbuf, leader_id);
307
+ /* Leader epoch */
308
+ rd_kafka_buf_write_i32(rkbuf, leader_epoch);
309
+ /* Field tags */
310
+ rd_kafka_buf_write_tags_empty(rkbuf);
311
+ break;
312
+ }
313
+ default:
314
+ break;
315
+ }
316
+ }
317
+
318
+ void rd_kafka_mock_Fetch_reply_tags_write(
319
+ rd_kafka_buf_t *rkbuf,
320
+ int tagtype,
321
+ rd_kafka_mock_broker_t **changed_leaders,
322
+ int changed_leader_cnt) {
323
+ int i;
324
+ switch (tagtype) {
325
+ case 0: /* NodeEndpoints */
326
+ /* #NodeEndpoints */
327
+ rd_kafka_buf_write_arraycnt(rkbuf, changed_leader_cnt);
328
+ for (i = 0; i < changed_leader_cnt; i++) {
329
+ rd_kafka_mock_broker_t *changed_leader =
330
+ changed_leaders[i];
331
+ /* Leader id */
332
+ rd_kafka_buf_write_i32(rkbuf, changed_leader->id);
333
+ /* Leader Hostname */
334
+ rd_kafka_buf_write_str(
335
+ rkbuf, changed_leader->advertised_listener, -1);
336
+
337
+ /* Leader Port number */
338
+ rd_kafka_buf_write_i32(rkbuf,
339
+ (int32_t)changed_leader->port);
340
+
341
+ /* Leader Rack */
342
+ rd_kafka_buf_write_str(rkbuf, changed_leader->rack, -1);
343
+
344
+ /* Field tags */
345
+ rd_kafka_buf_write_tags_empty(rkbuf);
346
+ }
347
+ default:
348
+ break;
349
+ }
350
+ }
351
+
352
+
353
+ /**
354
+ * @brief Handle FetchRequest
355
+ */
356
+ static int rd_kafka_mock_handle_Fetch(rd_kafka_mock_connection_t *mconn,
357
+ rd_kafka_buf_t *rkbuf) {
358
+ const rd_bool_t log_decode_errors = rd_true;
359
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
360
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
361
+ rd_kafka_resp_err_t all_err;
362
+ int32_t ReplicaId = -1, MaxWait, MinBytes, MaxBytes = -1,
363
+ SessionId = -1, Epoch, TopicsCnt;
364
+ int8_t IsolationLevel;
365
+ size_t totsize = 0;
366
+
367
+ int32_t tags_to_write[1] = {0};
368
+ uint64_t tags_to_write_cnt = 0;
369
+
370
+ int changed_leaders_cnt = 0;
371
+ rd_kafka_mock_broker_t **changed_leaders =
372
+ rd_calloc(mcluster->broker_cnt, sizeof(*changed_leaders));
373
+
374
+ if (rkbuf->rkbuf_reqhdr.ApiVersion <= 14) {
375
+ rd_kafka_buf_read_i32(rkbuf, &ReplicaId);
376
+ }
377
+ rd_kafka_buf_read_i32(rkbuf, &MaxWait);
378
+ rd_kafka_buf_read_i32(rkbuf, &MinBytes);
379
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3)
380
+ rd_kafka_buf_read_i32(rkbuf, &MaxBytes);
381
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 4)
382
+ rd_kafka_buf_read_i8(rkbuf, &IsolationLevel);
383
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 7) {
384
+ rd_kafka_buf_read_i32(rkbuf, &SessionId);
385
+ rd_kafka_buf_read_i32(rkbuf, &Epoch);
386
+ }
387
+
388
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
389
+ /* Response: ThrottleTime */
390
+ rd_kafka_buf_write_i32(resp, 0);
391
+ }
392
+
393
+
394
+ /* Inject error, if any */
395
+ all_err = rd_kafka_mock_next_request_error(mconn, resp);
396
+
397
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 7) {
398
+ /* Response: ErrorCode */
399
+ rd_kafka_buf_write_i16(resp, all_err);
400
+
401
+ /* Response: SessionId */
402
+ rd_kafka_buf_write_i32(resp, SessionId);
403
+ }
404
+
405
+ rd_kafka_buf_read_arraycnt(rkbuf, &TopicsCnt, RD_KAFKAP_TOPICS_MAX);
406
+
407
+ /* Response: #Topics */
408
+ rd_kafka_buf_write_arraycnt(resp, TopicsCnt);
409
+
410
+ while (TopicsCnt-- > 0) {
411
+ rd_kafkap_str_t Topic = RD_KAFKAP_STR_INITIALIZER;
412
+ rd_kafka_Uuid_t TopicId = RD_KAFKA_UUID_ZERO;
413
+ int32_t PartitionCnt;
414
+ rd_kafka_mock_topic_t *mtopic;
415
+ rd_bool_t find_topic_by_id = rd_true;
416
+
417
+ if (rkbuf->rkbuf_reqhdr.ApiVersion <= 12) {
418
+ rd_kafka_buf_read_str(rkbuf, &Topic);
419
+ find_topic_by_id = rd_false;
420
+ }
421
+
422
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 13) {
423
+ rd_kafka_buf_read_uuid(rkbuf, &TopicId);
424
+ }
425
+
426
+ rd_kafka_buf_read_arraycnt(rkbuf, &PartitionCnt,
427
+ RD_KAFKAP_PARTITIONS_MAX);
428
+
429
+ if (find_topic_by_id) {
430
+ mtopic =
431
+ rd_kafka_mock_topic_find_by_id(mcluster, TopicId);
432
+ /* Response: TopicId */
433
+ rd_kafka_buf_write_uuid(resp, &TopicId);
434
+ } else {
435
+ mtopic =
436
+ rd_kafka_mock_topic_find_by_kstr(mcluster, &Topic);
437
+ /* Response: Topic */
438
+ rd_kafka_buf_write_kstr(resp, &Topic);
439
+ }
440
+
441
+ /* Response: #Partitions */
442
+ rd_kafka_buf_write_arraycnt(resp, PartitionCnt);
443
+
444
+ while (PartitionCnt-- > 0) {
445
+ int32_t Partition, CurrentLeaderEpoch = -1,
446
+ LastFetchedEpoch = -1, PartMaxBytes;
447
+ int64_t FetchOffset, LogStartOffset;
448
+ rd_kafka_mock_partition_t *mpart = NULL;
449
+ rd_kafka_resp_err_t err = all_err;
450
+ rd_bool_t on_follower;
451
+ size_t partsize = 0;
452
+ const rd_kafka_mock_msgset_t *mset = NULL;
453
+ int32_t partition_tags_to_write[1] = {0};
454
+ uint64_t partition_tags_to_write_cnt = 0;
455
+
456
+ rd_kafka_buf_read_i32(rkbuf, &Partition);
457
+
458
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 9)
459
+ rd_kafka_buf_read_i32(rkbuf,
460
+ &CurrentLeaderEpoch);
461
+
462
+ rd_kafka_buf_read_i64(rkbuf, &FetchOffset);
463
+
464
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 12)
465
+ rd_kafka_buf_read_i32(rkbuf, &LastFetchedEpoch);
466
+
467
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 5)
468
+ rd_kafka_buf_read_i64(rkbuf, &LogStartOffset);
469
+
470
+ rd_kafka_buf_read_i32(rkbuf, &PartMaxBytes);
471
+
472
+ /* Partition tags */
473
+ rd_kafka_buf_skip_tags(rkbuf);
474
+
475
+ if (mtopic)
476
+ mpart = rd_kafka_mock_partition_find(mtopic,
477
+ Partition);
478
+ else if (find_topic_by_id)
479
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_ID;
480
+
481
+ /* Response: Partition */
482
+ rd_kafka_buf_write_i32(resp, Partition);
483
+
484
+ /* Fetch is directed at follower and this is
485
+ * the follower broker. */
486
+ on_follower =
487
+ mpart && mpart->follower_id == mconn->broker->id;
488
+
489
+ if (!err) {
490
+ if (!all_err && !mpart)
491
+ err =
492
+ RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
493
+ else if (!all_err &&
494
+ mpart->leader != mconn->broker &&
495
+ !on_follower)
496
+ err =
497
+ RD_KAFKA_RESP_ERR_NOT_LEADER_OR_FOLLOWER;
498
+ }
499
+
500
+ if (!err && mpart)
501
+ err =
502
+ rd_kafka_mock_partition_leader_epoch_check(
503
+ mpart, CurrentLeaderEpoch);
504
+
505
+ /* Find MessageSet for FetchOffset */
506
+ if (!err && FetchOffset != mpart->end_offset) {
507
+ /* Kafka currently only returns
508
+ * OFFSET_NOT_AVAILABLE
509
+ * in ListOffsets calls */
510
+ if (!(mset = rd_kafka_mock_msgset_find(
511
+ mpart, FetchOffset, on_follower)))
512
+ err =
513
+ RD_KAFKA_RESP_ERR_OFFSET_OUT_OF_RANGE;
514
+ rd_kafka_dbg(
515
+ mcluster->rk, MOCK, "MOCK",
516
+ "Topic %.*s [%" PRId32
517
+ "] fetch err %s for offset %" PRId64
518
+ " mset %p, on_follower %d, "
519
+ "start %" PRId64 ", end_offset %" PRId64
520
+ ", current epoch %" PRId32,
521
+ RD_KAFKAP_STR_PR(&Topic), Partition,
522
+ rd_kafka_err2name(err), FetchOffset, mset,
523
+ on_follower, mpart->start_offset,
524
+ mpart->end_offset, mpart->leader_epoch);
525
+ }
526
+
527
+
528
+ /* Response: ErrorCode */
529
+ rd_kafka_buf_write_i16(resp, err);
530
+
531
+ /* Response: Highwatermark */
532
+ rd_kafka_buf_write_i64(
533
+ resp,
534
+ mpart ? (on_follower ? mpart->follower_end_offset
535
+ : mpart->end_offset)
536
+ : -1);
537
+
538
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 4) {
539
+ /* Response: LastStableOffset */
540
+ rd_kafka_buf_write_i64(
541
+ resp, mpart ? mpart->end_offset : -1);
542
+ }
543
+
544
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 5) {
545
+ /* Response: LogStartOffset */
546
+ rd_kafka_buf_write_i64(
547
+ resp,
548
+ !mpart ? -1
549
+ : (on_follower
550
+ ? mpart->follower_start_offset
551
+ : mpart->start_offset));
552
+ }
553
+
554
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 4) {
555
+ /* Response: #Aborted */
556
+ rd_kafka_buf_write_arraycnt(resp, 0);
557
+ }
558
+
559
+
560
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 11) {
561
+ int32_t PreferredReadReplica =
562
+ mpart && mpart->leader == mconn->broker &&
563
+ mpart->follower_id != -1
564
+ ? mpart->follower_id
565
+ : -1;
566
+
567
+ /* Response: PreferredReplica */
568
+ rd_kafka_buf_write_i32(resp,
569
+ PreferredReadReplica);
570
+
571
+ if (PreferredReadReplica != -1) {
572
+ /* Don't return any data when
573
+ * PreferredReadReplica is set */
574
+ mset = NULL;
575
+ MaxWait = 0;
576
+ }
577
+ }
578
+
579
+
580
+ if (mset && partsize < (size_t)PartMaxBytes &&
581
+ totsize < (size_t)MaxBytes) {
582
+ /* Response: Records */
583
+ size_t written = rd_kafka_buf_write_kbytes(
584
+ resp, &mset->bytes);
585
+ partsize += written;
586
+ totsize += written;
587
+
588
+ /* FIXME: Multiple messageSets ? */
589
+ } else {
590
+ /* Empty Response: Records: Null */
591
+ rd_kafka_buf_write_arraycnt(resp, 0);
592
+ }
593
+
594
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 12 &&
595
+ err == RD_KAFKA_RESP_ERR_NOT_LEADER_OR_FOLLOWER) {
596
+ int changed_leader_idx;
597
+ for (changed_leader_idx = 0;
598
+ changed_leader_idx < changed_leaders_cnt;
599
+ changed_leader_idx++) {
600
+ if (changed_leaders[changed_leader_idx]
601
+ ->id == mpart->leader->id)
602
+ break;
603
+ }
604
+ if (changed_leader_idx == changed_leaders_cnt) {
605
+ changed_leaders[changed_leaders_cnt] =
606
+ mpart->leader;
607
+ changed_leaders_cnt++;
608
+ }
609
+ /* CurrentLeader */
610
+ partition_tags_to_write
611
+ [partition_tags_to_write_cnt] = 1;
612
+ partition_tags_to_write_cnt++;
613
+ }
614
+
615
+ /* Response: Partition tags */
616
+ rd_kafka_buf_write_tags(
617
+ resp,
618
+ rd_kafka_mock_Fetch_reply_tags_partition_write,
619
+ partition_tags_to_write,
620
+ partition_tags_to_write_cnt, mpart);
621
+ }
622
+
623
+ /* Topic tags */
624
+ rd_kafka_buf_skip_tags(rkbuf);
625
+ /* Response: Topic tags */
626
+ rd_kafka_buf_write_tags_empty(resp);
627
+ }
628
+
629
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 7) {
630
+ int32_t ForgottenTopicCnt;
631
+ rd_kafka_buf_read_arraycnt(rkbuf, &ForgottenTopicCnt,
632
+ RD_KAFKAP_TOPICS_MAX);
633
+ while (ForgottenTopicCnt-- > 0) {
634
+ rd_kafkap_str_t Topic = RD_KAFKAP_STR_INITIALIZER;
635
+ rd_kafka_Uuid_t TopicId = RD_KAFKA_UUID_ZERO;
636
+ int32_t ForgPartCnt;
637
+ if (rkbuf->rkbuf_reqhdr.ApiVersion <= 12) {
638
+ rd_kafka_buf_read_str(rkbuf, &Topic);
639
+ }
640
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 13) {
641
+ rd_kafka_buf_read_uuid(rkbuf, &TopicId);
642
+ }
643
+ rd_kafka_buf_read_arraycnt(rkbuf, &ForgPartCnt,
644
+ RD_KAFKAP_PARTITIONS_MAX);
645
+ while (ForgPartCnt-- > 0) {
646
+ int32_t Partition;
647
+ rd_kafka_buf_read_i32(rkbuf, &Partition);
648
+ }
649
+
650
+ /* ForgottenTopic tags */
651
+ rd_kafka_buf_skip_tags(rkbuf);
652
+ }
653
+ }
654
+
655
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 11) {
656
+ rd_kafkap_str_t RackId;
657
+ char *rack;
658
+ rd_kafka_buf_read_str(rkbuf, &RackId);
659
+ RD_KAFKAP_STR_DUPA(&rack, &RackId);
660
+ /* Matt might do something sensible with this */
661
+ }
662
+
663
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 16 && changed_leaders_cnt) {
664
+ tags_to_write[tags_to_write_cnt] = 0 /* NodeEndpoints */;
665
+ tags_to_write_cnt++;
666
+ }
667
+
668
+ /* Response: Top level tags */
669
+ rd_kafka_buf_write_tags(resp, rd_kafka_mock_Fetch_reply_tags_write,
670
+ tags_to_write, tags_to_write_cnt,
671
+ changed_leaders, changed_leaders_cnt);
672
+
673
+ /* If there was no data, delay up to MaxWait.
674
+ * This isn't strictly correct since we should cut the wait short
675
+ * and feed newly produced data if a producer writes to the
676
+ * partitions, but that is too much of a hassle here since we
677
+ * can't block the thread. */
678
+ if (!totsize && MaxWait > 0)
679
+ resp->rkbuf_ts_retry = rd_clock() + (MaxWait * 1000);
680
+
681
+ rd_kafka_mock_connection_send_response0(mconn, resp, rd_true);
682
+ rd_free(changed_leaders);
683
+ return 0;
684
+
685
+ err_parse:
686
+ rd_kafka_buf_destroy(resp);
687
+ rd_free(changed_leaders);
688
+ return -1;
689
+ }
690
+
691
+
692
+
693
+ /**
694
+ * @brief Handle ListOffsets
695
+ */
696
+ static int rd_kafka_mock_handle_ListOffsets(rd_kafka_mock_connection_t *mconn,
697
+ rd_kafka_buf_t *rkbuf) {
698
+ const rd_bool_t log_decode_errors = rd_true;
699
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
700
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
701
+ rd_kafka_resp_err_t all_err;
702
+ int32_t ReplicaId, TopicsCnt;
703
+ int8_t IsolationLevel;
704
+
705
+ rd_kafka_buf_read_i32(rkbuf, &ReplicaId);
706
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 2)
707
+ rd_kafka_buf_read_i8(rkbuf, &IsolationLevel);
708
+
709
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 2) {
710
+ /* Response: ThrottleTime */
711
+ rd_kafka_buf_write_i32(resp, 0);
712
+ }
713
+
714
+
715
+ /* Inject error, if any */
716
+ all_err = rd_kafka_mock_next_request_error(mconn, resp);
717
+
718
+ rd_kafka_buf_read_arraycnt(rkbuf, &TopicsCnt, RD_KAFKAP_TOPICS_MAX);
719
+
720
+ /* Response: #Topics */
721
+ rd_kafka_buf_write_arraycnt(resp, TopicsCnt);
722
+
723
+ while (TopicsCnt-- > 0) {
724
+ rd_kafkap_str_t Topic;
725
+ int32_t PartitionCnt;
726
+ rd_kafka_mock_topic_t *mtopic;
727
+
728
+ rd_kafka_buf_read_str(rkbuf, &Topic);
729
+ rd_kafka_buf_read_arraycnt(rkbuf, &PartitionCnt,
730
+ RD_KAFKAP_PARTITIONS_MAX);
731
+
732
+ mtopic = rd_kafka_mock_topic_find_by_kstr(mcluster, &Topic);
733
+
734
+ /* Response: Topic */
735
+ rd_kafka_buf_write_kstr(resp, &Topic);
736
+ /* Response: #Partitions */
737
+ rd_kafka_buf_write_arraycnt(resp, PartitionCnt);
738
+
739
+ while (PartitionCnt-- > 0) {
740
+ int32_t Partition, CurrentLeaderEpoch = -1;
741
+ int64_t Timestamp, Offset = -1;
742
+ int32_t MaxNumOffsets;
743
+ rd_kafka_mock_partition_t *mpart = NULL;
744
+ rd_kafka_resp_err_t err = all_err;
745
+
746
+ rd_kafka_buf_read_i32(rkbuf, &Partition);
747
+
748
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 4)
749
+ rd_kafka_buf_read_i32(rkbuf,
750
+ &CurrentLeaderEpoch);
751
+
752
+ rd_kafka_buf_read_i64(rkbuf, &Timestamp);
753
+
754
+ if (rkbuf->rkbuf_reqhdr.ApiVersion == 0)
755
+ rd_kafka_buf_read_i32(rkbuf, &MaxNumOffsets);
756
+
757
+ /* Partition tags */
758
+ rd_kafka_buf_skip_tags(rkbuf);
759
+
760
+ if (mtopic)
761
+ mpart = rd_kafka_mock_partition_find(mtopic,
762
+ Partition);
763
+
764
+ /* Response: Partition */
765
+ rd_kafka_buf_write_i32(resp, Partition);
766
+
767
+ if (!all_err && !mpart)
768
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
769
+ else if (!all_err && mpart->leader != mconn->broker)
770
+ err =
771
+ RD_KAFKA_RESP_ERR_NOT_LEADER_FOR_PARTITION;
772
+
773
+ if (!err && mpart)
774
+ err =
775
+ rd_kafka_mock_partition_leader_epoch_check(
776
+ mpart, CurrentLeaderEpoch);
777
+
778
+ /* Response: ErrorCode */
779
+ rd_kafka_buf_write_i16(resp, err);
780
+
781
+ if (!err && mpart) {
782
+ if (Timestamp == RD_KAFKA_OFFSET_BEGINNING)
783
+ Offset = mpart->start_offset;
784
+ else if (Timestamp == RD_KAFKA_OFFSET_END)
785
+ Offset = mpart->end_offset;
786
+ else if (Timestamp < 0)
787
+ Offset = -1;
788
+ else /* FIXME: by timestamp */
789
+ Offset = -1;
790
+ }
791
+
792
+ if (rkbuf->rkbuf_reqhdr.ApiVersion == 0) {
793
+ /* Response: #OldStyleOffsets */
794
+ rd_kafka_buf_write_i32(resp,
795
+ Offset != -1 ? 1 : 0);
796
+ /* Response: OldStyleOffsets[0] */
797
+ if (Offset != -1)
798
+ rd_kafka_buf_write_i64(resp, Offset);
799
+ } else {
800
+ /* Response: Timestamp (FIXME) */
801
+ rd_kafka_buf_write_i64(resp, -1);
802
+
803
+ /* Response: Offset */
804
+ rd_kafka_buf_write_i64(resp, Offset);
805
+ }
806
+
807
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 4) {
808
+ /* Response: LeaderEpoch */
809
+ const rd_kafka_mock_msgset_t *mset = NULL;
810
+ int32_t leader_epoch = -1;
811
+ rd_bool_t on_follower = rd_false;
812
+
813
+ if (mpart) {
814
+ on_follower =
815
+ mpart && mpart->follower_id ==
816
+ mconn->broker->id;
817
+
818
+ if (Offset >= 0 &&
819
+ (mset = rd_kafka_mock_msgset_find(
820
+ mpart, Offset, on_follower))) {
821
+ leader_epoch =
822
+ mset->leader_epoch;
823
+ }
824
+ }
825
+
826
+ rd_kafka_buf_write_i32(resp, leader_epoch);
827
+ }
828
+
829
+ /* Response: Partition tags */
830
+ rd_kafka_buf_write_tags_empty(resp);
831
+
832
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
833
+ "Topic %.*s [%" PRId32
834
+ "] returning "
835
+ "offset %" PRId64 " (leader epoch %" PRId32
836
+ ") for %s: %s",
837
+ RD_KAFKAP_STR_PR(&Topic), Partition,
838
+ Offset, mpart ? mpart->leader_epoch : -1,
839
+ rd_kafka_offset2str(Timestamp),
840
+ rd_kafka_err2str(err));
841
+ }
842
+
843
+ /* Topic tags */
844
+ rd_kafka_buf_skip_tags(rkbuf);
845
+ /* Response: Topic tags */
846
+ rd_kafka_buf_write_tags_empty(resp);
847
+ }
848
+
849
+
850
+ rd_kafka_mock_connection_send_response(mconn, resp);
851
+
852
+ return 0;
853
+
854
+ err_parse:
855
+ rd_kafka_buf_destroy(resp);
856
+ return -1;
857
+ }
858
+
859
+
860
+ /**
861
+ * @brief Handle OffsetFetch (fetch committed offsets)
862
+ */
863
+ static int rd_kafka_mock_handle_OffsetFetch(rd_kafka_mock_connection_t *mconn,
864
+ rd_kafka_buf_t *rkbuf) {
865
+ const rd_bool_t log_decode_errors = rd_true;
866
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
867
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
868
+ rd_kafka_mock_broker_t *mrkb;
869
+ rd_kafka_resp_err_t all_err;
870
+ int32_t TopicsCnt;
871
+ rd_kafkap_str_t GroupId;
872
+
873
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3) {
874
+ /* Response: ThrottleTime */
875
+ rd_kafka_buf_write_i32(resp, 0);
876
+ }
877
+
878
+ rd_kafka_buf_read_str(rkbuf, &GroupId);
879
+
880
+ /* Inject error, if any */
881
+ all_err = rd_kafka_mock_next_request_error(mconn, resp);
882
+
883
+ mrkb = rd_kafka_mock_cluster_get_coord(mcluster, RD_KAFKA_COORD_GROUP,
884
+ &GroupId);
885
+ if (!mrkb && !all_err)
886
+ all_err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR; // FIXME? check if
887
+ // its this mrkb?
888
+
889
+
890
+ rd_kafka_buf_read_arraycnt(rkbuf, &TopicsCnt, 100000);
891
+
892
+ /* Response: #Topics */
893
+ rd_kafka_buf_write_arraycnt(resp, TopicsCnt);
894
+
895
+ while (TopicsCnt-- > 0) {
896
+ rd_kafkap_str_t Topic;
897
+ int32_t PartitionCnt;
898
+ rd_kafka_mock_topic_t *mtopic;
899
+
900
+ rd_kafka_buf_read_str(rkbuf, &Topic);
901
+ rd_kafka_buf_read_arraycnt(rkbuf, &PartitionCnt, 100000);
902
+
903
+ mtopic = rd_kafka_mock_topic_find_by_kstr(mcluster, &Topic);
904
+
905
+ /* Response: Topic */
906
+ rd_kafka_buf_write_kstr(resp, &Topic);
907
+ /* Response: #Partitions */
908
+ rd_kafka_buf_write_arraycnt(resp, PartitionCnt);
909
+
910
+ while (PartitionCnt-- > 0) {
911
+ int32_t Partition;
912
+ rd_kafka_mock_partition_t *mpart = NULL;
913
+ const rd_kafka_mock_committed_offset_t *coff = NULL;
914
+ rd_kafka_resp_err_t err = all_err;
915
+
916
+ rd_kafka_buf_read_i32(rkbuf, &Partition);
917
+
918
+ if (mtopic)
919
+ mpart = rd_kafka_mock_partition_find(mtopic,
920
+ Partition);
921
+
922
+ /* Response: Partition */
923
+ rd_kafka_buf_write_i32(resp, Partition);
924
+
925
+ if (!all_err && !mpart)
926
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
927
+
928
+ if (!err)
929
+ coff = rd_kafka_mock_committed_offset_find(
930
+ mpart, &GroupId);
931
+
932
+ /* Response: CommittedOffset */
933
+ rd_kafka_buf_write_i64(resp, coff ? coff->offset : -1);
934
+
935
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 5) {
936
+ /* Response: CommittedLeaderEpoch */
937
+ rd_kafka_buf_write_i32(
938
+ resp, mpart ? mpart->leader_epoch : -1);
939
+ }
940
+
941
+ /* Response: Metadata */
942
+ rd_kafka_buf_write_kstr(resp,
943
+ coff ? coff->metadata : NULL);
944
+
945
+ /* Response: ErrorCode */
946
+ rd_kafka_buf_write_i16(resp, err);
947
+
948
+ /* Response: Struct tags */
949
+ rd_kafka_buf_write_tags_empty(resp);
950
+
951
+ if (coff)
952
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
953
+ "Topic %s [%" PRId32
954
+ "] returning "
955
+ "committed offset %" PRId64
956
+ " for group %s",
957
+ mtopic->name, mpart->id,
958
+ coff->offset, coff->group);
959
+ else
960
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
961
+ "Topic %.*s [%" PRId32
962
+ "] has no "
963
+ "committed offset for group %.*s: "
964
+ "%s",
965
+ RD_KAFKAP_STR_PR(&Topic),
966
+ Partition,
967
+ RD_KAFKAP_STR_PR(&GroupId),
968
+ rd_kafka_err2str(err));
969
+ }
970
+
971
+ /* Request: Skip struct tags */
972
+ rd_kafka_buf_skip_tags(rkbuf);
973
+
974
+ /* Response: Struct tags */
975
+ rd_kafka_buf_write_tags_empty(resp);
976
+ }
977
+
978
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 2) {
979
+ /* Response: Outer ErrorCode */
980
+ rd_kafka_buf_write_i16(resp, all_err);
981
+ }
982
+
983
+
984
+ rd_kafka_mock_connection_send_response(mconn, resp);
985
+
986
+ return 0;
987
+
988
+ err_parse:
989
+ rd_kafka_buf_destroy(resp);
990
+ return -1;
991
+ }
992
+
993
+
994
+
995
+ /**
996
+ * @brief Handle OffsetCommit
997
+ */
998
+ static int rd_kafka_mock_handle_OffsetCommit(rd_kafka_mock_connection_t *mconn,
999
+ rd_kafka_buf_t *rkbuf) {
1000
+ const rd_bool_t log_decode_errors = rd_true;
1001
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
1002
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
1003
+ rd_kafka_mock_broker_t *mrkb;
1004
+ rd_kafka_resp_err_t all_err;
1005
+ int32_t GenerationIdOrMemberEpoch = -1, TopicsCnt;
1006
+ rd_kafkap_str_t GroupId, MemberId, GroupInstanceId;
1007
+
1008
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3) {
1009
+ /* Response: ThrottleTime */
1010
+ rd_kafka_buf_write_i32(resp, 0);
1011
+ }
1012
+
1013
+ rd_kafka_buf_read_str(rkbuf, &GroupId);
1014
+
1015
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
1016
+ rd_kafka_buf_read_i32(rkbuf, &GenerationIdOrMemberEpoch);
1017
+ rd_kafka_buf_read_str(rkbuf, &MemberId);
1018
+ }
1019
+
1020
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 7)
1021
+ rd_kafka_buf_read_str(rkbuf, &GroupInstanceId);
1022
+
1023
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 2 &&
1024
+ rkbuf->rkbuf_reqhdr.ApiVersion <= 4) {
1025
+ int64_t RetentionTimeMs;
1026
+ rd_kafka_buf_read_i64(rkbuf, &RetentionTimeMs);
1027
+ }
1028
+
1029
+
1030
+ /* Inject error, if any */
1031
+ all_err = rd_kafka_mock_next_request_error(mconn, resp);
1032
+
1033
+ mrkb = rd_kafka_mock_cluster_get_coord(mcluster, RD_KAFKA_COORD_GROUP,
1034
+ &GroupId);
1035
+ if (!mrkb && !all_err)
1036
+ all_err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
1037
+
1038
+
1039
+ if (!all_err) {
1040
+ rd_kafka_mock_cgrp_classic_t *mcgrp_classic;
1041
+
1042
+ mcgrp_classic =
1043
+ rd_kafka_mock_cgrp_classic_find(mcluster, &GroupId);
1044
+ if (mcgrp_classic) {
1045
+ rd_kafka_mock_cgrp_classic_member_t *member = NULL;
1046
+
1047
+ if (!RD_KAFKAP_STR_IS_NULL(&MemberId))
1048
+ member = rd_kafka_mock_cgrp_classic_member_find(
1049
+ mcgrp_classic, &MemberId);
1050
+
1051
+ if (!member)
1052
+ all_err = RD_KAFKA_RESP_ERR_UNKNOWN_MEMBER_ID;
1053
+ else
1054
+ all_err =
1055
+ rd_kafka_mock_cgrp_classic_check_state(
1056
+ mcgrp_classic, member, rkbuf,
1057
+ GenerationIdOrMemberEpoch);
1058
+ } else {
1059
+ rd_kafka_mock_cgrp_consumer_t *mcgrp_consumer;
1060
+ rd_kafka_mock_cgrp_consumer_member_t *member = NULL;
1061
+
1062
+ mcgrp_consumer = rd_kafka_mock_cgrp_consumer_find(
1063
+ mcluster, &GroupId);
1064
+ if (mcgrp_consumer) {
1065
+ if (!RD_KAFKAP_STR_IS_NULL(&MemberId))
1066
+ member =
1067
+ rd_kafka_mock_cgrp_consumer_member_find(
1068
+ mcgrp_consumer, &MemberId);
1069
+
1070
+ if (!member)
1071
+ all_err =
1072
+ RD_KAFKA_RESP_ERR_UNKNOWN_MEMBER_ID;
1073
+ else
1074
+ all_err =
1075
+ GenerationIdOrMemberEpoch !=
1076
+ member->current_member_epoch
1077
+ ? RD_KAFKA_RESP_ERR_STALE_MEMBER_EPOCH
1078
+ : RD_KAFKA_RESP_ERR_NO_ERROR;
1079
+ }
1080
+ }
1081
+
1082
+ /* As happens here, a real broker doesn't check that partitions
1083
+ * are assigned to the member, but only the GenerationId. */
1084
+ }
1085
+
1086
+ rd_kafka_buf_read_arraycnt(rkbuf, &TopicsCnt, RD_KAFKAP_TOPICS_MAX);
1087
+
1088
+ /* Response: #Topics */
1089
+ rd_kafka_buf_write_arraycnt(resp, TopicsCnt);
1090
+
1091
+ while (TopicsCnt-- > 0) {
1092
+ rd_kafkap_str_t Topic;
1093
+ int32_t PartitionCnt;
1094
+ rd_kafka_mock_topic_t *mtopic;
1095
+
1096
+ rd_kafka_buf_read_str(rkbuf, &Topic);
1097
+ rd_kafka_buf_read_arraycnt(rkbuf, &PartitionCnt,
1098
+ RD_KAFKAP_PARTITIONS_MAX);
1099
+
1100
+ mtopic = rd_kafka_mock_topic_find_by_kstr(mcluster, &Topic);
1101
+
1102
+ /* Response: Topic */
1103
+ rd_kafka_buf_write_kstr(resp, &Topic);
1104
+ /* Response: #Partitions */
1105
+ rd_kafka_buf_write_arraycnt(resp, PartitionCnt);
1106
+
1107
+ while (PartitionCnt-- > 0) {
1108
+ int32_t Partition;
1109
+ rd_kafka_mock_partition_t *mpart = NULL;
1110
+ rd_kafka_resp_err_t err = all_err;
1111
+ int64_t CommittedOffset;
1112
+ rd_kafkap_str_t Metadata;
1113
+
1114
+ rd_kafka_buf_read_i32(rkbuf, &Partition);
1115
+
1116
+ if (mtopic)
1117
+ mpart = rd_kafka_mock_partition_find(mtopic,
1118
+ Partition);
1119
+
1120
+ /* Response: Partition */
1121
+ rd_kafka_buf_write_i32(resp, Partition);
1122
+
1123
+ if (!all_err && !mpart)
1124
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
1125
+
1126
+ rd_kafka_buf_read_i64(rkbuf, &CommittedOffset);
1127
+
1128
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 6) {
1129
+ int32_t CommittedLeaderEpoch;
1130
+ rd_kafka_buf_read_i32(rkbuf,
1131
+ &CommittedLeaderEpoch);
1132
+
1133
+ if (!err && mpart)
1134
+ err =
1135
+ rd_kafka_mock_partition_leader_epoch_check(
1136
+ mpart, CommittedLeaderEpoch);
1137
+ }
1138
+
1139
+ if (rkbuf->rkbuf_reqhdr.ApiVersion == 1) {
1140
+ int64_t CommitTimestamp;
1141
+ rd_kafka_buf_read_i64(rkbuf, &CommitTimestamp);
1142
+ }
1143
+
1144
+ rd_kafka_buf_read_str(rkbuf, &Metadata);
1145
+ rd_kafka_buf_skip_tags(rkbuf);
1146
+
1147
+ if (!err)
1148
+ rd_kafka_mock_commit_offset(mpart, &GroupId,
1149
+ CommittedOffset,
1150
+ &Metadata);
1151
+
1152
+ /* Response: ErrorCode */
1153
+ rd_kafka_buf_write_i16(resp, err);
1154
+ rd_kafka_buf_write_tags_empty(resp);
1155
+ }
1156
+ rd_kafka_buf_skip_tags(rkbuf);
1157
+ rd_kafka_buf_write_tags_empty(resp);
1158
+ }
1159
+
1160
+ rd_kafka_mock_connection_send_response(mconn, resp);
1161
+
1162
+ return 0;
1163
+
1164
+ err_parse:
1165
+ rd_kafka_buf_destroy(resp);
1166
+ return -1;
1167
+ }
1168
+
1169
+
1170
+
1171
+ /**
1172
+ * @brief Handle ApiVersionRequest
1173
+ */
1174
+ static int rd_kafka_mock_handle_ApiVersion(rd_kafka_mock_connection_t *mconn,
1175
+ rd_kafka_buf_t *rkbuf);
1176
+
1177
+
1178
+ /**
1179
+ * @brief Write a MetadataResponse.Topics. entry to \p resp.
1180
+ *
1181
+ * @param mtopic may be NULL
1182
+ */
1183
+ static void
1184
+ rd_kafka_mock_buf_write_Metadata_Topic(rd_kafka_mock_cluster_t *mcluster,
1185
+ rd_kafka_buf_t *resp,
1186
+ int16_t ApiVersion,
1187
+ rd_kafka_Uuid_t topic_id,
1188
+ const char *topic,
1189
+ const rd_kafka_mock_topic_t *mtopic,
1190
+ rd_kafka_resp_err_t err) {
1191
+ int i;
1192
+ int partition_cnt =
1193
+ (!mtopic || err == RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART ||
1194
+ err == RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_ID)
1195
+ ? 0
1196
+ : mtopic->partition_cnt;
1197
+
1198
+ /* Response: Topics.ErrorCode */
1199
+ rd_kafka_buf_write_i16(resp, err);
1200
+ /* Response: Topics.Name */
1201
+ rd_kafka_buf_write_str(resp, topic, -1);
1202
+
1203
+ if (ApiVersion >= 10) {
1204
+ /* Response: Topics.TopicId */
1205
+ rd_kafka_buf_write_uuid(resp, &topic_id);
1206
+ }
1207
+
1208
+ if (ApiVersion >= 1) {
1209
+ /* Response: Topics.IsInternal */
1210
+ rd_kafka_buf_write_bool(resp, rd_false);
1211
+ }
1212
+ /* Response: Topics.#Partitions */
1213
+ rd_kafka_buf_write_arraycnt(resp, partition_cnt);
1214
+
1215
+ for (i = 0; mtopic && i < partition_cnt; i++) {
1216
+ rd_kafka_mock_partition_leader_t *mpart_leader;
1217
+ rd_kafka_mock_partition_t *mpart = &mtopic->partitions[i];
1218
+ int r;
1219
+
1220
+ /* Response: ..Partitions.ErrorCode */
1221
+ rd_kafka_buf_write_i16(resp, 0);
1222
+ /* Response: ..Partitions.PartitionIndex */
1223
+ rd_kafka_buf_write_i32(resp, mpart->id);
1224
+
1225
+ mpart_leader =
1226
+ rd_kafka_mock_partition_next_leader_response(mpart);
1227
+ if (mpart_leader) {
1228
+ rd_kafka_dbg(
1229
+ mcluster->rk, MOCK, "MOCK",
1230
+ "MetadataRequest: using next leader response "
1231
+ "(%" PRId32 ", %" PRId32 ")",
1232
+ mpart_leader->leader_id,
1233
+ mpart_leader->leader_epoch);
1234
+
1235
+ /* Response: ..Partitions.Leader */
1236
+ rd_kafka_buf_write_i32(resp, mpart_leader->leader_id);
1237
+
1238
+ if (ApiVersion >= 7) {
1239
+ /* Response: ..Partitions.LeaderEpoch */
1240
+ rd_kafka_buf_write_i32(
1241
+ resp, mpart_leader->leader_epoch);
1242
+ }
1243
+ rd_kafka_mock_partition_leader_destroy(mpart,
1244
+ mpart_leader);
1245
+ mpart_leader = NULL;
1246
+ } else {
1247
+ /* Response: ..Partitions.Leader */
1248
+ rd_kafka_buf_write_i32(
1249
+ resp, mpart->leader ? mpart->leader->id : -1);
1250
+
1251
+ if (ApiVersion >= 7) {
1252
+ /* Response: ..Partitions.LeaderEpoch */
1253
+ rd_kafka_buf_write_i32(resp,
1254
+ mpart->leader_epoch);
1255
+ }
1256
+ }
1257
+
1258
+ /* Response: ..Partitions.#ReplicaNodes */
1259
+ rd_kafka_buf_write_arraycnt(resp, mpart->replica_cnt);
1260
+ for (r = 0; r < mpart->replica_cnt; r++)
1261
+ rd_kafka_buf_write_i32(resp, mpart->replicas[r]->id);
1262
+
1263
+ /* Response: ..Partitions.#IsrNodes */
1264
+ /* Let Replicas == ISRs for now */
1265
+ rd_kafka_buf_write_arraycnt(resp, mpart->replica_cnt);
1266
+ for (r = 0; r < mpart->replica_cnt; r++)
1267
+ rd_kafka_buf_write_i32(resp, mpart->replicas[r]->id);
1268
+
1269
+ if (ApiVersion >= 5) {
1270
+ /* Response: ...OfflineReplicas */
1271
+ rd_kafka_buf_write_arraycnt(resp, 0);
1272
+ }
1273
+
1274
+ rd_kafka_buf_write_tags_empty(resp);
1275
+ }
1276
+
1277
+ if (ApiVersion >= 8) {
1278
+ /* Response: Topics.TopicAuthorizedOperations */
1279
+ rd_kafka_buf_write_i32(resp, INT32_MIN);
1280
+ }
1281
+
1282
+ rd_kafka_buf_write_tags_empty(resp);
1283
+ }
1284
+
1285
+
1286
+ /**
1287
+ * @brief Handle MetadataRequest
1288
+ */
1289
+ static int rd_kafka_mock_handle_Metadata(rd_kafka_mock_connection_t *mconn,
1290
+ rd_kafka_buf_t *rkbuf) {
1291
+ const rd_bool_t log_decode_errors = rd_true;
1292
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
1293
+ rd_bool_t AllowAutoTopicCreation = rd_true;
1294
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
1295
+ const rd_kafka_mock_broker_t *mrkb;
1296
+ rd_kafka_topic_partition_list_t *requested_topics = NULL;
1297
+ rd_bool_t list_all_topics = rd_false;
1298
+ int32_t TopicsCnt;
1299
+ int i;
1300
+ size_t of_Brokers_cnt;
1301
+ int32_t response_Brokers_cnt = 0;
1302
+
1303
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3) {
1304
+ /* Response: ThrottleTime */
1305
+ rd_kafka_buf_write_i32(resp, 0);
1306
+ }
1307
+
1308
+ /* Response: #Brokers */
1309
+ of_Brokers_cnt = rd_kafka_buf_write_arraycnt_pos(resp);
1310
+
1311
+ TAILQ_FOREACH(mrkb, &mcluster->brokers, link) {
1312
+ if (!mrkb->up)
1313
+ continue;
1314
+ /* Response: Brokers.Nodeid */
1315
+ rd_kafka_buf_write_i32(resp, mrkb->id);
1316
+ /* Response: Brokers.Host */
1317
+ rd_kafka_buf_write_str(resp, mrkb->advertised_listener, -1);
1318
+ /* Response: Brokers.Port */
1319
+ rd_kafka_buf_write_i32(resp, (int32_t)mrkb->port);
1320
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
1321
+ /* Response: Brokers.Rack (Matt's going to love this) */
1322
+ rd_kafka_buf_write_str(resp, mrkb->rack, -1);
1323
+ }
1324
+ rd_kafka_buf_write_tags_empty(resp);
1325
+ response_Brokers_cnt++;
1326
+ }
1327
+ rd_kafka_buf_finalize_arraycnt(resp, of_Brokers_cnt,
1328
+ response_Brokers_cnt);
1329
+
1330
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 2) {
1331
+ /* Response: ClusterId */
1332
+ rd_kafka_buf_write_str(resp, mcluster->id, -1);
1333
+ }
1334
+
1335
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
1336
+ /* Response: ControllerId */
1337
+ rd_kafka_buf_write_i32(resp, mcluster->controller_id);
1338
+ }
1339
+
1340
+ /* #Topics */
1341
+ rd_kafka_buf_read_arraycnt(rkbuf, &TopicsCnt, RD_KAFKAP_TOPICS_MAX);
1342
+
1343
+ if (TopicsCnt > 0)
1344
+ requested_topics = rd_kafka_topic_partition_list_new(TopicsCnt);
1345
+ else if (rkbuf->rkbuf_reqhdr.ApiVersion == 0 || TopicsCnt == -1)
1346
+ list_all_topics = rd_true;
1347
+
1348
+ for (i = 0; i < TopicsCnt; i++) {
1349
+ rd_kafkap_str_t Topic;
1350
+ rd_kafka_Uuid_t TopicId = RD_KAFKA_UUID_ZERO;
1351
+ rd_kafka_topic_partition_t *rktpar;
1352
+ char *topic = NULL;
1353
+
1354
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 10) {
1355
+ /* TopicId */
1356
+ rd_kafka_buf_read_uuid(rkbuf, &TopicId);
1357
+ }
1358
+ rd_kafka_buf_read_str(rkbuf, &Topic);
1359
+ RD_KAFKAP_STR_DUPA(&topic, &Topic);
1360
+
1361
+ rktpar = rd_kafka_topic_partition_list_add(
1362
+ requested_topics, topic, RD_KAFKA_PARTITION_UA);
1363
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 10)
1364
+ rd_kafka_topic_partition_set_topic_id(rktpar, TopicId);
1365
+ rd_kafka_buf_skip_tags(rkbuf);
1366
+ }
1367
+
1368
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 4)
1369
+ rd_kafka_buf_read_bool(rkbuf, &AllowAutoTopicCreation);
1370
+
1371
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 8) {
1372
+ rd_bool_t IncludeClusterAuthorizedOperations;
1373
+ rd_bool_t IncludeTopicAuthorizedOperations;
1374
+ if (rkbuf->rkbuf_reqhdr.ApiVersion <= 10)
1375
+ rd_kafka_buf_read_bool(
1376
+ rkbuf, &IncludeClusterAuthorizedOperations);
1377
+ rd_kafka_buf_read_bool(rkbuf,
1378
+ &IncludeTopicAuthorizedOperations);
1379
+ }
1380
+
1381
+ if (list_all_topics) {
1382
+ rd_kafka_mock_topic_t *mtopic;
1383
+ /* Response: #Topics */
1384
+ rd_kafka_buf_write_arraycnt(resp, mcluster->topic_cnt);
1385
+
1386
+ TAILQ_FOREACH(mtopic, &mcluster->topics, link) {
1387
+ rd_kafka_mock_buf_write_Metadata_Topic(
1388
+ mcluster, resp, rkbuf->rkbuf_reqhdr.ApiVersion,
1389
+ mtopic->id, mtopic->name, mtopic, mtopic->err);
1390
+ }
1391
+
1392
+ } else if (requested_topics) {
1393
+ /* Response: #Topics */
1394
+ rd_kafka_buf_write_arraycnt(resp, requested_topics->cnt);
1395
+
1396
+ for (i = 0; i < requested_topics->cnt; i++) {
1397
+ const rd_kafka_topic_partition_t *rktpar =
1398
+ &requested_topics->elems[i];
1399
+ rd_kafka_mock_topic_t *mtopic = NULL;
1400
+ rd_kafka_resp_err_t err = RD_KAFKA_RESP_ERR_NO_ERROR;
1401
+ char *topic_name = rktpar->topic;
1402
+ rd_kafka_Uuid_t topic_id =
1403
+ rd_kafka_topic_partition_get_topic_id(rktpar);
1404
+ rd_bool_t invalid_before_12 =
1405
+ rkbuf->rkbuf_reqhdr.ApiVersion < 12 &&
1406
+ (!RD_KAFKA_UUID_IS_ZERO(topic_id) || !topic_name);
1407
+ rd_bool_t invalid_after_12 =
1408
+ rkbuf->rkbuf_reqhdr.ApiVersion >= 12 &&
1409
+ RD_KAFKA_UUID_IS_ZERO(topic_id) && !topic_name;
1410
+ if (invalid_before_12 || invalid_after_12) {
1411
+ err = RD_KAFKA_RESP_ERR_INVALID_REQUEST;
1412
+ }
1413
+
1414
+ if (!err) {
1415
+ rd_bool_t use_topic_id =
1416
+ !RD_KAFKA_UUID_IS_ZERO(topic_id);
1417
+ if (use_topic_id) {
1418
+ mtopic = rd_kafka_mock_topic_find_by_id(
1419
+ mcluster, topic_id);
1420
+ } else
1421
+ mtopic = rd_kafka_mock_topic_find(
1422
+ mcluster, topic_name);
1423
+
1424
+ if (mtopic) {
1425
+ topic_name = mtopic->name;
1426
+ topic_id = mtopic->id;
1427
+ } else if (!use_topic_id) {
1428
+ topic_name = rktpar->topic;
1429
+ } else {
1430
+ topic_name = NULL;
1431
+ }
1432
+
1433
+ if (!mtopic && topic_name &&
1434
+ AllowAutoTopicCreation) {
1435
+ mtopic =
1436
+ rd_kafka_mock_topic_auto_create(
1437
+ mcluster, topic_name, -1, &err);
1438
+ topic_id = mtopic->id;
1439
+ } else if (!mtopic) {
1440
+ err =
1441
+ use_topic_id
1442
+ ? RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_ID
1443
+ : RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
1444
+ }
1445
+ }
1446
+
1447
+ rd_kafka_mock_buf_write_Metadata_Topic(
1448
+ mcluster, resp, rkbuf->rkbuf_reqhdr.ApiVersion,
1449
+ topic_id, topic_name, mtopic,
1450
+ err ? err : mtopic->err);
1451
+ }
1452
+
1453
+ } else {
1454
+ /* Response: #Topics: brokers only */
1455
+ rd_kafka_buf_write_arraycnt(resp, 0);
1456
+ }
1457
+
1458
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 8 &&
1459
+ rkbuf->rkbuf_reqhdr.ApiVersion <= 10) {
1460
+ /* ClusterAuthorizedOperations */
1461
+ rd_kafka_buf_write_i32(resp, INT32_MIN);
1462
+ }
1463
+
1464
+ rd_kafka_buf_skip_tags(rkbuf);
1465
+ rd_kafka_buf_write_tags_empty(resp);
1466
+
1467
+ if (requested_topics)
1468
+ rd_kafka_topic_partition_list_destroy(requested_topics);
1469
+
1470
+ rd_kafka_mock_connection_send_response(mconn, resp);
1471
+
1472
+ return 0;
1473
+
1474
+ err_parse:
1475
+ if (requested_topics)
1476
+ rd_kafka_topic_partition_list_destroy(requested_topics);
1477
+
1478
+ rd_kafka_buf_destroy(resp);
1479
+ return -1;
1480
+ }
1481
+
1482
+
1483
+ /**
1484
+ * @brief Handle FindCoordinatorRequest
1485
+ */
1486
+ static int
1487
+ rd_kafka_mock_handle_FindCoordinator(rd_kafka_mock_connection_t *mconn,
1488
+ rd_kafka_buf_t *rkbuf) {
1489
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
1490
+ const rd_bool_t log_decode_errors = rd_true;
1491
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
1492
+ rd_kafkap_str_t Key;
1493
+ int8_t KeyType = RD_KAFKA_COORD_GROUP;
1494
+ const rd_kafka_mock_broker_t *mrkb = NULL;
1495
+ rd_kafka_resp_err_t err;
1496
+
1497
+ /* Key */
1498
+ rd_kafka_buf_read_str(rkbuf, &Key);
1499
+
1500
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
1501
+ /* KeyType */
1502
+ rd_kafka_buf_read_i8(rkbuf, &KeyType);
1503
+ }
1504
+
1505
+
1506
+ /*
1507
+ * Construct response
1508
+ */
1509
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
1510
+ /* Response: Throttle */
1511
+ rd_kafka_buf_write_i32(resp, 0);
1512
+ }
1513
+
1514
+ /* Inject error, if any */
1515
+ err = rd_kafka_mock_next_request_error(mconn, resp);
1516
+
1517
+ if (!err && RD_KAFKAP_STR_LEN(&Key) > 0) {
1518
+ mrkb = rd_kafka_mock_cluster_get_coord(mcluster, KeyType, &Key);
1519
+ rd_assert(mrkb);
1520
+ }
1521
+
1522
+ if (!mrkb && !err)
1523
+ err = RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE;
1524
+
1525
+ if (err) {
1526
+ /* Response: ErrorCode and ErrorMessage */
1527
+ rd_kafka_buf_write_i16(resp, err);
1528
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1)
1529
+ rd_kafka_buf_write_str(resp, rd_kafka_err2str(err), -1);
1530
+
1531
+ /* Response: NodeId, Host, Port */
1532
+ rd_kafka_buf_write_i32(resp, -1);
1533
+ rd_kafka_buf_write_str(resp, NULL, -1);
1534
+ rd_kafka_buf_write_i32(resp, -1);
1535
+ } else {
1536
+ /* Response: ErrorCode and ErrorMessage */
1537
+ rd_kafka_buf_write_i16(resp, 0);
1538
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1)
1539
+ rd_kafka_buf_write_str(resp, NULL, -1);
1540
+
1541
+ /* Response: NodeId, Host, Port */
1542
+ rd_kafka_buf_write_i32(resp, mrkb->id);
1543
+ rd_kafka_buf_write_str(resp, mrkb->advertised_listener, -1);
1544
+ rd_kafka_buf_write_i32(resp, (int32_t)mrkb->port);
1545
+ }
1546
+
1547
+ rd_kafka_mock_connection_send_response(mconn, resp);
1548
+ return 0;
1549
+
1550
+ err_parse:
1551
+ rd_kafka_buf_destroy(resp);
1552
+ return -1;
1553
+ }
1554
+
1555
+
1556
+
1557
+ /**
1558
+ * @brief Handle JoinGroupRequest
1559
+ */
1560
+ static int rd_kafka_mock_handle_JoinGroup(rd_kafka_mock_connection_t *mconn,
1561
+ rd_kafka_buf_t *rkbuf) {
1562
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
1563
+ rd_kafka_mock_broker_t *mrkb;
1564
+ const rd_bool_t log_decode_errors = rd_true;
1565
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
1566
+ rd_kafkap_str_t GroupId, MemberId, ProtocolType;
1567
+ rd_kafkap_str_t GroupInstanceId = RD_KAFKAP_STR_INITIALIZER;
1568
+ int32_t SessionTimeoutMs;
1569
+ int32_t MaxPollIntervalMs = -1;
1570
+ int32_t ProtocolCnt = 0;
1571
+ int32_t i;
1572
+ rd_kafka_resp_err_t err;
1573
+ rd_kafka_mock_cgrp_classic_t *mcgrp;
1574
+ rd_kafka_mock_cgrp_classic_proto_t *protos = NULL;
1575
+
1576
+ rd_kafka_buf_read_str(rkbuf, &GroupId);
1577
+ rd_kafka_buf_read_i32(rkbuf, &SessionTimeoutMs);
1578
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1)
1579
+ rd_kafka_buf_read_i32(rkbuf, &MaxPollIntervalMs);
1580
+ rd_kafka_buf_read_str(rkbuf, &MemberId);
1581
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 5)
1582
+ rd_kafka_buf_read_str(rkbuf, &GroupInstanceId);
1583
+ rd_kafka_buf_read_str(rkbuf, &ProtocolType);
1584
+ rd_kafka_buf_read_i32(rkbuf, &ProtocolCnt);
1585
+
1586
+ if (ProtocolCnt > 1000) {
1587
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
1588
+ "JoinGroupRequest: ProtocolCnt %" PRId32
1589
+ " > max allowed 1000",
1590
+ ProtocolCnt);
1591
+ rd_kafka_buf_destroy(resp);
1592
+ return -1;
1593
+ }
1594
+
1595
+ protos = rd_malloc(sizeof(*protos) * ProtocolCnt);
1596
+ for (i = 0; i < ProtocolCnt; i++) {
1597
+ rd_kafkap_str_t ProtocolName;
1598
+ rd_kafkap_bytes_t Metadata;
1599
+ rd_kafka_buf_read_str(rkbuf, &ProtocolName);
1600
+ rd_kafka_buf_read_kbytes(rkbuf, &Metadata);
1601
+ protos[i].name = rd_kafkap_str_copy(&ProtocolName);
1602
+ protos[i].metadata = rd_kafkap_bytes_copy(&Metadata);
1603
+ }
1604
+
1605
+ /*
1606
+ * Construct response
1607
+ */
1608
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 2) {
1609
+ /* Response: Throttle */
1610
+ rd_kafka_buf_write_i32(resp, 0);
1611
+ }
1612
+
1613
+ /* Inject error, if any */
1614
+ err = rd_kafka_mock_next_request_error(mconn, resp);
1615
+
1616
+ if (!err) {
1617
+ mrkb = rd_kafka_mock_cluster_get_coord(
1618
+ mcluster, RD_KAFKA_COORD_GROUP, &GroupId);
1619
+
1620
+ if (!mrkb)
1621
+ err = RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE;
1622
+ else if (mrkb != mconn->broker)
1623
+ err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
1624
+ }
1625
+
1626
+ if (!err) {
1627
+ mcgrp = rd_kafka_mock_cgrp_classic_get(mcluster, &GroupId,
1628
+ &ProtocolType);
1629
+ rd_assert(mcgrp);
1630
+
1631
+ /* This triggers an async rebalance, the response will be
1632
+ * sent later. */
1633
+ err = rd_kafka_mock_cgrp_classic_member_add(
1634
+ mcgrp, mconn, resp, &MemberId, &ProtocolType,
1635
+ &GroupInstanceId, protos, ProtocolCnt, SessionTimeoutMs);
1636
+ if (!err) {
1637
+ /* .._add() assumes ownership of resp and protos */
1638
+ protos = NULL;
1639
+ rd_kafka_mock_connection_set_blocking(mconn, rd_true);
1640
+ return 0;
1641
+ }
1642
+ }
1643
+
1644
+ rd_kafka_mock_cgrp_classic_protos_destroy(protos, ProtocolCnt);
1645
+
1646
+ /* Error case */
1647
+ rd_kafka_buf_write_i16(resp, err); /* ErrorCode */
1648
+ rd_kafka_buf_write_i32(resp, -1); /* GenerationId */
1649
+ rd_kafka_buf_write_str(resp, NULL, -1); /* ProtocolName */
1650
+ rd_kafka_buf_write_str(resp, NULL, -1); /* LeaderId */
1651
+ rd_kafka_buf_write_kstr(resp, NULL); /* MemberId */
1652
+ rd_kafka_buf_write_i32(resp, 0); /* MemberCnt */
1653
+
1654
+ rd_kafka_mock_connection_send_response(mconn, resp);
1655
+
1656
+ return 0;
1657
+
1658
+ err_parse:
1659
+ rd_kafka_buf_destroy(resp);
1660
+ if (protos)
1661
+ rd_kafka_mock_cgrp_classic_protos_destroy(protos, ProtocolCnt);
1662
+ return -1;
1663
+ }
1664
+
1665
+
1666
+ /**
1667
+ * @brief Handle HeartbeatRequest
1668
+ */
1669
+ static int rd_kafka_mock_handle_Heartbeat(rd_kafka_mock_connection_t *mconn,
1670
+ rd_kafka_buf_t *rkbuf) {
1671
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
1672
+ rd_kafka_mock_broker_t *mrkb;
1673
+ const rd_bool_t log_decode_errors = rd_true;
1674
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
1675
+ rd_kafkap_str_t GroupId, MemberId;
1676
+ rd_kafkap_str_t GroupInstanceId = RD_KAFKAP_STR_INITIALIZER;
1677
+ int32_t GenerationId;
1678
+ rd_kafka_resp_err_t err;
1679
+ rd_kafka_mock_cgrp_classic_t *mcgrp;
1680
+ rd_kafka_mock_cgrp_classic_member_t *member = NULL;
1681
+
1682
+ rd_kafka_buf_read_str(rkbuf, &GroupId);
1683
+ rd_kafka_buf_read_i32(rkbuf, &GenerationId);
1684
+ rd_kafka_buf_read_str(rkbuf, &MemberId);
1685
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3)
1686
+ rd_kafka_buf_read_str(rkbuf, &GroupInstanceId);
1687
+
1688
+ /*
1689
+ * Construct response
1690
+ */
1691
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
1692
+ /* Response: Throttle */
1693
+ rd_kafka_buf_write_i32(resp, 0);
1694
+ }
1695
+
1696
+ /* Inject error, if any */
1697
+ err = rd_kafka_mock_next_request_error(mconn, resp);
1698
+ if (!err) {
1699
+ mrkb = rd_kafka_mock_cluster_get_coord(
1700
+ mcluster, RD_KAFKA_COORD_GROUP, &GroupId);
1701
+
1702
+ if (!mrkb)
1703
+ err = RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE;
1704
+ else if (mrkb != mconn->broker)
1705
+ err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
1706
+ }
1707
+
1708
+ if (!err) {
1709
+ mcgrp = rd_kafka_mock_cgrp_classic_find(mcluster, &GroupId);
1710
+ if (!mcgrp)
1711
+ err = RD_KAFKA_RESP_ERR_GROUP_ID_NOT_FOUND;
1712
+ }
1713
+
1714
+ if (!err) {
1715
+ member =
1716
+ rd_kafka_mock_cgrp_classic_member_find(mcgrp, &MemberId);
1717
+ if (!member)
1718
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_MEMBER_ID;
1719
+ }
1720
+
1721
+ if (!err)
1722
+ err = rd_kafka_mock_cgrp_classic_check_state(
1723
+ mcgrp, member, rkbuf, GenerationId);
1724
+
1725
+ if (!err)
1726
+ rd_kafka_mock_cgrp_classic_member_active(mcgrp, member);
1727
+
1728
+ rd_kafka_buf_write_i16(resp, err); /* ErrorCode */
1729
+
1730
+ rd_kafka_mock_connection_send_response(mconn, resp);
1731
+
1732
+ return 0;
1733
+
1734
+ err_parse:
1735
+ rd_kafka_buf_destroy(resp);
1736
+ return -1;
1737
+ }
1738
+
1739
+
1740
+ /**
1741
+ * @brief Handle LeaveGroupRequest
1742
+ */
1743
+ static int rd_kafka_mock_handle_LeaveGroup(rd_kafka_mock_connection_t *mconn,
1744
+ rd_kafka_buf_t *rkbuf) {
1745
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
1746
+ rd_kafka_mock_broker_t *mrkb;
1747
+ const rd_bool_t log_decode_errors = rd_true;
1748
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
1749
+ rd_kafkap_str_t GroupId, MemberId;
1750
+ rd_kafka_resp_err_t err;
1751
+ rd_kafka_mock_cgrp_classic_t *mcgrp;
1752
+ rd_kafka_mock_cgrp_classic_member_t *member = NULL;
1753
+
1754
+ rd_kafka_buf_read_str(rkbuf, &GroupId);
1755
+ rd_kafka_buf_read_str(rkbuf, &MemberId);
1756
+
1757
+ /*
1758
+ * Construct response
1759
+ */
1760
+
1761
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
1762
+ /* Response: Throttle */
1763
+ rd_kafka_buf_write_i32(resp, 0);
1764
+ }
1765
+
1766
+ /* Inject error, if any */
1767
+ err = rd_kafka_mock_next_request_error(mconn, resp);
1768
+ if (!err) {
1769
+ mrkb = rd_kafka_mock_cluster_get_coord(
1770
+ mcluster, RD_KAFKA_COORD_GROUP, &GroupId);
1771
+
1772
+ if (!mrkb)
1773
+ err = RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE;
1774
+ else if (mrkb != mconn->broker)
1775
+ err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
1776
+ }
1777
+
1778
+ if (!err) {
1779
+ mcgrp = rd_kafka_mock_cgrp_classic_find(mcluster, &GroupId);
1780
+ if (!mcgrp)
1781
+ err = RD_KAFKA_RESP_ERR_GROUP_ID_NOT_FOUND;
1782
+ }
1783
+
1784
+ if (!err) {
1785
+ member =
1786
+ rd_kafka_mock_cgrp_classic_member_find(mcgrp, &MemberId);
1787
+ if (!member)
1788
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_MEMBER_ID;
1789
+ }
1790
+
1791
+ if (!err)
1792
+ err = rd_kafka_mock_cgrp_classic_check_state(mcgrp, member,
1793
+ rkbuf, -1);
1794
+
1795
+ if (!err)
1796
+ rd_kafka_mock_cgrp_classic_member_leave(mcgrp, member);
1797
+
1798
+ rd_kafka_buf_write_i16(resp, err); /* ErrorCode */
1799
+
1800
+ rd_kafka_mock_connection_send_response(mconn, resp);
1801
+
1802
+ return 0;
1803
+
1804
+ err_parse:
1805
+ rd_kafka_buf_destroy(resp);
1806
+ return -1;
1807
+ }
1808
+
1809
+
1810
+
1811
+ /**
1812
+ * @brief Handle SyncGroupRequest
1813
+ */
1814
+ static int rd_kafka_mock_handle_SyncGroup(rd_kafka_mock_connection_t *mconn,
1815
+ rd_kafka_buf_t *rkbuf) {
1816
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
1817
+ rd_kafka_mock_broker_t *mrkb;
1818
+ const rd_bool_t log_decode_errors = rd_true;
1819
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
1820
+ rd_kafkap_str_t GroupId, MemberId;
1821
+ rd_kafkap_str_t GroupInstanceId = RD_KAFKAP_STR_INITIALIZER;
1822
+ int32_t GenerationId, AssignmentCnt;
1823
+ int32_t i;
1824
+ rd_kafka_resp_err_t err;
1825
+ rd_kafka_mock_cgrp_classic_t *mcgrp = NULL;
1826
+ rd_kafka_mock_cgrp_classic_member_t *member = NULL;
1827
+
1828
+ rd_kafka_buf_read_str(rkbuf, &GroupId);
1829
+ rd_kafka_buf_read_i32(rkbuf, &GenerationId);
1830
+ rd_kafka_buf_read_str(rkbuf, &MemberId);
1831
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3)
1832
+ rd_kafka_buf_read_str(rkbuf, &GroupInstanceId);
1833
+ rd_kafka_buf_read_i32(rkbuf, &AssignmentCnt);
1834
+
1835
+ /*
1836
+ * Construct response
1837
+ */
1838
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
1839
+ /* Response: Throttle */
1840
+ rd_kafka_buf_write_i32(resp, 0);
1841
+ }
1842
+
1843
+ /* Inject error, if any */
1844
+ err = rd_kafka_mock_next_request_error(mconn, resp);
1845
+ if (!err) {
1846
+ mrkb = rd_kafka_mock_cluster_get_coord(
1847
+ mcluster, RD_KAFKA_COORD_GROUP, &GroupId);
1848
+
1849
+ if (!mrkb)
1850
+ err = RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE;
1851
+ else if (mrkb != mconn->broker)
1852
+ err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
1853
+ }
1854
+
1855
+ if (!err) {
1856
+ mcgrp = rd_kafka_mock_cgrp_classic_find(mcluster, &GroupId);
1857
+ if (!mcgrp)
1858
+ err = RD_KAFKA_RESP_ERR_GROUP_ID_NOT_FOUND;
1859
+ }
1860
+
1861
+ if (!err) {
1862
+ member =
1863
+ rd_kafka_mock_cgrp_classic_member_find(mcgrp, &MemberId);
1864
+ if (!member)
1865
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_MEMBER_ID;
1866
+ }
1867
+
1868
+ if (!err)
1869
+ err = rd_kafka_mock_cgrp_classic_check_state(
1870
+ mcgrp, member, rkbuf, GenerationId);
1871
+
1872
+ if (!err)
1873
+ rd_kafka_mock_cgrp_classic_member_active(mcgrp, member);
1874
+
1875
+ if (!err) {
1876
+ rd_bool_t is_leader = mcgrp->leader && mcgrp->leader == member;
1877
+
1878
+ if (AssignmentCnt > 0 && !is_leader)
1879
+ err =
1880
+ RD_KAFKA_RESP_ERR_NOT_LEADER_FOR_PARTITION; /* FIXME
1881
+ */
1882
+ else if (AssignmentCnt == 0 && is_leader)
1883
+ err = RD_KAFKA_RESP_ERR_INVALID_PARTITIONS; /* FIXME */
1884
+ }
1885
+
1886
+ for (i = 0; i < AssignmentCnt; i++) {
1887
+ rd_kafkap_str_t MemberId2;
1888
+ rd_kafkap_bytes_t Metadata;
1889
+ rd_kafka_mock_cgrp_classic_member_t *member2;
1890
+
1891
+ rd_kafka_buf_read_str(rkbuf, &MemberId2);
1892
+ rd_kafka_buf_read_kbytes(rkbuf, &Metadata);
1893
+
1894
+ if (err)
1895
+ continue;
1896
+
1897
+ /* Find member */
1898
+ member2 =
1899
+ rd_kafka_mock_cgrp_classic_member_find(mcgrp, &MemberId2);
1900
+ if (!member2)
1901
+ continue;
1902
+
1903
+ rd_kafka_mock_cgrp_classic_member_assignment_set(mcgrp, member2,
1904
+ &Metadata);
1905
+ }
1906
+
1907
+ if (!err) {
1908
+ err = rd_kafka_mock_cgrp_classic_member_sync_set(mcgrp, member,
1909
+ mconn, resp);
1910
+ /* .._sync_set() assumes ownership of resp */
1911
+ if (!err)
1912
+ return 0; /* Response will be sent when all members
1913
+ * are synchronized */
1914
+ }
1915
+
1916
+ /* Error case */
1917
+ rd_kafka_buf_write_i16(resp, err); /* ErrorCode */
1918
+ rd_kafka_buf_write_bytes(resp, NULL, -1); /* MemberState */
1919
+
1920
+ rd_kafka_mock_connection_send_response(mconn, resp);
1921
+
1922
+ return 0;
1923
+
1924
+ err_parse:
1925
+ rd_kafka_buf_destroy(resp);
1926
+ return -1;
1927
+ }
1928
+
1929
+
1930
+
1931
+ /**
1932
+ * @brief Generate a unique ProducerID
1933
+ */
1934
+ static const rd_kafka_pid_t
1935
+ rd_kafka_mock_pid_new(rd_kafka_mock_cluster_t *mcluster,
1936
+ const rd_kafkap_str_t *TransactionalId) {
1937
+ size_t tidlen =
1938
+ TransactionalId ? RD_KAFKAP_STR_LEN(TransactionalId) : 0;
1939
+ rd_kafka_mock_pid_t *mpid = rd_malloc(sizeof(*mpid) + tidlen);
1940
+ rd_kafka_pid_t ret;
1941
+
1942
+ mpid->pid.id = rd_jitter(1, 900000) * 1000;
1943
+ mpid->pid.epoch = 0;
1944
+
1945
+ if (tidlen > 0)
1946
+ memcpy(mpid->TransactionalId, TransactionalId->str, tidlen);
1947
+ mpid->TransactionalId[tidlen] = '\0';
1948
+
1949
+ mtx_lock(&mcluster->lock);
1950
+ rd_list_add(&mcluster->pids, mpid);
1951
+ ret = mpid->pid;
1952
+ mtx_unlock(&mcluster->lock);
1953
+
1954
+ return ret;
1955
+ }
1956
+
1957
+
1958
+ /**
1959
+ * @brief Finds a matching mcluster mock PID for the given \p pid.
1960
+ *
1961
+ * @locks_required mcluster->lock
1962
+ */
1963
+ rd_kafka_resp_err_t
1964
+ rd_kafka_mock_pid_find(rd_kafka_mock_cluster_t *mcluster,
1965
+ const rd_kafkap_str_t *TransactionalId,
1966
+ const rd_kafka_pid_t pid,
1967
+ rd_kafka_mock_pid_t **mpidp) {
1968
+ rd_kafka_mock_pid_t *mpid;
1969
+ rd_kafka_mock_pid_t skel = {pid};
1970
+
1971
+ *mpidp = NULL;
1972
+ mpid = rd_list_find(&mcluster->pids, &skel, rd_kafka_mock_pid_cmp_pid);
1973
+
1974
+ if (!mpid)
1975
+ return RD_KAFKA_RESP_ERR_UNKNOWN_PRODUCER_ID;
1976
+ else if (((TransactionalId != NULL) !=
1977
+ (*mpid->TransactionalId != '\0')) ||
1978
+ (TransactionalId &&
1979
+ rd_kafkap_str_cmp_str(TransactionalId,
1980
+ mpid->TransactionalId)))
1981
+ return RD_KAFKA_RESP_ERR_INVALID_PRODUCER_ID_MAPPING;
1982
+
1983
+ *mpidp = mpid;
1984
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
1985
+ }
1986
+
1987
+
1988
+ /**
1989
+ * @brief Checks if the given pid is known, else returns an error.
1990
+ */
1991
+ static rd_kafka_resp_err_t
1992
+ rd_kafka_mock_pid_check(rd_kafka_mock_cluster_t *mcluster,
1993
+ const rd_kafkap_str_t *TransactionalId,
1994
+ const rd_kafka_pid_t check_pid) {
1995
+ rd_kafka_mock_pid_t *mpid;
1996
+ rd_kafka_resp_err_t err = RD_KAFKA_RESP_ERR_NO_ERROR;
1997
+
1998
+ mtx_lock(&mcluster->lock);
1999
+ err =
2000
+ rd_kafka_mock_pid_find(mcluster, TransactionalId, check_pid, &mpid);
2001
+ if (!err && check_pid.epoch != mpid->pid.epoch)
2002
+ err = RD_KAFKA_RESP_ERR_INVALID_PRODUCER_EPOCH;
2003
+ mtx_unlock(&mcluster->lock);
2004
+
2005
+ if (unlikely(err))
2006
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK",
2007
+ "PID check failed for TransactionalId=%.*s: "
2008
+ "expected %s, not %s: %s",
2009
+ RD_KAFKAP_STR_PR(TransactionalId),
2010
+ mpid ? rd_kafka_pid2str(mpid->pid) : "none",
2011
+ rd_kafka_pid2str(check_pid),
2012
+ rd_kafka_err2name(err));
2013
+ return err;
2014
+ }
2015
+
2016
+
2017
+ /**
2018
+ * @brief Bump the epoch for an existing pid, or return an error
2019
+ * if the current_pid does not match an existing pid.
2020
+ */
2021
+ static rd_kafka_resp_err_t
2022
+ rd_kafka_mock_pid_bump(rd_kafka_mock_cluster_t *mcluster,
2023
+ const rd_kafkap_str_t *TransactionalId,
2024
+ rd_kafka_pid_t *current_pid) {
2025
+ rd_kafka_mock_pid_t *mpid;
2026
+ rd_kafka_resp_err_t err;
2027
+
2028
+ mtx_lock(&mcluster->lock);
2029
+ err = rd_kafka_mock_pid_find(mcluster, TransactionalId, *current_pid,
2030
+ &mpid);
2031
+ if (err) {
2032
+ mtx_unlock(&mcluster->lock);
2033
+ return err;
2034
+ }
2035
+
2036
+ if (current_pid->epoch != mpid->pid.epoch) {
2037
+ mtx_unlock(&mcluster->lock);
2038
+ return RD_KAFKA_RESP_ERR_INVALID_PRODUCER_EPOCH;
2039
+ }
2040
+
2041
+ mpid->pid.epoch++;
2042
+ *current_pid = mpid->pid;
2043
+ mtx_unlock(&mcluster->lock);
2044
+
2045
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCK", "Bumped PID %s",
2046
+ rd_kafka_pid2str(*current_pid));
2047
+
2048
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
2049
+ }
2050
+
2051
+
2052
+ /**
2053
+ * @brief Handle InitProducerId
2054
+ */
2055
+ static int
2056
+ rd_kafka_mock_handle_InitProducerId(rd_kafka_mock_connection_t *mconn,
2057
+ rd_kafka_buf_t *rkbuf) {
2058
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
2059
+ const rd_bool_t log_decode_errors = rd_true;
2060
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
2061
+ rd_kafkap_str_t TransactionalId;
2062
+ rd_kafka_pid_t pid = RD_KAFKA_PID_INITIALIZER;
2063
+ rd_kafka_pid_t current_pid = RD_KAFKA_PID_INITIALIZER;
2064
+ int32_t TxnTimeoutMs;
2065
+ rd_kafka_resp_err_t err;
2066
+
2067
+ /* TransactionalId */
2068
+ rd_kafka_buf_read_str(rkbuf, &TransactionalId);
2069
+ /* TransactionTimeoutMs */
2070
+ rd_kafka_buf_read_i32(rkbuf, &TxnTimeoutMs);
2071
+
2072
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3) {
2073
+ /* ProducerId */
2074
+ rd_kafka_buf_read_i64(rkbuf, &current_pid.id);
2075
+ /* ProducerEpoch */
2076
+ rd_kafka_buf_read_i16(rkbuf, &current_pid.epoch);
2077
+ }
2078
+
2079
+ /*
2080
+ * Construct response
2081
+ */
2082
+
2083
+ /* ThrottleTimeMs */
2084
+ rd_kafka_buf_write_i32(resp, 0);
2085
+
2086
+ /* Inject error */
2087
+ err = rd_kafka_mock_next_request_error(mconn, resp);
2088
+
2089
+ if (!err && !RD_KAFKAP_STR_IS_NULL(&TransactionalId)) {
2090
+ if (RD_KAFKAP_STR_LEN(&TransactionalId) == 0)
2091
+ err = RD_KAFKA_RESP_ERR_INVALID_REQUEST;
2092
+ else if (rd_kafka_mock_cluster_get_coord(
2093
+ mcluster, RD_KAFKA_COORD_TXN, &TransactionalId) !=
2094
+ mconn->broker)
2095
+ err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
2096
+ }
2097
+
2098
+ if (!err) {
2099
+ if (rd_kafka_pid_valid(current_pid)) {
2100
+ /* Producer is asking for the transactional coordinator
2101
+ * to bump the epoch (KIP-360).
2102
+ * Verify that current_pid matches and then
2103
+ * bump the epoch. */
2104
+ err = rd_kafka_mock_pid_bump(mcluster, &TransactionalId,
2105
+ &current_pid);
2106
+ if (!err)
2107
+ pid = current_pid;
2108
+
2109
+ } else {
2110
+ /* Generate a new pid */
2111
+ pid = rd_kafka_mock_pid_new(mcluster, &TransactionalId);
2112
+ }
2113
+ }
2114
+
2115
+ /* ErrorCode */
2116
+ rd_kafka_buf_write_i16(resp, err);
2117
+
2118
+ /* ProducerId */
2119
+ rd_kafka_buf_write_i64(resp, pid.id);
2120
+ /* ProducerEpoch */
2121
+ rd_kafka_buf_write_i16(resp, pid.epoch);
2122
+
2123
+ rd_kafka_mock_connection_send_response(mconn, resp);
2124
+
2125
+ return 0;
2126
+
2127
+ err_parse:
2128
+ rd_kafka_buf_destroy(resp);
2129
+ return -1;
2130
+ }
2131
+
2132
+
2133
+
2134
+ /**
2135
+ * @brief Handle AddPartitionsToTxn
2136
+ */
2137
+ static int
2138
+ rd_kafka_mock_handle_AddPartitionsToTxn(rd_kafka_mock_connection_t *mconn,
2139
+ rd_kafka_buf_t *rkbuf) {
2140
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
2141
+ const rd_bool_t log_decode_errors = rd_true;
2142
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
2143
+ rd_kafka_resp_err_t all_err;
2144
+ rd_kafkap_str_t TransactionalId;
2145
+ rd_kafka_pid_t pid;
2146
+ int32_t TopicsCnt;
2147
+
2148
+ /* Response: ThrottleTimeMs */
2149
+ rd_kafka_buf_write_i32(resp, 0);
2150
+
2151
+ /* TransactionalId */
2152
+ rd_kafka_buf_read_str(rkbuf, &TransactionalId);
2153
+ /* ProducerId */
2154
+ rd_kafka_buf_read_i64(rkbuf, &pid.id);
2155
+ /* Epoch */
2156
+ rd_kafka_buf_read_i16(rkbuf, &pid.epoch);
2157
+ /* #Topics */
2158
+ rd_kafka_buf_read_i32(rkbuf, &TopicsCnt);
2159
+
2160
+ /* Response: #Results */
2161
+ rd_kafka_buf_write_i32(resp, TopicsCnt);
2162
+
2163
+ /* Inject error */
2164
+ all_err = rd_kafka_mock_next_request_error(mconn, resp);
2165
+
2166
+ if (!all_err &&
2167
+ rd_kafka_mock_cluster_get_coord(mcluster, RD_KAFKA_COORD_TXN,
2168
+ &TransactionalId) != mconn->broker)
2169
+ all_err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
2170
+
2171
+ if (!all_err)
2172
+ all_err =
2173
+ rd_kafka_mock_pid_check(mcluster, &TransactionalId, pid);
2174
+
2175
+ while (TopicsCnt-- > 0) {
2176
+ rd_kafkap_str_t Topic;
2177
+ int32_t PartsCnt;
2178
+ const rd_kafka_mock_topic_t *mtopic;
2179
+
2180
+ /* Topic */
2181
+ rd_kafka_buf_read_str(rkbuf, &Topic);
2182
+ /* Response: Topic */
2183
+ rd_kafka_buf_write_kstr(resp, &Topic);
2184
+
2185
+ /* #Partitions */
2186
+ rd_kafka_buf_read_i32(rkbuf, &PartsCnt);
2187
+ /* Response: #Partitions */
2188
+ rd_kafka_buf_write_i32(resp, PartsCnt);
2189
+
2190
+ mtopic = rd_kafka_mock_topic_find_by_kstr(mcluster, &Topic);
2191
+
2192
+ while (PartsCnt--) {
2193
+ int32_t Partition;
2194
+ rd_kafka_resp_err_t err = all_err;
2195
+
2196
+ /* Partition */
2197
+ rd_kafka_buf_read_i32(rkbuf, &Partition);
2198
+ /* Response: Partition */
2199
+ rd_kafka_buf_write_i32(resp, Partition);
2200
+
2201
+ if (!mtopic || Partition < 0 ||
2202
+ Partition >= mtopic->partition_cnt)
2203
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
2204
+ else if (mtopic && mtopic->err)
2205
+ err = mtopic->err;
2206
+
2207
+ /* Response: ErrorCode */
2208
+ rd_kafka_buf_write_i16(resp, err);
2209
+ }
2210
+ }
2211
+
2212
+ rd_kafka_mock_connection_send_response(mconn, resp);
2213
+
2214
+ return 0;
2215
+
2216
+ err_parse:
2217
+ rd_kafka_buf_destroy(resp);
2218
+ return -1;
2219
+ }
2220
+
2221
+
2222
+ /**
2223
+ * @brief Handle AddOffsetsToTxn
2224
+ */
2225
+ static int
2226
+ rd_kafka_mock_handle_AddOffsetsToTxn(rd_kafka_mock_connection_t *mconn,
2227
+ rd_kafka_buf_t *rkbuf) {
2228
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
2229
+ const rd_bool_t log_decode_errors = rd_true;
2230
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
2231
+ rd_kafka_resp_err_t err;
2232
+ rd_kafkap_str_t TransactionalId, GroupId;
2233
+ rd_kafka_pid_t pid;
2234
+
2235
+ /* TransactionalId */
2236
+ rd_kafka_buf_read_str(rkbuf, &TransactionalId);
2237
+ /* ProducerId */
2238
+ rd_kafka_buf_read_i64(rkbuf, &pid.id);
2239
+ /* Epoch */
2240
+ rd_kafka_buf_read_i16(rkbuf, &pid.epoch);
2241
+ /* GroupIdId */
2242
+ rd_kafka_buf_read_str(rkbuf, &GroupId);
2243
+
2244
+ /* Response: ThrottleTimeMs */
2245
+ rd_kafka_buf_write_i32(resp, 0);
2246
+
2247
+ /* Inject error */
2248
+ err = rd_kafka_mock_next_request_error(mconn, resp);
2249
+
2250
+ if (!err &&
2251
+ rd_kafka_mock_cluster_get_coord(mcluster, RD_KAFKA_COORD_TXN,
2252
+ &TransactionalId) != mconn->broker)
2253
+ err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
2254
+
2255
+ if (!err)
2256
+ err = rd_kafka_mock_pid_check(mcluster, &TransactionalId, pid);
2257
+
2258
+ /* Response: ErrorCode */
2259
+ rd_kafka_buf_write_i16(resp, err);
2260
+
2261
+ rd_kafka_mock_connection_send_response(mconn, resp);
2262
+
2263
+ return 0;
2264
+
2265
+ err_parse:
2266
+ rd_kafka_buf_destroy(resp);
2267
+ return -1;
2268
+ }
2269
+
2270
+
2271
+ /**
2272
+ * @brief Handle TxnOffsetCommit
2273
+ */
2274
+ static int
2275
+ rd_kafka_mock_handle_TxnOffsetCommit(rd_kafka_mock_connection_t *mconn,
2276
+ rd_kafka_buf_t *rkbuf) {
2277
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
2278
+ const rd_bool_t log_decode_errors = rd_true;
2279
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
2280
+ rd_kafka_resp_err_t err;
2281
+ rd_kafkap_str_t TransactionalId, GroupId;
2282
+ rd_kafka_pid_t pid;
2283
+ int32_t TopicsCnt;
2284
+
2285
+ /* Response: ThrottleTimeMs */
2286
+ rd_kafka_buf_write_i32(resp, 0);
2287
+
2288
+ /* TransactionalId */
2289
+ rd_kafka_buf_read_str(rkbuf, &TransactionalId);
2290
+ /* GroupId */
2291
+ rd_kafka_buf_read_str(rkbuf, &GroupId);
2292
+ /* ProducerId */
2293
+ rd_kafka_buf_read_i64(rkbuf, &pid.id);
2294
+ /* Epoch */
2295
+ rd_kafka_buf_read_i16(rkbuf, &pid.epoch);
2296
+
2297
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3) {
2298
+ int32_t GenerationId;
2299
+ rd_kafkap_str_t kMemberId, kGroupInstanceId;
2300
+
2301
+ /* GenerationId */
2302
+ rd_kafka_buf_read_i32(rkbuf, &GenerationId);
2303
+ /* MemberId */
2304
+ rd_kafka_buf_read_str(rkbuf, &kMemberId);
2305
+ /* GroupInstanceId */
2306
+ rd_kafka_buf_read_str(rkbuf, &kGroupInstanceId);
2307
+ }
2308
+
2309
+ /* #Topics */
2310
+ rd_kafka_buf_read_arraycnt(rkbuf, &TopicsCnt, 100000);
2311
+
2312
+ /* Response: #Results */
2313
+ rd_kafka_buf_write_arraycnt(resp, TopicsCnt);
2314
+
2315
+ /* Inject error */
2316
+ err = rd_kafka_mock_next_request_error(mconn, resp);
2317
+
2318
+ if (!err &&
2319
+ rd_kafka_mock_cluster_get_coord(mcluster, RD_KAFKA_COORD_GROUP,
2320
+ &GroupId) != mconn->broker)
2321
+ err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
2322
+
2323
+ if (!err)
2324
+ err = rd_kafka_mock_pid_check(mcluster, &TransactionalId, pid);
2325
+
2326
+ while (TopicsCnt-- > 0) {
2327
+ rd_kafkap_str_t Topic;
2328
+ int32_t PartsCnt;
2329
+ rd_kafka_mock_topic_t *mtopic;
2330
+
2331
+ /* Topic */
2332
+ rd_kafka_buf_read_str(rkbuf, &Topic);
2333
+ /* Response: Topic */
2334
+ rd_kafka_buf_write_kstr(resp, &Topic);
2335
+
2336
+ mtopic = rd_kafka_mock_topic_find_by_kstr(mcluster, &Topic);
2337
+
2338
+ /* #Partitions */
2339
+ rd_kafka_buf_read_arraycnt(rkbuf, &PartsCnt, 100000);
2340
+
2341
+ /* Response: #Partitions */
2342
+ rd_kafka_buf_write_arraycnt(resp, PartsCnt);
2343
+
2344
+ while (PartsCnt-- > 0) {
2345
+ int32_t Partition;
2346
+ int64_t Offset;
2347
+ rd_kafkap_str_t Metadata;
2348
+ rd_kafka_mock_partition_t *mpart;
2349
+
2350
+ /* Partition */
2351
+ rd_kafka_buf_read_i32(rkbuf, &Partition);
2352
+ /* Response: Partition */
2353
+ rd_kafka_buf_write_i32(resp, Partition);
2354
+
2355
+ mpart = rd_kafka_mock_partition_find(mtopic, Partition);
2356
+ if (!err && !mpart)
2357
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
2358
+
2359
+ /* CommittedOffset */
2360
+ rd_kafka_buf_read_i64(rkbuf, &Offset);
2361
+
2362
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 2) {
2363
+ /* CommittedLeaderEpoch */
2364
+ int32_t CommittedLeaderEpoch;
2365
+ rd_kafka_buf_read_i32(rkbuf,
2366
+ &CommittedLeaderEpoch);
2367
+ if (!err && mpart)
2368
+ err =
2369
+ rd_kafka_mock_partition_leader_epoch_check(
2370
+ mpart, CommittedLeaderEpoch);
2371
+ }
2372
+
2373
+ /* CommittedMetadata */
2374
+ rd_kafka_buf_read_str(rkbuf, &Metadata);
2375
+
2376
+ /* Response: ErrorCode */
2377
+ rd_kafka_buf_write_i16(resp, err);
2378
+
2379
+ /* Request: Struct tags */
2380
+ rd_kafka_buf_skip_tags(rkbuf);
2381
+
2382
+ /* Response: Struct tags */
2383
+ rd_kafka_buf_write_tags_empty(resp);
2384
+ }
2385
+
2386
+ /* Request: Struct tags */
2387
+ rd_kafka_buf_skip_tags(rkbuf);
2388
+
2389
+ /* Response: Struct tags */
2390
+ rd_kafka_buf_write_tags_empty(resp);
2391
+ }
2392
+
2393
+ rd_kafka_mock_connection_send_response(mconn, resp);
2394
+
2395
+ return 0;
2396
+
2397
+ err_parse:
2398
+ rd_kafka_buf_destroy(resp);
2399
+ return -1;
2400
+ }
2401
+
2402
+
2403
+ /**
2404
+ * @brief Handle EndTxn
2405
+ */
2406
+ static int rd_kafka_mock_handle_EndTxn(rd_kafka_mock_connection_t *mconn,
2407
+ rd_kafka_buf_t *rkbuf) {
2408
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
2409
+ const rd_bool_t log_decode_errors = rd_true;
2410
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
2411
+ rd_kafka_resp_err_t err;
2412
+ rd_kafkap_str_t TransactionalId;
2413
+ rd_kafka_pid_t pid;
2414
+ rd_bool_t committed;
2415
+
2416
+ /* TransactionalId */
2417
+ rd_kafka_buf_read_str(rkbuf, &TransactionalId);
2418
+ /* ProducerId */
2419
+ rd_kafka_buf_read_i64(rkbuf, &pid.id);
2420
+ /* ProducerEpoch */
2421
+ rd_kafka_buf_read_i16(rkbuf, &pid.epoch);
2422
+ /* Committed */
2423
+ rd_kafka_buf_read_bool(rkbuf, &committed);
2424
+
2425
+ /*
2426
+ * Construct response
2427
+ */
2428
+
2429
+ /* ThrottleTimeMs */
2430
+ rd_kafka_buf_write_i32(resp, 0);
2431
+
2432
+ /* Inject error */
2433
+ err = rd_kafka_mock_next_request_error(mconn, resp);
2434
+
2435
+ if (!err &&
2436
+ rd_kafka_mock_cluster_get_coord(mcluster, RD_KAFKA_COORD_TXN,
2437
+ &TransactionalId) != mconn->broker)
2438
+ err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
2439
+
2440
+ if (!err)
2441
+ err = rd_kafka_mock_pid_check(mcluster, &TransactionalId, pid);
2442
+
2443
+ /* ErrorCode */
2444
+ rd_kafka_buf_write_i16(resp, err);
2445
+
2446
+ rd_kafka_mock_connection_send_response(mconn, resp);
2447
+
2448
+ return 0;
2449
+
2450
+ err_parse:
2451
+ rd_kafka_buf_destroy(resp);
2452
+ return -1;
2453
+ }
2454
+
2455
+ static int
2456
+ rd_kafka_mock_handle_OffsetForLeaderEpoch(rd_kafka_mock_connection_t *mconn,
2457
+ rd_kafka_buf_t *rkbuf) {
2458
+ const rd_bool_t log_decode_errors = rd_true;
2459
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
2460
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
2461
+ rd_kafka_resp_err_t err;
2462
+ int32_t TopicsCnt, i;
2463
+
2464
+ /* Response: ThrottleTimeMs */
2465
+ rd_kafka_buf_write_i32(resp, 0);
2466
+
2467
+ /* #Topics */
2468
+ rd_kafka_buf_read_arraycnt(rkbuf, &TopicsCnt, RD_KAFKAP_TOPICS_MAX);
2469
+
2470
+ /* Response: #Topics */
2471
+ rd_kafka_buf_write_arraycnt(resp, TopicsCnt);
2472
+
2473
+ /* Inject error */
2474
+ err = rd_kafka_mock_next_request_error(mconn, resp);
2475
+
2476
+ for (i = 0; i < TopicsCnt; i++) {
2477
+ rd_kafkap_str_t Topic;
2478
+ int32_t PartitionsCnt, j;
2479
+ rd_kafka_mock_topic_t *mtopic;
2480
+
2481
+ /* Topic */
2482
+ rd_kafka_buf_read_str(rkbuf, &Topic);
2483
+
2484
+ mtopic = rd_kafka_mock_topic_find_by_kstr(mcluster, &Topic);
2485
+
2486
+ /* Response: Topic */
2487
+ rd_kafka_buf_write_kstr(resp, &Topic);
2488
+
2489
+ /* #Partitions */
2490
+ rd_kafka_buf_read_arraycnt(rkbuf, &PartitionsCnt,
2491
+ RD_KAFKAP_PARTITIONS_MAX);
2492
+
2493
+ /* Response: #Partitions */
2494
+ rd_kafka_buf_write_arraycnt(resp, PartitionsCnt);
2495
+
2496
+ for (j = 0; j < PartitionsCnt; j++) {
2497
+ rd_kafka_mock_partition_t *mpart;
2498
+ int32_t Partition, CurrentLeaderEpoch, LeaderEpoch;
2499
+ int64_t EndOffset = -1;
2500
+
2501
+ /* Partition */
2502
+ rd_kafka_buf_read_i32(rkbuf, &Partition);
2503
+ /* CurrentLeaderEpoch */
2504
+ rd_kafka_buf_read_i32(rkbuf, &CurrentLeaderEpoch);
2505
+ /* LeaderEpoch */
2506
+ rd_kafka_buf_read_i32(rkbuf, &LeaderEpoch);
2507
+
2508
+ mpart = rd_kafka_mock_partition_find(mtopic, Partition);
2509
+ if (!err && !mpart)
2510
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART;
2511
+
2512
+ if (!err && mpart)
2513
+ err =
2514
+ rd_kafka_mock_partition_leader_epoch_check(
2515
+ mpart, CurrentLeaderEpoch);
2516
+
2517
+ if (!err && mpart) {
2518
+ EndOffset =
2519
+ rd_kafka_mock_partition_offset_for_leader_epoch(
2520
+ mpart, LeaderEpoch);
2521
+ }
2522
+
2523
+ /* Response: ErrorCode */
2524
+ rd_kafka_buf_write_i16(resp, err);
2525
+ /* Response: Partition */
2526
+ rd_kafka_buf_write_i32(resp, Partition);
2527
+ /* Response: LeaderEpoch */
2528
+ rd_kafka_buf_write_i32(resp, LeaderEpoch);
2529
+ /* Response: Partition */
2530
+ rd_kafka_buf_write_i64(resp, EndOffset);
2531
+ }
2532
+ }
2533
+
2534
+ rd_kafka_mock_connection_send_response(mconn, resp);
2535
+
2536
+ return 0;
2537
+
2538
+ err_parse:
2539
+ rd_kafka_buf_destroy(resp);
2540
+ return -1;
2541
+ }
2542
+
2543
+ /**
2544
+ * @brief Handle GetTelemetrySubscriptions
2545
+ */
2546
+ static int rd_kafka_mock_handle_GetTelemetrySubscriptions(
2547
+ rd_kafka_mock_connection_t *mconn,
2548
+ rd_kafka_buf_t *rkbuf) {
2549
+ const rd_bool_t log_decode_errors = rd_true;
2550
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
2551
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
2552
+ rd_kafka_resp_err_t err;
2553
+ size_t i;
2554
+ rd_kafka_Uuid_t ClientInstanceId;
2555
+ rd_kafka_Uuid_t zero_uuid = RD_KAFKA_UUID_ZERO;
2556
+
2557
+ /* Request: ClientInstanceId */
2558
+ rd_kafka_buf_read_uuid(rkbuf, &ClientInstanceId);
2559
+ if (ClientInstanceId.least_significant_bits ==
2560
+ zero_uuid.least_significant_bits &&
2561
+ ClientInstanceId.most_significant_bits ==
2562
+ zero_uuid.most_significant_bits) {
2563
+ /* Some random numbers */
2564
+ ClientInstanceId.least_significant_bits = 129;
2565
+ ClientInstanceId.most_significant_bits = 298;
2566
+ }
2567
+
2568
+ /* Response: ThrottleTimeMs */
2569
+ rd_kafka_buf_write_i32(resp, 0);
2570
+
2571
+ /* Inject error */
2572
+ err = rd_kafka_mock_next_request_error(mconn, resp);
2573
+
2574
+ /* Response: ErrorCode */
2575
+ rd_kafka_buf_write_i16(resp, err);
2576
+
2577
+ /* Response: ClientInstanceId*/
2578
+ rd_kafka_buf_write_uuid(resp, &ClientInstanceId);
2579
+
2580
+ /* Response: SubscriptionId */
2581
+ // TODO: Calculate subscription ID.
2582
+ rd_kafka_buf_write_i32(resp, 0);
2583
+
2584
+ /* Response: #AcceptedCompressionTypes */
2585
+ rd_kafka_buf_write_arraycnt(resp, 4);
2586
+
2587
+ /* Response: AcceptedCompressionTypes */
2588
+ rd_kafka_buf_write_i8(resp, RD_KAFKA_COMPRESSION_ZSTD);
2589
+ rd_kafka_buf_write_i8(resp, RD_KAFKA_COMPRESSION_LZ4);
2590
+ rd_kafka_buf_write_i8(resp, RD_KAFKA_COMPRESSION_GZIP);
2591
+ rd_kafka_buf_write_i8(resp, RD_KAFKA_COMPRESSION_SNAPPY);
2592
+
2593
+ /* Response: PushIntervalMs */
2594
+ /* We use the value in telemetry_push_interval_ms, and if not set, the
2595
+ * default of 5 minutes. */
2596
+ rd_kafka_buf_write_i32(resp, mcluster->telemetry_push_interval_ms > 0
2597
+ ? mcluster->telemetry_push_interval_ms
2598
+ : (5 * 60 * 1000));
2599
+
2600
+ /* Response: TelemetryMaxBytes */
2601
+ rd_kafka_buf_write_i32(resp, 10000);
2602
+
2603
+ /* Response: DeltaTemporality */
2604
+ rd_kafka_buf_write_bool(resp, rd_true);
2605
+
2606
+ /* Response: #RequestedMetrics */
2607
+ rd_kafka_buf_write_arraycnt(resp, mcluster->metrics_cnt);
2608
+
2609
+ for (i = 0; i < mcluster->metrics_cnt; i++)
2610
+ rd_kafka_buf_write_str(resp, mcluster->metrics[i], -1);
2611
+
2612
+ rd_kafka_mock_connection_send_response(mconn, resp);
2613
+
2614
+ return 0;
2615
+
2616
+ err_parse:
2617
+ rd_kafka_buf_destroy(resp);
2618
+ return -1;
2619
+ }
2620
+
2621
+ /**
2622
+ * @brief Handle PushTelemetry
2623
+ */
2624
+
2625
+ static void rd_kafka_mock_handle_PushTelemetry_decoded_NumberDataPoint(
2626
+ void *opaque,
2627
+ const opentelemetry_proto_metrics_v1_NumberDataPoint *decoded) {
2628
+ rd_kafka_broker_t *rkb = opaque;
2629
+ if (decoded->which_value ==
2630
+ opentelemetry_proto_metrics_v1_NumberDataPoint_as_int_tag)
2631
+ rd_rkb_log(rkb, LOG_INFO, "MOCKTELEMETRY",
2632
+ "NumberDataPoint int value: %" PRId64
2633
+ " time: %" PRIu64,
2634
+ decoded->value.as_int, decoded->time_unix_nano);
2635
+ else if (decoded->which_value ==
2636
+ opentelemetry_proto_metrics_v1_NumberDataPoint_as_double_tag)
2637
+ rd_rkb_log(rkb, LOG_INFO, "MOCKTELEMETRY",
2638
+ "NumberDataPoint double value: %f time: %" PRIu64,
2639
+ decoded->value.as_double, decoded->time_unix_nano);
2640
+ }
2641
+
2642
+ static void
2643
+ rd_kafka_mock_handle_PushTelemetry_decoded_int64(void *opaque,
2644
+ int64_t int64_value) {
2645
+ rd_kafka_broker_t *rkb = opaque;
2646
+ rd_rkb_log(rkb, LOG_INFO, "MOCKTELEMETRY", "int64 value: %" PRId64,
2647
+ int64_value);
2648
+ }
2649
+
2650
+ static void
2651
+ rd_kafka_mock_handle_PushTelemetry_decoded_string(void *opaque,
2652
+ const uint8_t *decoded) {
2653
+ rd_kafka_broker_t *rkb = opaque;
2654
+ rd_rkb_log(rkb, LOG_INFO, "MOCKTELEMETRY", "string value: %s", decoded);
2655
+ }
2656
+
2657
+ static void rd_kafka_mock_handle_PushTelemetry_decoded_type(
2658
+ void *opaque,
2659
+ rd_kafka_telemetry_metric_type_t type) {
2660
+ rd_kafka_broker_t *rkb = opaque;
2661
+ rd_rkb_log(rkb, LOG_INFO, "MOCKTELEMETRY", "Metric type: %d", type);
2662
+ }
2663
+
2664
+ static void rd_kafka_mock_handle_PushTelemetry_decode_error(void *opaque,
2665
+ const char *error,
2666
+ ...) {
2667
+ rd_kafka_broker_t *rkb = opaque;
2668
+ va_list ap;
2669
+ va_start(ap, error);
2670
+ rd_rkb_log(rkb, LOG_ERR, "MOCKTELEMETRY", error, ap);
2671
+ va_end(ap);
2672
+ rd_assert(!*"Failure while decoding telemetry data");
2673
+ }
2674
+
2675
+ void rd_kafka_mock_handle_PushTelemetry_payload(rd_kafka_broker_t *rkb,
2676
+ void *payload,
2677
+ size_t size) {
2678
+ rd_kafka_telemetry_decode_interface_t decode_interface = {
2679
+ .decoded_string = rd_kafka_mock_handle_PushTelemetry_decoded_string,
2680
+ .decoded_NumberDataPoint =
2681
+ rd_kafka_mock_handle_PushTelemetry_decoded_NumberDataPoint,
2682
+ .decoded_int64 = rd_kafka_mock_handle_PushTelemetry_decoded_int64,
2683
+ .decoded_type = rd_kafka_mock_handle_PushTelemetry_decoded_type,
2684
+ .decode_error = rd_kafka_mock_handle_PushTelemetry_decode_error,
2685
+ .opaque = rkb,
2686
+ };
2687
+ rd_kafka_telemetry_decode_metrics(&decode_interface, payload, size);
2688
+ }
2689
+
2690
+ static int rd_kafka_mock_handle_PushTelemetry(rd_kafka_mock_connection_t *mconn,
2691
+ rd_kafka_buf_t *rkbuf) {
2692
+ rd_kafka_broker_t *rkb = mconn->broker->cluster->dummy_rkb;
2693
+ const rd_bool_t log_decode_errors = rd_true;
2694
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
2695
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
2696
+ rd_kafka_Uuid_t ClientInstanceId;
2697
+ int32_t SubscriptionId;
2698
+ rd_bool_t terminating;
2699
+ int8_t CompressionType;
2700
+ rd_kafka_compression_t compression_type = RD_KAFKA_COMPRESSION_NONE;
2701
+ rd_kafkap_bytes_t metrics;
2702
+ rd_kafka_resp_err_t err;
2703
+
2704
+ rd_kafka_buf_read_uuid(rkbuf, &ClientInstanceId);
2705
+ rd_kafka_buf_read_i32(rkbuf, &SubscriptionId);
2706
+ rd_kafka_buf_read_bool(rkbuf, &terminating);
2707
+ rd_kafka_buf_read_i8(rkbuf, &CompressionType);
2708
+ compression_type = CompressionType;
2709
+ rd_kafka_buf_read_kbytes(rkbuf, &metrics);
2710
+
2711
+ void *uncompressed_payload = NULL;
2712
+ size_t uncompressed_payload_len = 0;
2713
+ rd_assert(metrics.data != NULL);
2714
+
2715
+ if (compression_type != RD_KAFKA_COMPRESSION_NONE) {
2716
+ rd_rkb_log(rkb, LOG_DEBUG, "MOCKTELEMETRY",
2717
+ "Compression type %s",
2718
+ rd_kafka_compression2str(compression_type));
2719
+ int err_uncompress =
2720
+ rd_kafka_telemetry_uncompress_metrics_payload(
2721
+ rkb, compression_type, (void *)metrics.data,
2722
+ metrics.len, &uncompressed_payload,
2723
+ &uncompressed_payload_len);
2724
+ if (err_uncompress) {
2725
+ rd_kafka_dbg(mcluster->rk, MOCK, "MOCKTELEMETRY",
2726
+ "Failed to uncompress "
2727
+ "telemetry payload.");
2728
+ goto err_parse;
2729
+ }
2730
+ } else {
2731
+ uncompressed_payload = (void *)metrics.data;
2732
+ uncompressed_payload_len = metrics.len;
2733
+ }
2734
+
2735
+ rd_assert(uncompressed_payload != NULL);
2736
+ rd_kafka_mock_handle_PushTelemetry_payload(rkb, uncompressed_payload,
2737
+ uncompressed_payload_len);
2738
+ if (compression_type != RD_KAFKA_COMPRESSION_NONE)
2739
+ rd_free(uncompressed_payload);
2740
+
2741
+ /* ThrottleTime */
2742
+ rd_kafka_buf_write_i32(resp, 0);
2743
+
2744
+ /* ErrorCode */
2745
+ err = rd_kafka_mock_next_request_error(mconn, resp);
2746
+ rd_kafka_buf_write_i16(resp, err);
2747
+
2748
+ rd_kafka_mock_connection_send_response(mconn, resp);
2749
+
2750
+ return 0;
2751
+
2752
+ err_parse:
2753
+ rd_kafka_buf_destroy(resp);
2754
+ return -1;
2755
+ }
2756
+ static void rd_kafka_mock_handle_ConsumerGroupHeartbeat_write_TopicPartitions(
2757
+ rd_kafka_buf_t *rkbuf,
2758
+ rd_kafka_topic_partition_list_t *rktparlist) {
2759
+ const rd_kafka_topic_partition_field_t fields[] = {
2760
+ RD_KAFKA_TOPIC_PARTITION_FIELD_PARTITION,
2761
+ RD_KAFKA_TOPIC_PARTITION_FIELD_END};
2762
+ rd_kafka_topic_partition_list_sort_by_topic_id(rktparlist);
2763
+ rd_kafka_buf_write_topic_partitions(
2764
+ rkbuf, rktparlist, rd_false /*don't skip invalid offsets*/,
2765
+ rd_false /*any offset*/, rd_true /* use_topic id */,
2766
+ rd_false /* don't use topic name */, fields);
2767
+ }
2768
+
2769
+ static int
2770
+ rd_kafka_mock_handle_ConsumerGroupHeartbeat(rd_kafka_mock_connection_t *mconn,
2771
+ rd_kafka_buf_t *rkbuf) {
2772
+ const rd_bool_t log_decode_errors = rd_true;
2773
+ rd_bool_t sent_assignment_parse_err = rd_false;
2774
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
2775
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
2776
+ rd_kafka_topic_partition_list_t *sent_assignment = NULL,
2777
+ *existing_assignment = NULL,
2778
+ *next_assignment = NULL;
2779
+ rd_kafka_topic_partition_t *rktpar;
2780
+ rd_kafkap_str_t GroupId, MemberId, InstanceId, RackId, ServerAssignor,
2781
+ SubscribedTopicRegex;
2782
+ rd_kafkap_str_t *SubscribedTopicNames = NULL;
2783
+ int32_t MemberEpoch, RebalanceTimeoutMs, SubscribedTopicNamesCnt;
2784
+ int32_t i;
2785
+ rd_kafka_resp_err_t err;
2786
+ rd_kafka_mock_cgrp_consumer_t *mcgrp = NULL;
2787
+ rd_kafka_mock_broker_t *mrkb = NULL;
2788
+ rd_kafka_mock_cgrp_consumer_member_t *member = NULL;
2789
+
2790
+ /* GroupId */
2791
+ rd_kafka_buf_read_str(rkbuf, &GroupId);
2792
+ rd_assert(!RD_KAFKAP_STR_IS_NULL(&GroupId));
2793
+
2794
+ /* MemberId */
2795
+ rd_kafka_buf_read_str(rkbuf, &MemberId);
2796
+ rd_assert(!RD_KAFKAP_STR_IS_NULL(&MemberId));
2797
+
2798
+ /* MemberEpoch */
2799
+ rd_kafka_buf_read_i32(rkbuf, &MemberEpoch);
2800
+ rd_assert(MemberEpoch >= -2);
2801
+
2802
+ /* InstanceId */
2803
+ rd_kafka_buf_read_str(rkbuf, &InstanceId);
2804
+
2805
+ /* RackId */
2806
+ rd_kafka_buf_read_str(rkbuf, &RackId);
2807
+
2808
+ /* RebalanceTimeoutMs */
2809
+ rd_kafka_buf_read_i32(rkbuf, &RebalanceTimeoutMs);
2810
+ rd_assert(RebalanceTimeoutMs >= -1);
2811
+
2812
+ /* #SubscribedTopicNames */
2813
+ rd_kafka_buf_read_arraycnt(rkbuf, &SubscribedTopicNamesCnt,
2814
+ RD_KAFKAP_TOPICS_MAX);
2815
+ if (SubscribedTopicNamesCnt >= 0) {
2816
+ SubscribedTopicNames = rd_calloc(
2817
+ SubscribedTopicNamesCnt > 0 ? SubscribedTopicNamesCnt : 1,
2818
+ sizeof(rd_kafkap_str_t));
2819
+ for (i = 0; i < SubscribedTopicNamesCnt; i++) {
2820
+ /* SubscribedTopicNames[i] */
2821
+ rd_kafka_buf_read_str(rkbuf, &SubscribedTopicNames[i]);
2822
+ }
2823
+ }
2824
+
2825
+ rd_kafka_buf_read_str(rkbuf, &SubscribedTopicRegex);
2826
+
2827
+ /* ServerAssignor */
2828
+ rd_kafka_buf_read_str(rkbuf, &ServerAssignor);
2829
+
2830
+ /* #TopicPartitions */
2831
+ const rd_kafka_topic_partition_field_t sent_assignment_fields[] = {
2832
+ RD_KAFKA_TOPIC_PARTITION_FIELD_PARTITION,
2833
+ RD_KAFKA_TOPIC_PARTITION_FIELD_END};
2834
+ sent_assignment = rd_kafka_buf_read_topic_partitions_nullable(
2835
+ rkbuf, rd_true, rd_false, 0, sent_assignment_fields,
2836
+ &sent_assignment_parse_err);
2837
+ if (sent_assignment_parse_err)
2838
+ goto err_parse;
2839
+
2840
+ if (sent_assignment) {
2841
+ rd_kafka_Uuid_t last_topic_id = RD_KAFKA_UUID_ZERO;
2842
+ rd_kafka_mock_topic_t *mtopic = NULL;
2843
+ existing_assignment =
2844
+ rd_kafka_topic_partition_list_new(sent_assignment->cnt);
2845
+ RD_KAFKA_TPLIST_FOREACH(rktpar, sent_assignment) {
2846
+ rd_kafka_Uuid_t current_topic_id =
2847
+ rd_kafka_topic_partition_get_topic_id(rktpar);
2848
+
2849
+ if (rd_kafka_Uuid_cmp(current_topic_id,
2850
+ last_topic_id) != 0) {
2851
+ last_topic_id = current_topic_id;
2852
+ mtopic = rd_kafka_mock_topic_find_by_id(
2853
+ mcluster, current_topic_id);
2854
+ }
2855
+
2856
+ if (mtopic) {
2857
+ rd_kafka_topic_partition_t *added =
2858
+ rd_kafka_topic_partition_list_add(
2859
+ existing_assignment, "",
2860
+ rktpar->partition);
2861
+ rd_kafka_topic_partition_set_topic_id(
2862
+ added, last_topic_id);
2863
+ }
2864
+ }
2865
+ }
2866
+
2867
+ /* Inject error, if any */
2868
+ err = rd_kafka_mock_next_request_error(mconn, resp);
2869
+
2870
+ if (!err) {
2871
+ mrkb = rd_kafka_mock_cluster_get_coord(
2872
+ mcluster, RD_KAFKA_COORD_GROUP, &GroupId);
2873
+
2874
+ if (!mrkb)
2875
+ err = RD_KAFKA_RESP_ERR_COORDINATOR_NOT_AVAILABLE;
2876
+ else if (mrkb != mconn->broker)
2877
+ err = RD_KAFKA_RESP_ERR_NOT_COORDINATOR;
2878
+ }
2879
+
2880
+ if (!err) {
2881
+ mtx_lock(&mcluster->lock);
2882
+ mcgrp = rd_kafka_mock_cgrp_consumer_get(mcluster, &GroupId);
2883
+ rd_assert(mcgrp);
2884
+
2885
+ member = rd_kafka_mock_cgrp_consumer_member_add(
2886
+ mcgrp, mconn, &MemberId, &InstanceId, SubscribedTopicNames,
2887
+ SubscribedTopicNamesCnt, &SubscribedTopicRegex);
2888
+
2889
+ if (member) {
2890
+ if (MemberEpoch >= 0) {
2891
+ next_assignment =
2892
+ rd_kafka_mock_cgrp_consumer_member_next_assignment(
2893
+ member, existing_assignment,
2894
+ &MemberEpoch);
2895
+ if (MemberEpoch < 0) {
2896
+ err =
2897
+ RD_KAFKA_RESP_ERR_FENCED_MEMBER_EPOCH;
2898
+ }
2899
+ } else {
2900
+ rd_kafka_mock_cgrp_consumer_member_leave(
2901
+ mcgrp, member, MemberEpoch == -2);
2902
+ member = NULL;
2903
+ }
2904
+ } else {
2905
+ err = RD_KAFKA_RESP_ERR_UNKNOWN_MEMBER_ID;
2906
+ }
2907
+ mtx_unlock(&mcluster->lock);
2908
+ } else {
2909
+ switch (err) {
2910
+ case RD_KAFKA_RESP_ERR_UNKNOWN_MEMBER_ID:
2911
+ case RD_KAFKA_RESP_ERR_FENCED_MEMBER_EPOCH:
2912
+ /* In case the error was set
2913
+ * by `rd_kafka_mock_next_request_error`. */
2914
+ MemberEpoch = -1;
2915
+ mtx_lock(&mcluster->lock);
2916
+ mcgrp = rd_kafka_mock_cgrp_consumer_find(mcluster,
2917
+ &GroupId);
2918
+ if (!mcgrp) {
2919
+ mtx_unlock(&mcluster->lock);
2920
+ break;
2921
+ }
2922
+
2923
+ rd_kafka_mock_cgrp_consumer_member_t *member =
2924
+ rd_kafka_mock_cgrp_consumer_member_find(mcgrp,
2925
+ &MemberId);
2926
+ if (member) {
2927
+ rd_kafka_mock_cgrp_consumer_member_fenced(
2928
+ mcgrp, member);
2929
+ member = NULL;
2930
+ }
2931
+ mtx_unlock(&mcluster->lock);
2932
+ default:
2933
+ break;
2934
+ }
2935
+ }
2936
+
2937
+ /*
2938
+ * Construct response
2939
+ */
2940
+ /* Response: Throttle */
2941
+ rd_kafka_buf_write_i32(resp, 0);
2942
+
2943
+ /* Response: ErrorCode */
2944
+ rd_kafka_buf_write_i16(resp, err);
2945
+
2946
+ /* Response: ErrorMessage */
2947
+ rd_kafka_buf_write_str(resp, rd_kafka_err2str(err), -1);
2948
+
2949
+ /* Response: MemberId */
2950
+ if (!err && member)
2951
+ rd_kafka_buf_write_str(resp, member->id, -1);
2952
+ else
2953
+ rd_kafka_buf_write_str(resp, NULL, -1);
2954
+
2955
+ /* Response: MemberEpoch */
2956
+ rd_kafka_buf_write_i32(resp, MemberEpoch);
2957
+
2958
+ /* Response: HeartbeatIntervalMs */
2959
+ if (mcgrp) {
2960
+ rd_kafka_buf_write_i32(resp, mcgrp->heartbeat_interval_ms);
2961
+ } else {
2962
+ rd_kafka_buf_write_i32(resp, 0);
2963
+ }
2964
+
2965
+ if (next_assignment) {
2966
+ /* Response: Assignment */
2967
+ rd_kafka_buf_write_i8(resp, 1);
2968
+
2969
+ /* Response: TopicPartitions */
2970
+ rd_kafka_mock_handle_ConsumerGroupHeartbeat_write_TopicPartitions(
2971
+ resp, next_assignment);
2972
+
2973
+ rd_kafka_buf_write_tags_empty(resp);
2974
+ } else {
2975
+ /* Response: Assignment */
2976
+ rd_kafka_buf_write_i8(resp, -1);
2977
+ }
2978
+
2979
+ rd_kafka_mock_connection_send_response(mconn, resp);
2980
+
2981
+ rd_free(SubscribedTopicNames);
2982
+ RD_IF_FREE(sent_assignment, rd_kafka_topic_partition_list_destroy);
2983
+ RD_IF_FREE(existing_assignment, rd_kafka_topic_partition_list_destroy);
2984
+ RD_IF_FREE(next_assignment, rd_kafka_topic_partition_list_destroy);
2985
+ return 0;
2986
+
2987
+ err_parse:
2988
+ RD_IF_FREE(SubscribedTopicNames, rd_free);
2989
+ RD_IF_FREE(sent_assignment, rd_kafka_topic_partition_list_destroy);
2990
+ RD_IF_FREE(existing_assignment, rd_kafka_topic_partition_list_destroy);
2991
+ RD_IF_FREE(next_assignment, rd_kafka_topic_partition_list_destroy);
2992
+ rd_kafka_buf_destroy(resp);
2993
+ return -1;
2994
+ }
2995
+
2996
+ /**
2997
+ * @brief Default request handlers
2998
+ */
2999
+ const struct rd_kafka_mock_api_handler
3000
+ rd_kafka_mock_api_handlers[RD_KAFKAP__NUM] = {
3001
+ /* [request-type] = { MinVersion, MaxVersion, FlexVersion, callback } */
3002
+ [RD_KAFKAP_Produce] = {0, 10, 9, rd_kafka_mock_handle_Produce},
3003
+ [RD_KAFKAP_Fetch] = {0, 16, 12, rd_kafka_mock_handle_Fetch},
3004
+ [RD_KAFKAP_ListOffsets] = {0, 7, 6, rd_kafka_mock_handle_ListOffsets},
3005
+ [RD_KAFKAP_OffsetFetch] = {0, 6, 6, rd_kafka_mock_handle_OffsetFetch},
3006
+ [RD_KAFKAP_OffsetCommit] = {0, 9, 8, rd_kafka_mock_handle_OffsetCommit},
3007
+ [RD_KAFKAP_ApiVersion] = {0, 2, 3, rd_kafka_mock_handle_ApiVersion},
3008
+ [RD_KAFKAP_Metadata] = {0, 12, 9, rd_kafka_mock_handle_Metadata},
3009
+ [RD_KAFKAP_FindCoordinator] = {0, 3, 3,
3010
+ rd_kafka_mock_handle_FindCoordinator},
3011
+ [RD_KAFKAP_InitProducerId] = {0, 4, 2,
3012
+ rd_kafka_mock_handle_InitProducerId},
3013
+ [RD_KAFKAP_JoinGroup] = {0, 6, 6, rd_kafka_mock_handle_JoinGroup},
3014
+ [RD_KAFKAP_Heartbeat] = {0, 5, 4, rd_kafka_mock_handle_Heartbeat},
3015
+ [RD_KAFKAP_LeaveGroup] = {0, 4, 4, rd_kafka_mock_handle_LeaveGroup},
3016
+ [RD_KAFKAP_SyncGroup] = {0, 4, 4, rd_kafka_mock_handle_SyncGroup},
3017
+ [RD_KAFKAP_AddPartitionsToTxn] =
3018
+ {0, 1, -1, rd_kafka_mock_handle_AddPartitionsToTxn},
3019
+ [RD_KAFKAP_AddOffsetsToTxn] = {0, 1, -1,
3020
+ rd_kafka_mock_handle_AddOffsetsToTxn},
3021
+ [RD_KAFKAP_TxnOffsetCommit] = {0, 3, 3,
3022
+ rd_kafka_mock_handle_TxnOffsetCommit},
3023
+ [RD_KAFKAP_EndTxn] = {0, 1, -1, rd_kafka_mock_handle_EndTxn},
3024
+ [RD_KAFKAP_OffsetForLeaderEpoch] =
3025
+ {2, 2, -1, rd_kafka_mock_handle_OffsetForLeaderEpoch},
3026
+ [RD_KAFKAP_ConsumerGroupHeartbeat] =
3027
+ {1, 1, 1, rd_kafka_mock_handle_ConsumerGroupHeartbeat},
3028
+ [RD_KAFKAP_GetTelemetrySubscriptions] =
3029
+ {0, 0, 0, rd_kafka_mock_handle_GetTelemetrySubscriptions},
3030
+ [RD_KAFKAP_PushTelemetry] = {0, 0, 0,
3031
+ rd_kafka_mock_handle_PushTelemetry},
3032
+ };
3033
+
3034
+
3035
+
3036
+ /**
3037
+ * @brief Handle ApiVersionRequest.
3038
+ *
3039
+ * @remark This is the only handler that needs to handle unsupported
3040
+ * ApiVersions.
3041
+ */
3042
+ static int rd_kafka_mock_handle_ApiVersion(rd_kafka_mock_connection_t *mconn,
3043
+ rd_kafka_buf_t *rkbuf) {
3044
+ rd_kafka_mock_cluster_t *mcluster = mconn->broker->cluster;
3045
+ rd_kafka_buf_t *resp = rd_kafka_mock_buf_new_response(rkbuf);
3046
+ size_t of_ApiKeysCnt;
3047
+ int cnt = 0;
3048
+ rd_kafka_resp_err_t err = RD_KAFKA_RESP_ERR_NO_ERROR;
3049
+ int i;
3050
+
3051
+ /* Inject error */
3052
+ err = rd_kafka_mock_next_request_error(mconn, resp);
3053
+
3054
+ if (!err && !rd_kafka_mock_cluster_ApiVersion_check(
3055
+ mcluster, rkbuf->rkbuf_reqhdr.ApiKey,
3056
+ rkbuf->rkbuf_reqhdr.ApiVersion))
3057
+ err = RD_KAFKA_RESP_ERR_UNSUPPORTED_VERSION;
3058
+
3059
+ /* ApiVersionRequest/Response with flexver (>=v3) has a mix
3060
+ * of flexver and standard fields for backwards compatibility reasons,
3061
+ * so we handcraft the response instead. */
3062
+ resp->rkbuf_flags &= ~RD_KAFKA_OP_F_FLEXVER;
3063
+
3064
+ /* ErrorCode */
3065
+ rd_kafka_buf_write_i16(resp, err);
3066
+
3067
+ /* #ApiKeys (updated later) */
3068
+ /* FIXME: FLEXVER: This is a uvarint and will require more than 1 byte
3069
+ * if the array count exceeds 126. */
3070
+ if (rkbuf->rkbuf_flags & RD_KAFKA_OP_F_FLEXVER)
3071
+ of_ApiKeysCnt = rd_kafka_buf_write_i8(resp, 0);
3072
+ else
3073
+ of_ApiKeysCnt = rd_kafka_buf_write_i32(resp, 0);
3074
+
3075
+ for (i = 0; i < RD_KAFKAP__NUM; i++) {
3076
+ if (!mcluster->api_handlers[i].cb ||
3077
+ mcluster->api_handlers[i].MaxVersion == -1)
3078
+ continue;
3079
+
3080
+
3081
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 3) {
3082
+ if (err && i != RD_KAFKAP_ApiVersion)
3083
+ continue;
3084
+ }
3085
+
3086
+ /* ApiKey */
3087
+ rd_kafka_buf_write_i16(resp, (int16_t)i);
3088
+ /* MinVersion */
3089
+ rd_kafka_buf_write_i16(resp,
3090
+ mcluster->api_handlers[i].MinVersion);
3091
+ /* MaxVersion */
3092
+ rd_kafka_buf_write_i16(resp,
3093
+ mcluster->api_handlers[i].MaxVersion);
3094
+
3095
+ cnt++;
3096
+ }
3097
+
3098
+ /* FIXME: uvarint */
3099
+ if (rkbuf->rkbuf_flags & RD_KAFKA_OP_F_FLEXVER) {
3100
+ rd_assert(cnt <= 126);
3101
+ rd_kafka_buf_update_i8(resp, of_ApiKeysCnt, cnt);
3102
+ } else
3103
+ rd_kafka_buf_update_i32(resp, of_ApiKeysCnt, cnt);
3104
+
3105
+ if (rkbuf->rkbuf_reqhdr.ApiVersion >= 1) {
3106
+ /* ThrottletimeMs */
3107
+ rd_kafka_buf_write_i32(resp, 0);
3108
+ }
3109
+
3110
+ rd_kafka_mock_connection_send_response(mconn, resp);
3111
+
3112
+ return 0;
3113
+ }