@@ -174,6 +174,14 @@ class KafkaDataRpcTest : public ::testing::TestWithParam<test_parameters> {
174174 .offsets .high_watermark ;
175175 }
176176
177+ result<partition_offsets, cluster::errc>
178+ get_single_partition_offsets (model::topic_partition tp) {
179+ return _kd->client ()
180+ .local ()
181+ .get_single_partition_offsets (std::move (tp))
182+ .get ();
183+ }
184+
177185 result<consume_reply, cluster::errc> consume (
178186 model::topic_partition tp,
179187 kafka::offset start_offset,
@@ -405,6 +413,48 @@ TEST_P(KafkaDataRpcTest, ProduceWithLeaderMitigationRetries) {
405413 ASSERT_TRUE (r.last_offset .has_value ());
406414 EXPECT_EQ (get_hwm (ntp), kafka::offset (model::next_offset (*r.last_offset )));
407415}
416+
417+ TEST_P (KafkaDataRpcTest, ClientCanGetSinglePartitionOffsets) {
418+ auto ntp = make_ntp (" single_offsets" );
419+ create_topic (model::topic_namespace (ntp.ns , ntp.tp .topic ));
420+
421+ auto res = get_single_partition_offsets (ntp.tp );
422+ ASSERT_TRUE (res.has_value ());
423+ // No records produced — HWM is 0 (next of -1), LSO is -1
424+ EXPECT_EQ (res.value ().high_watermark , kafka::offset (0 ));
425+ EXPECT_EQ (res.value ().last_stable_offset , kafka::offset (-1 ));
426+
427+ // After producing a record, offsets should advance.
428+ auto batch = model::test::make_random_batch ({.count = 1 , .records = 1 });
429+ auto pr = produce_with_leader_mitigation (ntp, std::move (batch));
430+ ASSERT_EQ (pr.ec , cluster::errc::success);
431+
432+ auto res2 = get_single_partition_offsets (ntp.tp );
433+ ASSERT_TRUE (res2.has_value ());
434+ EXPECT_EQ (
435+ res2.value ().high_watermark ,
436+ kafka::offset (model::next_offset (*pr.last_offset )));
437+ }
438+
439+ TEST_P (KafkaDataRpcTest, GetSinglePartitionOffsetsReturnsTopicNotExists) {
440+ auto ntp = make_ntp (" does-not-exist" );
441+ auto res = get_single_partition_offsets (ntp.tp );
442+ ASSERT_TRUE (res.has_error ());
443+ EXPECT_EQ (res.error (), cluster::errc::topic_not_exists);
444+ }
445+
446+ TEST_P (KafkaDataRpcTest, GetSinglePartitionOffsetsRetries) {
447+ auto ntp = make_ntp (" retry_offsets" );
448+ create_topic (model::topic_namespace (ntp.ns , ntp.tp .topic ));
449+
450+ // Inject timeouts on the first 2 attempts; the basic retry policy
451+ // should back off and succeed on the 3rd attempt.
452+ set_errors_to_inject (2 );
453+ auto res = get_single_partition_offsets (ntp.tp );
454+ ASSERT_TRUE (res.has_value ());
455+ EXPECT_EQ (res.value ().high_watermark , kafka::offset (0 ));
456+ EXPECT_EQ (res.value ().last_stable_offset , kafka::offset (-1 ));
457+ }
408458INSTANTIATE_TEST_SUITE_P (
409459 WorksLocallyAndRemotely,
410460 KafkaDataRpcTest,
0 commit comments