9
9
using std::atomic;
10
10
using std::vector;
11
11
using std::string;
12
+ using std::unordered_map;
12
13
using std::to_string;
13
14
using std::move;
14
15
using std::bind;
@@ -37,10 +38,12 @@ uint64_t ConsumerMock::make_consumer_id() {
37
38
ConsumerMock::ConsumerMock (ConfigurationMock config, EventProcessorPtr processor,
38
39
ClusterPtr cluster)
39
40
: HandleMock(move(processor), move(cluster)), config_(move(config)),
41
+ offset_reset_policy_ (get_offset_policy()), emit_eofs_(get_partition_eof_enabled()),
40
42
consumer_id_(make_consumer_id()) {
41
43
if (!config_.has_key (CONFIG_GROUP_ID)) {
42
44
throw runtime_error (" Failed to find " + CONFIG_GROUP_ID + " in config" );
43
45
}
46
+ group_id_ = config_.get (CONFIG_GROUP_ID);
44
47
}
45
48
46
49
ConsumerMock::~ConsumerMock () {
@@ -73,7 +76,13 @@ void ConsumerMock::assign(const vector<TopicPartitionMock>& topic_partitions) {
73
76
for (const TopicPartitionMock& topic_partition : topic_partitions) {
74
77
const auto id = make_id (topic_partition);
75
78
// We'll store the next offset from the one we've seen so far
76
- const uint64_t next_offset = topic_partition.get_offset () + 1 ;
79
+ uint64_t next_offset;
80
+ if (topic_partition.get_offset () == RD_KAFKA_OFFSET_INVALID) {
81
+ next_offset = 0 ;
82
+ }
83
+ else {
84
+ next_offset = topic_partition.get_offset () + 1 ;
85
+ }
77
86
78
87
auto iter = assigned_partitions_.find (id);
79
88
if (iter == assigned_partitions_.end ()) {
@@ -93,14 +102,15 @@ void ConsumerMock::assign(const vector<TopicPartitionMock>& topic_partitions) {
93
102
using namespace std ::placeholders;
94
103
// Now assign these partitions. This will atomically fetch all message we should fetch and
95
104
// then subscribe us to the topic/partitions
96
- get_cluster ().assign (consumer_id_, topic_partitions,
105
+ get_cluster ().assign (consumer_id_, topic_partitions, offset_reset_policy_,
97
106
bind (&ConsumerMock::on_message, this , _1, _2, _3, _4));
98
107
}
99
108
100
109
void ConsumerMock::unassign () {
101
110
lock_guard<mutex> _ (mutex_);
102
- get_cluster ().unassign (consumer_id_);
103
111
assigned_partitions_.clear ();
112
+ consumable_topic_partitions_.clear ();
113
+ get_cluster ().unassign (consumer_id_);
104
114
}
105
115
106
116
void ConsumerMock::pause_partitions (const vector<TopicPartitionMock>& topic_partitions) {
@@ -124,11 +134,10 @@ void ConsumerMock::resume_partitions(const vector<TopicPartitionMock>& topic_par
124
134
}
125
135
}
126
136
127
- unique_ptr<MessageHandle> ConsumerMock::poll (std::chrono::milliseconds timeout) {
128
- auto wait_until = steady_clock::now () + timeout;
137
+ unique_ptr<MessageHandle> ConsumerMock::poll (milliseconds timeout) {
129
138
unique_lock<mutex> lock (mutex_);
130
- while (consumable_topic_partitions_.empty () && steady_clock::now () > wait_until ) {
131
- messages_condition_.wait_until (lock, wait_until );
139
+ if (consumable_topic_partitions_.empty ()) {
140
+ messages_condition_.wait_for (lock, timeout );
132
141
}
133
142
if (consumable_topic_partitions_.empty ()) {
134
143
return nullptr ;
@@ -189,20 +198,48 @@ ConsumerMock::TopicPartitionId ConsumerMock::make_id(const TopicPartitionMock& t
189
198
return make_tuple (topic_partition.get_topic (), topic_partition.get_partition ());
190
199
}
191
200
201
+ KafkaCluster::ResetOffsetPolicy ConsumerMock::get_offset_policy () const {
202
+ static const string KEY_NAME = " auto.offset.reset" ;
203
+ static unordered_map<string, KafkaCluster::ResetOffsetPolicy> MAPPINGS = {
204
+ { " smallest" , KafkaCluster::ResetOffsetPolicy::Earliest },
205
+ { " earliest" , KafkaCluster::ResetOffsetPolicy::Earliest },
206
+ { " beginning" , KafkaCluster::ResetOffsetPolicy::Earliest },
207
+ { " latest" , KafkaCluster::ResetOffsetPolicy::Latest },
208
+ { " largest" , KafkaCluster::ResetOffsetPolicy::Latest },
209
+ { " end" , KafkaCluster::ResetOffsetPolicy::Latest },
210
+ };
211
+
212
+ const ConfigurationMock* topic_config = config_.get_default_topic_configuration ();
213
+ if (!topic_config || !topic_config->has_key (KEY_NAME)) {
214
+ return KafkaCluster::ResetOffsetPolicy::Earliest;
215
+ }
216
+ else {
217
+ auto iter = MAPPINGS.find (topic_config->get (KEY_NAME));
218
+ if (iter == MAPPINGS.end ()) {
219
+ throw runtime_error (" invalid auto.offset.reset value" );
220
+ }
221
+ return iter->second ;
222
+ }
223
+ }
224
+
225
+ bool ConsumerMock::get_partition_eof_enabled () const {
226
+ static const string KEY_NAME = " enable.partition.eof" ;
227
+ return !config_.has_key (KEY_NAME) || config_.get (KEY_NAME) == " true" ;
228
+ }
229
+
192
230
void ConsumerMock::on_assignment (const vector<TopicPartitionMock>& topic_partitions) {
193
231
handle_rebalance (RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS, topic_partitions);
194
232
}
195
233
196
234
void ConsumerMock::on_revocation () {
197
- // Fetch and reset all assigned topic partitions
235
+ // Fetch and all assigned topic partitions
198
236
vector<TopicPartitionMock> topic_partitions = [&]() {
199
237
lock_guard<mutex> _ (mutex_);
200
238
vector<TopicPartitionMock> output;
201
239
for (const auto & topic_partition_pair : assigned_partitions_) {
202
240
const TopicPartitionId& id = topic_partition_pair.first ;
203
241
output.emplace_back (get<0 >(id), get<1 >(id));
204
242
}
205
- assigned_partitions_.clear ();
206
243
return output;
207
244
}();
208
245
handle_rebalance (RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS, topic_partitions);
@@ -211,13 +248,13 @@ void ConsumerMock::on_revocation() {
211
248
void ConsumerMock::on_message (const string& topic_name, unsigned partition, uint64_t offset,
212
249
const KafkaMessageMock& message) {
213
250
auto id = make_tuple (topic_name, partition);
251
+ MessageAggregate aggregate = { topic_name, partition, offset, &message };
214
252
215
253
// We should only process this if we don't have this topic/partition assigned (assignment
216
254
// pending?) or the message offset comes after the next offset we have stored
217
255
lock_guard<mutex> _ (mutex_);
218
256
auto iter = assigned_partitions_.find (id);
219
- MessageAggregate aggregate = { topic_name, partition, offset, &message };
220
- if (iter != assigned_partitions_.end ()) {
257
+ if (iter == assigned_partitions_.end ()) {
221
258
throw runtime_error (" got message for unexpected partition " + to_string (partition));
222
259
}
223
260
if (offset > iter->second .next_offset ) {
@@ -240,7 +277,7 @@ void ConsumerMock::handle_rebalance(rd_kafka_resp_err_t type,
240
277
auto rebalance_callback = config_.get_rebalance_callback ();
241
278
if (rebalance_callback) {
242
279
auto handle = to_rdkafka_handle (topic_partitions);
243
- rebalance_callback (nullptr , type, handle.get (), opaque_ );
280
+ rebalance_callback (nullptr , type, handle.get (), config_. get_opaque () );
244
281
}
245
282
}
246
283
0 commit comments