Skip to content

Commit

Permalink
Development/iptestadministrator (#1704)
Browse files Browse the repository at this point in the history
* [Tests/unit] : Do not depend on 'IPTestAdministrator' if not used

* [Tests/unit/tests] : Cherry pick 'test_iptestmanager' from development/namespaces

* [Tests/unit / Tests/unit/tests] : Improve synchronization usage of 'IPTestAdministrator'

* [core/IPCChannel] : cherry-pick from 'development/ipcchannel_dangling_handlers'

* Tests/unit/core] : align tests with '957977381dfa8137f1475131622390ebed2bdcf7'

* [Tests/unit] : Improve synchronization with premature signalling

* [Tests/unit] : Add test cases to 'Tests/unit/tests/test_iptestmanager.cpp'

* [Tests/unit/core] : align tests with '346fb6ec2a0da5058f7a581190e63c7cb61d929c'

Including various improvements for some test.

* [Tests/unit/core] : amend '7c9a286d1398de9f2b470b02bb58596120f0d8c9'

* [Tests/core/unit] : cherry pick from 'development/messageunit'

* [Tests/unit/core] : Use 'IPTestAdministrator' for 'PopMessageShouldReturnLastPushedMessageInOtherProcess' in test_message_unit'

* [Tests/unit/IPTestAdministrator] : Try to prevent to leak shared memory descriptors

* Revert "[core/IPCChannel] : cherry-pick from 'development/ipcchannel_dangling_handlers'"

This reverts commit 8bc4c8a.

* [Tests/unit/core] : disable 'test_ipc'

---------

Co-authored-by: MFransen69 <[email protected]>
  • Loading branch information
msieben and MFransen69 committed Aug 7, 2024
1 parent ca7ca3e commit d91261d
Show file tree
Hide file tree
Showing 22 changed files with 2,014 additions and 1,508 deletions.
370 changes: 167 additions & 203 deletions Tests/unit/IPTestAdministrator.cpp

Large diffs are not rendered by default.

70 changes: 35 additions & 35 deletions Tests/unit/IPTestAdministrator.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,51 +21,51 @@

#include <string>
#include <time.h>
#include <atomic>
#include <functional>

#ifndef MODULE_NAME
#include "Module.h"
#endif

#include <core/core.h>

#ifndef __LINUX__
static_assert(false, "Only LINUX is supported");
#endif

class IPTestAdministrator
{
private:
static constexpr uint32_t MaxWaitTime = 2; // In seconds
public :

using Callback = std::function<void (IPTestAdministrator&)>;

IPTestAdministrator(Callback /* executed by parent */, Callback /* executed by child */, const uint32_t initHandshakeValue, const uint32_t waitTime /* seconds */);
~IPTestAdministrator();

public:
typedef void (*OtherSideMain)(IPTestAdministrator & testAdmin);
IPTestAdministrator(const IPTestAdministrator&) = delete;
const IPTestAdministrator& operator=(const IPTestAdministrator&) = delete;

IPTestAdministrator(OtherSideMain otherSideMain, const uint32_t waitTime = MaxWaitTime);
IPTestAdministrator(OtherSideMain otherSideMain, void* data, const uint32_t waitTime = MaxWaitTime);
~IPTestAdministrator();
uint32_t Wait(uint32_t expectedHandshakeValue) const;
uint32_t Signal(uint32_t expectedNextHandshakeValue, uint8_t maxRetries = 0);

void ForkChildProcess(OtherSideMain otherSideMain);
// Method to sync the two test processes.
bool Sync(const std::string & str);
void WaitForChildCompletion();
uint32_t WaitTimeDivisor() const {
return _waitTimeDivisor;
}

void* Data() { return m_data; }
private:
static const uint32_t m_messageBufferSize = 1024;
private :

struct SharedData
{
pthread_mutex_t m_stateMutex; // Guards state (are we first or second?)
pthread_cond_t m_waitingForSecondCond; // Used to wait for second
pthread_mutex_t m_waitingForSecondCondMutex;
bool m_waitingForOther; // whether we are waiting for the other side or not
bool m_messageTheSame; // whether message comparison was a success
char m_message[m_messageBufferSize]; // Expected message string
bool m_backToNormal;
pthread_cond_t m_waitingForNormalCond; // To wait for first to restore state to normal
pthread_mutex_t m_waitingForNormalCondMutex;
};
struct SharedData
{
// std::atomic integral> has standard layout!
// A pointer may be converted to a pointer of the first non-static data element with reinterpret_cast
std::atomic<uint32_t> handshakeValue;
};

SharedData * m_sharedData;
pid_t m_childPid; // Set if we are parent processs.
void* m_data;
uint32_t m_maxWaitTime; // In seconds.
constexpr static uint32_t _waitTimeDivisor = 10;

const char * GetProcessName() const;
void TimedLock(pthread_mutex_t * mutex, const std::string & str);
void TimedWait(pthread_cond_t * cond, pthread_mutex_t * mutex, const std::string & str);

void FillTimeOut(timespec & timeSpec);
SharedData* _sharedData;
int _shm_id;
pid_t _pid;
uint32_t _waitTime; // Seconds
};
75 changes: 59 additions & 16 deletions Tests/unit/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

