|
26 | 26 | #include <boost/test/unit_test.hpp>
|
27 | 27 |
|
28 | 28 | #include <chrono>
|
| 29 | +#include <limits> |
| 30 | +#include <ratio> |
| 31 | +#include <sstream> |
29 | 32 | #include <string>
|
30 | 33 | #include <string_view>
|
31 | 34 | #include <system_error>
|
@@ -112,6 +115,22 @@ static constexpr std::string_view wrong_compaction_strategy = R"json({
|
112 | 115 | "retention_duration": 36000000000
|
113 | 116 | })json";
|
114 | 117 |
|
| 118 | +static constexpr std::string_view negative_properties_manifest = R"json({ |
| 119 | + "version": 1, |
| 120 | + "namespace": "negative-test-namespace", |
| 121 | + "topic": "full-test-topic", |
| 122 | + "partition_count": 64, |
| 123 | + "replication_factor": 6, |
| 124 | + "revision_id": 1, |
| 125 | + "compression": "snappy", |
| 126 | + "cleanup_policy_bitflags": "compact,delete", |
| 127 | + "compaction_strategy": "offset", |
| 128 | + "timestamp_type": "LogAppendTime", |
| 129 | + "segment_size": -1234, |
| 130 | + "retention_bytes": -42342, |
| 131 | + "retention_duration": -36000000000 |
| 132 | +})json"; |
| 133 | + |
115 | 134 | inline ss::input_stream<char> make_manifest_stream(std::string_view json) {
|
116 | 135 | iobuf i;
|
117 | 136 | i.append(json.data(), json.size());
|
@@ -224,6 +243,46 @@ SEASTAR_THREAD_TEST_CASE(full_config_update_all_fields_correct) {
|
224 | 243 | std::chrono::milliseconds(36000000000));
|
225 | 244 | }
|
226 | 245 |
|
| 246 | +SEASTAR_THREAD_TEST_CASE(topic_manifest_min_serialization) { |
| 247 | + manifest_topic_configuration min_cfg{cfg}; |
| 248 | + min_cfg.properties.retention_bytes = tristate<size_t>( |
| 249 | + std::numeric_limits<size_t>::min()); |
| 250 | + min_cfg.properties.retention_duration = tristate<std::chrono::milliseconds>( |
| 251 | + std::chrono::milliseconds::min()); |
| 252 | + min_cfg.properties.segment_size = std::make_optional( |
| 253 | + std::numeric_limits<size_t>::min()); |
| 254 | + topic_manifest m(min_cfg, model::initial_revision_id{0}); |
| 255 | + auto [is, size] = m.serialize().get(); |
| 256 | + iobuf buf; |
| 257 | + auto os = make_iobuf_ref_output_stream(buf); |
| 258 | + ss::copy(is, os).get(); |
| 259 | + |
| 260 | + auto rstr = make_iobuf_input_stream(std::move(buf)); |
| 261 | + topic_manifest restored; |
| 262 | + restored.update(std::move(rstr)).get(); |
| 263 | + BOOST_REQUIRE(m == restored); |
| 264 | +} |
| 265 | + |
| 266 | +SEASTAR_THREAD_TEST_CASE(topic_manifest_max_serialization) { |
| 267 | + manifest_topic_configuration max_cfg{cfg}; |
| 268 | + max_cfg.properties.retention_bytes = tristate<size_t>( |
| 269 | + std::numeric_limits<size_t>::max()); |
| 270 | + max_cfg.properties.retention_duration = tristate<std::chrono::milliseconds>( |
| 271 | + std::chrono::milliseconds::max()); |
| 272 | + max_cfg.properties.segment_size = std::make_optional( |
| 273 | + std::numeric_limits<size_t>::max()); |
| 274 | + topic_manifest m(max_cfg, model::initial_revision_id{0}); |
| 275 | + auto [is, size] = m.serialize().get(); |
| 276 | + iobuf buf; |
| 277 | + auto os = make_iobuf_ref_output_stream(buf); |
| 278 | + ss::copy(is, os).get(); |
| 279 | + |
| 280 | + auto rstr = make_iobuf_input_stream(std::move(buf)); |
| 281 | + topic_manifest restored; |
| 282 | + restored.update(std::move(rstr)).get(); |
| 283 | + BOOST_REQUIRE(m == restored); |
| 284 | +} |
| 285 | + |
227 | 286 | SEASTAR_THREAD_TEST_CASE(missing_required_fields_throws) {
|
228 | 287 | topic_manifest m;
|
229 | 288 | BOOST_REQUIRE_EXCEPTION(
|
@@ -294,3 +353,20 @@ SEASTAR_THREAD_TEST_CASE(update_non_empty_manifest) {
|
294 | 353 |
|
295 | 354 | BOOST_REQUIRE(m == restored);
|
296 | 355 | }
|
| 356 | + |
| 357 | +SEASTAR_THREAD_TEST_CASE(test_negative_property_manifest) { |
| 358 | + topic_manifest m(cfg, model::initial_revision_id(0)); |
| 359 | + m.update(make_manifest_stream(negative_properties_manifest)).get(); |
| 360 | + auto tp_cfg = m.get_topic_config(); |
| 361 | + BOOST_REQUIRE(tp_cfg.has_value()); |
| 362 | + BOOST_REQUIRE_EQUAL(64, tp_cfg->partition_count); |
| 363 | + BOOST_REQUIRE_EQUAL(6, tp_cfg->replication_factor); |
| 364 | + auto tp_props = tp_cfg->properties; |
| 365 | + BOOST_REQUIRE(tp_props.retention_duration.has_optional_value()); |
| 366 | + BOOST_REQUIRE_EQUAL( |
| 367 | + tp_props.retention_duration.value().count(), -36000000000); |
| 368 | + |
| 369 | + // The usigned types that were passed in negative values shouldn't be set. |
| 370 | + BOOST_REQUIRE(tp_props.retention_bytes.is_disabled()); |
| 371 | + BOOST_REQUIRE(!tp_props.segment_size.has_value()); |
| 372 | +} |
0 commit comments