diff --git a/other/analysis/run-cppcheck b/other/analysis/run-cppcheck index ce60e567..deb6739b 100755 --- a/other/analysis/run-cppcheck +++ b/other/analysis/run-cppcheck @@ -31,8 +31,6 @@ CPPCHECK_CXX+=("--suppress=objectIndex") # False positive in auto_tests. CPPCHECK_CXX+=("--suppress=shadowArgument") CPPCHECK_CXX+=("--suppress=shadowFunction") -# Range-for is fine. -CPPCHECK_CXX+=("--suppress=useStlAlgorithm") run() { echo "Running cppcheck in variant '$*'" diff --git a/testing/BUILD.bazel b/testing/BUILD.bazel index de91456a..68e89a15 100644 --- a/testing/BUILD.bazel +++ b/testing/BUILD.bazel @@ -59,13 +59,3 @@ cc_binary( "//c-toxcore/toxcore:mono_time", ], ) - -cc_binary( - name = "random_testing", - testonly = 1, - srcs = ["random_testing.cc"], - deps = [ - ":misc_tools", - "//c-toxcore/toxcore:tox", - ], -) diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt index 9b118d16..b25614df 100644 --- a/testing/CMakeLists.txt +++ b/testing/CMakeLists.txt @@ -14,7 +14,4 @@ target_link_modules(misc_tools toxcore) if (BUILD_MISC_TESTS) add_executable(Messenger_test Messenger_test.c) target_link_modules(Messenger_test toxcore misc_tools) - - add_executable(random_testing random_testing.cc) - target_link_modules(random_testing toxcore misc_tools) endif() diff --git a/testing/random_testing.cc b/testing/random_testing.cc deleted file mode 100644 index 26794f17..00000000 --- a/testing/random_testing.cc +++ /dev/null @@ -1,431 +0,0 @@ -// Program to perform random actions in a network of toxes. -// -// Useful to find reproducing test cases for seemingly random bugs. - -#include -#include -#include -#include -#include -#include -#include - -#include "../toxcore/tox.h" -#include "misc_tools.h" - -namespace { - -// Whether to write log messages when handling callbacks. -constexpr bool LOG_CALLBACKS = false; - -// Number of participants in the test run. -constexpr uint32_t NUM_TOXES = 10; -// Maximum amount of time in iterations to wait for bootstrapping and friend -// connections to succeed. -constexpr uint32_t MAX_BOOTSTRAP_ITERATIONS = 1000; -// Number of conferences up to which users may create their own new conferences. -// They may still be invited and join. -constexpr uint32_t MAX_CONFERENCES_PER_USER = 3; -// Maximum number of actions per program execution. -constexpr uint32_t MAX_ACTIONS = 10000; -// Maximum number of attempts at executing a random action. -constexpr uint32_t MAX_ACTION_ATTEMPTS = 100; -// Number of tox_iterate calls between each action. -constexpr uint32_t ITERATIONS_PER_ACTION = 1; - -struct Tox_Options_Deleter { - void operator()(Tox_Options *options) const { tox_options_free(options); } -}; - -using Tox_Options_Ptr = std::unique_ptr; - -struct Tox_Deleter { - void operator()(Tox *tox) const { tox_kill(tox); } -}; - -using Tox_Ptr = std::unique_ptr; - -struct Local_State { - uint32_t friends_online = 0; - uint32_t next_invite = 0; - - explicit Local_State(Tox_Ptr tox, uint32_t id) - : tox_(std::move(tox)) - , id_(id) - { - } - - Tox *tox() const { return tox_.get(); } - uint32_t id() const { return id_; } - -private: - Tox_Ptr tox_; - uint32_t id_; -}; - -struct Action; - -struct Random { - std::uniform_int_distribution<> tox_selector; - std::uniform_int_distribution<> friend_selector; - std::uniform_int_distribution<> name_length_selector; - std::uniform_int_distribution<> message_length_selector; - std::uniform_int_distribution<> byte_selector; - - std::vector action_weights; - std::discrete_distribution action_selector; - - explicit Random(std::vector const &actions); -}; - -struct Action { - uint32_t weight; - char const *title; - bool (*can)(Local_State const &state); - void (*run)(Local_State *state, Random *rnd, std::mt19937 *rng); -}; - -std::vector get_action_weights(std::vector const &actions) -{ - std::vector weights; - for (Action const &action : actions) { - weights.push_back(action.weight); - } - return weights; -} - -Random::Random(std::vector const &actions) - : tox_selector(0, NUM_TOXES - 1) - , friend_selector(0, NUM_TOXES - 2) - , name_length_selector(0, TOX_MAX_NAME_LENGTH - 1) - , message_length_selector(0, TOX_MAX_MESSAGE_LENGTH - 1) - , byte_selector(0, 255) - , action_weights(get_action_weights(actions)) - , action_selector(action_weights.begin(), action_weights.end()) -{ -} - -struct Global_State : std::vector { - // Non-copyable; - Global_State(Global_State const &) = delete; - Global_State(Global_State &&) = default; - ~Global_State(); - explicit Global_State(std::vector const &actions) - : actions_(actions) - , rnd_(actions) - , action_counter_(actions.size()) - { - } - - Action const &action(size_t id) const { return actions_.at(id); } - Random *rnd() { return &rnd_; } - std::vector &action_counter() { return action_counter_; } - -private: - std::vector const &actions_; - Random rnd_; - std::vector action_counter_; -}; - -Global_State::~Global_State() { } - -void handle_friend_connection_status( - Tox *tox, uint32_t friend_number, Tox_Connection connection_status, void *user_data) -{ - Local_State *state = static_cast(user_data); - - if (connection_status == TOX_CONNECTION_NONE) { - std::printf("Tox #%u lost friend %u!\n", state->id(), friend_number); - state->friends_online--; - } else { - state->friends_online++; - } -} - -void handle_conference_invite(Tox *tox, uint32_t friend_number, Tox_Conference_Type type, - const uint8_t *cookie, size_t length, void *user_data) -{ - Local_State *state = static_cast(user_data); - - if (LOG_CALLBACKS) { - std::printf("Tox #%u joins the conference it was invited to\n", state->id()); - } - - Tox_Err_Conference_Join err; - tox_conference_join(tox, friend_number, cookie, length, &err); - assert(err == TOX_ERR_CONFERENCE_JOIN_OK); -} - -void handle_conference_message(Tox *tox, uint32_t conference_number, uint32_t peer_number, - Tox_Message_Type type, const uint8_t *message, size_t length, void *user_data) -{ - Local_State *state = static_cast(user_data); - - if (LOG_CALLBACKS) { - std::printf("Tox #%u received a message of length %u\n", state->id(), - static_cast(length)); - } -} - -void handle_conference_peer_list_changed(Tox *tox, uint32_t conference_number, void *user_data) -{ - Local_State *state = static_cast(user_data); - - if (LOG_CALLBACKS) { - std::printf( - "Tox #%u rebuilds peer list for conference %u\n", state->id(), conference_number); - } - - Tox_Err_Conference_Peer_Query err; - uint32_t const count = tox_conference_peer_count(tox, conference_number, &err); - assert(err == TOX_ERR_CONFERENCE_PEER_QUERY_OK); - - for (uint32_t peer_number = 0; peer_number < count; peer_number++) { - size_t size = tox_conference_peer_get_name_size(tox, conference_number, peer_number, &err); - assert(err == TOX_ERR_CONFERENCE_PEER_QUERY_OK); - - std::vector name(size); - tox_conference_peer_get_name(tox, conference_number, peer_number, &name[0], &err); - assert(err == TOX_ERR_CONFERENCE_PEER_QUERY_OK); - } -} - -Global_State make_toxes(std::vector const &actions) -{ - Global_State toxes(actions); - - Tox_Options_Ptr options(tox_options_new(nullptr)); - tox_options_set_local_discovery_enabled(options.get(), false); - - for (uint32_t i = 0; i < NUM_TOXES; i++) { - Tox_Err_New err; - toxes.emplace_back(Tox_Ptr(tox_new(options.get(), &err)), i); - assert(err == TOX_ERR_NEW_OK); - assert(toxes.back().tox() != nullptr); - - tox_callback_friend_connection_status(toxes.back().tox(), handle_friend_connection_status); - tox_callback_conference_invite(toxes.back().tox(), handle_conference_invite); - tox_callback_conference_message(toxes.back().tox(), handle_conference_message); - tox_callback_conference_peer_list_changed( - toxes.back().tox(), handle_conference_peer_list_changed); - } - - std::printf("Bootstrapping %u toxes\n", NUM_TOXES); - - uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; - tox_self_get_dht_id(toxes.front().tox(), dht_key); - const uint16_t dht_port = tox_self_get_udp_port(toxes.front().tox(), nullptr); - - for (Local_State const &state : toxes) { - Tox_Err_Bootstrap err; - tox_bootstrap(state.tox(), "localhost", dht_port, dht_key, &err); - assert(err == TOX_ERR_BOOTSTRAP_OK); - } - - std::printf("Creating full mesh of friendships\n"); - - for (Local_State const &state1 : toxes) { - for (Local_State const &state2 : toxes) { - if (state1.tox() != state2.tox()) { - Tox_Err_Friend_Add err; - uint8_t key[TOX_PUBLIC_KEY_SIZE]; - - tox_self_get_public_key(state1.tox(), key); - tox_friend_add_norequest(state2.tox(), key, &err); - assert(err == TOX_ERR_FRIEND_ADD_OK); - } - } - } - - return toxes; -} - -bool all_connected(Global_State const &toxes) -{ - return std::all_of(toxes.begin(), toxes.end(), - [](Local_State const &state) { return state.friends_online == NUM_TOXES - 1; }); -} - -bool bootstrap_toxes(Global_State *toxes) -{ - std::printf( - "Waiting for %u iterations for all friends to come online\n", MAX_BOOTSTRAP_ITERATIONS); - - for (uint32_t i = 0; i < MAX_BOOTSTRAP_ITERATIONS; i++) { - c_sleep(tox_iteration_interval(toxes->front().tox())); - - for (Local_State &state : *toxes) { - tox_iterate(state.tox(), &state); - } - - if (all_connected(*toxes)) { - std::printf("Took %u iterations\n", i); - return true; - } - } - - return false; -} - -bool execute_random_action(Global_State *toxes, std::mt19937 *rng) -{ - // First, choose a random actor. - Local_State &actor = toxes->at(toxes->rnd()->tox_selector(*rng)); - size_t const action_id = toxes->rnd()->action_selector(*rng); - Action const &action = toxes->action(action_id); - if (!action.can(actor)) { - return false; - } - - std::printf("Tox #%u %s", actor.id(), action.title); - action.run(&actor, toxes->rnd(), rng); - std::printf("\n"); - - toxes->action_counter().at(action_id)++; - - return true; -} - -bool attempt_action(Global_State *toxes, std::mt19937 *rng) -{ - for (uint32_t i = 0; i < MAX_ACTION_ATTEMPTS; i++) { - if (execute_random_action(toxes, rng)) { - return true; - } - } - - return false; -} - -} // namespace - -int main() -{ - std::vector const actions = { - { - 10, - "creates a new conference", - [](Local_State const &state) { - return tox_conference_get_chatlist_size(state.tox()) < MAX_CONFERENCES_PER_USER; - }, - [](Local_State *state, Random *rnd, std::mt19937 *rng) { - Tox_Err_Conference_New err; - tox_conference_new(state->tox(), &err); - assert(err == TOX_ERR_CONFERENCE_NEW_OK); - }, - }, - { - 10, - "invites a random friend to a conference", - [](Local_State const &state) { - return tox_conference_get_chatlist_size(state.tox()) != 0; - }, - [](Local_State *state, Random *rnd, std::mt19937 *rng) { - size_t chat_count = tox_conference_get_chatlist_size(state->tox()); - assert(chat_count != 0); // Condition above. - Tox_Err_Conference_Invite err; - tox_conference_invite(state->tox(), rnd->friend_selector(*rng), - state->next_invite % chat_count, &err); - state->next_invite++; - assert(err == TOX_ERR_CONFERENCE_INVITE_OK); - }, - }, - { - 10, - "deletes the last conference", - [](Local_State const &state) { - return tox_conference_get_chatlist_size(state.tox()) != 0; - }, - [](Local_State *state, Random *rnd, std::mt19937 *rng) { - Tox_Err_Conference_Delete err; - tox_conference_delete( - state->tox(), tox_conference_get_chatlist_size(state->tox()) - 1, &err); - assert(err == TOX_ERR_CONFERENCE_DELETE_OK); - }, - }, - { - 10, - "sends a message to the last conference", - [](Local_State const &state) { - return tox_conference_get_chatlist_size(state.tox()) != 0; - }, - [](Local_State *state, Random *rnd, std::mt19937 *rng) { - std::vector message(rnd->message_length_selector(*rng)); - for (uint8_t &byte : message) { - byte = rnd->byte_selector(*rng); - } - - Tox_Err_Conference_Send_Message err; - tox_conference_send_message(state->tox(), - tox_conference_get_chatlist_size(state->tox()) - 1, TOX_MESSAGE_TYPE_NORMAL, - message.data(), message.size(), &err); - if (err == TOX_ERR_CONFERENCE_SEND_MESSAGE_OK) { - printf(" (OK, length = %u)", static_cast(message.size())); - } else { - printf(" (FAILED: %u)", err); - } - }, - }, - { - 10, - "changes their name", - [](Local_State const &state) { return true; }, - [](Local_State *state, Random *rnd, std::mt19937 *rng) { - std::vector name(rnd->name_length_selector(*rng)); - for (uint8_t &byte : name) { - byte = rnd->byte_selector(*rng); - } - - Tox_Err_Set_Info err; - tox_self_set_name(state->tox(), name.data(), name.size(), &err); - assert(err == TOX_ERR_SET_INFO_OK); - - printf(" (length = %u)", static_cast(name.size())); - }, - }, - { - 10, - "sets their name to empty", - [](Local_State const &state) { return true; }, - [](Local_State *state, Random *rnd, std::mt19937 *rng) { - Tox_Err_Set_Info err; - tox_self_set_name(state->tox(), nullptr, 0, &err); - assert(err == TOX_ERR_SET_INFO_OK); - }, - }, - }; - - Global_State toxes = make_toxes(actions); - - std::mt19937 rng; - uint32_t action_number; - for (action_number = 0; action_number < MAX_ACTIONS; action_number++) { - if (!all_connected(toxes) && !bootstrap_toxes(&toxes)) { - std::printf("Bootstrapping took too long; %u actions performed\n", action_number); - return EXIT_FAILURE; - } - - if (!attempt_action(&toxes, &rng)) { - std::printf("System is stuck after %u actions: none of the toxes can perform an action " - "anymore\n", - action_number); - return EXIT_FAILURE; - } - - for (uint32_t i = 0; i < ITERATIONS_PER_ACTION; i++) { - c_sleep(ITERATION_INTERVAL); - - for (Local_State &state : toxes) { - tox_iterate(state.tox(), &state); - } - } - } - - std::printf("Test execution success: %u actions performed\n", action_number); - std::printf("Per-action statistics:\n"); - for (uint32_t i = 0; i < toxes.action_counter().size(); i++) { - std::printf("%u x '%s'\n", toxes.action_counter().at(i), actions[i].title); - } - - return 0; -}