mirror of
https://github.com/scylladb/scylladb.git
synced 2026-06-01 12:36:56 +00:00
in 30e82a81, we add a contraint to the template parameter of
boost_test_print_type() to prevent it from being matched with
types which can be formatted with operator<<. but it failed to
work. we still have test failure reports like:
```
[Exception] - critical check ['s', 's', 't', '_', 'm', 'r', '.', 'i', 's', '_', 'e', 'n', 'd', '_', 'o', 'f', '_', 's', 't', 'r', 'e', 'a', 'm', '(', ')'] has failed
```
this is not what we expect. the reason is that we passed the template
parameters to the `has_left_shift` trait in the wrong order, see
https://live.boost.org/doc/libs/1_83_0/libs/type_traits/doc/html/boost_typetraits/reference/has_left_shift.html.
we should have passed the lhs of operator<< expression as first
parameter, and rhs the second.
so, in this change, we correct the type constraint by passing the
template parameter in the right order, now the error message looks
better, like:
```
test/boost/mutation_query_test.cc(110): error: in "test_partition_query_is_full": check !partition_slice_builder(*s) .with_range({}) .build() .is_full() has failed
```
it turns out boost::transformed_range<> is formattable with operator<<,
as it fulfills the constraints of `boost::has_left_shift<ostream, R>`,
but when printing it, the compiler fails when it tries to insert the
elements in the range to the output stream.
so, in order to workaround this issue, we add a specialization for
`boost::transformed_range<F, R`.
also, to improve the readability, we reimplement the `has_left_shift<>`
as a concept, so that it's obvious that we need to put both the output
stream as the first parameter.
Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>
Closes scylladb/scylladb#20233
173 lines
6.5 KiB
C++
173 lines
6.5 KiB
C++
/*
|
|
* Copyright (C) 2018-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
#include "test/lib/scylla_test_case.hh"
|
|
|
|
#include <fmt/ranges.h>
|
|
|
|
#include "transport/request.hh"
|
|
#include "transport/response.hh"
|
|
|
|
#include "test/lib/random_utils.hh"
|
|
#include "test/lib/test_utils.hh"
|
|
|
|
namespace boost {
|
|
|
|
template <typename F, typename R>
|
|
requires fmt::is_formattable<std::ranges::range_value_t<R>>::value
|
|
std::ostream& boost_test_print_type(std::ostream& os, const transformed_range<F, R>& rng) {
|
|
fmt::print(os, "{}", rng);
|
|
return os;
|
|
}
|
|
|
|
}
|
|
|
|
namespace cql3 {
|
|
|
|
bool operator==(const cql3::raw_value_view& a, const cql3::raw_value_view& b) {
|
|
if (a.is_value()) {
|
|
return b.is_value() && b.with_value([&] (const FragmentedView auto& v2) {
|
|
return a.with_value([&] (const FragmentedView auto& v1) {
|
|
return equal_unsigned(v1, v2);
|
|
});
|
|
});
|
|
} else {
|
|
return a.is_null() == b.is_null();
|
|
}
|
|
}
|
|
|
|
} // namespace cql3
|
|
|
|
SEASTAR_THREAD_TEST_CASE(test_response_request_reader) {
|
|
auto stream_id = tests::random::get_int<int16_t>();
|
|
auto opcode = tests::random::get_int<uint8_t>(uint8_t(cql_transport::cql_binary_opcode::AUTH_SUCCESS));
|
|
auto res = cql_transport::response(stream_id, cql_transport::cql_binary_opcode(opcode), tracing::trace_state_ptr());
|
|
|
|
// Null value
|
|
res.write_value(bytes_opt());
|
|
|
|
// Unset value
|
|
res.write_int(-2);
|
|
|
|
// "Value" value
|
|
auto value = tests::random::get_bytes(tests::random::get_int<int16_t>(1024));
|
|
res.write_value(bytes_opt(value));
|
|
|
|
// Name and value list
|
|
auto names_and_values = boost::copy_range<std::vector<std::pair<sstring, bytes_opt>>>(
|
|
boost::irange<int16_t>(0, tests::random::get_int<int16_t>(16) + 16)
|
|
| boost::adaptors::transformed([] (int) {
|
|
return std::pair(
|
|
tests::random::get_sstring(),
|
|
!tests::random::get_int(4) ? bytes_opt() : bytes_opt(tests::random::get_bytes(tests::random::get_int<int16_t>(1024)))
|
|
);
|
|
})
|
|
);
|
|
res.write_short(names_and_values.size());
|
|
for (auto& [ name, value ] : names_and_values) {
|
|
res.write_string(name);
|
|
res.write_value(value);
|
|
}
|
|
|
|
// String list
|
|
auto string_list = boost::copy_range<std::vector<sstring>>(
|
|
boost::irange<int16_t>(0, tests::random::get_int<int16_t>(16) + 16)
|
|
| boost::adaptors::transformed([] (int) {
|
|
return tests::random::get_sstring();
|
|
})
|
|
);
|
|
res.write_string_list(string_list);
|
|
|
|
// String map
|
|
auto string_map = boost::copy_range<std::map<sstring, sstring>>(
|
|
boost::irange<int16_t>(0, tests::random::get_int<int16_t>(16) + 16)
|
|
| boost::adaptors::transformed([] (int) {
|
|
return std::pair(tests::random::get_sstring(), tests::random::get_sstring());
|
|
})
|
|
);
|
|
res.write_string_map(string_map);
|
|
auto string_unordered_map = std::unordered_map<sstring, sstring>(string_map.begin(), string_map.end());
|
|
|
|
static constexpr auto version = 4;
|
|
|
|
using sc = cql_transport::event::schema_change;
|
|
res.serialize({sc::change_type::CREATED, sc::target_type::KEYSPACE, "foo"}, version);
|
|
res.serialize({sc::change_type::CREATED, sc::target_type::TABLE, "foo", "bar"}, version);
|
|
res.serialize({sc::change_type::CREATED, sc::target_type::TYPE, "foo", "bar"}, version);
|
|
res.serialize({sc::change_type::CREATED, sc::target_type::FUNCTION, "foo", "bar", "zed"}, version);
|
|
res.serialize({sc::change_type::CREATED, sc::target_type::AGGREGATE, "foo", "bar", "zed"}, version);
|
|
|
|
auto msg = res.make_message(version, cql_transport::cql_compression::none).release();
|
|
auto total_length = msg.len();
|
|
auto fbufs = fragmented_temporary_buffer(msg.release(), total_length);
|
|
|
|
bytes_ostream linearization_buffer;
|
|
auto req = cql_transport::request_reader(fbufs.get_istream(), linearization_buffer);
|
|
BOOST_CHECK_EQUAL(unsigned(uint8_t(req.read_byte())), version | 0x80);
|
|
BOOST_CHECK_EQUAL(unsigned(req.read_byte()), 0); // flags
|
|
BOOST_CHECK_EQUAL(req.read_short(), stream_id);
|
|
BOOST_CHECK_EQUAL(unsigned(req.read_byte()), unsigned(opcode));
|
|
BOOST_CHECK_EQUAL(req.read_int() + 9, total_length);
|
|
|
|
auto v1 = req.read_value_view(version);
|
|
BOOST_CHECK(!v1.unset && v1.value.is_null());
|
|
auto v2 = req.read_value_view(version);
|
|
BOOST_CHECK(v2.unset);
|
|
BOOST_CHECK_EQUAL(to_bytes(req.read_value_view(version).value), value);
|
|
|
|
std::vector<sstring_view> names;
|
|
std::vector<cql3::raw_value_view> values;
|
|
cql3::unset_bind_variable_vector unset;
|
|
req.read_name_and_value_list(version, names, values, unset);
|
|
BOOST_CHECK(std::none_of(unset.begin(), unset.end(), std::identity()));
|
|
BOOST_CHECK_EQUAL(names, names_and_values | boost::adaptors::transformed([] (auto& name_and_value) {
|
|
return sstring_view(name_and_value.first);
|
|
}));
|
|
BOOST_CHECK_EQUAL(values, names_and_values | boost::adaptors::transformed([] (auto& name_and_value) {
|
|
if (!name_and_value.second) {
|
|
return cql3::raw_value_view::make_null();
|
|
}
|
|
return cql3::raw_value_view::make_value(fragmented_temporary_buffer::view(*name_and_value.second));
|
|
}));
|
|
|
|
auto received_string_list = std::vector<sstring>();
|
|
req.read_string_list(received_string_list);
|
|
BOOST_CHECK_EQUAL(received_string_list, string_list);
|
|
|
|
auto received_string_map = req.read_string_map();
|
|
BOOST_CHECK_EQUAL(received_string_map, string_unordered_map);
|
|
|
|
BOOST_CHECK_EQUAL(req.read_string(), "CREATED");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "KEYSPACE");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "foo");
|
|
|
|
BOOST_CHECK_EQUAL(req.read_string(), "CREATED");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "TABLE");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "foo");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "bar");
|
|
|
|
BOOST_CHECK_EQUAL(req.read_string(), "CREATED");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "TYPE");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "foo");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "bar");
|
|
|
|
BOOST_CHECK_EQUAL(req.read_string(), "CREATED");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "FUNCTION");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "foo");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "bar");
|
|
BOOST_CHECK_EQUAL(req.read_short(), 1);
|
|
BOOST_CHECK_EQUAL(req.read_string(), "zed");
|
|
|
|
BOOST_CHECK_EQUAL(req.read_string(), "CREATED");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "AGGREGATE");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "foo");
|
|
BOOST_CHECK_EQUAL(req.read_string(), "bar");
|
|
BOOST_CHECK_EQUAL(req.read_short(), 1);
|
|
BOOST_CHECK_EQUAL(req.read_string(), "zed");
|
|
}
|