/* * Copyright (C) 2015-present ScyllaDB */ /* * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 */ #pragma once #include "utils/assert.hh" #include "utils/managed_bytes.hh" #include "test/lib/cql_test_env.hh" #include "transport/messages/result_message_base.hh" #include "bytes.hh" #include #include #include class columns_assertions { const cql3::metadata& _metadata; const std::vector& _columns; std::source_location _loc; columns_assertions& do_with_raw_column(const char* name, std::function func); void fail(const sstring& msg); public: columns_assertions(const cql3::metadata& metadata, const std::vector& columns, std::source_location loc) : _metadata(metadata), _columns(columns), _loc(loc) { } columns_assertions& with_raw_column(const char* name, std::function predicate); columns_assertions& with_raw_column(const char* name, managed_bytes_view value); template columns_assertions& with_typed_column(const char* name, std::function predicate) { return do_with_raw_column(name, [this, name, predicate] (data_type type, managed_bytes_view value) { if (type != data_type_for()) { fail(seastar::format("Column {} is not of type {}, but of type {}", name, data_type_for()->name(), type->name())); } std::optional t_opt; if (!value.empty()) { t_opt.emplace(value_cast(type->deserialize(value))); } if (!predicate(t_opt.has_value() ? &t_opt.value() : nullptr)) { fail(seastar::format("Column {} failed predicate check: value = {}", name, value)); } }); } template columns_assertions& with_typed_column(const char* name, std::function predicate) { return with_typed_column(name, [this, name, predicate] (const T* value) { if (!value) { fail(seastar::format("Column {} is null", name)); } return predicate(*value); }); } template columns_assertions& with_typed_column(const char* name, const T& value) { return with_typed_column(name, [this, name, &value] (const T& cell_value) { if (cell_value != value) { fail(seastar::format("Expected column {} to have value {}, but got {}", name, value, cell_value)); } return true; }); } }; namespace tests { using dump_to_logs = bool_class; } // namespace tests class rows_assertions { shared_ptr _rows; std::source_location _loc; public: rows_assertions(shared_ptr rows, tests::dump_to_logs dump, std::source_location loc); rows_assertions with_size(size_t size); rows_assertions with_size(std::function predicate); rows_assertions is_empty(); rows_assertions is_not_empty(); rows_assertions with_column_types(std::initializer_list column_types); rows_assertions with_row(std::initializer_list values); // Verifies that the result has the following rows and only that rows, in that order. rows_assertions with_rows(std::vector> rows); // Verifies that the result has the following rows and only those rows. rows_assertions with_rows_ignore_order(std::vector> rows); rows_assertions with_serialized_columns_count(size_t columns_count); columns_assertions with_columns_of_row(size_t row_index); rows_assertions& assert_for_columns_of_each_row(std::function func); rows_assertions is_null(); rows_assertions is_not_null(); }; class result_msg_assertions { shared_ptr _msg; std::source_location _loc; public: result_msg_assertions(shared_ptr msg, std::source_location loc); // Pass dump_to_logs::yes, to dump the content of the result to the log. // The results are logged with testlog.debug(). rows_assertions is_rows(tests::dump_to_logs dump = tests::dump_to_logs::no); }; result_msg_assertions assert_that(shared_ptr msg, std::source_location loc = std::source_location::current()); template void assert_that_failed(future& f) { try { f.get(); SCYLLA_ASSERT(f.failed()); } catch (...) { } } template void assert_that_failed(future&& f) { try { f.get(); SCYLLA_ASSERT(f.failed()); } catch (...) { } } /// Invokes env.execute_cql(query), awaits its result, and returns it. If an exception is thrown, /// invokes BOOST_FAIL with useful diagnostics. /// /// \note Should be called from a seastar::thread context, as it awaits the CQL result. shared_ptr cquery_nofail( cql_test_env& env, std::string_view query, std::unique_ptr&& qo = nullptr, const std::source_location& loc = std::source_location::current()); /// Asserts that cquery_nofail(e, qstr) contains expected rows, in any order. void require_rows(cql_test_env& e, std::string_view qstr, const std::vector>& expected, const std::source_location& loc = std::source_location::current()); /// Like require_rows, but wraps assertions in \c eventually. void eventually_require_rows( cql_test_env& e, std::string_view qstr, const std::vector>& expected, const std::source_location& loc = std::source_location::current()); /// Asserts that e.execute_prepared(id, values) contains expected rows, in any order. void require_rows(cql_test_env& e, cql3::prepared_cache_key_type id, const std::vector& values, const std::vector>& expected, const std::source_location& loc = std::source_location::current()); /// Asserts that a cell at the given table.partition.row.column position contains expected data future<> require_column_has_value(cql_test_env&, const sstring& table_name, std::vector pk, std::vector ck, const sstring& column_name, data_value expected);