forked from byterazor/EventManager
ADD: first version
This commit is contained in:
parent
7759fae428
commit
2c1b0f4c28
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
build
|
||||
compile_commands.json
|
82
CMakeLists.txt
Normal file
82
CMakeLists.txt
Normal file
@ -0,0 +1,82 @@
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
# This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
#
|
||||
|
||||
cmake_minimum_required (VERSION 3.1 FATAL_ERROR)
|
||||
project (EventManager VERSION 0.0.1 LANGUAGES CXX)
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules )
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
|
||||
include(compdb)
|
||||
|
||||
find_package (Threads REQUIRED)
|
||||
|
||||
option(EM_TESTS "ENABLE/DISABLE all tests for EventManager" ON)
|
||||
IF(${EM_TESTS})
|
||||
message(STATUS "EventManager tests enabled")
|
||||
add_subdirectory(libs/Catch2)
|
||||
include(CTest)
|
||||
include(libs/Catch2/contrib/Catch.cmake)
|
||||
ELSE()
|
||||
message(STATUS "EventManager tests disabled")
|
||||
ENDIF()
|
||||
|
||||
|
||||
#
|
||||
# all source files for the server library
|
||||
#
|
||||
SET(EVENTMANAGER_SOURCES
|
||||
include/EventManager/Event.hpp
|
||||
src/EventManager/Event.cpp
|
||||
include/EventManager/Participant.hpp
|
||||
src/EventManager/Participant.cpp
|
||||
include/EventManager/Manager.hpp
|
||||
src/EventManager/Manager.cpp
|
||||
)
|
||||
|
||||
add_library(objlib OBJECT ${EVENTMANAGER_SOURCES})
|
||||
set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1)
|
||||
target_include_directories(objlib
|
||||
PUBLIC
|
||||
include
|
||||
PRIVATE
|
||||
src
|
||||
)
|
||||
target_link_libraries(objlib PUBLIC Threads::Threads)
|
||||
|
||||
add_library(eventmanager SHARED $<TARGET_OBJECTS:objlib>)
|
||||
target_include_directories(eventmanager
|
||||
PUBLIC
|
||||
include
|
||||
PRIVATE
|
||||
src
|
||||
)
|
||||
target_link_libraries(eventmanager PUBLIC Threads::Threads)
|
||||
|
||||
add_library(eventmanager-static STATIC $<TARGET_OBJECTS:objlib>)
|
||||
target_include_directories(eventmanager-static
|
||||
PUBLIC
|
||||
include
|
||||
PRIVATE
|
||||
src
|
||||
)
|
||||
target_link_libraries(eventmanager-static PUBLIC Threads::Threads)
|
||||
|
||||
#
|
||||
# add tests as executable
|
||||
#
|
||||
add_executable(test_event tests/test_event.cpp)
|
||||
target_link_libraries(test_event Catch2::Catch2 eventmanager-static)
|
||||
catch_discover_tests(test_event)
|
||||
|
||||
add_executable(test_basic tests/test_basic.cpp)
|
||||
target_link_libraries(test_basic Catch2::Catch2 eventmanager-static)
|
||||
catch_discover_tests(test_basic)
|
31
cmake/Modules/compdb.cmake
Normal file
31
cmake/Modules/compdb.cmake
Normal file
@ -0,0 +1,31 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
# This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
|
||||
|
||||
find_program(COMPDB_PATH
|
||||
NAME compdb
|
||||
PATHS ~/.local/bin/
|
||||
/bin
|
||||
/sbin
|
||||
/usr/bin
|
||||
/usr/sbin
|
||||
/usr/local/bin
|
||||
/usr/local/sbin
|
||||
)
|
||||
|
||||
|
||||
|
||||
if (COMPDB_PATH)
|
||||
IF(NOT TARGET COMPD)
|
||||
add_custom_target(COMPD
|
||||
ALL
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMAND ${COMPDB_PATH} -p ${CMAKE_CURRENT_BINARY_DIR} list >compile_commands.json
|
||||
)
|
||||
endif()
|
||||
endif()
|
132
cmake/Modules/doxygen.cmake
Normal file
132
cmake/Modules/doxygen.cmake
Normal file
@ -0,0 +1,132 @@
|
||||
#
|
||||
# Copyright (C) 2018 by George Cave - gcave@stablecoder.ca
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
|
||||
find_package(Doxygen)
|
||||
|
||||
option(BUILD_DOCUMENTATION "Build API documentation using Doxygen. (make doc)"
|
||||
${DOXYGEN_FOUND})
|
||||
|
||||
# Builds doxygen documentation with a default 'Doxyfile.in' or with a specified
|
||||
# one, and can make the results installable (under the `doc` install target)
|
||||
#
|
||||
# This can only be used once per project, as each target generated is as
|
||||
# `doc-${PROJECT_NAME}` unless TARGET_NAME is specified.
|
||||
# ~~~
|
||||
# Optional Arguments:
|
||||
#
|
||||
# ADD_TO_DOC
|
||||
# If specified, adds this generated target to be a dependency of the more general
|
||||
# `doc` target.
|
||||
#
|
||||
# INSTALLABLE
|
||||
# Adds the generated documentation to the generic `install` target, under the
|
||||
# `documentation` installation group.
|
||||
#
|
||||
# PROCESS_DOXYFILE
|
||||
# If set, then will process the found Doxyfile through the CMAKE `configure_file`
|
||||
# function for macro replacements before using it. (@ONLY)
|
||||
#
|
||||
# TARGET_NAME <str>
|
||||
# The name to give the doc target. (Default: doc-${PROJECT_NAME})
|
||||
#
|
||||
# OUTPUT_DIR <str>
|
||||
# The directory to place the generated output. (Default: ${CMAKE_CURRENT_BINARY_DIR}/doc)
|
||||
#
|
||||
# INSTALL_PATH <str>
|
||||
# The path to install the documenttation under. (if not specified, defaults to
|
||||
# 'share/${PROJECT_NAME})
|
||||
#
|
||||
# DOXYFILE_PATH <str>
|
||||
# The given doxygen file to use/process. (Defaults to'${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile')
|
||||
# ~~~
|
||||
function(build_docs)
|
||||
set(OPTIONS ADD_TO_DOC INSTALLABLE PROCESS_DOXYFILE)
|
||||
set(SINGLE_VALUE_KEYWORDS
|
||||
TARGET_NAME
|
||||
INSTALL_PATH
|
||||
DOXYFILE_PATH
|
||||
OUTPUT_DIR)
|
||||
set(MULTI_VALUE_KEYWORDS)
|
||||
cmake_parse_arguments(build_docs
|
||||
"${OPTIONS}"
|
||||
"${SINGLE_VALUE_KEYWORDS}"
|
||||
"${MULTI_VALUE_KEYWORDS}"
|
||||
${ARGN})
|
||||
|
||||
if(BUILD_DOCUMENTATION)
|
||||
if(NOT DOXYGEN_FOUND)
|
||||
message(FATAL_ERROR "Doxygen is needed to build the documentation.")
|
||||
endif()
|
||||
|
||||
if(NOT build_docs_DOXYFILE_PATH)
|
||||
set(DOXYFILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile)
|
||||
elseif(EXISTS ${build_docs_DOXYFILE_PATH})
|
||||
set(DOXYFILE_PATH ${build_docs_DOXYFILE_PATH})
|
||||
else()
|
||||
set(DOXYFILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${build_docs_DOXYFILE_PATH})
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${DOXYFILE_PATH})
|
||||
message(
|
||||
SEND_ERROR
|
||||
"Could not find Doxyfile to use for procesing documentation at: ${DOXYFILE_PATH}"
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(build_docs_PROCESS_DOXYFILE)
|
||||
set(DOXYFILE ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||
configure_file(${DOXYFILE_PATH} ${DOXYFILE} @ONLY)
|
||||
else()
|
||||
set(DOXYFILE ${DOXYFILE_PATH})
|
||||
endif()
|
||||
|
||||
if(build_docs_OUTPUT_DIR)
|
||||
set(OUT_DIR ${build_docs_OUTPUT_DIR})
|
||||
else()
|
||||
set(OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doc)
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY ${OUT_DIR})
|
||||
|
||||
if(build_docs_TARGET_NAME)
|
||||
set(TARGET_NAME ${build_docs_TARGET_NAME})
|
||||
else()
|
||||
set(TARGET_NAME doc-${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
add_custom_target(${TARGET_NAME}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE}
|
||||
WORKING_DIRECTORY ${OUT_DIR}
|
||||
VERBATIM)
|
||||
|
||||
if(build_docs_ADD_TO_DOC)
|
||||
if(NOT TARGET doc)
|
||||
add_custom_target(doc)
|
||||
endif()
|
||||
|
||||
add_dependencies(doc ${TARGET_NAME})
|
||||
endif()
|
||||
|
||||
if(build_docs_INSTALLABLE)
|
||||
if(NOT build_docs_INSTALL_PATH)
|
||||
set(build_docs_INSTALL_PATH share/${PROJECT_NAME})
|
||||
endif()
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/
|
||||
COMPONENT documentation
|
||||
DESTINATION ${build_docs_INSTALL_PATH})
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
99
include/EventManager/Event.hpp
Normal file
99
include/EventManager/Event.hpp
Normal file
@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
* This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
*/
|
||||
|
||||
/** @file */
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
namespace EventManager
|
||||
{
|
||||
|
||||
// forward declaration of a participant
|
||||
class Participant;
|
||||
|
||||
/// Eventtype to notify all participants that a shutdown is immanent
|
||||
const static std::uint32_t EVENT_TYPE_SHUTDOWN = 0;
|
||||
|
||||
class Event
|
||||
{
|
||||
private:
|
||||
/// the type of the event
|
||||
std::uint32_t type_;
|
||||
|
||||
/// the id which uniquly identifies the event
|
||||
std::uint64_t id_;
|
||||
|
||||
/// a possible response id, identifying if this event is in repsonse to another event
|
||||
std::uint64_t responseId_;
|
||||
|
||||
/// identifies if this event is a response to another event
|
||||
std::atomic<bool> isResponse_;
|
||||
|
||||
/// emitter of the event
|
||||
std::shared_ptr<EventManager::Participant> emitter_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief constructor for creating a simple event
|
||||
*
|
||||
* @param type - what kinf of event is this
|
||||
*/
|
||||
Event(std::uint32_t type);
|
||||
|
||||
/**
|
||||
* @brief Constructor to create a response Event
|
||||
*/
|
||||
Event(std::uint32_t type, const EventManager::Event &event);
|
||||
|
||||
/**
|
||||
* @brief Constructor to create a response Event
|
||||
*/
|
||||
Event(std::uint32_t type, const std::shared_ptr<EventManager::Event> event);
|
||||
|
||||
/**
|
||||
* @brief return the id of the event
|
||||
*/
|
||||
std::uint64_t id() const { return id_;}
|
||||
|
||||
/**
|
||||
* @brief return the response id if this event is a response
|
||||
*/
|
||||
std::uint64_t responseId() const {
|
||||
if (!isResponse_)
|
||||
{
|
||||
throw std::runtime_error("is not a response event");
|
||||
}
|
||||
return responseId_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if the event is a response
|
||||
*/
|
||||
bool isResponse() const { return isResponse_;}
|
||||
|
||||
/**
|
||||
* @brief return the type of the event
|
||||
*/
|
||||
std::uint32_t type() const { return type_;}
|
||||
|
||||
/**
|
||||
* @brief set the emitter of the event
|
||||
*/
|
||||
void emitter(std::shared_ptr<EventManager::Participant> participant) { emitter_=participant;}
|
||||
|
||||
/**
|
||||
* @brief return the emitter of the event
|
||||
*/
|
||||
std::shared_ptr<EventManager::Participant> emitter() const {return emitter_;}
|
||||
|
||||
}; //
|
||||
}; // namespace EventManager
|
190
include/EventManager/Manager.hpp
Normal file
190
include/EventManager/Manager.hpp
Normal file
@ -0,0 +1,190 @@
|
||||
#pragma once
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
* This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
*/
|
||||
|
||||
/** @file */
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <EventManager/Event.hpp>
|
||||
|
||||
namespace EventManager
|
||||
{
|
||||
|
||||
// forward declaration of EventManager::Participant
|
||||
class Participant;
|
||||
|
||||
class Manager
|
||||
{
|
||||
/// the thread the event manager is transmitting events in
|
||||
std::unique_ptr<std::thread> mainThread_;
|
||||
|
||||
/// is the main thread running
|
||||
std::atomic<bool> isMainThreadRunning_;
|
||||
|
||||
/// stop the main thread
|
||||
std::atomic<bool> stopMainThread_;
|
||||
|
||||
/// the thread the event manager is scheduling plugins in
|
||||
std::unique_ptr<std::thread> schedulingThread_;
|
||||
|
||||
/// is the scheduling thread running
|
||||
std::atomic<bool> isSchedulingThreadRunning_;
|
||||
|
||||
/// stop the scheduling thread
|
||||
std::atomic<bool> stopSchedulingThread_;
|
||||
|
||||
/// map holding all the event type and plugin combinations
|
||||
std::map<std::uint32_t, std::list<std::shared_ptr<EventManager::Participant>>> eventMap_;
|
||||
|
||||
/// queue for incomng events
|
||||
std::queue<std::shared_ptr<EventManager::Event>> eventQueue_;
|
||||
|
||||
/// mutex to protect the event queue
|
||||
std::mutex mutexEventQueue_;
|
||||
|
||||
/// condition variable to wake of thread on new emit
|
||||
std::condition_variable newEventInQueue_;
|
||||
|
||||
/// list of all plugins requiring scheduling
|
||||
std::list<std::shared_ptr<EventManager::Participant>> schedulingParticipants_;
|
||||
|
||||
/// mutex to protect schedulingPlugins_
|
||||
std::mutex mutexSchedulingParticipants_;
|
||||
|
||||
/*
|
||||
* all private methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief the method running in the main thread
|
||||
*/
|
||||
void mainProcess_();
|
||||
|
||||
/**
|
||||
* @brief the method running in the scheduling thread
|
||||
*/
|
||||
void schedulingProcess_();
|
||||
|
||||
/**
|
||||
* @brief process one event (call all the participants)
|
||||
*/
|
||||
void processEvent(const std::shared_ptr<EventManager::Event> event);
|
||||
|
||||
/**
|
||||
* @brief start the main thread
|
||||
*/
|
||||
void startMain_();
|
||||
|
||||
/**
|
||||
* @brief stop the main thread
|
||||
*/
|
||||
void stopMain_();
|
||||
|
||||
/**
|
||||
* @brief start the scheduling thread
|
||||
*/
|
||||
void startScheduling_();
|
||||
|
||||
/**
|
||||
* @brief stop the scheduling thread
|
||||
*/
|
||||
void stopScheduling_();
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor for the event manager
|
||||
*
|
||||
* Just initializes all attributes to its starting value
|
||||
*/
|
||||
Manager() : mainThread_(nullptr), isMainThreadRunning_(false),
|
||||
stopMainThread_(false), schedulingThread_(nullptr),
|
||||
isSchedulingThreadRunning_(false), stopSchedulingThread_(false){}
|
||||
|
||||
|
||||
~Manager();
|
||||
/**
|
||||
* @brief start the event manager
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* @brief stop the event manager
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* @brief check if the eventmanager is running
|
||||
*/
|
||||
bool isRunning();
|
||||
|
||||
/**
|
||||
* @brief emit an event and make sure it is delivered to all subscribed plugins
|
||||
*
|
||||
* @param event - the event to emit
|
||||
*/
|
||||
void emit(std::shared_ptr<EventManager::Event> event);
|
||||
|
||||
/**
|
||||
* @brief subscribe a plugin for the given event type
|
||||
*
|
||||
* @param type - the event type to subscribe to
|
||||
* @param plugin - shared pointer to the plugin which subscribes
|
||||
*/
|
||||
void subscribe(std::uint32_t type, std::shared_ptr<EventManager::Participant> plugin);
|
||||
|
||||
/**
|
||||
* @brief unsubscribe a plugin from the given event type
|
||||
*
|
||||
* @param type - the event type to unsubscribe from
|
||||
* @param plugin - shared pointer to the plugin which unsubscribes
|
||||
*/
|
||||
void unsubscribe(std::uint32_t type, std::shared_ptr<EventManager::Participant> plugin);
|
||||
|
||||
/**
|
||||
* @brief unsubscribe a plugin from the all event types
|
||||
*
|
||||
* @param plugin - shared pointer to the plugin which unsubscribes
|
||||
*/
|
||||
void unsubscribe(std::shared_ptr<EventManager::Participant> plugin);
|
||||
|
||||
/**
|
||||
* @brief check if there are any subscriptions within the event manager
|
||||
*/
|
||||
bool empty() const;
|
||||
|
||||
/**
|
||||
* @brief Wait for the EventManager to become empty.
|
||||
*
|
||||
* @param timeout - how many milliseconds to wait for EventManager becoming empty
|
||||
*
|
||||
* @return true - EventManager is empty
|
||||
* @return false - EventManager is not empty
|
||||
*/
|
||||
bool waitEmpty(std::uint32_t timeoutMS) const;
|
||||
|
||||
/**
|
||||
* @brief schedule the given plugin regularly
|
||||
*
|
||||
* @param plugin - the plugin to schedule
|
||||
*/
|
||||
void schedule(std::shared_ptr<EventManager::Participant> plugin);
|
||||
|
||||
}; // class Manager
|
||||
|
||||
}; //namespace EventManager
|
152
include/EventManager/Participant.hpp
Normal file
152
include/EventManager/Participant.hpp
Normal file
@ -0,0 +1,152 @@
|
||||
#pragma once
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
* This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
*/
|
||||
|
||||
/** @file */
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <EventManager/Event.hpp>
|
||||
|
||||
namespace EventManager
|
||||
{
|
||||
|
||||
// forward declaration for the EventManager::Manager
|
||||
class Manager;
|
||||
|
||||
/**
|
||||
* @brief The entity participating in the event system.
|
||||
*/
|
||||
class Participant : public std::enable_shared_from_this<Participant>
|
||||
{
|
||||
private:
|
||||
|
||||
/// pointer to the event manager
|
||||
std::shared_ptr<EventManager::Manager> manager_;
|
||||
|
||||
/// is the participant scheduled by the EventManager::Manager
|
||||
std::atomic<bool> isScheduledByManager_;
|
||||
|
||||
/// queue for incomng events
|
||||
std::queue<std::shared_ptr<EventManager::Event>> eventQueue_;
|
||||
|
||||
/// mutex to protect the event queue
|
||||
std::mutex mutexEventQueue_;
|
||||
|
||||
/// condition variable to wake of thread on new trigger
|
||||
std::condition_variable newEventInQueue_;
|
||||
|
||||
/// has the participant locked the queue itself already
|
||||
std::atomic<bool> isQueueLocked_;
|
||||
|
||||
/*
|
||||
* all private methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Method called if the participant is scheduled by EventManager::Manager
|
||||
*
|
||||
* This method needs to be implemented by the child class.
|
||||
* Please make sure this method returns as fast as possible!
|
||||
* No endless loops are supported.
|
||||
* Just process some incoming events and then return!
|
||||
*/
|
||||
virtual void schedule_() { throw std::runtime_error(std::string(__PRETTY_FUNCTION__) + " not implemented");}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief check if events are available
|
||||
*/
|
||||
bool _hasEvents();
|
||||
|
||||
/**
|
||||
* @brief Lock the queue to process all events
|
||||
*/
|
||||
void _lockQueue();
|
||||
|
||||
/**
|
||||
* @brief UnLock the queue to process all events
|
||||
*/
|
||||
void _unlockQueue();
|
||||
|
||||
/**
|
||||
* @brief fetch one event from the queue
|
||||
*/
|
||||
std::shared_ptr<EventManager::Event> _fetchEvent();
|
||||
|
||||
/**
|
||||
* @brief wait for a new event
|
||||
*/
|
||||
void _waitForEvent();
|
||||
|
||||
|
||||
/**
|
||||
* @brief This method subscribes the participant to an event type
|
||||
*
|
||||
* @param type - the event type to subscribe this participant to
|
||||
*/
|
||||
void _subscribe(std::uint32_t type);
|
||||
|
||||
/**
|
||||
* @brief unsubscribe the participant from the given event type
|
||||
*/
|
||||
void _unsubscribe(std::uint32_t type);
|
||||
|
||||
/**
|
||||
* @brief unsubscribe the participant from the all event types
|
||||
*/
|
||||
void _unsubscribe();
|
||||
|
||||
/**
|
||||
* @brief Method to emit an event to the event manager
|
||||
*
|
||||
* @param event - the event to emit
|
||||
*/
|
||||
void _emit(std::shared_ptr<EventManager::Event> event);
|
||||
|
||||
/**
|
||||
* @brief enable scheduling of this particpant through the EventManager::Manager
|
||||
*/
|
||||
void _enableScheduling();
|
||||
|
||||
/**
|
||||
* @brief check if the participant is scheduled by event manager
|
||||
*/
|
||||
bool isScheduledByManager() const {return isScheduledByManager_;}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor setting the participant up for use
|
||||
*/
|
||||
Participant();
|
||||
|
||||
void setManager(std::shared_ptr<EventManager::Manager> manager) { manager_=manager;_subscribe(EVENT_TYPE_SHUTDOWN);}
|
||||
|
||||
/**
|
||||
* @brief Method called by the EventManager::Manager to schedule the particpant
|
||||
*
|
||||
*/
|
||||
void schedule() {schedule_();};
|
||||
|
||||
|
||||
/**
|
||||
* @brief emit an event to this participant
|
||||
*/
|
||||
void emit(std::shared_ptr<EventManager::Event> event);
|
||||
|
||||
};//
|
||||
|
||||
}; // namespace EventManager
|
34
src/EventManager/Event.cpp
Normal file
34
src/EventManager/Event.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
* This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
*/
|
||||
|
||||
/** @file */
|
||||
#include <EventManager/Event.hpp>
|
||||
#include <random>
|
||||
|
||||
EventManager::Event::Event(std::uint32_t type) : type_(type), responseId_(0), isResponse_(false), emitter_(nullptr)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 rng(rd());
|
||||
|
||||
std::uniform_int_distribution<std::mt19937::result_type> dist(1,std::numeric_limits<int>::max());
|
||||
|
||||
id_ = dist(rng);
|
||||
}
|
||||
|
||||
EventManager::Event::Event(std::uint32_t type, const EventManager::Event &event) : Event(type)
|
||||
{
|
||||
responseId_=event.id();
|
||||
isResponse_=true;
|
||||
}
|
||||
|
||||
EventManager::Event::Event(std::uint32_t type, const std::shared_ptr<EventManager::Event> event) : Event(type)
|
||||
{
|
||||
responseId_=event->id();
|
||||
isResponse_=true;
|
||||
}
|
326
src/EventManager/Manager.cpp
Normal file
326
src/EventManager/Manager.cpp
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
* This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
*/
|
||||
|
||||
/** @file */
|
||||
#include <EventManager/Manager.hpp>
|
||||
#include <EventManager/Participant.hpp>
|
||||
#include <iostream>
|
||||
|
||||
void EventManager::Manager::startMain_()
|
||||
{
|
||||
|
||||
if (isMainThreadRunning_)
|
||||
{
|
||||
throw std::runtime_error("Main thread already running");
|
||||
}
|
||||
|
||||
stopMainThread_=false;
|
||||
|
||||
mainThread_ = std::make_unique<std::thread>(&EventManager::Manager::mainProcess_,this);
|
||||
|
||||
std::int32_t timeout = 6000;
|
||||
|
||||
while(!isMainThreadRunning_ && timeout > 0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
timeout-=100;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
{
|
||||
stopMainThread_=true;
|
||||
throw std::runtime_error("EventManager: can not start main thread");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EventManager::Manager::startScheduling_()
|
||||
{
|
||||
|
||||
if (isSchedulingThreadRunning_)
|
||||
{
|
||||
throw std::runtime_error("Scheduling thread already running");
|
||||
}
|
||||
|
||||
stopSchedulingThread_=false;
|
||||
|
||||
schedulingThread_ = std::make_unique<std::thread>(&EventManager::Manager::schedulingProcess_,this);
|
||||
|
||||
std::int32_t timeout = 6000;
|
||||
|
||||
while(!isSchedulingThreadRunning_ && timeout > 0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
timeout-=100;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
{
|
||||
stopSchedulingThread_=true;
|
||||
throw std::runtime_error("EventManager: can not start scheduling thread");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void EventManager::Manager::stopMain_()
|
||||
{
|
||||
std::int32_t timeout = 6000;
|
||||
stopMainThread_=true;
|
||||
newEventInQueue_.notify_one();
|
||||
|
||||
while(isMainThreadRunning_ && timeout > 0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
timeout-=100;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
{
|
||||
throw std::runtime_error("can not stop main thread");
|
||||
}
|
||||
|
||||
mainThread_->join();
|
||||
}
|
||||
|
||||
void EventManager::Manager::stopScheduling_()
|
||||
{
|
||||
std::int32_t timeout = 6000;
|
||||
stopSchedulingThread_=true;
|
||||
|
||||
while(isSchedulingThreadRunning_ && timeout > 0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
timeout-=100;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
{
|
||||
throw std::runtime_error("can not stop scheduling thread");
|
||||
}
|
||||
|
||||
schedulingThread_->join();
|
||||
}
|
||||
|
||||
void EventManager::Manager::start()
|
||||
{
|
||||
startMain_();
|
||||
try {
|
||||
startScheduling_();
|
||||
} catch (std::exception &e)
|
||||
{
|
||||
stopMain_();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
void EventManager::Manager::stop()
|
||||
{
|
||||
stopMain_();
|
||||
stopScheduling_();
|
||||
}
|
||||
|
||||
EventManager::Manager::~Manager()
|
||||
{
|
||||
if (isMainThreadRunning_)
|
||||
{
|
||||
stopMain_();
|
||||
}
|
||||
|
||||
if (isSchedulingThreadRunning_)
|
||||
{
|
||||
stopScheduling_();
|
||||
}
|
||||
}
|
||||
|
||||
void EventManager::Manager::processEvent(const std::shared_ptr<EventManager::Event> event)
|
||||
{
|
||||
|
||||
auto it = eventMap_.find(event->type());
|
||||
|
||||
if (it != eventMap_.end())
|
||||
{
|
||||
|
||||
for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
|
||||
{
|
||||
if (event->emitter() != *it2)
|
||||
{
|
||||
(*it2)->emit(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void EventManager::Manager::mainProcess_()
|
||||
{
|
||||
isMainThreadRunning_=true;
|
||||
|
||||
while(!stopMainThread_)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutexEventQueue_);
|
||||
newEventInQueue_.wait(lock);
|
||||
while(!eventQueue_.empty())
|
||||
{
|
||||
std::shared_ptr<EventManager::Event> event = eventQueue_.front();
|
||||
eventQueue_.pop();
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
}
|
||||
|
||||
isMainThreadRunning_=false;
|
||||
|
||||
}
|
||||
|
||||
void EventManager::Manager::schedulingProcess_()
|
||||
{
|
||||
isSchedulingThreadRunning_=true;
|
||||
|
||||
while(!stopSchedulingThread_)
|
||||
{
|
||||
mutexSchedulingParticipants_.lock();
|
||||
if (!schedulingParticipants_.empty())
|
||||
{
|
||||
for (auto it = schedulingParticipants_.begin(); it != schedulingParticipants_.end(); ++it)
|
||||
{
|
||||
(*it)->schedule();
|
||||
}
|
||||
}
|
||||
mutexSchedulingParticipants_.unlock();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
isSchedulingThreadRunning_=false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void EventManager::Manager::subscribe(std::uint32_t type, std::shared_ptr<EventManager::Participant> participant)
|
||||
{
|
||||
|
||||
// check if participant is already registered
|
||||
auto it = eventMap_.find(type);
|
||||
|
||||
if (it != eventMap_.end())
|
||||
{
|
||||
|
||||
auto it2 = std::find(it->second.begin(), it->second.end(),participant);
|
||||
|
||||
if (it2 == it->second.end())
|
||||
{
|
||||
it->second.push_back(participant);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
eventMap_[type].push_back(participant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EventManager::Manager::unsubscribe(std::uint32_t type, std::shared_ptr<EventManager::Participant> participant)
|
||||
{
|
||||
|
||||
auto it = eventMap_.find(type);
|
||||
|
||||
if (it == eventMap_.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto it2 = std::find(it->second.begin(), it->second.end(),participant);
|
||||
|
||||
if (it2 != it->second.end())
|
||||
{
|
||||
it->second.erase(it2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EventManager::Manager::unsubscribe(std::shared_ptr<EventManager::Participant> participant)
|
||||
{
|
||||
|
||||
for (auto it = eventMap_.begin(); it != eventMap_.end(); ++it)
|
||||
{
|
||||
unsubscribe(it->first,participant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void EventManager::Manager::emit(const std::shared_ptr<EventManager::Event> event)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutexEventQueue_);
|
||||
eventQueue_.push(event);
|
||||
}
|
||||
newEventInQueue_.notify_one();
|
||||
|
||||
}
|
||||
|
||||
bool EventManager::Manager::isRunning()
|
||||
{
|
||||
|
||||
if (isMainThreadRunning_ && isSchedulingThreadRunning_)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventManager::Manager::empty() const
|
||||
{
|
||||
bool isEmpty=true;
|
||||
|
||||
for (auto it = eventMap_.begin(); it != eventMap_.end(); ++it)
|
||||
{
|
||||
if ( !(*it).second.empty())
|
||||
{
|
||||
isEmpty=false;
|
||||
}
|
||||
}
|
||||
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
bool EventManager::Manager::waitEmpty(std::uint32_t timeoutMS) const
|
||||
{
|
||||
std::uint32_t timeout=timeoutMS;
|
||||
|
||||
while(!empty() && timeout > 0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
timeout-=100;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void EventManager::Manager::schedule(std::shared_ptr<EventManager::Participant> participant)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutexSchedulingParticipants_);
|
||||
|
||||
auto it = std::find(schedulingParticipants_.begin(), schedulingParticipants_.end(), participant);
|
||||
|
||||
if (it == schedulingParticipants_.end())
|
||||
{
|
||||
schedulingParticipants_.push_back(participant);
|
||||
}
|
||||
}
|
120
src/EventManager/Participant.cpp
Normal file
120
src/EventManager/Participant.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
* This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
*/
|
||||
|
||||
/** @file */
|
||||
#include <EventManager/Participant.hpp>
|
||||
#include <EventManager/Manager.hpp>
|
||||
#include <iostream>
|
||||
|
||||
EventManager::Participant::Participant() : manager_(nullptr),
|
||||
isScheduledByManager_(false), isQueueLocked_(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void EventManager::Participant::emit(std::shared_ptr<EventManager::Event> event)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutexEventQueue_);
|
||||
eventQueue_.push(event);
|
||||
}
|
||||
newEventInQueue_.notify_one();
|
||||
}
|
||||
|
||||
bool EventManager::Participant::_hasEvents()
|
||||
{
|
||||
if (isQueueLocked_)
|
||||
{
|
||||
return !eventQueue_.empty();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> guard(mutexEventQueue_);
|
||||
|
||||
|
||||
return !eventQueue_.empty();
|
||||
}
|
||||
|
||||
void EventManager::Participant::_lockQueue()
|
||||
{
|
||||
mutexEventQueue_.lock();
|
||||
isQueueLocked_=true;
|
||||
}
|
||||
|
||||
void EventManager::Participant::_unlockQueue()
|
||||
{
|
||||
mutexEventQueue_.unlock();
|
||||
isQueueLocked_=false;
|
||||
}
|
||||
|
||||
std::shared_ptr<EventManager::Event> EventManager::Participant::_fetchEvent()
|
||||
{
|
||||
if (!isQueueLocked_)
|
||||
{
|
||||
throw std::runtime_error("queue not locked");
|
||||
}
|
||||
|
||||
std::shared_ptr<EventManager::Event> event = eventQueue_.front();
|
||||
eventQueue_.pop();
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void EventManager::Participant::_waitForEvent()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutexEventQueue_);
|
||||
newEventInQueue_.wait(lock);
|
||||
isQueueLocked_=true;
|
||||
}
|
||||
|
||||
void EventManager::Participant::_enableScheduling()
|
||||
{
|
||||
if (manager_ == nullptr)
|
||||
{
|
||||
throw std::runtime_error("no event manager set yet");
|
||||
}
|
||||
manager_->schedule(shared_from_this());
|
||||
isScheduledByManager_=true;
|
||||
}
|
||||
|
||||
void EventManager::Participant::_subscribe(std::uint32_t type)
|
||||
{
|
||||
if (manager_ == nullptr)
|
||||
{
|
||||
throw std::runtime_error("no event manager set yet");
|
||||
}
|
||||
manager_->subscribe(type, shared_from_this());
|
||||
}
|
||||
|
||||
void EventManager::Participant::_unsubscribe(std::uint32_t type)
|
||||
{
|
||||
if (manager_ == nullptr)
|
||||
{
|
||||
throw std::runtime_error("no event manager set yet");
|
||||
}
|
||||
manager_->unsubscribe(type, shared_from_this());
|
||||
}
|
||||
|
||||
void EventManager::Participant::_unsubscribe()
|
||||
{
|
||||
if (manager_ == nullptr)
|
||||
{
|
||||
throw std::runtime_error("no event manager set yet");
|
||||
}
|
||||
manager_->unsubscribe(shared_from_this());
|
||||
}
|
||||
|
||||
void EventManager::Participant::_emit(std::shared_ptr<EventManager::Event> event)
|
||||
{
|
||||
if (manager_ == nullptr)
|
||||
{
|
||||
throw std::runtime_error("no event manager set yet");
|
||||
}
|
||||
event->emitter(shared_from_this());
|
||||
manager_->emit(event);
|
||||
}
|
164
tests/test_basic.cpp
Normal file
164
tests/test_basic.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
* This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
*/
|
||||
|
||||
/** @file */
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
#include <EventManager/Event.hpp>
|
||||
#include <EventManager/Manager.hpp>
|
||||
#include <EventManager/Participant.hpp>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
|
||||
|
||||
const static std::uint32_t TEST_EVENT0 = 10;
|
||||
const static std::uint32_t TEST_EVENT1 = 20;
|
||||
|
||||
class myParticipant : public EventManager::Participant
|
||||
{
|
||||
private:
|
||||
bool receivedEvent_;
|
||||
|
||||
std::uint32_t eventType_;
|
||||
|
||||
std::uint32_t id_;
|
||||
|
||||
void shutdown_() {
|
||||
_unsubscribe();
|
||||
}
|
||||
|
||||
void schedule_() {
|
||||
std::shared_ptr<EventManager::Event> event = nullptr;
|
||||
|
||||
_lockQueue();
|
||||
if (_hasEvents())
|
||||
{
|
||||
event = _fetchEvent();
|
||||
}
|
||||
_unlockQueue();
|
||||
if (event == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->type() == EventManager::EVENT_TYPE_SHUTDOWN)
|
||||
{
|
||||
shutdown_();
|
||||
}
|
||||
else if (event->type() == eventType_)
|
||||
{
|
||||
receivedEvent_=true;
|
||||
}
|
||||
}
|
||||
public:
|
||||
myParticipant(std::uint32_t id,std::uint32_t eventType) : EventManager::Participant()
|
||||
{
|
||||
id_=id;
|
||||
receivedEvent_=false;
|
||||
eventType_=eventType;
|
||||
|
||||
}
|
||||
|
||||
bool eventReceived() const { return receivedEvent_;}
|
||||
|
||||
void init() {
|
||||
_subscribe(eventType_);
|
||||
_enableScheduling();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
SCENARIO("Basic Usage of EventManager", "[Manager]")
|
||||
{
|
||||
GIVEN("an EventManager::Manager and two participants")
|
||||
{
|
||||
|
||||
std::shared_ptr<EventManager::Manager> manager;
|
||||
REQUIRE_NOTHROW([&]()
|
||||
{
|
||||
manager = std::make_shared<EventManager::Manager>();
|
||||
}());
|
||||
|
||||
REQUIRE(manager->empty() == true);
|
||||
|
||||
std::shared_ptr<myParticipant> participant0;
|
||||
REQUIRE_NOTHROW([&]()
|
||||
{
|
||||
participant0 = std::make_shared<myParticipant>(0,TEST_EVENT0);
|
||||
participant0->setManager(manager);
|
||||
participant0->init();
|
||||
}());
|
||||
|
||||
REQUIRE(manager->empty() == false);
|
||||
|
||||
std::shared_ptr<myParticipant> participant1;
|
||||
REQUIRE_NOTHROW([&]()
|
||||
{
|
||||
participant1 = std::make_shared<myParticipant>(1,TEST_EVENT1);
|
||||
participant1->setManager(manager);
|
||||
participant1->init();
|
||||
}());
|
||||
|
||||
REQUIRE(manager->empty() == false);
|
||||
|
||||
REQUIRE_NOTHROW([&]()
|
||||
{
|
||||
manager->start();
|
||||
}());
|
||||
|
||||
REQUIRE(manager->isRunning() == true);
|
||||
|
||||
WHEN("emitting shutdown event")
|
||||
{
|
||||
std::shared_ptr<EventManager::Event> shutdown = std::make_shared<EventManager::Event>(EventManager::EVENT_TYPE_SHUTDOWN);
|
||||
|
||||
manager->emit(shutdown);
|
||||
manager->waitEmpty(3000);
|
||||
|
||||
|
||||
THEN("participants are shutting down")
|
||||
{
|
||||
REQUIRE(manager->empty() == true);
|
||||
|
||||
REQUIRE_NOTHROW([&]()
|
||||
{
|
||||
manager->stop();
|
||||
}());
|
||||
|
||||
REQUIRE(manager->isRunning() == false);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("emitting events event")
|
||||
{
|
||||
std::shared_ptr<EventManager::Event> shutdown = std::make_shared<EventManager::Event>(EventManager::EVENT_TYPE_SHUTDOWN);
|
||||
std::shared_ptr<EventManager::Event> e0 = std::make_shared<EventManager::Event>(TEST_EVENT0);
|
||||
std::shared_ptr<EventManager::Event> e1 = std::make_shared<EventManager::Event>(TEST_EVENT1);
|
||||
manager->emit(e0);
|
||||
manager->emit(e1);
|
||||
manager->emit(shutdown);
|
||||
manager->waitEmpty(3000);
|
||||
|
||||
|
||||
THEN("participants recevied events and are shutting down")
|
||||
{
|
||||
REQUIRE(manager->empty() == true);
|
||||
REQUIRE(participant0->eventReceived());
|
||||
REQUIRE(participant1->eventReceived());
|
||||
|
||||
REQUIRE_NOTHROW([&]()
|
||||
{
|
||||
manager->stop();
|
||||
}());
|
||||
|
||||
REQUIRE(manager->isRunning() == false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
tests/test_event.cpp
Normal file
55
tests/test_event.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Dominik Meyer <dmeyer@federationhq.de>
|
||||
* This file is part of the EventManager distribution hosted at https://gitea.federationhq.de/byterazor/EventManager.git
|
||||
*/
|
||||
|
||||
/** @file */
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
#include <EventManager/Event.hpp>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
|
||||
SCENARIO("Use Event Class", "[Event]")
|
||||
{
|
||||
GIVEN("nothing")
|
||||
{
|
||||
WHEN("creating an Event from scratch")
|
||||
{
|
||||
std::unique_ptr<EventManager::Event> e = std::make_unique<EventManager::Event>(10);
|
||||
|
||||
THEN("the attributes can be correctly fetched")
|
||||
{
|
||||
REQUIRE(e->id() >= std::numeric_limits<std::uint64_t>::min());
|
||||
REQUIRE(e->id() <= std::numeric_limits<std::uint64_t>::max());
|
||||
REQUIRE(e->isResponse() == false);
|
||||
REQUIRE_THROWS([&]()
|
||||
{
|
||||
e->responseId();
|
||||
}());
|
||||
}
|
||||
}
|
||||
WHEN("creating an response Event")
|
||||
{
|
||||
std::unique_ptr<EventManager::Event> e = std::make_unique<EventManager::Event>(10);
|
||||
std::unique_ptr<EventManager::Event> r = std::make_unique<EventManager::Event>(10, *e);
|
||||
|
||||
THEN("the attributes can be correctly fetched")
|
||||
{
|
||||
REQUIRE(r->id() >= std::numeric_limits<std::uint64_t>::min());
|
||||
REQUIRE(r->id() <= std::numeric_limits<std::uint64_t>::max());
|
||||
REQUIRE(r->isResponse() == true);
|
||||
std::uint64_t rid=0;
|
||||
REQUIRE_NOTHROW([&]()
|
||||
{
|
||||
rid=r->responseId();
|
||||
}());
|
||||
REQUIRE(rid == e->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user