set(TEST_RUNNER_NAME "Thunder_test_core")



if(LINUX)
# IPTestAdministrator only supported on LINUX platform
add_executable(${TEST_RUNNER_NAME}
../IPTestAdministrator.cpp
#test_cyclicbuffer.cpp
Expand All @@ -28,12 +28,12 @@ add_executable(${TEST_RUNNER_NAME}
test_doorbell.cpp
test_enumerate.cpp
test_event.cpp
test_hex2strserialization.cpp
test_filesystem.cpp
test_frametype.cpp
test_hash.cpp
test_hex2strserialization.cpp
#test_ipc.cpp
test_ipcclient.cpp
test_ipc.cpp
test_iso639.cpp
test_iterator.cpp
test_jsonparser.cpp
Expand Down Expand Up @@ -79,20 +79,63 @@ add_executable(${TEST_RUNNER_NAME}
test_websockettext.cpp
test_workerpool.cpp
test_xgetopt.cpp
test_message_dispatcher.cpp
)
#[[ if(MESSAGING)
target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp)
target_link_libraries(${TEST_RUNNER_NAME}
ThunderMessaging
)
#[[
target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp)
target_link_libraries(${TEST_RUNNER_NAME}
ThunderMessaging
)
]]
else()
target_sources(${TEST_RUNNER_NAME} PRIVATE test_tracing.cpp)
target_link_libraries(${TEST_RUNNER_NAME}
ThunderTracing
)
endif() ]]
add_executable(${TEST_RUNNER_NAME}
test_databuffer.cpp
test_dataelement.cpp
test_dataelementfile.cpp
test_enumerate.cpp
test_event.cpp
test_filesystem.cpp
test_frametype.cpp
test_hash.cpp
test_hex2strserialization.cpp
test_iso639.cpp
test_iterator.cpp
test_jsonparser.cpp
test_keyvalue.cpp
test_library.cpp
test_lockablecontainer.cpp
test_measurementtype.cpp
test_memberavailability.cpp
# test_message_dispatcher.cpp
test_messageException.cpp
test_networkinfo.cpp
test_nodeid.cpp
test_numbertype.cpp
test_optional.cpp
test_parser.cpp
test_portability.cpp
test_processinfo.cpp
test_queue.cpp
test_rangetype.cpp
test_readwritelock.cpp
test_rectangle.cpp
test_semaphore.cpp
test_singleton.cpp
test_statetrigger.cpp
test_stopwatch.cpp
test_synchronize.cpp
test_systeminfo.cpp
test_textfragment.cpp
test_textreader.cpp
test_thread.cpp
test_threadpool.cpp
test_time.cpp
test_timer.cpp
test_tristate.cpp
#test_valuerecorder.cpp
test_workerpool.cpp
test_xgetopt.cpp
)
endif()

