in a recent seastar change (644bb662), we do not include
`seastar/testing/random.hh` in `seastar/testing/test_runner.hh` anymore,
as the latter is not a facade of the former, and neither does it use the
former. as a sequence, some tests which take the advantage of the
included `seastar/testing/random.hh` do not build with the latest
seastar:
```
FAILED: test/lib/CMakeFiles/test-lib.dir/key_utils.cc.o
/usr/bin/clang++ -DBOOST_REGEX_DYN_LINK -DBOOST_REGEX_NO_LIB -DBOOST_UNIT_TEST_FRAMEWORK_DYN_LINK -DBOOST_UNIT_TEST_FRAMEWORK_NO_LIB -DDEVEL -DFMT_SHARED -DSCYLLA_BUILD_MODE=dev -DSCYLLA_ENABLE_ERROR_INJECTION -DSCYLLA_ENABLE_PREEMPTION_SOURCE -DSEASTAR_API_LEVEL=7 -DSEASTAR_ENABLE_ALLOC_FAILURE_INJECTION -DSEASTAR_LOGGER_COMPILE_TIME_FMT -DSEASTAR_LOGGER_TYPE_STDOUT -DSEASTAR_SCHEDULING_GROUPS_COUNT=16 -DSEASTAR_SSTRING -DSEASTAR_TYPE_ERASE_MORE -DXXH_PRIVATE_API -I/__w/scylladb/scylladb -I/__w/scylladb/scylladb/build/gen -I/__w/scylladb/scylladb/seastar/include -I/__w/scylladb/scylladb/build/seastar/gen/include -I/__w/scylladb/scylladb/build/seastar/gen/src -I/__w/scylladb/scylladb/build -isystem /__w/scylladb/scylladb/abseil -isystem /__w/scylladb/scylladb/build/rust -O2 -std=gnu++23 -fvisibility=hidden -Wall -Werror -Wextra -Wno-error=deprecated-declarations -Wimplicit-fallthrough -Wno-c++11-narrowing -Wno-deprecated-copy -Wno-mismatched-tags -Wno-missing-field-initializers -Wno-overloaded-virtual -Wno-unsupported-friend -Wno-enum-constexpr-conversion -Wno-unused-parameter -ffile-prefix-map=/__w/scylladb/scylladb/build=. -march=westmere -Xclang -fexperimental-assignment-tracking=disabled -Werror=unused-result -fstack-clash-protection -MD -MT test/lib/CMakeFiles/test-lib.dir/key_utils.cc.o -MF test/lib/CMakeFiles/test-lib.dir/key_utils.cc.o.d -o test/lib/CMakeFiles/test-lib.dir/key_utils.cc.o -c /__w/scylladb/scylladb/test/lib/key_utils.cc
In file included from /__w/scylladb/scylladb/test/lib/key_utils.cc:11:
/__w/scylladb/scylladb/test/lib/random_utils.hh:25:30: error: no member named 'local_random_engine' in namespace 'seastar::testing'
25 | return seastar::testing::local_random_engine;
| ~~~~~~~~~~~~~~~~~~^
1 error generated.
```
in this change, we include `seastar/testing/random.hh` when the random
facility is used, so that they can be compiled with the latest seastar
library.
Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>
Closes scylladb/scylladb#20368
192 lines
4.9 KiB
C++
192 lines
4.9 KiB
C++
/*
|
|
* Copyright (C) 2018-present ScyllaDB
|
|
*/
|
|
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <random>
|
|
|
|
#include <boost/range/algorithm/generate.hpp>
|
|
#include <iostream>
|
|
|
|
#include <seastar/testing/random.hh>
|
|
#include <seastar/testing/test_runner.hh>
|
|
|
|
#include "bytes.hh"
|
|
#include "utils/assert.hh"
|
|
#include "utils/preempt.hh"
|
|
|
|
namespace tests::random {
|
|
|
|
inline std::default_random_engine& gen() {
|
|
return seastar::testing::local_random_engine;
|
|
}
|
|
|
|
/// Produces random integers from a set of steps.
|
|
///
|
|
/// Each step has a weight and a uniform distribution that determines the range
|
|
/// of values for that step. The probability of the generated number to be from
|
|
/// any given step is Ws/Wt, where Ws is the weight of the step and Wt is the
|
|
/// sum of the weight of all steps.
|
|
template <typename Integer>
|
|
class stepped_int_distribution {
|
|
public:
|
|
struct step {
|
|
double weight;
|
|
std::pair<Integer, Integer> range;
|
|
};
|
|
|
|
private:
|
|
std::discrete_distribution<Integer> _step_index_dist;
|
|
std::vector<std::uniform_int_distribution<Integer>> _step_ranges;
|
|
|
|
public:
|
|
explicit stepped_int_distribution(std::initializer_list<step> steps) {
|
|
std::vector<double> step_weights;
|
|
for (auto& s : steps) {
|
|
step_weights.push_back(s.weight);
|
|
_step_ranges.emplace_back(s.range.first, s.range.second);
|
|
}
|
|
_step_index_dist = std::discrete_distribution<Integer>{step_weights.begin(), step_weights.end()};
|
|
}
|
|
template <typename RandomEngine>
|
|
Integer operator()(RandomEngine& engine) {
|
|
return _step_ranges[_step_index_dist(engine)](engine);
|
|
}
|
|
};
|
|
|
|
template<typename T, typename RandomEngine>
|
|
T get_int(T min, T max, RandomEngine& engine) {
|
|
std::uniform_int_distribution<T> dist(min, max);
|
|
return dist(engine);
|
|
}
|
|
|
|
template<typename T, typename RandomEngine>
|
|
T get_int(T max, RandomEngine& engine) {
|
|
return get_int(T{0}, max, engine);
|
|
}
|
|
|
|
template<typename T, typename RandomEngine>
|
|
T get_int(RandomEngine& engine) {
|
|
return get_int(T{0}, std::numeric_limits<T>::max(), engine);
|
|
}
|
|
|
|
template<typename T>
|
|
T get_int() {
|
|
return get_int(T{0}, std::numeric_limits<T>::max(), gen());
|
|
}
|
|
|
|
template<typename T>
|
|
T get_int(T max) {
|
|
return get_int(T{0}, max, gen());
|
|
}
|
|
|
|
template<typename T>
|
|
T get_int(T min, T max) {
|
|
return get_int(min, max, gen());
|
|
}
|
|
|
|
template <typename Real, typename RandomEngine>
|
|
Real get_real(Real min, Real max, RandomEngine& engine) {
|
|
auto dist = std::uniform_real_distribution<Real>(min, max);
|
|
return dist(engine);
|
|
}
|
|
|
|
template <typename Real, typename RandomEngine>
|
|
Real get_real(Real max, RandomEngine& engine) {
|
|
return get_real<Real>(Real{0}, max, engine);
|
|
}
|
|
|
|
/// Returns true with probability p.
|
|
/// p = 1.0 means 100%.
|
|
inline
|
|
bool with_probability(double p) {
|
|
return get_real<double>(1, gen()) < p;
|
|
}
|
|
|
|
template <typename Real, typename RandomEngine>
|
|
Real get_real(RandomEngine& engine) {
|
|
return get_real<Real>(Real{0}, std::numeric_limits<Real>::max(), engine);
|
|
}
|
|
|
|
template <typename Real>
|
|
Real get_real(Real min, Real max) {
|
|
return get_real<Real>(min, max, gen());
|
|
}
|
|
|
|
template <typename Real>
|
|
Real get_real(Real max) {
|
|
return get_real<Real>(Real{0}, max, gen());
|
|
}
|
|
|
|
template <typename Real>
|
|
Real get_real() {
|
|
return get_real<Real>(Real{0}, std::numeric_limits<Real>::max(), gen());
|
|
}
|
|
|
|
template <typename RandomEngine>
|
|
inline bool get_bool(RandomEngine& engine) {
|
|
static std::bernoulli_distribution dist;
|
|
return dist(engine);
|
|
}
|
|
|
|
inline bool get_bool() {
|
|
return get_bool(gen());
|
|
}
|
|
|
|
inline bytes get_bytes(size_t n) {
|
|
bytes b(bytes::initialized_later(), n);
|
|
boost::generate(b, [] { return get_int<bytes::value_type>(); });
|
|
return b;
|
|
}
|
|
|
|
inline bytes get_bytes() {
|
|
return get_bytes(get_int<unsigned>(128 * 1024));
|
|
}
|
|
|
|
template <typename RandomEngine>
|
|
inline sstring get_sstring(size_t n, RandomEngine& engine) {
|
|
sstring str = uninitialized_string(n);
|
|
boost::generate(str, [&engine] { return get_int<sstring::value_type>('a', 'z', engine); });
|
|
return str;
|
|
}
|
|
|
|
inline sstring get_sstring(size_t n) {
|
|
return get_sstring(n, gen());
|
|
}
|
|
|
|
inline sstring get_sstring() {
|
|
return get_sstring(get_int<unsigned>(1024));
|
|
}
|
|
|
|
// Picks a random subset of size `m` from the given vector.
|
|
template <typename T>
|
|
std::vector<T> random_subset(std::vector<T> v, unsigned m, std::mt19937& engine) {
|
|
SCYLLA_ASSERT(m <= v.size());
|
|
std::shuffle(v.begin(), v.end(), engine);
|
|
return {v.begin(), v.begin() + m};
|
|
}
|
|
|
|
// Picks a random subset of size `m` from the set {0, ..., `n` - 1}.
|
|
template<typename T>
|
|
std::vector<T> random_subset(unsigned n, unsigned m, std::mt19937& engine) {
|
|
SCYLLA_ASSERT(m <= n);
|
|
|
|
std::vector<T> the_set(n);
|
|
std::iota(the_set.begin(), the_set.end(), T{});
|
|
return random_subset(std::move(the_set), m, engine);
|
|
}
|
|
|
|
inline
|
|
preemption_check random_preempt() {
|
|
return [] () noexcept {
|
|
return get_bool();
|
|
};
|
|
}
|
|
|
|
}
|