Skip to content

Commit 29c9f20

Browse files
authored
feat(testing): introduce mock testing utilities (#109)
1 parent c9e01de commit 29c9f20

17 files changed

Lines changed: 1072 additions & 0 deletions
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <algorithm>
22+
#include <memory>
23+
#include <utility>
24+
#include <vector>
25+
26+
#include "arrow/api.h"
27+
#include "arrow/c/bridge.h"
28+
#include "paimon/common/metrics/metrics_impl.h"
29+
#include "paimon/common/reader/reader_utils.h"
30+
#include "paimon/common/utils/arrow/status_utils.h"
31+
#include "paimon/common/utils/date_time_utils.h"
32+
#include "paimon/reader/prefetch_file_batch_reader.h"
33+
namespace paimon::test {
34+
35+
class MockFileBatchReader : public PrefetchFileBatchReader {
36+
public:
37+
MockFileBatchReader(const std::shared_ptr<arrow::Array>& data,
38+
const std::shared_ptr<arrow::DataType>& file_schema,
39+
int32_t read_batch_size)
40+
: data_(data),
41+
file_schema_(file_schema),
42+
read_schema_(arrow::schema(file_schema->fields())),
43+
batch_size_(read_batch_size) {
44+
// add all valid bitmap
45+
int32_t data_length = data_ ? data_->length() : 0;
46+
bitmap_ = RoaringBitmap32();
47+
bitmap_.AddRange(0, data_length);
48+
read_end_pos_ = data_length;
49+
int64_t seed = DateTimeUtils::GetCurrentUTCTimeUs();
50+
std::srand(seed);
51+
}
52+
53+
MockFileBatchReader(const std::shared_ptr<arrow::Array>& data,
54+
const std::shared_ptr<arrow::DataType>& schema,
55+
const RoaringBitmap32& bitmap, int32_t read_batch_size)
56+
: MockFileBatchReader(data, schema, read_batch_size) {
57+
bitmap_ = bitmap;
58+
}
59+
60+
Result<std::unique_ptr<::ArrowSchema>> GetFileSchema() const override {
61+
std::unique_ptr<ArrowSchema> c_schema = std::make_unique<ArrowSchema>();
62+
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportType(*file_schema_, c_schema.get()));
63+
return c_schema;
64+
}
65+
66+
void SetNextBatchStatus(const Status& status) {
67+
next_batch_status_ = status;
68+
}
69+
70+
void EnableRandomizeBatchSize(bool enabled) {
71+
enable_randomize_batch_size_ = enabled;
72+
}
73+
74+
Status SetReadSchema(::ArrowSchema* read_schema, const std::shared_ptr<Predicate>& predicate,
75+
const std::optional<RoaringBitmap32>& selection_bitmap) override {
76+
// Noted that SetReadSchema only change inner read_schema_, but take no effective on
77+
// NextBatch
78+
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Schema> arrow_schema,
79+
arrow::ImportSchema(read_schema));
80+
read_schema_ = arrow_schema;
81+
return Status::OK();
82+
}
83+
84+
Result<std::vector<std::pair<uint64_t, uint64_t>>> GenReadRanges(
85+
bool* need_prefetch) const override {
86+
uint64_t begin_row_num = 0;
87+
PAIMON_ASSIGN_OR_RAISE(uint64_t end_row_num, GetNumberOfRows());
88+
std::vector<std::pair<uint64_t, uint64_t>> read_ranges;
89+
for (uint64_t begin = begin_row_num; begin < end_row_num; begin += batch_size_) {
90+
uint64_t end = std::min(begin + batch_size_, end_row_num);
91+
read_ranges.emplace_back(begin, end);
92+
}
93+
*need_prefetch = true;
94+
return read_ranges;
95+
}
96+
97+
Status SeekToRow(uint64_t row_number) override {
98+
current_pos_ = row_number;
99+
return Status::OK();
100+
}
101+
102+
Status SetReadRanges(const std::vector<std::pair<uint64_t, uint64_t>>& read_ranges) override {
103+
read_ranges_ = read_ranges;
104+
return Status::OK();
105+
}
106+
107+
Result<ReadBatch> NextBatch() override {
108+
PAIMON_ASSIGN_OR_RAISE(ReadBatchWithBitmap batch_with_bitmap, NextBatchWithBitmap());
109+
return ReaderUtils::ApplyBitmapToReadBatch(std::move(batch_with_bitmap),
110+
arrow::default_memory_pool());
111+
}
112+
113+
Result<ReadBatchWithBitmap> NextBatchWithBitmap() override {
114+
while (true) {
115+
PAIMON_RETURN_NOT_OK(next_batch_status_);
116+
if (current_pos_ >= read_end_pos_) {
117+
previous_batch_first_row_num_ = current_pos_;
118+
return BatchReader::MakeEofBatchWithBitmap();
119+
}
120+
int32_t actual_batch_size = batch_size_;
121+
if (enable_randomize_batch_size_) {
122+
actual_batch_size = std::rand() % batch_size_ + 1;
123+
}
124+
int32_t batch_end_pos = std::min(read_end_pos_, current_pos_ + actual_batch_size);
125+
auto slice = data_->Slice(current_pos_, batch_end_pos - current_pos_);
126+
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(
127+
std::shared_ptr<arrow::Array> concat_slice,
128+
arrow::Concatenate({slice}, arrow::default_memory_pool()));
129+
RoaringBitmap32 bitmap;
130+
for (auto iter = bitmap_.EqualOrLarger(current_pos_);
131+
iter != bitmap_.End() && *iter < batch_end_pos; ++iter) {
132+
bitmap.Add(*iter - current_pos_);
133+
}
134+
previous_batch_first_row_num_ = current_pos_;
135+
current_pos_ = batch_end_pos;
136+
if (bitmap.IsEmpty()) {
137+
continue;
138+
}
139+
std::unique_ptr<ArrowArray> c_array = std::make_unique<ArrowArray>();
140+
std::unique_ptr<ArrowSchema> c_schema = std::make_unique<ArrowSchema>();
141+
PAIMON_RETURN_NOT_OK_FROM_ARROW(
142+
arrow::ExportArray(*concat_slice, c_array.get(), c_schema.get()));
143+
return std::make_pair(std::make_pair(std::move(c_array), std::move(c_schema)),
144+
std::move(bitmap));
145+
}
146+
}
147+
148+
std::shared_ptr<Metrics> GetReaderMetrics() const override {
149+
auto metrics = std::make_shared<MetricsImpl>();
150+
metrics->SetCounter("mock.number.of.rows", GetNumberOfRows().value_or(-1));
151+
return metrics;
152+
}
153+
154+
Result<uint64_t> GetPreviousBatchFirstRowNumber() const override {
155+
return previous_batch_first_row_num_;
156+
}
157+
158+
Result<uint64_t> GetNumberOfRows() const override {
159+
return data_ ? data_->length() : 0;
160+
}
161+
uint64_t GetNextRowToRead() const override {
162+
return current_pos_;
163+
}
164+
void Close() override {}
165+
166+
std::vector<std::pair<uint64_t, uint64_t>> GetReadRanges() const {
167+
return read_ranges_;
168+
}
169+
170+
bool SupportPreciseBitmapSelection() const override {
171+
return false;
172+
}
173+
174+
private:
175+
std::shared_ptr<arrow::Array> data_;
176+
std::shared_ptr<arrow::DataType> file_schema_;
177+
std::shared_ptr<arrow::Schema> read_schema_;
178+
RoaringBitmap32 bitmap_;
179+
int32_t batch_size_ = 0;
180+
int32_t current_pos_ = 0;
181+
int32_t read_end_pos_ = 0;
182+
int32_t previous_batch_first_row_num_ = -1;
183+
Status next_batch_status_;
184+
bool enable_randomize_batch_size_ = true;
185+
std::vector<std::pair<uint64_t, uint64_t>> read_ranges_;
186+
};
187+
188+
} // namespace paimon::test
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include "paimon/testing/mock/mock_file_format.h"
20+
21+
#include <utility>
22+
23+
#include "arrow/c/helpers.h"
24+
#include "paimon/status.h"
25+
#include "paimon/testing/mock/mock_format_writer_builder.h"
26+
#include "paimon/testing/mock/mock_stats_extractor.h"
27+
28+
namespace paimon::test {
29+
Result<std::unique_ptr<ReaderBuilder>> MockFileFormat::CreateReaderBuilder(
30+
int32_t batch_size) const {
31+
return Status::NotImplemented("");
32+
}
33+
Result<std::unique_ptr<WriterBuilder>> MockFileFormat::CreateWriterBuilder(
34+
::ArrowSchema* schema, int32_t batch_size) const {
35+
ArrowSchemaRelease(schema);
36+
return std::make_unique<MockFormatWriterBuilder>();
37+
}
38+
39+
Result<std::unique_ptr<FormatStatsExtractor>> MockFileFormat::CreateStatsExtractor(
40+
::ArrowSchema* schema) const {
41+
ArrowSchemaRelease(schema);
42+
return std::make_unique<MockStatsExtractor>();
43+
}
44+
45+
} // namespace paimon::test
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <cstdint>
22+
#include <memory>
23+
#include <string>
24+
25+
#include "paimon/format/file_format.h"
26+
#include "paimon/format/format_stats_extractor.h"
27+
#include "paimon/format/reader_builder.h"
28+
#include "paimon/format/writer_builder.h"
29+
#include "paimon/result.h"
30+
31+
struct ArrowSchema;
32+
33+
namespace paimon::test {
34+
35+
class MockFileFormat : public FileFormat {
36+
public:
37+
MockFileFormat() : identifier_("mock_format") {}
38+
39+
const std::string& Identifier() const override {
40+
return identifier_;
41+
}
42+
Result<std::unique_ptr<ReaderBuilder>> CreateReaderBuilder(int32_t batch_size) const override;
43+
Result<std::unique_ptr<WriterBuilder>> CreateWriterBuilder(::ArrowSchema* schema,
44+
int32_t batch_size) const override;
45+
Result<std::unique_ptr<FormatStatsExtractor>> CreateStatsExtractor(
46+
::ArrowSchema* schema) const override;
47+
48+
private:
49+
const std::string identifier_;
50+
};
51+
52+
} // namespace paimon::test
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include "paimon/testing/mock/mock_file_format_factory.h"
20+
21+
#include <utility>
22+
23+
#include "paimon/factories/factory.h"
24+
#include "paimon/testing/mock/mock_file_format.h"
25+
26+
namespace paimon::test {
27+
28+
const char MockFileFormatFactory::IDENTIFIER[] = "mock_format";
29+
30+
Result<std::unique_ptr<FileFormat>> MockFileFormatFactory::Create(
31+
const std::map<std::string, std::string>& options) const {
32+
return std::make_unique<MockFileFormat>();
33+
}
34+
35+
REGISTER_PAIMON_FACTORY(MockFileFormatFactory);
36+
37+
} // namespace paimon::test
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <map>
22+
#include <memory>
23+
#include <string>
24+
25+
#include "paimon/format/file_format.h"
26+
#include "paimon/format/file_format_factory.h"
27+
#include "paimon/result.h"
28+
29+
namespace paimon::test {
30+
31+
class MockFileFormatFactory : public FileFormatFactory {
32+
public:
33+
static const char IDENTIFIER[];
34+
35+
const char* Identifier() const override {
36+
return IDENTIFIER;
37+
}
38+
39+
Result<std::unique_ptr<FileFormat>> Create(
40+
const std::map<std::string, std::string>& options) const override;
41+
};
42+
43+
} // namespace paimon::test

0 commit comments

Comments
 (0)