set_source_files_properties(test_systeminfo.cpp PROPERTIES COMPILE_OPTIONS "-fexceptions")

Expand Down
8 changes: 4 additions & 4 deletions Tests/unit/core/test_cyclicbuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
* limitations under the License.
*/

#ifdef __APPLE__
#include <time.h>
#endif

#include <gtest/gtest.h>

#ifndef MODULE_NAME
Expand All @@ -27,10 +31,6 @@

#include "../IPTestAdministrator.h"

#ifdef __APPLE__
#include <time.h>
#endif

namespace Thunder {
namespace Tests {
namespace Core {
Expand Down
103 changes: 58 additions & 45 deletions Tests/unit/core/test_doorbell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,74 +33,87 @@ namespace Core {

TEST(Core_DoorBell, simpleSet)
{
std::string fileName {"/tmp/doorbell01"};
auto lambdaFunc = [fileName] (IPTestAdministrator & testAdmin) {
constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000;
constexpr uint8_t maxRetries = 1;

const std::string fileName {"/tmp/doorbell01"};

IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) {
::Thunder::Core::DoorBell doorBell(fileName.c_str());

EXPECT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE);
if (doorBell.Wait(::Thunder::Core::infinite) == ::Thunder::Core::ERROR_NONE) {
doorBell.Acknowledge();
testAdmin.Sync("First ring");
}

EXPECT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE);
if (doorBell.Wait(::Thunder::Core::infinite) == ::Thunder::Core::ERROR_NONE) {
doorBell.Acknowledge();
testAdmin.Sync("Second ring");
}
ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE);
doorBell.Acknowledge();

ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE);

ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE);
doorBell.Acknowledge();

ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE);

doorBell.Relinquish();
};

static std::function<void (IPTestAdministrator&)> lambdaVar = lambdaFunc;

IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); };
IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) {
// a small delay so the child can be set up
SleepMs(maxInitTime);

IPTestAdministrator testAdmin(otherSide);
{
::Thunder::Core::DoorBell doorBell(fileName.c_str());
::SleepMs(10);

doorBell.Ring();
testAdmin.Sync("First ring");
ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE);

doorBell.Ring();
testAdmin.Sync("Second ring");
}
ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE);
};

IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime);

// Code after this line is executed by both parent and child

::Thunder::Core::Singleton::Dispose();
}

TEST(Core_DoorBell, simpleSetReversed)
{

constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000;
constexpr uint8_t maxRetries = 1;

std::string fileName {"/tmp/doorbell02"};
auto lambdaFunc = [fileName] (IPTestAdministrator & testAdmin) {
const std::string fileName {"/tmp/doorbell02"};

IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) {
::Thunder::Core::DoorBell doorBell(fileName.c_str());
::SleepMs(10);

// A small delay so the child can be set up
SleepMs(maxInitTime);

doorBell.Ring();
testAdmin.Sync("First ring");
ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE);

doorBell.Ring();
testAdmin.Sync("Second ring");
ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE);
};

static std::function<void (IPTestAdministrator&)> lambdaVar = lambdaFunc;
IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) {
::Thunder::Core::DoorBell doorBell(fileName.c_str());

IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); };
ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE);
doorBell.Acknowledge();

ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE);

ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE);
doorBell.Acknowledge();

ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE);

IPTestAdministrator testAdmin(otherSide);
{
::Thunder::Core::DoorBell doorBell(fileName.c_str());
EXPECT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE);
if (doorBell.Wait(::Thunder::Core::infinite) == ::Thunder::Core::ERROR_NONE) {
doorBell.Acknowledge();
testAdmin.Sync("First ring");
}

EXPECT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE);
if (doorBell.Wait(::Thunder::Core::infinite) == ::Thunder::Core::ERROR_NONE) {
doorBell.Acknowledge();
testAdmin.Sync("Second ring");
}
doorBell.Relinquish();
}
};

IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime);

// Code after this line is executed by both parent and child

::Thunder::Core::Singleton::Dispose();
}

Expand Down
Loading

0 comments on commit d91261d

Please sign in to comment.